diff --git a/.gitignore b/.gitignore index 53a8f108dcb..bcf4fe6f9e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ +#bower deps +**/wwwroot/lib/ bin/ obj/ .idea/ latest/ +node_modules/ /env-vars.bat *.suo #ignore thumbnails created by windows @@ -38,20 +41,30 @@ build/*.dll *.user *.userprefs packages/ +.vs/ +.vscode/ +*.lock.json +*.nuget.props +*.nuget.targets release/latest/ *.nupkg release/* +requestlogs/ + +*.DS_Store -src/ServiceStack.MonoTouch/.DS_Store NuGet/ + build/ -*.DS_Store *.dotCover - -src/ServiceStack/Properties/Resources.resources - -src/ServiceStack.userprefs - -src/ServiceStack.userprefs + +*.DotSettings +*.DotSettings.user + +src/ServiceStack/Properties/Resources.resources + +src/ServiceStack.userprefs +*.xap +src/ServiceStack.sln.DotSettings diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..f0466547e12 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +## Contributor License Agreement + +* Please sign the [Contributor License Agreement](https://docs.google.com/forms/d/16Op0fmKaqYtxGL4sg7w_g-cXXyCoWjzppgkuqzOeKyk/viewform) in order to have your changes merged. + +See the [Contributing Wiki](https://github.com/ServiceStack/ServiceStack/wiki/Contributing) to learn how you can Contribute! diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index def59fc2258..5e9b96594eb 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -145,7 +145,7 @@ - [ecgan](https://github.com/ecgan) (Gan Eng Chin) - [its-tyson](https://github.com/its-tyson) (Tyson Stolarski) - [tischlda](https://github.com/tischlda) (David Tischler) - - [connectassist](https://github.com/connectassist) (Carl Healy) + - [tyst](https://github.com/tyst) (Carl Healy) - [starteleport](https://github.com/starteleport) - [jfoshee](https://github.com/jfoshee) (Jacob Foshee) - [nardin](https://github.com/nardin) (Mamaev Michail) @@ -208,7 +208,7 @@ - [ddotlic](https://github.com/ddotlic) (Drazen Dotlic) - [chrismcv](https://github.com/chrismcv) (Chris McVittie) - [marcioalthmann](https://github.com/marcioalthmann) (Márcio Fábio Althmann) - - [mmertsock](https://github.com/mmertsock) + - [mmertsock](https://github.com/mmertsock) (Mike Mertsock) - [johnkamau](https://github.com/johnkamau) (John Kamau) - [uhaciogullari](https://github.com/uhaciogullari) (Ufuk Hacıoğulları) - [davybrion](https://github.com/davybrion) (Davy Brion) @@ -222,4 +222,88 @@ - [jeremy-bridges](https://github.com/jeremy-bridges) (Jeremy Bridges) - [andreabalducci](https://github.com/andreabalducci) (Andrea Balducci) - [robertthegrey](https://github.com/RobertTheGrey) (Robert Greyling) - \ No newline at end of file + - [robertbeal](https://github.com/robertbeal) (Robert Beal) + - [improvedk](https://github.com/improvedk) (Mark Rasmussen) + - [foresterh](https://github.com/foresterh) (Jamie Houston) + - [peterkahl](https://github.com/peterkahl) (Peter Kahl) + - [helgel](https://github.com/helgel) + - [anthonycarl](https://github.com/anthonycarl) (Anthony Carl) + - [mrjul](https://github.com/mrjul) (Julien Lebosquain) + - [pwhe23](https://github.com/pwhe23) (Paul Wheeler) + - [aleksd](https://github.com/aleksd) + - [miketrebilcock](https://github.com/miketrebilcock) (Mike Trebilcock) + - [markwoodhall](https://github.com/markwoodhall) (Mark Woodhall) + - [theonlylawislove](https://github.com/theonlylawislove) (Paul Knopf) + - [callumvass](https://github.com/callumvass) (Callum Vass) + - [bpruitt-goddard](https://github.com/bpruitt-goddard) + - [gregpakes](https://github.com/gregpakes) (Greg Pakes) + - [caspiancanuck](https://github.com/caspiancanuck) (Caspian Canuck) + - [merwer](https://github.com/merwer) + - [pavelsavara](https://github.com/pavelsavara) (Pavel Savara) + - [markwalls](https://github.com/markwalls) (Mark Walls) + - [prasannavl](https://github.com/prasannavl) (Prasanna Loganathar) + - [wilfrem](https://github.com/wilfrem) + - [emiba](https://github.com/emiba) + - [lucky-ly](https://github.com/lucky-ly) (Dmitry Svechnikov) + - [hhandoko](https://github.com/hhandoko) (Herdy Handoko) + - [datawingsoftware](https://github.com/datawingsoftware) + - [tal952](https://github.com/tal952) + - [bretternst](https://github.com/bretternst) + - [kevinhoward](https://github.com/kevinhoward) (Kevin Howard) + - [mattbutton](https://github.com/mattbutton) (Matt Button) + - [torbenrahbekkoch](https://github.com/torbenrahbekkoch) (Torben Rahbek Koch) + - [pilotmartin](https://github.com/pilotmartin) (Pilot Martin) + - [catlion](https://github.com/catlion) + - [tstade](https://github.com/tstade) (Toft Stade) + - [niltz](https://github.com/niltz) (Jeff Sawatzky) + - [nhalm](https://github.com/nhalm) + - [fhurta](https://github.com/fhurta) (Filip Hurta) + - [discobanan](https://github.com/discobanan) + - [x-cray](https://github.com/x-cray) + - [jeremistadler](https://github.com/jeremistadler) (Jeremi Stadler) + - [bangbite](https://github.com/bangbite) + - [felipesabino](https://github.com/felipesabino) (Felipe Sabino) + - [xelom](https://github.com/xelom) (Arıl Bozoluk) + - [shiweichuan](https://github.com/shiweichuan) (Weichuan Shi) + - [kojoru](https://github.com/kojoru) (Konstantin Yakushev) + - [eddiegroves](https://github.com/eddiegroves) (Eddie Groves) + - [fetters5](https://github.com/fetters5) + - [rcollette](https://github.com/rcollette) (Richard Collette) + - [urihendler](https://github.com/urihendler) (Uri Hendler) + - [laurencee](https://github.com/laurencee) (Laurence Evans) + - [m-andrew-albright](https://github.com/m-andrew-albright) (Andrew Albright) + - [lee337](https://github.com/lee337) (Lee Venkatsamy) + - [kaza](https://github.com/kaza) + - [mishfit](https://github.com/mishfit) + - [rfvgyhn](https://github.com/rfvgyhn) (Chris) + - [augustoproiete](https://github.com/augustoproiete) (C. Augusto Proiete) + - [sjuxax](https://github.com/sjuxax) (Jeff Cook) + - [madaleno](https://github.com/madaleno) (Luis Madaleno) + - [yavosh](https://github.com/yavosh) (Yavor Shahpasov) + - [fvoncina](https://github.com/fvoncina) (Facundo Voncina) + - [devrios](https://github.com/devrios) (Dev Rios) + - [bfkelsey](https://github.com/bfkelsey) (Ben Kelsey) + - [maksimenko](https://github.com/maksimenko) + - [dixon](https://github.com/dixon) (Jarrod Dixon) + - [kal](https://github.com/kal) (Kal Ahmed) + - [mhanney](https://github.com/mhanney) (Michael Hanney) + - [bcms](https://github.com/bcms) + - [mgravell](https://github.com/mgravell) (Marc Gravell) + - [lafama](https://github.com/lafama) (Denis Ndwiga) + - [jamesgroat](https://github.com/jamesgroat) (James Groat) + - [jamesearl](https://github.com/jamesearl) (James Cunningham) + - [remkoboschker](https://github.com/remkoboschker) (Remko Boschker) + - [shelakel](https://github.com/shelakel) + - [schmidt4brains](https://github.com/schmidt4brains) (Doug Schmidt) + - [joplaal](https://github.com/joplaal) + - [aifdsc](https://github.com/aifdsc) (Stephan Desmoulin) + - [nicklarsen](https://github.com/nicklarsen) (NickLarsen) + - [et1975](https://github.com/et1975) (Eugene Tolmachev) + - [barambani](https://github.com/barambani) + - [nhalm](https://github.com/et1975) + - [scottmcarthur](https://github.com/scottmcarthur) (Scott McArthur) + - [siliconrob](https://github.com/Siliconrob) (Robin Michael) + + + + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index c08e97186e5..00000000000 --- a/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2007-2013, Demis Bellot, ServiceStack. -http://www.servicestack.net -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 the ServiceStack nor the - names of its 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 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/NuGet.Config b/NuGet.Config new file mode 100644 index 00000000000..8c1ce21b6f6 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/NuGet/NuGet.exe b/NuGet/NuGet.exe deleted file mode 100644 index c296edf177f..00000000000 Binary files a/NuGet/NuGet.exe and /dev/null differ diff --git a/NuGet/NuGetPack.cmd b/NuGet/NuGetPack.cmd deleted file mode 100644 index 3e44ec5c8c4..00000000000 --- a/NuGet/NuGetPack.cmd +++ /dev/null @@ -1,13 +0,0 @@ -nuget pack ServiceStack\servicestack.nuspec -symbols -nuget pack ServiceStack.Common\servicestack.common.nuspec -symbols -nuget pack ServiceStack.Mvc\servicestack.mvc.nuspec -symbols -nuget pack ServiceStack.Api.Swagger\servicestack.api.swagger.nuspec -symbols -nuget pack ServiceStack.Razor\servicestack.razor.nuspec -symbols - -nuget pack ServiceStack.Host.AspNet\servicestack.host.aspnet.nuspec -nuget pack ServiceStack.Host.Mvc\servicestack.host.mvc.nuspec -nuget pack ServiceStack.Client.Silverlight\servicestack.client.silverlight.nuspec -nuget pack ServiceStack.Authentication.OpenId\servicestack.authentication.openid.nuspec -symbols -nuget pack ServiceStack.Plugins.ProtoBuf\servicestack.plugins.protobuf.nuspec -symbols -nuget pack ServiceStack.Plugins.MsgPack\servicestack.plugins.msgpack.nuspec -symbols - diff --git a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/LICENSE b/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/LICENSE deleted file mode 100644 index 9129770f4c5..00000000000 --- a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/LICENSE +++ /dev/null @@ -1,5 +0,0 @@ -Copyright 2011-2012 Wordnik, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. \ No newline at end of file diff --git a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/css/screen.css b/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/css/screen.css deleted file mode 100644 index 06050e760d9..00000000000 --- a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/css/screen.css +++ /dev/null @@ -1,1759 +0,0 @@ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -body { - line-height: 1; -} - -ol, ul { - list-style: none; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -caption, th, td { - text-align: left; - font-weight: normal; - vertical-align: middle; -} - -q, blockquote { - quotes: none; -} - -q:before, q:after, blockquote:before, blockquote:after { - content: ""; - content: none; -} - -a img { - border: none; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary { - display: block; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - text-decoration: none; -} - -h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover { - text-decoration: underline; -} - -h1 span.divider, h2 span.divider, h3 span.divider, h4 span.divider, h5 span.divider, h6 span.divider { - color: #aaaaaa; -} - -h1 { - color: black; - font-size: 1.5em; - line-height: 1.3em; - padding: 10px 0 10px 0; - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -h2 { - color: black; - font-size: 1.3em; - padding: 10px 0 10px 0; -} - -h2 a { - color: black; -} - -h2 span.sub { - font-size: 0.7em; - color: #999999; - font-style: italic; -} - -h2 span.sub a { - color: #777777; -} - -h3 { - color: black; - font-size: 1.1em; - padding: 10px 0 10px 0; -} - -.heading_with_menu { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -.heading_with_menu h1, .heading_with_menu h2, .heading_with_menu h3, .heading_with_menu h4, .heading_with_menu h5, .heading_with_menu h6 { - display: block; - clear: none; - float: left; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - width: 60%; -} - -.heading_with_menu ul { - display: block; - clear: none; - float: right; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - margin-top: 10px; -} - -input.parameter { - width: 300px; - border: 1px solid #aaa; -} - -.body-textarea { - width: 300px; - height: 100px; - border: 1px solid #aaa; -} - -p { - line-height: 1.4em; - padding: 0 0 10px; - color: #333333; -} - -ol { - margin: 0px 0 10px; - padding: 0 0 0 18px; - list-style-type: decimal; -} - -ol li { - padding: 5px 0px; - font-size: 0.9em; - color: #333333; -} - -.markdown h3 { - color: #547f00; -} - -.markdown h4 { - color: #666666; -} - -.markdown pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #fcf6db; - border: 1px solid #e5e0c6; - padding: 10px; - margin: 0 0 10px 0; -} - -.markdown pre code { - line-height: 1.6em; -} - -.markdown p code, .markdown li code { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #f0f0f0; - color: black; - padding: 1px 3px; -} - -.markdown ol, .markdown ul { - font-family: "Droid Sans", sans-serif; - margin: 5px 0 10px; - padding: 0 0 0 18px; - list-style-type: disc; -} - -.markdown ol li, .markdown ul li { - padding: 3px 0px; - line-height: 1.4em; - color: #333333; -} - -div.gist { - margin: 20px 0 25px 0 !important; -} - -p.big, div.big p { - font-size: 1em; - margin-bottom: 10px; -} - -span.weak { - color: #666666; -} - -span.blank, span.empty { - color: #888888; - font-style: italic; -} - -a { - color: #547f00; -} - -b, strong { - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -.code { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; -} - -pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #fcf6db; - border: 1px solid #e5e0c6; - padding: 10px; -} - -pre code { - line-height: 1.6em; -} - -.required { - font-weight: bold; -} - -table.fullwidth { - width: 100%; -} - -table thead tr th { - padding: 5px; - font-size: 0.9em; - color: #666666; - border-bottom: 1px solid #999999; -} - -table tbody tr.offset { - background-color: #f5f5f5; -} - -table tbody tr td { - padding: 6px; - font-size: 0.9em; - border-bottom: 1px solid #cccccc; - vertical-align: top; - line-height: 1.3em; -} - -table tbody tr:last-child td { - border-bottom: none; -} - -table tbody tr.offset { - background-color: #f0f0f0; -} - -form.form_box { - background-color: #ebf3f9; - border: 1px solid #c3d9ec; - padding: 10px; -} - -form.form_box label { - color: #0f6ab4 !important; -} - -form.form_box input[type=submit] { - display: block; - padding: 10px; -} - -form.form_box p { - font-size: 0.9em; - padding: 0 0 15px; - color: #7e7b6d; -} - -form.form_box p a { - color: #646257; -} - -form.form_box p strong { - color: black; -} - -form.form_box p.weak { - font-size: 0.8em; -} - -form.formtastic fieldset.inputs ol li p.inline-hints { - margin-left: 0; - font-style: italic; - font-size: 0.9em; - margin: 0; -} - -form.formtastic fieldset.inputs ol li label { - display: block; - clear: both; - width: auto; - padding: 0 0 3px; - color: #666666; -} - -form.formtastic fieldset.inputs ol li label abbr { - padding-left: 3px; - color: #888888; -} - -form.formtastic fieldset.inputs ol li.required label { - color: black; -} - -form.formtastic fieldset.inputs ol li.string input, form.formtastic fieldset.inputs ol li.url input, form.formtastic fieldset.inputs ol li.numeric input { - display: block; - padding: 4px; - width: auto; - clear: both; -} - -form.formtastic fieldset.inputs ol li.string input.title, form.formtastic fieldset.inputs ol li.url input.title, form.formtastic fieldset.inputs ol li.numeric input.title { - font-size: 1.3em; -} - -form.formtastic fieldset.inputs ol li.text textarea { - font-family: "Droid Sans", sans-serif; - height: 250px; - padding: 4px; - display: block; - clear: both; -} - -form.formtastic fieldset.inputs ol li.select select { - display: block; - clear: both; -} - -form.formtastic fieldset.inputs ol li.boolean { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -form.formtastic fieldset.inputs ol li.boolean input { - display: block; - float: left; - clear: none; - margin: 0 5px 0 0; -} - -form.formtastic fieldset.inputs ol li.boolean label { - display: block; - float: left; - clear: none; - margin: 0; - padding: 0; -} - -form.formtastic fieldset.buttons { - margin: 0; - padding: 0; -} - -form.fullwidth ol li.string input, form.fullwidth ol li.url input, form.fullwidth ol li.text textarea, form.fullwidth ol li.numeric input { - width: 500px !important; -} - -body { - font-family: "Droid Sans", sans-serif; -} - -body #content_message { - margin: 10px 15px; - font-style: italic; - color: #999999; -} - -body #header { - background-color: #89bf04; - padding: 14px; -} - -body #header a#logo { - font-size: 1.5em; - font-weight: bold; - text-decoration: none; - background: transparent url(../images/logo_small.png) no-repeat left center; - padding: 20px 0 20px 40px; - color: white; -} - -body #header form#api_selector { - display: block; - clear: none; - float: right; -} - -body #header form#api_selector .input { - display: block; - clear: none; - float: left; - margin: 0 10px 0 0; -} - -body #header form#api_selector .input input { - font-size: 0.9em; - padding: 3px; - margin: 0; -} - -body #header form#api_selector .input input#input_baseUrl { - width: 400px; -} - -body #header form#api_selector .input input#input_apiKey { - width: 200px; -} - -body #header form#api_selector .input a#explore { - display: block; - text-decoration: none; - font-weight: bold; - padding: 6px 8px; - font-size: 0.9em; - color: white; - background-color: #547f00; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -o-border-radius: 4px; - -ms-border-radius: 4px; - -khtml-border-radius: 4px; - border-radius: 4px; -} - -body #header form#api_selector .input a#explore:hover { - background-color: #547f00; -} - -body p#colophon { - margin: 0 15px 40px 15px; - padding: 10px 0; - font-size: 0.8em; - border-top: 1px solid #dddddd; - font-family: "Droid Sans", sans-serif; - color: #999999; - font-style: italic; -} - -body p#colophon a { - text-decoration: none; - color: #547f00; -} - -body ul#resources { - font-family: "Droid Sans", sans-serif; - font-size: 0.9em; -} - -body ul#resources li.resource { - border-bottom: 1px solid #dddddd; -} - -body ul#resources li.resource:last-child { - border-bottom: none; -} - -body ul#resources li.resource div.heading { - border: 1px solid transparent; - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource div.heading h2 { - color: #999999; - padding-left: 0; - display: block; - clear: none; - float: left; - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -body ul#resources li.resource div.heading h2 a { - color: #999999; -} - -body ul#resources li.resource div.heading h2 a:hover { - color: black; -} - -body ul#resources li.resource div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 14px 10px 0 0; -} - -body ul#resources li.resource div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource div.heading ul.options li:first-child, body ul#resources li.resource div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource div.heading ul.options li:last-child, body ul#resources li.resource div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource div.heading ul.options li { - color: #666666; - font-size: 0.9em; -} - -body ul#resources li.resource div.heading ul.options li a { - color: #aaaaaa; - text-decoration: none; -} - -body ul#resources li.resource div.heading ul.options li a:hover { - text-decoration: underline; - color: black; -} - -body ul#resources li.resource:hover div.heading h2 a, body ul#resources li.resource.active div.heading h2 a { - color: black; -} - -body ul#resources li.resource:hover div.heading ul.options li a, body ul#resources li.resource.active div.heading ul.options li a { - color: #555555; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #e7f0f7; - border: 1px solid #c3d9ec; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #0f6ab4; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { - border-right-color: #c3d9ec; - color: #0f6ab4; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { - color: #0f6ab4; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { - background-color: #ebf3f9; - border: 1px solid #c3d9ec; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { - color: #0f6ab4; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fa5d2; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #e7f6ec; - border: 1px solid #c3e8d1; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #10a54a; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { - border-right-color: #c3e8d1; - color: #10a54a; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { - color: #10a54a; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { - background-color: #ebf7f0; - border: 1px solid #c3e8d1; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { - color: #10a54a; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fc992; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #f9f2e9; - border: 1px solid #f0e0ca; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #c5862b; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { - border-right-color: #f0e0ca; - color: #c5862b; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { - color: #c5862b; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { - background-color: #faf5ee; - border: 1px solid #f0e0ca; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { - color: #c5862b; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #dcb67f; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #FCE9E3; - border: 1px solid #F5D5C3; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #D38042; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { - border-right-color: #f0cecb; - color: #D38042; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { - color: #D38042; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { - background-color: #faf0ef; - border: 1px solid #f0cecb; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { - color: #D38042; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #F5D5C3; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #dcb67f; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px 0; - padding: 0 0 0 0px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 0 0; - padding: 0; - background-color: #fcffcd; - border: 1px solid black; - border-color: #ffd20f; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #ffd20f; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options { - float: none; - clear: both; - overflow: hidden; - margin: 0; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { - border-right-color: #ffd20f; - color: #ffd20f; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { - color: #ffd20f; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { - background-color: #fcffcd; - border: 1px solid black; - border-color: #ffd20f; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { - color: #ffd20f; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px 0px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header img { - display: block; - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fc992; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.response div.block { - background-color: #fcf6db; - border: 1px solid black; - border-color: #e5e0c6; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #f5e8e8; - border: 1px solid #e8c6c7; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #a41e22; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { - border-right-color: #e8c6c7; - color: #a41e22; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { - color: #a41e22; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { - background-color: #f7eded; - border: 1px solid #e8c6c7; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { - color: #a41e22; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #c8787a; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - - -.model-signature { - font-family: "Droid Sans", sans-serif; - font-size: 1em; - line-height: 1.5em; -} - -.model-signature .description div { - font-size: 0.9em; - line-height: 1.5em; - margin-left: 1em; -} - -.model-signature .description .strong { - font-weight: bold; - color: #000; - font-size: .9em; -} - -.model-signature .description .stronger { - font-weight: bold; - color: #000; -} - -.model-signature .signature-nav a { - text-decoration: none; - color: #AAA; -} - -.model-signature pre { - font-size: .85em; - line-height: 1.2em; - overflow: auto; - max-height: 200px; - cursor: pointer; -} - -.model-signature pre:hover { - background-color: #ffffdd; -} - -.model-signature .snippet small { - font-size: 0.75em; -} - -.model-signature .signature-container { - clear: both; -} - -.model-signature .signature-nav a:hover { - text-decoration: underline; - color: black; -} - -.model-signature .signature-nav .selected { - color: black; - text-decoration: none; -} - -.model-signature ul.signature-nav { - display: block; - margin: 0; - padding: 0; -} - -.model-signature ul.signature-nav li { - float: left; - margin: 0 5px 5px 0; - padding: 2px 5px 2px 0; - border-right: 1px solid #ddd; -} - -.model-signature ul.signature-nav li:last-child { - padding-right: 0; - border-right: none; -} - -.model-signature .propName { - font-weight: bold; -} -.model-signature .propType { - color: #5555aa; -} -.model-signature .propOptKey { - font-style: italic; -} -.model-signature .propOpt { - color: #555; -} - -pre code { - background: none; -} - -.content pre { - font-size: 12px; - margin-top: 5px; - padding: 5px; -} - -.content > .content-type > div > label { - clear: both; - display: block; - color: #0F6AB4; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -.swagger-ui-wrap { - max-width: 960px; - margin-left: auto; - margin-right: auto; -} - -.icon-btn { - cursor: pointer; -} - -#message-bar { - min-height: 30px; - text-align: center; - padding-top: 10px; -} - -.message-success { - color: #89BF04; -} - -.message-fail { - color: #cc0000; -} \ No newline at end of file diff --git a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/images/pet_store_api.png b/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/images/pet_store_api.png deleted file mode 100644 index f9f9cd4aeb3..00000000000 Binary files a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/images/pet_store_api.png and /dev/null differ diff --git a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/images/wordnik_api.png b/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/images/wordnik_api.png deleted file mode 100644 index dca4f1455ac..00000000000 Binary files a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/images/wordnik_api.png and /dev/null differ diff --git a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/index.html b/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/index.html deleted file mode 100644 index 66c6fa23c65..00000000000 --- a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/index.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - Swagger UI - - - - - - - - - - - - - - - - - - - - -
-   -
- -
- -
- - - - diff --git a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/lib/backbone-min.js b/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/lib/backbone-min.js deleted file mode 100644 index c1c0d4fff28..00000000000 --- a/NuGet/ServiceStack.Api.Swagger/content/swagger-ui/lib/backbone-min.js +++ /dev/null @@ -1,38 +0,0 @@ -// Backbone.js 0.9.2 - -// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Backbone may be freely distributed under the MIT license. -// For all details and documentation: -// http://backbonejs.org -(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks= -{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g= -z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent= -{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null== -b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent: -b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)}; -a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error, -h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t(); -return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending= -{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length|| -!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator); -this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c=b))this.iframe=i(' + +
+ +
+
+ +
+ + + diff --git a/src/ServiceStack/modules/ui/docs/RegisterDocs.html b/src/ServiceStack/modules/ui/docs/RegisterDocs.html new file mode 100644 index 00000000000..c4e3422900a --- /dev/null +++ b/src/ServiceStack/modules/ui/docs/RegisterDocs.html @@ -0,0 +1,10 @@ + + diff --git a/src/ServiceStack/modules/ui/index.html b/src/ServiceStack/modules/ui/index.html new file mode 100644 index 00000000000..1331596b44b --- /dev/null +++ b/src/ServiceStack/modules/ui/index.html @@ -0,0 +1,148 @@ + + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + diff --git a/src/ServiceStack/modules/ui/js/appInit.js b/src/ServiceStack/modules/ui/js/appInit.js new file mode 100644 index 00000000000..940153c2f8a --- /dev/null +++ b/src/ServiceStack/modules/ui/js/appInit.js @@ -0,0 +1,71 @@ +/*minify:*/ +//APP.config.debugMode = false +let BASE_URL = lastLeftPart(trimEnd(document.baseURI,'/'),'/') +let bearerToken = null +let authsecret = null +function createClient(fn) { + return new JsonServiceClient(BASE_URL).apply(c => { + c.bearerToken = bearerToken + c.enableAutoRefreshToken = false + if (authsecret) c.headers.set('authsecret', authsecret) + let apiFmt = APP.httpHandlers['ApiHandlers.Json'] + if (apiFmt) + c.basePath = apiFmt.replace('/{Request}', '') + if (fn) fn(c) + }) +} +let client = createClient() +APP.api.operations.forEach(op => { + if (!op.tags) op.tags = [] +}) +let appOps = APP.api.operations.filter(op => !op.request.namespace.startsWith('ServiceStack')) +let appTags = Array.from(new Set(appOps.flatMap(op => op.tags))).sort() +let sideNav = appTags.map(tag => ({ + tag, + expanded: true, + operations: appOps.filter(op => op.tags.indexOf(tag) >= 0) +})) +let ssOps = APP.api.operations.filter(op => op.request.namespace.startsWith('ServiceStack')) +let ssTags = Array.from(new Set(ssOps.flatMap(op => op.tags))).sort() +ssTags.map(tag => ({ + tag, + expanded: true, + operations: ssOps.filter(op => op.tags.indexOf(tag) >= 0) +})).forEach(nav => sideNav.push(nav)) +let other = { + tag: appTags.length > 0 ? 'other' : 'APIs', + expanded: true, + operations: [...appOps, ...ssOps].filter(op => op.tags.length === 0) +} +if (other.operations.length > 0) sideNav.push(other) +let alwaysHideTags = APP.ui.alwaysHideTags || !DEBUG && APP.ui.hideTags +if (alwaysHideTags) { + sideNav = sideNav.filter(group => alwaysHideTags.indexOf(group.tag) < 0) +} +let CACHE = {} +let OpsMap = {} +let TypesMap = {} +let HttpErrors = { 401:'Unauthorized', 403:'Forbidden' } +APP.api.operations.forEach(op => { + OpsMap[op.request.name] = op + TypesMap[op.request.name] = op.request + if (op.response) TypesMap[op.response.name] = op.response +}) +APP.api.types.forEach(type => TypesMap[type.name] = type) +let cleanSrc = src => src.trim(); +function invalidAccessMessage(op, authRoles, authPerms) { + if (authRoles.indexOf('Admin') >= 0) return null + let missingRoles = op.requiredRoles.filter(x => authRoles.indexOf(x) < 0) + if (missingRoles.length > 0) + return `Requires ${missingRoles.map(x => '' + x + '').join(', ')} Role` + (missingRoles.length > 1 ? 's' : '') + let missingPerms = op.requiredPermissions.filter(x => authPerms.indexOf(x) < 0) + if (missingPerms.length > 0) + return `Requires ${missingPerms.map(x => '' + x + '').join(', ')} Permission` + (missingPerms.length > 1 ? 's' : '') + if (missingRoles.length > 0) + return `Requires any ${missingRoles.map(x => '' + x + '').join(', ')} Role` + (missingRoles.length > 1 ? 's' : '') + missingPerms = op.requiresAnyPermission.filter(x => authPerms.indexOf(x) < 0) + if (missingPerms.length > 0) + return `Requires any ${missingPerms.map(x => '' + x + '').join(', ')} Permission` + (missingPerms.length > 1 ? 's' : '') + return null +} +/*:minify*/ diff --git a/src/ServiceStack/modules/ui/js/stores.js b/src/ServiceStack/modules/ui/js/stores.js new file mode 100644 index 00000000000..bb47b9960ea --- /dev/null +++ b/src/ServiceStack/modules/ui/js/stores.js @@ -0,0 +1,275 @@ +/*minify:*/ +App.useTransitions({ sidebar: true }) +let breakpoints = App.useBreakpoints({ + handlers: { + change({ previous, current }) { console.log('breakpoints.change', previous, current) } /*debug*/ + } +}) +let routes = App.usePageRoutes({ + page:'op', + queryKeys:'tab,lang,preview,detailSrc,form,response,body,provider,doc'.split(','), + handlers: { + nav(state) { console.log('nav', state) } /*debug*/ + } +}) +let store = PetiteVue.reactive({ + previewResult: null, + copied: false, + filter: '', + sideNav, + detailSrcResult: {}, + debug: APP.config.debugMode, + api: null, + auth: window.AUTH, + baseUrl: BASE_URL, + get useLang() { return routes.lang || 'csharp' }, + init() { + this.loadDetailSrc() + this.loadLang() + this.loadPreview() + setBodyClass({ page: routes.op }) + }, + get filteredSideNav() { + let filter = op => { + let lowerFilter = this.filter.toLowerCase() + if (op.requiresAuth && !this.debug) + { + if (!this.auth) + return false + if (invalidAccessMessage(op, this.auth.roles, this.auth.permissions)) + return false + } + return !lowerFilter || op.request.name.toLowerCase().indexOf(lowerFilter) >= 0 + } + let ret = this.sideNav.filter(nav => nav.operations.some(filter)) + .map(nav => ({ + ...nav, + operations: nav.operations.filter(filter) + })) + return ret + }, + toggle(tag) { + let nav = this.sideNav.find(x => x.tag === tag) + nav.expanded = !nav.expanded + }, + loadLang() { + if (!this.activeLangSrc) { + let cache = this.langCache() + if (CACHE[cache.url]) { + this.langResult = { cache, result: CACHE[cache.url] } + } else { + this.cachedFetch(cache.url) + .then(src => { + this.langResult = { cache, result: CACHE[cache.url] = cleanSrc(src) } + if (!this.activeLangSrc) { + this.loadLang() + } + }) + } + } + }, + getTypeUrl(types) { return `/types/csharp?IncludeTypes=${types}&WithoutOptions=true&MakeVirtual=false&MakePartial=false&AddServiceStackTypes=true` }, + get previewCache() { + if (routes.preview.startsWith('types.')) { + let types = routes.preview.substring('types.'.length) + return { preview: routes.preview, url: this.getTypeUrl(types), lang:'csharp' } + } + return null + }, + loadPreview() { + if (!this.previewSrc) { + let cache = this.previewCache + if (!cache) return + if (CACHE[cache.url]) { + this.previewResult = { type:'src', ...cache, result: CACHE[cache.url] } + } else { + this.cachedFetch(cache.url) + .then(src => { + this.previewResult = { + type:'src', + ...cache, + result: CACHE[cache.url] = cache.lang ? cleanSrc(src) : src + } + }) + } + } + }, + get previewSrc() { + let r = this.previewResult + if (!r) return '' + return routes.preview === r.preview && r.type === 'src' && r.lang ? r.result : '' + }, + get activeLangSrc() { + let cache = this.langResult && this.langResult.cache + let ret = cache && routes.op === cache.op && this.useLang === cache.lang ? this.langResult.result : null + return ret + }, + loadDetailSrc() { + if (!routes.detailSrc) return + let cache = { url: this.getTypeUrl(routes.detailSrc) } + if (CACHE[cache.url]) { + this.detailSrcResult[cache.url] = { ...cache, result: CACHE[cache.url] } + } else { + this.cachedFetch(cache.url).then(src => { + this.detailSrcResult[cache.url] = { ...cache, result: CACHE[cache.url] = cleanSrc(src) } + }) + } + }, + get activeDetailSrc() { return routes.detailSrc && this.detailSrcResult[this.getTypeUrl(routes.detailSrc)] }, + get op() { + return routes.op ? APP.api.operations.find(op => op.request.name === routes.op) : null + }, + get opName() { return this.op && this.op.request.name }, + get opTabs() { + return this.op + ? { ['API']:'', 'Details':'details', ['Code']:'code' } + : {} + }, + get isServiceStackType() { + return this.op && this.op.request.namespace.startsWith("ServiceStack") + }, + langCache() { + let op = routes.op, lang = this.useLang + return { op, lang, url: `/types/${lang}?IncludeTypes=${op}.*&WithoutOptions=true&MakeVirtual=false&MakePartial=false` + (this.isServiceStackType ? '&AddServiceStackTypes=true' : '') } + }, + cachedFetch(url) { + return new Promise((resolve,reject) => { + let src = CACHE[url] + if (src) { + resolve(src) + } else { + fetch(url) + .then(r => { + if (r.ok) return r.text() + else throw r.statusText + }) + .then(src => { + resolve(CACHE[url] = src) + }) + .catch(e => { + console.error(`fetchCache (${url}):`, e) + reject(e) + }) + } + }) + }, + SignIn() { + return APP.plugins.auth + ? SignIn({ + plugin: APP.plugins.auth, + provider:() => routes.provider, + login:args => this.login(args), + api: () => this.api, + }) + : NoAuth({ message:`${APP.app.serviceName} API Explorer` }) + }, + login(args) { + let provider = routes.provider || 'credentials' + let authProvider = APP.plugins.auth.authProviders.find(x => x.name === provider) + if (!authProvider) + throw new Error("!authProvider") + let auth = new Authenticate() + bearerToken = authsecret = null + if (authProvider.type === 'Bearer') { + bearerToken = client.bearerToken = (args['BearerToken'] || '').trim() + } else if (authProvider.type === 'authsecret') { + authsecret = (args['authsecret'] || '').trim() + client.headers.set('authsecret',authsecret) + } else { + auth = new Authenticate({ provider, ...args }) + } + client.api(auth, { jsconfig: 'eccn' }) + .then(r => { + this.api = r + if (r.error && !r.error.message) + r.error.message = HttpErrors[r.errorCode] || r.errorCode + if (this.api.succeeded) { + this.auth = this.api.response + setBodyClass({ auth: this.auth }) + } + }) + }, + logout() { + setBodyClass({ auth: this.auth }) + client.api(new Authenticate({ provider: 'logout' })) + authsecret = bearerToken = client.bearerToken = null + client.headers.delete('authsecret') + this.auth = null + }, + get authRoles() { return this.auth && this.auth.roles || [] }, + get authPermissions() { return this.auth && this.auth.permissions || [] }, + get authProfileUrl() { return this.auth && this.auth.profileUrl }, + get authLinks() { + let to = [] + let roleLinks = this.auth && APP.plugins.auth && APP.plugins.auth.roleLinks || {} + if (Object.keys(roleLinks).length > 0) { + this.authRoles.forEach(role => { + if (!roleLinks[role]) return; + roleLinks[role].forEach(link => to.push(link)) + }) + } + return to + }, + get displayName() { + let auth = this.auth + return auth + ? auth.displayName || (auth.firstName ? `${auth.firstName} ${auth.lastName}` : null) || auth.userName || auth.email + : null + }, + invalidAccess() { + let op = this.op + if (!op || !op.requiresAuth) return null + if (!this.auth) return `${op.request.name} requires Authentication` + ;return invalidAccessMessage(op, this.auth.roles, this.auth.permissions) + }, +}) +App.events.subscribe('route:nav', args => store.init()) +function typeProperties(type) { + let props = [] + while (type) { + if (type.properties) props.push(...type.properties) + type = type.inherits ? TypesMap[type.inherits.name] : null + } + return props.map(prop => prop.type.endsWith('[]') + ? {...prop, type:'List`1', genericArgs:[prop.type.substring(0,prop.type.length-2)] } + : prop) +} +let NumTypesMap = { + Byte: 'byte', + Int16: 'short', + Int32: 'int', + Int64: 'long', + UInt16: 'ushort', + Unt32: 'uint', + UInt64: 'ulong', + Single: 'float', + Double: 'double', + Decimal: 'decimal', +} +let NumTypes = [ ...Object.keys(NumTypesMap), ...Object.values(NumTypesMap) ] +let TypeAliases = { + String: 'string', + Boolean: 'bool', + ...NumTypesMap, +} +function isNumberType(type) { + return type && NumTypes.indexOf(type) >= 0 +} +function typeAlias(typeName) { + return TypeAliases[typeName] || typeName +} +function unwrap(type) { return type && type.endsWith('?') ? type.substring(0,type.length-1) : type } +function typeName2(name, genericArgs) { + if (!name) return '' + if (!genericArgs) + genericArgs = [] + if (name === 'Nullable`1') + return typeAlias(genericArgs[0]) + '?' + if (name.endsWith('[]')) + return `List<${typeAlias(name.substring(0,name.length-2))}>` + ;if (genericArgs.length === 0) + return typeAlias(name) + return leftPart(typeAlias(name), '`') + '<' + genericArgs.join(',') + '>' +} +function typeName(metaType) { return metaType && typeName2(metaType.name, metaType.genericArgs) } +/*:minify*/ diff --git a/src/build-sln.bat b/src/build-sln.bat new file mode 100644 index 00000000000..67c231c7e9c --- /dev/null +++ b/src/build-sln.bat @@ -0,0 +1,3 @@ +SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe" + +%MSBUILD% ServiceStack.sln diff --git a/src/packages/Nancy.0.10.0/lib/net40/Nancy.dll b/src/packages/Nancy.0.10.0/lib/net40/Nancy.dll deleted file mode 100644 index 569dc9d6531..00000000000 Binary files a/src/packages/Nancy.0.10.0/lib/net40/Nancy.dll and /dev/null differ diff --git a/src/packages/Nancy.Hosting.Aspnet.0.10.0/content/web.config.transform b/src/packages/Nancy.Hosting.Aspnet.0.10.0/content/web.config.transform deleted file mode 100644 index e87dacb719b..00000000000 --- a/src/packages/Nancy.Hosting.Aspnet.0.10.0/content/web.config.transform +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/packages/Nancy.Hosting.Aspnet.0.10.0/lib/net40/Nancy.Hosting.Aspnet.dll b/src/packages/Nancy.Hosting.Aspnet.0.10.0/lib/net40/Nancy.Hosting.Aspnet.dll deleted file mode 100644 index 53aab424811..00000000000 Binary files a/src/packages/Nancy.Hosting.Aspnet.0.10.0/lib/net40/Nancy.Hosting.Aspnet.dll and /dev/null differ diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/BuildProviders/Nancy.ViewEngines.Razor.BuildProviders.dll b/src/packages/Nancy.Viewengines.Razor.0.10.0/BuildProviders/Nancy.ViewEngines.Razor.BuildProviders.dll deleted file mode 100644 index ed2b7284862..00000000000 Binary files a/src/packages/Nancy.Viewengines.Razor.0.10.0/BuildProviders/Nancy.ViewEngines.Razor.BuildProviders.dll and /dev/null differ diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/GetNancyRazorBuildProviderPostBuildCmd.ps1 b/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/GetNancyRazorBuildProviderPostBuildCmd.ps1 deleted file mode 100644 index 9594245d81a..00000000000 --- a/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/GetNancyRazorBuildProviderPostBuildCmd.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -$solutionDir = [System.IO.Path]::GetDirectoryName($dte.Solution.FullName) + "\" -$path = $installPath.Replace($solutionDir, "`$(SolutionDir)") - -$BuildProvidersDir = Join-Path $path "BuildProviders" -$ViewEngineDir = Join-Path $path "lib\Net40" - -$NancyRazorBuildProviderPostBuildCmd = " -xcopy /s /y `"$BuildProvidersDir\Nancy.ViewEngines.Razor.BuildProviders.dll`" `"`$(ProjectDir)bin`" -xcopy /s /y `"$ViewEngineDir\Nancy.ViewEngines.Razor.dll`" `"`$(ProjectDir)bin`"" \ No newline at end of file diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/install.ps1 b/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/install.ps1 deleted file mode 100644 index e1ea11fef7c..00000000000 --- a/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/install.ps1 +++ /dev/null @@ -1,50 +0,0 @@ -param($installPath, $toolsPath, $package, $project) - -. (Join-Path $toolsPath "GetNancyRazorBuildProviderPostBuildCmd.ps1") - -# Get the current Post Build Event cmd -$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value - -# Append our post build command if it's not already there -if (!$currentPostBuildCmd.Contains($NancyRazorBuildProviderPostBuildCmd)) { - $project.Properties.Item("PostBuildEvent").Value += $NancyRazorBuildProviderPostBuildCmd -} - -function Get-VsFileSystem { - $componentModel = Get-VSComponentModel - $fileSystemProvider = $componentModel.GetService([NuGet.VisualStudio.IFileSystemProvider]) - $solutionManager = $componentModel.GetService([NuGet.VisualStudio.ISolutionManager]) - - $fileSystem = $fileSystemProvider.GetFileSystem($solutionManager.SolutionDirectory) - - return $fileSystem -} - -$projectRoot = $project.Properties.Item("FullPath").Value - -if (!$projectRoot) { - return; -} - -$destDirectory = $projectRoot -$fileSystem = Get-VsFileSystem - -$file = Join-Path $installPath "content\web.config.transform" - -ls $file -Filter *.transform | %{ - $destPath = Join-Path $destDirectory "web.config" - if (!(Test-Path $destPath)) { - $fileStream = $null - try { - $fileStream = [System.IO.File]::OpenRead($_.FullName) - $fileSystem.AddFile($destPath, $fileStream) - $project.ProjectItems.AddFromFile($destPath) - } catch { - # We don't want an exception to surface if we can't add the file for some reason - } finally { - if ($fileStream -ne $null) { - $fileStream.Dispose() - } - } - } -} \ No newline at end of file diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/uninstall.ps1 b/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/uninstall.ps1 deleted file mode 100644 index bff1d4ccaad..00000000000 --- a/src/packages/Nancy.Viewengines.Razor.0.10.0/Tools/uninstall.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -param($installPath, $toolsPath, $package, $project) - -. (Join-Path $toolsPath "GetNancyRazorBuildProviderPostBuildCmd.ps1") - -# Get the current Post Build Event cmd -$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value - -# Remove our post build command from it (if it's there) -$project.Properties.Item("PostBuildEvent").Value = $currentPostBuildCmd.Replace($NancyRazorBuildProviderPostBuildCmd, "") diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/content/app.config.transform b/src/packages/Nancy.Viewengines.Razor.0.10.0/content/app.config.transform deleted file mode 100644 index a709e64f256..00000000000 --- a/src/packages/Nancy.Viewengines.Razor.0.10.0/content/app.config.transform +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/content/web.config.transform b/src/packages/Nancy.Viewengines.Razor.0.10.0/content/web.config.transform deleted file mode 100644 index e6667ed045f..00000000000 --- a/src/packages/Nancy.Viewengines.Razor.0.10.0/content/web.config.transform +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/lib/net40/Nancy.ViewEngines.Razor.dll b/src/packages/Nancy.Viewengines.Razor.0.10.0/lib/net40/Nancy.ViewEngines.Razor.dll deleted file mode 100644 index abd817284b1..00000000000 Binary files a/src/packages/Nancy.Viewengines.Razor.0.10.0/lib/net40/Nancy.ViewEngines.Razor.dll and /dev/null differ diff --git a/src/packages/Nancy.Viewengines.Razor.0.10.0/lib/net40/System.Web.Razor.dll b/src/packages/Nancy.Viewengines.Razor.0.10.0/lib/net40/System.Web.Razor.dll deleted file mode 100644 index 1ee1122a6a7..00000000000 Binary files a/src/packages/Nancy.Viewengines.Razor.0.10.0/lib/net40/System.Web.Razor.dll and /dev/null differ diff --git a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net20/System.Data.SQLite.Linq.dll b/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net20/System.Data.SQLite.Linq.dll deleted file mode 100644 index 91d583cc054..00000000000 Binary files a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net20/System.Data.SQLite.Linq.dll and /dev/null differ diff --git a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net20/System.Data.SQLite.dll b/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net20/System.Data.SQLite.dll deleted file mode 100644 index 9d99b006ed0..00000000000 Binary files a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net20/System.Data.SQLite.dll and /dev/null differ diff --git a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net40/System.Data.SQLite.Linq.dll b/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net40/System.Data.SQLite.Linq.dll deleted file mode 100644 index 31c463596b5..00000000000 Binary files a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net40/System.Data.SQLite.Linq.dll and /dev/null differ diff --git a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net40/System.Data.SQLite.dll b/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net40/System.Data.SQLite.dll deleted file mode 100644 index ef3da76c0aa..00000000000 Binary files a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net40/System.Data.SQLite.dll and /dev/null differ diff --git a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net45/System.Data.SQLite.Linq.dll b/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net45/System.Data.SQLite.Linq.dll deleted file mode 100644 index 71a4551ce70..00000000000 Binary files a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net45/System.Data.SQLite.Linq.dll and /dev/null differ diff --git a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net45/System.Data.SQLite.dll b/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net45/System.Data.SQLite.dll deleted file mode 100644 index 28ecb4309af..00000000000 Binary files a/src/packages/System.Data.SQLite.x64.1.0.84.0/lib/net45/System.Data.SQLite.dll and /dev/null differ diff --git a/src/packages/System.Web.Razor.Unofficial.2.0.2/lib/net40/System.Web.Razor.Unofficial.dll b/src/packages/System.Web.Razor.Unofficial.2.0.2/lib/net40/System.Web.Razor.Unofficial.dll deleted file mode 100644 index 2a523e9e4a2..00000000000 Binary files a/src/packages/System.Web.Razor.Unofficial.2.0.2/lib/net40/System.Web.Razor.Unofficial.dll and /dev/null differ diff --git a/src/packages/repositories.config b/src/packages/repositories.config deleted file mode 100644 index 40901b6aaff..00000000000 --- a/src/packages/repositories.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/servicestack.snk b/src/servicestack.snk new file mode 100644 index 00000000000..dade7cea36f Binary files /dev/null and b/src/servicestack.snk differ diff --git a/src/shared-local-instance.db b/src/shared-local-instance.db new file mode 100644 index 00000000000..d40bd91b79d Binary files /dev/null and b/src/shared-local-instance.db differ diff --git a/tests/Check.ServiceInterface/AnnotationsService.cs b/tests/Check.ServiceInterface/AnnotationsService.cs new file mode 100644 index 00000000000..4198b7caaff --- /dev/null +++ b/tests/Check.ServiceInterface/AnnotationsService.cs @@ -0,0 +1,10 @@ +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class AnnotationsService : Service + { + public object Any(HelloAnnotations request) => request; + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/AnonTypeService.cs b/tests/Check.ServiceInterface/AnonTypeService.cs new file mode 100644 index 00000000000..ecabf8b4ae8 --- /dev/null +++ b/tests/Check.ServiceInterface/AnonTypeService.cs @@ -0,0 +1,15 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/anontype")] + public class AnonType { } + + public class AnonTypeService : Service + { + public object Any(AnonType request) + { + return new { PrimaryKeyId = 1 }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/AutoQueryDataServices.cs b/tests/Check.ServiceInterface/AutoQueryDataServices.cs new file mode 100644 index 00000000000..ba5b4df1ec0 --- /dev/null +++ b/tests/Check.ServiceInterface/AutoQueryDataServices.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/query/requestlogs")] + [Route("/query/requestlogs/{Date}")] + public class QueryRequestLogs : QueryData + { + public DateTime? Date { get; set; } + public bool ViewErrors { get; set; } + } + + [AutoQueryViewer(Name = "Today's Logs", Title = "Logs from Today")] + public class TodayLogs : QueryData { } + public class TodayErrorLogs : QueryData { } + + public class YesterdayLogs : QueryData { } + public class YesterdayErrorLogs : QueryData { } + + public class AutoQueryDataServices : Service + { + public IAutoQueryData AutoQuery { get; set; } + + public object Any(QueryPosts request) => request; + public object Any(EchoTypes request) => request; + + public object Any(QueryRequestLogs query) + { + var date = query.Date.GetValueOrDefault(DateTime.UtcNow); + var logSuffix = query.ViewErrors ? "-errors" : ""; + var csvLogsFile = VirtualFileSources.GetFile("requestlogs/{0}-{1}/{0}-{1}-{2}{3}.csv".Fmt( + date.Year.ToString("0000"), + date.Month.ToString("00"), + date.Day.ToString("00"), + logSuffix)); + + if (csvLogsFile == null) + throw HttpError.NotFound("No logs found on " + date.ToShortDateString()); + + var logs = csvLogsFile.ReadAllText().FromCsv>(); + + var q = AutoQuery.CreateQuery(query, Request, + db: new MemoryDataSource(logs, query, Request)); + + return AutoQuery.Execute(query, q); + } + + public object Any(TodayLogs request) + { + return Any(new QueryRequestLogs { Date = DateTime.UtcNow }); + } + public object Any(TodayErrorLogs request) + { + return Any(new QueryRequestLogs { Date = DateTime.UtcNow, ViewErrors = true }); + } + + public object Any(YesterdayLogs request) + { + return Any(new QueryRequestLogs { Date = DateTime.UtcNow.AddDays(-1) }); + } + public object Any(YesterdayErrorLogs request) + { + return Any(new QueryRequestLogs { Date = DateTime.UtcNow.AddDays(-1), ViewErrors = true }); + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/AutoQueryServices.cs b/tests/Check.ServiceInterface/AutoQueryServices.cs new file mode 100644 index 00000000000..fe88674226f --- /dev/null +++ b/tests/Check.ServiceInterface/AutoQueryServices.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using Check.ServiceModel; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceInterface +{ + [Route("/querydata/rockstars")] + public class QueryDataRockstars : QueryData + { + public int? Age { get; set; } + } + + [Route("/query/rockstars")] + public class QueryRockstars : QueryDb + { + public int? Age { get; set; } + } + + [Route("/query/rockstars/cached")] + public class QueryRockstarsCached : QueryDb + { + public int? Age { get; set; } + } + + [ConnectionInfo(NamedConnection = "pgsql")] + [Route("/pgsql/rockstars")] + public class QueryPostgresRockstars : QueryDb + { + public int? Age { get; set; } + } + + [NamedConnection("pgsql")] + public class PgRockstar : Rockstar {} + + [Route("/pgsql/pgrockstars")] + public class QueryPostgresPgRockstars : QueryDb + { + public int? Age { get; set; } + } + + public class QueryRockstarsConventions : QueryDb + { + public int[] Ids { get; set; } + public int? AgeOlderThan { get; set; } + public int? AgeGreaterThanOrEqualTo { get; set; } + public int? AgeGreaterThan { get; set; } + public int? GreaterThanAge { get; set; } + public string FirstNameStartsWith { get; set; } + public string LastNameEndsWith { get; set; } + public string LastNameContains { get; set; } + public string RockstarAlbumNameContains { get; set; } + public int? RockstarIdAfter { get; set; } + public int? RockstarIdOnOrAfter { get; set; } + } + + [AutoQueryViewer(Title = "Search for Rockstars", Description = "Use this option to search for Rockstars!")] + public class QueryCustomRockstars : QueryDb + { + public int? Age { get; set; } + } + + [Route("/customrockstars")] + public class QueryRockstarAlbums : QueryDb, IJoin + { + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + } + + public class QueryRockstarAlbumsImplicit : QueryDb, IJoin + { + } + + public class QueryRockstarAlbumsLeftJoin : QueryDb, ILeftJoin + { + public int? Age { get; set; } + public string AlbumName { get; set; } + } + + + public class QueryOverridedRockstars : QueryDb + { + public int? Age { get; set; } + } + + public class QueryOverridedCustomRockstars : QueryDb + { + public int? Age { get; set; } + } + + [Route("/query-custom/rockstars")] + public class QueryFieldRockstars : QueryDb + { + public string FirstName { get; set; } //default to 'AND FirstName = {Value}' + + public string[] FirstNames { get; set; } //Collections default to 'FirstName IN ({Values}) + + [QueryDbField(Operand = ">=")] + public int? Age { get; set; } + + [QueryDbField(Template = "UPPER({Field}) LIKE UPPER({Value})", Field = "FirstName")] + public string FirstNameCaseInsensitive { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value}", Field = "FirstName", ValueFormat = "{0}%")] + public string FirstNameStartsWith { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value}", Field = "LastName", ValueFormat = "%{0}")] + public string LastNameEndsWith { get; set; } + + [QueryDbField(Template = "{Field} BETWEEN {Value1} AND {Value2}", Field = "FirstName")] + public string[] FirstNameBetween { get; set; } + + [QueryDbField(Term = QueryTerm.Or, Template = "UPPER({Field}) LIKE UPPER({Value})", Field = "LastName")] + public string OrLastName { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value1} OR {Field} LIKE {Value2}", Field = "FirstName", ValueFormat = "%{0}%")] + public string[] FirstNameContainsMulti { get; set; } + } + + public class QueryFieldRockstarsDynamic : QueryDb + { + public int? Age { get; set; } + } + + public class QueryRockstarsFilter : QueryDb + { + public int? Age { get; set; } + } + + public class QueryCustomRockstarsFilter : QueryDb + { + public int? Age { get; set; } + } + + public interface IFilterRockstars { } + public class QueryRockstarsIFilter : QueryDb, IFilterRockstars + { + public int? Age { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [Route("/OrRockstars")] + public class QueryOrRockstars : QueryDb + { + public int? Age { get; set; } + public string FirstName { get; set; } + } + + [QueryDb(QueryTerm.Or)] + public class QueryGetRockstars : QueryDb + { + public int[] Ids { get; set; } + public List Ages { get; set; } + public List FirstNames { get; set; } + public int[] IdsBetween { get; set; } + } + + [QueryDb(QueryTerm.Or)] + public class QueryGetRockstarsDynamic : QueryDb { } + + public class RockstarAlbum + { + [AutoIncrement] + public int Id { get; set; } + public int RockstarId { get; set; } + public string Name { get; set; } + } + + public class CustomRockstar + { + [AutoQueryViewerField(Title = "Name")] + public string FirstName { get; set; } + + [AutoQueryViewerField(HideInSummary = true)] + public string LastName { get; set; } + public int? Age { get; set; } + + [AutoQueryViewerField(Title = "Album")] + public string RockstarAlbumName { get; set; } + + [AutoQueryViewerField(Title = "Genre")] + public string RockstarGenreName { get; set; } + } + + [Route("/movies/search")] + [QueryDb(QueryTerm.And)] //Default + public class SearchMovies : QueryDb { } + + [Route("/movies")] + [QueryDb(QueryTerm.Or)] + public class QueryMovies : QueryDb + { + public int[] Ids { get; set; } + public string[] ImdbIds { get; set; } + public string[] Ratings { get; set; } + } + + public class Movie + { + [AutoIncrement] + public int Id { get; set; } + public string ImdbId { get; set; } + public string Title { get; set; } + public string Rating { get; set; } + public decimal Score { get; set; } + public string Director { get; set; } + public DateTime ReleaseDate { get; set; } + public string TagLine { get; set; } + public List Genres { get; set; } + } + + public class StreamMovies : QueryDb + { + public string[] Ratings { get; set; } + } + + public class QueryUnknownRockstars : QueryDb + { + public int UnknownInt { get; set; } + public string UnknownProperty { get; set; } + + } + [Route("/query/rockstar-references")] + public class QueryRockstarsWithReferences : QueryDb + { + public int? Age { get; set; } + } + + [Alias("Rockstar")] + public class RockstarReference + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + + [Reference] + public List Albums { get; set; } + } + + public class AutoQueryService : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + //Override with custom impl + public QueryResponse Any(QueryRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request); + //q.Take(1); + return AutoQuery.Execute(dto, q, Request); + } + } + + [CacheResponse(Duration = 3600)] + public class AutoQueryCachedServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + public QueryResponse Any(QueryRockstarsCached request) => + AutoQuery.Execute(request, AutoQuery.CreateQuery(request, Request), Request); + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/BuiltInDtosService.cs b/tests/Check.ServiceInterface/BuiltInDtosService.cs new file mode 100644 index 00000000000..5e978637377 --- /dev/null +++ b/tests/Check.ServiceInterface/BuiltInDtosService.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using ServiceStack; + +namespace Check.ServiceInterface +{ + //throws AmbiguousMatchException when ServerEventsFeature is registered + public class BuiltInDtosService : Service + { + //public object Any(GetEventSubscribers request) + //{ + // return new List>(); + //} + + //public object Any(UpdateEventSubscriber request) + //{ + // return new UpdateEventSubscriberResponse(); + //} + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/ChangeRequestService.cs b/tests/Check.ServiceInterface/ChangeRequestService.cs new file mode 100644 index 00000000000..5fb91183871 --- /dev/null +++ b/tests/Check.ServiceInterface/ChangeRequestService.cs @@ -0,0 +1,97 @@ +using System.Collections.Specialized; +using System.Web; +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/changerequest/{Id}")] + public class ChangeRequest + { + public string Id { get; set; } + } + + public class ChangeRequestResponse + { + public string ContentType { get; set; } + public string Header { get; set; } + public string QueryString { get; set; } + public string Form { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomHttpRequest : HttpRequestBase + { + private readonly HttpRequestBase original; + private readonly NameValueCollection queryString = new NameValueCollection(); + private readonly NameValueCollection formData = new NameValueCollection(); + + public CustomHttpRequest(object original) + { + this.original = (HttpRequestBase)original; + + this.original.ContentType = this.original.ContentType; + + foreach (string key in this.original.QueryString.Keys) + { + queryString[key] = this.original.QueryString[key]; + } + + foreach (string key in this.original.Form.Keys) + { + formData[key] = this.original.Form[key]; + } + } + + public override string ContentType + { + get + { + return original.ContentType; + } + set + { + original.ContentType = value; + } + } + + public override NameValueCollection QueryString + { + get { return queryString; } + } + + public override NameValueCollection Form + { + get { return formData; } + } + + public override NameValueCollection Headers + { + get + { + return original.Headers; + } + } + } + + public class ChangeRequestService : Service + { + public object Any(ChangeRequest request) + { + var aspReq = new CustomHttpRequest(base.Request.OriginalRequest) { + ContentType = MimeTypes.FormUrlEncoded + }; + + aspReq.QueryString["Id"] = request.Id; + aspReq.Form["Id"] = request.Id; + aspReq.Headers["Id"] = request.Id; + + return new ChangeRequestResponse { + ContentType = aspReq.ContentType, + Header = aspReq.Headers["Id"], + QueryString = aspReq.QueryString["Id"], + Form = aspReq.Form["Id"], + }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/Check.ServiceInterface.csproj b/tests/Check.ServiceInterface/Check.ServiceInterface.csproj new file mode 100644 index 00000000000..488df39d4e4 --- /dev/null +++ b/tests/Check.ServiceInterface/Check.ServiceInterface.csproj @@ -0,0 +1,112 @@ + + + + + Debug + AnyCPU + {9982317F-831C-478B-9CC3-57F888BCD97A} + Library + Properties + Check.ServiceInterface + Check.ServiceInterface + v4.7.2 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Check.ServiceInterface/CompressedServices.cs b/tests/Check.ServiceInterface/CompressedServices.cs new file mode 100644 index 00000000000..9f5f2439a64 --- /dev/null +++ b/tests/Check.ServiceInterface/CompressedServices.cs @@ -0,0 +1,23 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/compress/{Path*}")] + public class CompressFile + { + public string Path { get; set; } + } + + [CompressResponse] + public class CompressedServices : Service + { + public object Any(CompressFile request) + { + var file = VirtualFileSources.GetFile(request.Path); + if (file == null) + throw HttpError.NotFound($"{request.Path} does not exist"); + + return new HttpResult(file); + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/Configure.NativeTypes.cs b/tests/Check.ServiceInterface/Configure.NativeTypes.cs new file mode 100644 index 00000000000..1886f2122b0 --- /dev/null +++ b/tests/Check.ServiceInterface/Configure.NativeTypes.cs @@ -0,0 +1,31 @@ +using System; +using Check.ServiceModel.Types; +using ServiceStack; +using ServiceStack.NativeTypes.CSharp; + +namespace Check.ServiceInterface +{ + /// + /// Run before AppHost.Configure() is run. + /// + public class ConfigureNativeTypes : IConfigureAppHost + { + public void Configure(IAppHost appHost) + { + CSharpGenerator.PreTypeFilter = (sb, type) => + { + if (!type.IsEnum.GetValueOrDefault() && !type.IsInterface.GetValueOrDefault()) + { + sb.AppendLine("[Serializable]"); + } + }; + + var nativeTypes = appHost.GetPlugin(); + nativeTypes.MetadataTypesConfig.ExportTypes.Add(typeof(DayOfWeek)); + nativeTypes.MetadataTypesConfig.IgnoreTypes.Add(typeof(IgnoreInMetadataConfig)); + + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute)); + //nativeTypes.MetadataTypesConfig.GlobalNamespace = "Check.ServiceInterface"; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/CustomRoutesService.cs b/tests/Check.ServiceInterface/CustomRoutesService.cs new file mode 100644 index 00000000000..44354c2a9d2 --- /dev/null +++ b/tests/Check.ServiceInterface/CustomRoutesService.cs @@ -0,0 +1,31 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/Routing/LeadPost.aspx")] + public class LegacyLeadPost + { + public string LeadType { get; set; } + public int MyId { get; set; } + } + + [Route("/info/{Id}")] + public class Info + { + public string Id { get; set; } + } + + public class CustomRoutesService : Service + { + public object Any(LegacyLeadPost request) + { + return request; + } + + public object Any(Info request) + { + return request.ToAbsoluteUri() + + " | " + request.ToAbsoluteUri(base.Request); + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/DiscoverTypesService.cs b/tests/Check.ServiceInterface/DiscoverTypesService.cs new file mode 100644 index 00000000000..84ed3aab53b --- /dev/null +++ b/tests/Check.ServiceInterface/DiscoverTypesService.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class ArrayElementInDictionary + { + public int Id { get; set; } + } + + public class DiscoverTypes : IReturn + { + public Dictionary ElementInDictionary { get; set; } + } + + public class DiscoverTypesService : Service + { + public object Any(DiscoverTypes request) => request; + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/EchoesService.cs b/tests/Check.ServiceInterface/EchoesService.cs new file mode 100644 index 00000000000..97d5eec98f5 --- /dev/null +++ b/tests/Check.ServiceInterface/EchoesService.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ +/// + /// The Echoes web service. + /// + public class EchoesService : Service + { + public IServiceClient Client { get; set; } + + /// + /// GET echoes. + /// + /// The request. + /// The . + public object Post(Echoes request) + { + return new Echo { Sentence = request.Sentence }; + } + + public object Any(CachedEcho request) + { + if (request.Reload) + Cache.ClearCaches(request.Sentence); + + return Request.ToOptimizedResultUsingCache(Cache, request.Sentence, () => + new Echo {Sentence = request.Sentence}); + } + + public async Task Any(AsyncTest request) + { + var response = await Client.PostAsync(new Echoes { Sentence = "Foo" }); + return response; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/ErrorServices.cs b/tests/Check.ServiceInterface/ErrorServices.cs new file mode 100644 index 00000000000..0bd96b92a36 --- /dev/null +++ b/tests/Check.ServiceInterface/ErrorServices.cs @@ -0,0 +1,51 @@ +using System; +using Check.ServiceModel; +using ServiceStack; +using ServiceStack.Web; + +namespace Check.ServiceInterface +{ + + public class CustomHttpErrorService : Service + { + public object Any(CustomHttpError request) + { + throw new HttpError(request.StatusCode, request.StatusDescription); + } + + public object Any(AlwaysThrows request) + { + throw new Exception(request.GetType().Name); + } + } + + public class AlwaysThrowsService : Service + { + [AlwaysThrows] + public object Any(AlwaysThrowsFilterAttribute request) => request; + + public object Any(AlwaysThrowsGlobalFilter request) => request; + } + + public class AlwaysThrowsAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + throw new Exception(requestDto.GetType().Name); + } + } + + public class CustomFieldHttpErrorService : Service + { + public object Any(CustomFieldHttpError request) + { + throw new HttpError(new CustomFieldHttpErrorResponse + { + Custom = "Ignored", + ResponseStatus = new ResponseStatus("StatusErrorCode", "StatusErrorMessage") + }, + 500, + "HeaderErrorCode"); + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/ErrorsService.cs b/tests/Check.ServiceInterface/ErrorsService.cs new file mode 100644 index 00000000000..e492e15273f --- /dev/null +++ b/tests/Check.ServiceInterface/ErrorsService.cs @@ -0,0 +1,82 @@ +using System; +using System.IO; +using System.Net; +using Check.ServiceModel; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.FluentValidation; + +namespace Check.ServiceInterface +{ + public class ErrorsService : Service + { + public object Any(ThrowHttpError request) + { + throw new HttpError(request.Status, request.Message); + } + + public object Any(Throw404 request) + { + throw HttpError.NotFound(request.Message ?? "Custom Status Description"); + } + + public object Any(Return404 request) + { + return HttpError.NotFound("Custom Status Description"); + } + + public object Any(Return404Result request) + { + return new HttpResult(HttpStatusCode.NotFound, "Custom Status Description"); + } + + public object Any(ThrowType request) + { + switch (request.Type ?? "Exception") + { + case "Exception": + throw new Exception(request.Message ?? "Server Error"); + case "NotFound": + throw HttpError.NotFound(request.Message ?? "What you're looking for isn't here"); + case "Unauthorized": + throw HttpError.Unauthorized(request.Message ?? "You shall not pass!"); + case "Conflict": + throw HttpError.Conflict(request.Message ?? "We haz Conflict!"); + case "NotImplementedException": + throw new NotImplementedException(request.Message ?? "Not implemented yet, try again later"); + case "ArgumentException": + throw new ArgumentException(request.Message ?? "Client Argument Error"); + case "AuthenticationException": + throw new AuthenticationException(request.Message ?? "We haz issue Authenticating"); + case "UnauthorizedAccessException": + throw new UnauthorizedAccessException(request.Message ?? "You shall not pass!"); + case "OptimisticConcurrencyException": + throw new OptimisticConcurrencyException(request.Message ?? "Sorry too optimistic"); + case "UnhandledException": + throw new FileNotFoundException(request.Message ?? "File was never here"); + case "RawResponse": + Response.StatusCode = 418; + Response.StatusDescription = request.Message ?? "On a tea break"; + Response.EndRequest(); + break; + } + + return request; + } + + public object Any(ThrowValidation request) + { + return request.ConvertTo(); + } + } + + public class ThrowValidationValidator : AbstractValidator + { + public ThrowValidationValidator() + { + RuleFor(x => x.Age).InclusiveBetween(1, 120); + RuleFor(x => x.Required).NotEmpty(); + RuleFor(x => x.Email).NotEmpty().EmailAddress(); + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/FallbackRouteService.cs b/tests/Check.ServiceInterface/FallbackRouteService.cs new file mode 100644 index 00000000000..4f5e4e607ec --- /dev/null +++ b/tests/Check.ServiceInterface/FallbackRouteService.cs @@ -0,0 +1,34 @@ +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + //[FallbackRoute("{PathInfo*}")] + public class FallbackRoute + { + public string PathInfo { get; set; } + } + + public class FallbackRouteService : Service + { + public object Any(FallbackRoute request) + { + if (request.PathInfo == "TestView") + { + return new HttpResult(base.Gateway.Send(new CachedEcho + { + Reload = true, + Sentence = "Echo Result", + })) + { + View = "TestView" + }; + } + + return new HttpResult(request) + { + View = "/default.cshtml" + }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/IssueServices.cs b/tests/Check.ServiceInterface/IssueServices.cs new file mode 100644 index 00000000000..87a7f938f11 --- /dev/null +++ b/tests/Check.ServiceInterface/IssueServices.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class NoRepeat : IReturn + { + public Guid Id { get; set; } + } + + public class NoRepeatResponse + { + public Guid Id { get; set; } + } + + public class BatchThrows : IReturn + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class BatchThrowsAsync : IReturn + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class BatchThrowsResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class AutoBatchServices : IService + { + private static readonly HashSet ReceivedGuids = new HashSet(); + + public NoRepeatResponse Any(NoRepeat request) + { + if (ReceivedGuids.Contains(request.Id)) + throw new ArgumentException("Id {0} already received".Fmt(request.Id)); + + ReceivedGuids.Add(request.Id); + + return new NoRepeatResponse + { + Id = request.Id + }; + } + + public object Any(BatchThrows request) + { + throw new Exception("Batch Throws"); + } + + public async Task Any(BatchThrowsAsync request) + { + await Task.Delay(0); + + throw new Exception("Batch Throws"); + } + } + + [Route("/code", "post", Summary = @"Intellisense desteği sunar", + Notes = "")] + public class AutoComplete : IReturn + { + public int objectId { get; set; } + public int line { get; set; } + public int col { get; set; } + public string code { get; set; } + } + [Route("/code/object", "GET", Summary = @"Objenin adından objeyi döner", + Notes = "")] + public class ObjectId : IReturn + { + public string objectName { get; set; } + } + [Route("/code/execute", "get", Summary = @"Objeyi çalıştırır", + Notes = "")] + public class Execute : IReturn + { + public string objectName { get; set; } + public string args { get; set; } + } + + public class StringListResponse + { + public List data { get; set; } + } + public class StringResponse + { + public string data { get; set; } + } + public class ObjectDesignResponse + { + public ObjectDesign data { get; set; } + } + + public class ObjectDesign + { + public int Id { get; set; } + } + public class IntegerResponse + { + public int data { get; set; } + } + + public class CodeServices : Service + { + public object Get(ObjectId request) + { + int.TryParse(request.objectName ?? "-1", out var data); + return new IntegerResponse { data = data }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/JwtServices.cs b/tests/Check.ServiceInterface/JwtServices.cs new file mode 100644 index 00000000000..18b553d1119 --- /dev/null +++ b/tests/Check.ServiceInterface/JwtServices.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.Text; + +namespace Check.ServiceInterface +{ + [Route("/jwt")] + public class CreateJwt : AuthUserSession, IReturn + { + public DateTime? JwtExpiry { get; set; } + } + + public class CreateJwtResponse + { + public string Token { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/jwt-refresh")] + public class CreateRefreshJwt : IReturn + { + public string UserAuthId { get; set; } + public DateTime? JwtExpiry { get; set; } + } + + public class CreateRefreshJwtResponse + { + public string Token { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class JwtServices : Service + { + public object Any(CreateJwt request) + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + if (request.JwtExpiry != null) + { + jwtProvider.CreatePayloadFilter = (jwtPayload, session) => + jwtPayload["exp"] = request.JwtExpiry.Value.ToUnixTime().ToString(); + } + + var jwtSession = request.ConvertTo(); + var token = jwtProvider.CreateJwtBearerToken(jwtSession); + + jwtProvider.CreatePayloadFilter = null; + + return new CreateJwtResponse + { + Token = token + }; + } + + public object Any(CreateRefreshJwt request) + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var jwtHeader = new JsonObject + { + {"typ", "JWTR"}, //RefreshToken + {"alg", jwtProvider.HashAlgorithm} + }; + + var keyId = jwtProvider.GetKeyId(Request); + if (keyId != null) + jwtHeader["kid"] = keyId; + + var now = DateTime.UtcNow; + var jwtPayload = new JsonObject + { + {"sub", request.UserAuthId ?? "1"}, + {"iat", now.ToUnixTime().ToString()}, + {"exp", (request.JwtExpiry ?? DateTime.UtcNow.AddDays(1)).ToUnixTime().ToString()}, + }; + + if (jwtProvider.Audience != null) + jwtPayload["aud"] = jwtProvider.Audience; + + var hashAlgoritm = jwtProvider.GetHashAlgorithm(); + var refreshToken = JwtAuthProvider.CreateJwt(jwtHeader, jwtPayload, hashAlgoritm); + + return new CreateRefreshJwtResponse + { + Token = refreshToken + }; + } + } +} diff --git a/tests/Check.ServiceInterface/MetadataDtoIssue.cs b/tests/Check.ServiceInterface/MetadataDtoIssue.cs new file mode 100644 index 00000000000..4d7750f5502 --- /dev/null +++ b/tests/Check.ServiceInterface/MetadataDtoIssue.cs @@ -0,0 +1,53 @@ +using System; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceInterface +{ + [References(typeof(acsprofileResponse))] + [Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE")] + [Route("/api/acsprofiles/{profileId}")] + [Alias("ACSProfiles")] + public class ACSProfile : IReturn, IHasVersion, IHasSessionId + { + [PrimaryKey] + public string profileId { get; set; } + + [StringLength(20)] + public string shortName { get; set; } + + [StringLength(60)] + public string longName { get; set; } + + [StringLength(20)] + [Index(Unique = false)] + public string regionId { get; set; } + + [StringLength(20)] + [Index(Unique = false)] + public string groupId { get; set; } + + [StringLength(12)] + [Index(Unique = false)] + public string deviceID { get; set; } + + public DateTime lastUpdated { get; set; } + + public bool enabled { get; set; } + public int Version { get; set; } + public string SessionId { get; set; } + } + + public class acsprofileResponse + { + public string profileId { get; set; } + } + + public class ACSProfileService : Service + { + public object Any(ACSProfile request) + { + return new acsprofileResponse { profileId = request.profileId }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/MetadataTestService.cs b/tests/Check.ServiceInterface/MetadataTestService.cs new file mode 100644 index 00000000000..1387a0e46db --- /dev/null +++ b/tests/Check.ServiceInterface/MetadataTestService.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class MetadataTestService : Service + { + public object Any(MetadataTest request) + { + return new MetadataTestResponse + { + Id = request.Id, + Results = new List + { + new MetadataTestChild + { + Name = "foo", + Results = new List + { + new MetadataTestNestedChild { Name = "bar" }, + } + } + } + }; + } + + public object Any(GetExample request) + { + return new GetExampleResponse + { + MenuExample1 = new MenuExample + { + MenuItemExample1 = new MenuItemExample { Name1 = "foo" } + } + }; + } + + public object Any(MetadataRequest request) => request; + + public object Any(ExcludeMetadataType request) => request; + public object Any(ExcludeMetadataProperty request) => request; + } + + public class MetadataRequest : IReturn + { + public MetadataType MetadataType { get; set; } + } + +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/NamedConnectionService.cs b/tests/Check.ServiceInterface/NamedConnectionService.cs new file mode 100644 index 00000000000..b242244e670 --- /dev/null +++ b/tests/Check.ServiceInterface/NamedConnectionService.cs @@ -0,0 +1,31 @@ +using System.Data; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace Check.ServiceInterface +{ + [Route("/namedconnection")] + public class NamedConnection + { + public string EmailAddresses { get; set; } + } + + public class NamedConnectionService : Service + { + public IDbConnectionFactory ConnectionFactory { get; set; } + + public object Any(NamedConnection request) + { + using (var db = ConnectionFactory.OpenDbConnection("SqlServer")) + { + using (var cmd = db.SqlProc( + "GetUserIdsFromEmailAddresses", new {request.EmailAddresses})) + { + var userIds = cmd.ConvertToList(); + return userIds; + } + } + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/NativeTypeIssuesService.cs b/tests/Check.ServiceInterface/NativeTypeIssuesService.cs new file mode 100644 index 00000000000..b1a2f9bec42 --- /dev/null +++ b/tests/Check.ServiceInterface/NativeTypeIssuesService.cs @@ -0,0 +1,14 @@ +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class NativeTypeIssuesService : Service + { + public object Any(Issue221Long request) => request; + + public object Any(TestAttributeExport request) => request; + + public object Any(RecursiveNode request) => request; + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/NativeTypesTestService.cs b/tests/Check.ServiceInterface/NativeTypesTestService.cs new file mode 100644 index 00000000000..da0189c6e65 --- /dev/null +++ b/tests/Check.ServiceInterface/NativeTypesTestService.cs @@ -0,0 +1,331 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Check.ServiceModel.Operations; +using Check.ServiceModel.Types; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class NativeTypesTestService : Service + { + public class HelloInService : IReturn + { + public string Name { get; set; } + } + + public object Any(HelloACodeGenTest request) + { + return new HelloACodeGenTestResponse { FirstResult = request.FirstField }; + } + + public object Any(HelloInService request) + { + return new HelloResponse { Result = request.Name }; + } + + public object Any(Hello request) + { + return new HelloResponse { Result = request.Name }; + } + + public object Any(HelloAnnotated request) + { + return new HelloAnnotatedResponse { Result = request.Name }; + } + + public object Any(HelloWithNestedClass request) + { + return new HelloResponse { Result = request.Name }; + } + + public object Any(HelloList request) + { + return request.Names.Map(name => new ListResult { Result = name }); + } + + public object Any(HelloReturnList request) + { + return request.Names.Map(name => new OnlyInReturnListArg { Result = name }); + } + + public object Any(HelloArray request) + { + return request.Names.Map(name => new ArrayResult { Result = name }); + } + + public object Any(HelloExisting request) + { + return new HelloExistingResponse + { + ArrayResults = request.Names.Map(x => new ArrayResult { Result = x }).ToArray(), + ListResults = request.Names.Map(x => new ListResult { Result = x }), + }; + } + + public object Any(HelloWithEnum request) + { + return request; + } + + public object Any(HelloWithEnumList request) => request; + + public object Any(HelloWithEnumMap request) => request; + + public object Any(HelloExternal request) + { + return request; + } + + public object Any(RestrictedAttributes request) + { + return request; + } + + public object Any(AllowedAttributes request) + { + return request; + } + + public object Any(HelloAttributeStringTest request) + { + return request; + } + + public object Any(HelloAllTypes request) + { + return new HelloAllTypesResponse + { + AllTypes = request.AllTypes, + AllCollectionTypes = request.AllCollectionTypes, + Result = request.Name + }; + } + + public object Any(AllTypes request) + { + return request; + } + + public object Any(HelloString request) + { + return request.Name; + } + + public void Any(HelloVoid request) + { + } + + public object Any(HelloWithDataContract request) + { + return new HelloWithDataContractResponse { Result = request.Name }; + } + + public object Any(HelloWithDescription request) + { + return new HelloWithDescriptionResponse { Result = request.Name }; + } + + public object Any(HelloWithInheritance request) + { + return new HelloWithInheritanceResponse { Result = request.Name }; + } + + public object Any(HelloWithGenericInheritance request) + { + return request; + } + + public object Any(HelloWithGenericInheritance2 request) + { + return request; + } + + public object Any(HelloWithNestedInheritance request) + { + return request; + } + + public object Any(HelloWithListInheritance request) + { + return request; + } + + public object Any(HelloWithReturn request) + { + return new HelloWithAlternateReturnResponse { Result = request.Name }; + } + + public object Any(HelloWithRoute request) + { + return new HelloWithRouteResponse { Result = request.Name }; + } + + public object Any(HelloWithType request) + { + return new HelloWithTypeResponse + { + Result = new HelloType { Result = request.Name } + }; + } + + public object Any(HelloStruct request) + { + return request; + } + + public object Any(HelloSession request) + { + return new HelloSessionResponse + { + Result = base.SessionAs() + }; + } + + public object Any(HelloInterface request) + { + return request; + } + + public object Any(HelloImplementsInterface request) => request; + + public object Get(Request1 request) + { + return new Request1Response(); + } + + public object Get(Request2 request) + { + return new Request2Response(); + } + + public object Any(HelloInnerTypes request) + { + return new HelloInnerTypesResponse(); + } + + public object Any(GetUserSession request) + { + return new CustomUserSession(); + } + + public object Any(QueryTemplate request) + { + return new QueryResponseTemplate(); + } + + public object Any(HelloReserved request) + { + return request; + } + + public object Any(HelloDictionary request) + { + return new Dictionary { { request.Key ?? "key", request.Value } }; + } + + public object Any(HelloBuiltin request) + { + return request; + } + + public object Any(HelloGet request) + { + return new HelloVerbResponse { Result = HttpMethods.Get }; + } + + public object Any(HelloPost request) + { + return new HelloVerbResponse { Result = HttpMethods.Post }; + } + + public object Any(HelloPut request) + { + return new HelloVerbResponse { Result = HttpMethods.Put }; + } + + public object Any(HelloDelete request) + { + return new HelloVerbResponse { Result = HttpMethods.Delete }; + } + + public object Any(HelloPatch request) + { + return new HelloVerbResponse { Result = HttpMethods.Patch }; + } + + public void Any(HelloReturnVoid request) + { + } + + public object Any(EnumRequest request) + { + return new EnumResponse { Operator = request.Operator }; + } + + public object Any(ExcludeTest1 request) + { + return new ExcludeTestNested { Id = 1 }; + } + + public object Any(ExcludeTest2 request) + { + return request.GetType().Name; + } + + public object Any(ExcludeMetadata request) + { + return request; + } + + public object Any(RestrictLocalhost request) + { + return request; + } + + public object Any(RestrictInternal request) + { + return request; + } + + public object Any(RestrictExternal request) + { + return request; + } + + public object Any(IgnoreInMetadataConfig request) + { + return request; + } + + public object Any(HelloTuple request) => request; + + [Authenticate] + public object Any(HelloAuthenticated request) + { + var session = GetSession(); + + return new HelloAuthenticatedResponse + { + Version = request.Version, + SessionId = session.Id, + UserName = session.UserName, + Email = session.Email, + IsAuthenticated = session.IsAuthenticated, + }; + } + } + + public class GetUserSession : IReturn + { + } + + public partial class CustomUserSession + : AuthUserSession + { + [DataMember] + public virtual string CustomName { get; set; } + + [DataMember] + public virtual string CustomInfo { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/Properties/AssemblyInfo.cs b/tests/Check.ServiceInterface/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..cd7e5d6b56f --- /dev/null +++ b/tests/Check.ServiceInterface/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Check.ServiceInterface")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Check.ServiceInterface")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1798e3f7-8d28-47f2-ac69-34e44a8445c0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/Check.ServiceInterface/ReturnDataService.cs b/tests/Check.ServiceInterface/ReturnDataService.cs new file mode 100644 index 00000000000..9032e12762b --- /dev/null +++ b/tests/Check.ServiceInterface/ReturnDataService.cs @@ -0,0 +1,12 @@ +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class ReturnDataService : Service + { + public object Any(ReturnString request) => request.Data; + public object Any(ReturnBytes request) => request.Data; + public object Any(ReturnStream request) => request.Data; + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/ReturnGenericListServices.cs b/tests/Check.ServiceInterface/ReturnGenericListServices.cs new file mode 100644 index 00000000000..3e7dec4b134 --- /dev/null +++ b/tests/Check.ServiceInterface/ReturnGenericListServices.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/Request1/", "GET")] + public partial class GetRequest1 : IReturn>, IGet { } + + [Route("/Request3", "GET")] + public partial class GetRequest2 : IReturn, IGet { } + + public partial class ReturnedDto + { + public virtual int Id { get; set; } + } + + public class ReturnGenericListServices : Service + { + public object Any(GetRequest1 request) => request; + public object Any(GetRequest2 request) => request; + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/RouteMatchService.cs b/tests/Check.ServiceInterface/RouteMatchService.cs new file mode 100644 index 00000000000..d0ce4a70523 --- /dev/null +++ b/tests/Check.ServiceInterface/RouteMatchService.cs @@ -0,0 +1,59 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/matchroute/html", Matches = "AcceptsHtml")] + public class MatchesHtml : IReturn + { + public string Name { get; set; } + } + + [Route("/matchroute/json", Matches = "AcceptsJson")] + public class MatchesJson : IReturn + { + public string Name { get; set; } + } + + [Route("/matchroute/csv", Matches = "AcceptsCsv")] + public class MatchesCsv : IReturn + { + public string Name { get; set; } + } + + [Route("/matchlast/{Id}", Matches = @"**/{int}")] + public class MatchesLastInt + { + public int Id { get; set; } + } + + [Route("/matchlast/{Slug}")] + public class MatchesNotLastInt + { + public string Slug { get; set; } + } + + [Route("/matchregex/{Id}", Matches = @"PathInfo =~ \/[0-9]+$")] + public class MatchesId + { + public int Id { get; set; } + } + + [Route("/matchregex/{Slug}")] + public class MatchesSlug + { + public string Slug { get; set; } + } + + public class RouteMatchService : Service + { + public object Any(MatchesHtml request) => request; + public object Any(MatchesJson request) => request; + //public object Any(MatchesCsv request) => request; + + public object Any(MatchesLastInt request) => request; + public object Any(MatchesNotLastInt request) => request; + + public object Any(MatchesId request) => request; + public object Any(MatchesSlug request) => request; + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/SwaggerServices.cs b/tests/Check.ServiceInterface/SwaggerServices.cs new file mode 100644 index 00000000000..1d032d8718a --- /dev/null +++ b/tests/Check.ServiceInterface/SwaggerServices.cs @@ -0,0 +1,16 @@ +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class SwaggerServices : Service + { + public object Any(SwaggerVersionTest request) => request; + + public object Any(SwaggerRangeTest request) => request; + + public object Any(SwaggerDescTest request) => request; + + public object Any(SwaggerSearch request) => new EmptyResponse(); + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/TechStacksService.cs b/tests/Check.ServiceInterface/TechStacksService.cs new file mode 100644 index 00000000000..72d4ce76931 --- /dev/null +++ b/tests/Check.ServiceInterface/TechStacksService.cs @@ -0,0 +1,10 @@ +using Check.ServiceModel; +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class TechStacksService : Service + { + public object Any(GetTechnology request) => new GetTechnologyResponse(); + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/TestErrorService.cs b/tests/Check.ServiceInterface/TestErrorService.cs new file mode 100644 index 00000000000..c784b3a00a2 --- /dev/null +++ b/tests/Check.ServiceInterface/TestErrorService.cs @@ -0,0 +1,37 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/test/errorview")] + public class TestErrorView + { + public string Id { get; set; } + } + + public class TestErrorService : Service + { + public object Any(TestErrorView request) + { + return request; + } + } + + + [Route("/timestamp", Verbs = "GET")] + public class GetTimestamp : IReturn + { + } + + public class TimestampData + { + public long Timestamp { get; set; } + } + + public class TimestampService : Service + { + public object Get(GetTimestamp request) + { + return new TimestampData { Timestamp = 635980054734850470 }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/TestMinifierServices.cs b/tests/Check.ServiceInterface/TestMinifierServices.cs new file mode 100644 index 00000000000..30625f4d4db --- /dev/null +++ b/tests/Check.ServiceInterface/TestMinifierServices.cs @@ -0,0 +1,14 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + public class TestMiniverView {} + + public class TestMinifierServices : Service + { + public object Any(TestMiniverView request) + { + return request; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/TestProfilerService.cs b/tests/Check.ServiceInterface/TestProfilerService.cs new file mode 100644 index 00000000000..25be922fc2b --- /dev/null +++ b/tests/Check.ServiceInterface/TestProfilerService.cs @@ -0,0 +1,29 @@ +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace Check.ServiceInterface +{ + public class DummyTable + { + public int Id { get; set; } + public string Name { get; set; } + } + + [Route("/testexecproc")] + public class TestExecProc {} + + public class TestProfilerService : Service + { + public IDbConnectionFactory ConnectionFactory { get; set; } + + public object Any(TestExecProc request) + { + using (var sqlServer = ConnectionFactory.OpenDbConnection("SqlServer")) + { + var results = sqlServer.SqlList("EXEC DummyTable @Times", new { Times = 10 }); + return results; + } + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/VirtualPathServices.cs b/tests/Check.ServiceInterface/VirtualPathServices.cs new file mode 100644 index 00000000000..ad7fd8cc4dd --- /dev/null +++ b/tests/Check.ServiceInterface/VirtualPathServices.cs @@ -0,0 +1,24 @@ +using ServiceStack; + +namespace Check.ServiceInterface +{ + [Route("/files/{Path*}")] + public class GetFile + { + public string Path { get; set; } + } + + public class FileServices : Service + { + public object Any(GetFile request) + { + var file = VirtualFileSources.GetFile(request.Path); + if (file == null) + throw HttpError.NotFound("File '{0}' does not exist".Fmt(request.Path)); + + return new HttpResult(file) { + ContentType = MimeTypes.GetMimeType(file.Extension) + }; + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceInterface/app.config b/tests/Check.ServiceInterface/app.config new file mode 100644 index 00000000000..f6e7dca8dcb --- /dev/null +++ b/tests/Check.ServiceInterface/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Check.ServiceModel/Annotations.cs b/tests/Check.ServiceModel/Annotations.cs new file mode 100644 index 00000000000..62b873b4de7 --- /dev/null +++ b/tests/Check.ServiceModel/Annotations.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel.DataAnnotations; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceModel +{ + [Alias("AliasAnnotations")] + [Schema("Annotations.dbo")] + [NamedConnection("AnnotationsDb")] + [Tag("web"),Tag("mobile"),Tag("desktop")] + public class HelloAnnotations : IReturn + { + [Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName = "Id", Order = 1)] + [AutoIncrement] + public int Id { get; set; } + + [Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName = "ItemNumber", Order = 1)] + public string ItemNumber { get; set; } + + [Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName = "WarehouseCode", Order = 2)] + public string WarehouseCode { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Qty", Order = 3)] + public int? QtyOnHand { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Lot Serial", Order = 4)] + public string LotSerial { get; set; } + + [Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName = "LocationCode", Order = 5)] + public string LocationCode { get; set; } + + [Display(AutoGenerateField = false, AutoGenerateFilter = true, ShortName = "Device ID", Order = 6)] + public string DeviceId { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Counted", Order = 7)] + [DataType(DataType.DateTime)] + [DisplayFormat(DataFormatString = "MM/dd/yyyy HH:mm:ss")] + public DateTime CountDate { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Counted By", Order = 8)] + public string DeviceUser { get; set; } + + [Display(AutoGenerateField = false, AutoGenerateFilter = false, ShortName = "BatchKey", Order = 9)] + public int? BatchKey { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = false, ShortName = "Item", Order = -1)] + [Association(name: "Item.ItemID", thisKey: "ItemKey", otherKey: "ItemKey")] + public int ItemKey { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Expiration Date", Order = 4)] + [DataType(DataType.DateTime)] + [DisplayFormat(DataFormatString = "MM/yyyy")] + public DateTime? ExpirationDate { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Updated", Order = 14)] + [DataType(DataType.DateTime)] + [DisplayFormat(DataFormatString = "MM/dd/yyyy HH:mm:ss")] + public DateTime? UpdateDate { get; set; } + + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "Updated By", Order = 15)] + public string UpdatedBy { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/AutoQueryTypes.cs b/tests/Check.ServiceModel/AutoQueryTypes.cs new file mode 100644 index 00000000000..29c3e92b785 --- /dev/null +++ b/tests/Check.ServiceModel/AutoQueryTypes.cs @@ -0,0 +1,32 @@ +using ServiceStack; + +namespace Check.ServiceModel +{ + public class OnlyDefinedInGenericType + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class QueryPocoBase : QueryDb + { + public int Id { get; set; } + } + + public class OnlyDefinedInGenericTypeFrom + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class OnlyDefinedInGenericTypeInto + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class QueryPocoIntoBase : QueryDb + { + public int Id { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/Check.ServiceModel.csproj b/tests/Check.ServiceModel/Check.ServiceModel.csproj new file mode 100644 index 00000000000..286d11a2dab --- /dev/null +++ b/tests/Check.ServiceModel/Check.ServiceModel.csproj @@ -0,0 +1,81 @@ + + + + + Debug + AnyCPU + {213EF4BA-786A-432F-B147-5702B18DE3CC} + Library + Properties + Check.ServiceModel + Check.ServiceModel + v4.7.2 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {680A1709-25EB-4D52-A87F-EE03FFD94BAA} + ServiceStack + + + + + \ No newline at end of file diff --git a/tests/Check.ServiceModel/CodeGenTestTypes.cs b/tests/Check.ServiceModel/CodeGenTestTypes.cs new file mode 100644 index 00000000000..35ab5432c92 --- /dev/null +++ b/tests/Check.ServiceModel/CodeGenTestTypes.cs @@ -0,0 +1,825 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Runtime.Serialization; +using Check.ServiceModel.Types; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceModel.Operations +{ + [System.ComponentModel.Description("Description for HelloACodeGenTest")] + [Tag("web")] + public class HelloACodeGenTest + { + [Description("Description for FirstField")] + public int FirstField { get; set; } + + public List SecondFields { get; set; } + } + + [DataContract] + [Tag("mobile")] + public class HelloACodeGenTestResponse + { + [DataMember] + [Description("Description for FirstResult")] + public int FirstResult { get; set; } + + [DataMember] + [ApiMember(Description = "Description for SecondResult")] + public int SecondResult { get; set; } + } + + [Route("/hello")] + [Route("/hello/{Name}")] + [Tag("web"),Tag("mobile")] + public class Hello + { + [Required] + public string Name { get; set; } + public string Title { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + } + + [Tag("desktop")] + public class HelloWithNestedClass : IReturn + { + public string Name { get; set; } + public NestedClass NestedClassProp { get; set; } + + // This will generate a class definition "public partial class Hello.NestedClass" + public class NestedClass + { + public string Value { get; set; } + } + } + + public class ListResult + { + public string Result { get; set; } + } + + public class OnlyInReturnListArg + { + public string Result { get; set; } + } + + public class ArrayResult + { + public string Result { get; set; } + } + + [Tag("web")] + public class HelloList : IReturn> + { + public List Names { get; set; } + } + + [Tag("mobile")] + public class HelloReturnList : IReturn> + { + public List Names { get; set; } + } + + [Tag("desktop")] + public class HelloArray : IReturn + { + public List Names { get; set; } + } + + [Tag("mobile"),Tag("desktop")] + public class HelloExisting : IReturn + { + public List Names { get; set; } + } + + public class HelloExistingResponse + { + public HelloList HelloList { get; set; } + public HelloArray HelloArray { get; set; } + public ArrayResult[] ArrayResults { get; set; } + public List ListResults { get; set; } + } + + public class HelloWithEnum + { + public EnumType EnumProp { get; set; } + public EnumTypeFlags EnumTypeFlags { get; set; } + + public EnumWithValues EnumWithValues { get; set; } + public EnumType? NullableEnumProp { get; set; } + + public EnumFlags EnumFlags { get; set; } + public EnumAsInt EnumAsInt { get; set; } + public EnumStyle EnumStyle { get; set; } + public EnumStyleMembers EnumStyleMembers { get; set; } + } + + public class HelloWithEnumList + { + public List EnumProp { get; set; } + public List EnumWithValues { get; set; } + public List NullableEnumProp { get; set; } + + public List EnumFlags { get; set; } + public List EnumStyle { get; set; } + } + + public class HelloWithEnumMap + { + public Dictionary EnumProp { get; set; } + public Dictionary EnumWithValues { get; set; } + public Dictionary NullableEnumProp { get; set; } + + public Dictionary EnumFlags { get; set; } + public Dictionary EnumStyle { get; set; } + } + + public enum EnumType + { + Value1, + Value2, + Value3, + } + + [Flags] + public enum EnumTypeFlags + { + Value1, + Value2, + Value3, + } + + public enum EnumWithValues + { + None = 0, + [EnumMember(Value = "Member 1")] + Value1 = 1, + [Description("Member 2")] + Value2 = 2, + } + + [Flags] + public enum EnumFlags + { + Value0 = 0, + [EnumMember(Value = "Value 1")] + Value1 = 1, + [Description("Value 2")] + Value2 = 2, + Value3 = 4, + Value123 = Value1 | Value2 | Value3, + } + + [EnumAsInt] + public enum EnumAsInt + { + Value1 = 1000, + Value2 = 2000, + Value3 = 3000, + } + + public enum EnumStyle + { + lower, + UPPER, + PascalCase, + camelCase, + camelUPPER, + PascalUPPER, + } + + public enum EnumStyleMembers + { + [EnumMember(Value = "lower")] + Lower, + [EnumMember(Value = "UPPER")] + Upper, + [EnumMember(Value = "PascalCase")] + PascalCase, + [EnumMember(Value = "camelCase")] + CamelCase, + [EnumMember(Value = "camelUPPER")] + CamelUpper, + [EnumMember(Value = "PascalUPPER")] + PascalUpper, + } + + [Restrict(InternalOnly = true)] + [System.ComponentModel.Description("Description on HelloAll type")] + [DataContract] + public class HelloAnnotated + : IReturn + { + [DataMember] + public string Name { get; set; } + } + + [Restrict(ExternalOnly = true)] + public class HelloExternal + { + public string Name { get; set; } + } + + [Restrict(InternalOnly = true)] + [Alias("Alias")] + public class RestrictedAttributes + { + [PrimaryKey] + [AutoIncrement] + public int Id { get; set; } + + [Index] + [ApiAllowableValues("DateKind", typeof(DateTimeKind))] + public string Name { get; set; } + + public Hello Hello { get; set; } + } + + [DataContract] + [Route("/allowed-attributes", "GET")] + [Api(@"AllowedAttributes Description")] + [ApiResponse(HttpStatusCode.BadRequest, "Your request was not understood")] + [Description("Description on AllowedAttributes")] + public class AllowedAttributes + { + [Required] + [Range(1, 10)] + [Default(5)] + [DataMember] + public int Id { get; set; } + + [Range(1.0, 10.0)] + [DataMember(Name = "Aliased")] + [ApiMember(Description = "Range Description", + ParameterType = "path", DataType = "double", IsRequired = true)] + public double Range { get; set; } + + [StringLength(20)] + [References(typeof(Hello))] + [Meta("Foo", "Bar")] + public string Name { get; set; } + } + + [Api(@"Multi +Line +Class")] + public class HelloAttributeStringTest + { + [ApiMember(Description = @"Multi +Line +Property")] + public string Overflow { get; set; } + + [ApiMember(Description = "Some \\ escaped \t \n chars")] + public string EscapedChars { get; set; } + } + + [System.ComponentModel.Description("Description on HelloAllResponse type")] + [DataContract] + public class HelloAnnotatedResponse + { + [DataMember] + public string Result { get; set; } + } + + public class HelloAllTypes + { + public string Name { get; set; } + public AllTypes AllTypes { get; set; } + public AllCollectionTypes AllCollectionTypes { get; set; } + } + + public class HelloAllTypesResponse + { + public string Result { get; set; } + public AllTypes AllTypes { get; set; } + public AllCollectionTypes AllCollectionTypes { get; set; } + } + + public class HelloString : IReturn + { + public string Name { get; set; } + } + + public class HelloVoid : IReturnVoid + { + public string Name { get; set; } + } + + [DataContract] + public class HelloWithDataContract + { + [DataMember(Name = "name", Order = 1, IsRequired = true, EmitDefaultValue = false)] + public string Name { get; set; } + + [DataMember(Name = "id", Order = 2, EmitDefaultValue = false)] + public int Id { get; set; } + } + + [DataContract] + public class HelloWithDataContractResponse + { + [DataMember(Name = "result", Order = 1, IsRequired = true, EmitDefaultValue = false)] + public string Result { get; set; } + } + + [System.ComponentModel.Description("Description on HelloWithDescription type")] + public class HelloWithDescription + { + public string Name { get; set; } + } + + [System.ComponentModel.Description("Description on HelloWithDescriptionResponse type")] + public class HelloWithDescriptionResponse + { + public string Result { get; set; } + } + + public class HelloWithInheritance + : HelloBase + { + public string Name { get; set; } + } + + public class HelloWithInheritanceResponse + : HelloResponseBase + { + public string Result { get; set; } + } + + public class HelloWithGenericInheritance : HelloBase + { + public string Result { get; set; } + } + + public class HelloWithGenericInheritance2 : HelloBase + { + public string Result { get; set; } + } + + public class HelloWithNestedInheritance : HelloBase + { + public class Item + { + public string Value { get; set; } + } + } + + public class HelloWithListInheritance : List {} + + public class InheritedItem + { + public string Name { get; set; } + } + + public abstract class HelloBase + { + public List Items { get; set; } + public List Counts { get; set; } + } + + public class HelloWithReturn + : IReturn + { + public string Name { get; set; } + } + + public class HelloWithAlternateReturnResponse + : HelloWithReturnResponse + { + public string AltResult { get; set; } + } + + [Route("/helloroute")] + public class HelloWithRoute + { + public string Name { get; set; } + } + + public class HelloWithRouteResponse + { + public string Result { get; set; } + } + + public class HelloWithType + { + public string Name { get; set; } + } + + public class HelloWithTypeResponse + { + public HelloType Result { get; set; } + } +} + +namespace Check.ServiceModel.Types +{ + public class AllTypes : IReturn + { + public int Id { get; set; } + public int? NullableId { get; set; } + public byte Byte { get; set; } + public short Short { get; set; } + public int Int { get; set; } + public long Long { get; set; } + public UInt16 UShort { get; set; } + public uint UInt { get; set; } + public ulong ULong { get; set; } + public float Float { get; set; } + public double Double { get; set; } + public decimal Decimal { get; set; } + public string String { get; set; } + public DateTime DateTime { get; set; } + public TimeSpan TimeSpan { get; set; } + public DateTimeOffset DateTimeOffset { get; set; } + public Guid Guid { get; set; } + public Char Char { get; set; } + public KeyValuePair KeyValuePair { get; set; } + public DateTime? NullableDateTime { get; set; } + public TimeSpan? NullableTimeSpan { get; set; } + public List StringList { get; set; } + public string[] StringArray { get; set; } + public Dictionary StringMap { get; set; } + public Dictionary IntStringMap { get; set; } + public SubType SubType { get; set; } + public Point Point { get; set; } + + [DataMember(Name = "aliasedName")] + public string OriginalName { get; set; } + } + + public class AllCollectionTypes + { + public int[] IntArray { get; set; } + public List IntList { get; set; } + + public string[] StringArray { get; set; } + public List StringList { get; set; } + + public Poco[] PocoArray { get; set; } + public List PocoList { get; set; } + + public byte?[] NullableByteArray { get; set; } + public List NullableByteList { get; set; } + + public DateTime?[] NullableDateTimeArray { get; set; } + public List NullableDateTimeList { get; set; } + + public Dictionary> PocoLookup { get; set; } + public Dictionary>> PocoLookupMap { get; set; } + } + + public class Poco + { + public string Name { get; set; } + } + + public struct Point + { + public Point(double x=0, double y=0) : this() + { + X = x; + Y = y; + } + + public Point(string point) : this() + { + var parts = point.Split(','); + X = double.Parse(parts[0]); + Y = double.Parse(parts[1]); + } + + public double X { get; set; } + public double Y { get; set; } + + public override string ToString() + { + return X.ToString(CultureInfo.InvariantCulture) + "," + Y.ToString(CultureInfo.InvariantCulture); + } + } + + public class HelloStruct : IReturn + { + public Point Point { get; set; } + public Point? NullablePoint { get; set; } + } + + public abstract class HelloBase + { + public int Id { get; set; } + } + + public class HelloResponseBase + { + public int RefId { get; set; } + } + + public class HelloType + { + public string Result { get; set; } + } + + public class HelloWithReturnResponse + { + public string Result { get; set; } + } + + public class SubType + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class HelloSession : IReturn + { + } + + public class HelloSessionResponse + { + public AuthUserSession Result { get; set; } + } + + public class HelloInterface : IGenericInterface + { + public IPoco Poco { get; set; } + public IEmptyInterface EmptyInterface { get; set; } + public EmptyClass EmptyClass { get; set; } + public string Value { get; set; } + //public IGenericInterface GenericInterface { get; set; } + } + + public class HelloImplementsInterface : IReturn, ImplementsPoco + { + public string Name { get; set; } + } + + public interface ImplementsPoco + { + string Name { get; set; } + } + + public interface IPoco + { + string Name { get; set; } + } + + public interface IEmptyInterface {} + public class EmptyClass {} + + public interface IGenericInterface + { + T Value { get; } + } + + /// + /// Duplicate Types + /// + public class TypeB + { + public string Foo { get; set; } + } + + public class TypeA + { + public List Bar { get; set; } + } + + public class Request1 : IReturn + { + public TypeA Test { get; set; } + } + + public class Request1Response + { + public TypeA Test { get; set; } + } + + public class Request2 : IReturn + { + public TypeA Test { get; set; } + } + + public class Request2Response + { + public TypeA Test { get; set; } + } + + public class TypesGroup + { + public class InnerType + { + public long Id { get; set; } + public string Name { get; set; } + } + + public class InnerTypeItem + { + public long Id { get; set; } + public string Name { get; set; } + } + + public enum InnerEnum + { + Foo, + Bar, + Baz + } + } + + public class HelloInnerTypes : IReturn { } + + public class HelloInnerTypesResponse + { + public TypesGroup.InnerType InnerType { get; set; } + + public TypesGroup.InnerEnum InnerEnum { get; set; } + + public List InnerList { get; set; } + } + + public class QueryTemplate : IReturn> {} + + [DataContract] + public class QueryResponseTemplate : IHasResponseStatus, IMeta + { + [DataMember(Order = 1)] + public virtual int Offset { get; set; } + + [DataMember(Order = 2)] + public virtual int Total { get; set; } + + [DataMember(Order = 3)] + public virtual List Results { get; set; } + + [DataMember(Order = 4)] + public virtual Dictionary Meta { get; set; } + + [DataMember(Order = 5)] + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public class HelloReserved + { + public string Class { get; set; } + public string Type { get; set; } + public string extension { get; set; } + } + + public class HelloDictionary : IReturn> + { + public string Key { get; set; } + public string Value { get; set; } + } + + [DataContract] + public enum ShortDays + { + [EnumMember(Value = "MON")] + Monday, + [EnumMember(Value = "TUE")] + Tuesday, + [EnumMember(Value = "WED")] + Wednesday, + [EnumMember(Value = "THU")] + Thursday, + [EnumMember(Value = "FRI")] + Friday, + [EnumMember(Value = "SAT")] + Saturday, + [EnumMember(Value = "SUN")] + Sunday, + } + + public class HelloBuiltin + { + public DayOfWeek DayOfWeek { get; set; } + public ShortDays ShortDays { get; set; } + } + + public class HelloVerbResponse + { + public string Result { get; set; } + } + + public class HelloGet : IReturn, IGet + { + public int Id { get; set; } + } + public class HelloPost : HelloBase, IReturn, IPost + { + } + public class HelloPut : IReturn, IPut + { + public int Id { get; set; } + } + public class HelloDelete : IReturn, IDelete + { + public int Id { get; set; } + } + public class HelloPatch : IReturn, IPatch + { + public int Id { get; set; } + } + + public class HelloReturnVoid : IReturnVoid + { + public int Id { get; set; } + } + + public class EnumRequest : IReturn, IPut + { + public ScopeType Operator { get; set; } + } + + public class EnumResponse + { + public ScopeType Operator { get; set; } + } + + [DataContract] + public enum ScopeType + { + [EnumMember] + Global = 1, + [EnumMember] + Sale = 2, + } + + public class ExcludeTest1 : IReturn + { + } + + public class ExcludeTest2 : IReturn + { + public ExcludeTestNested ExcludeTestNested { get; set; } + } + + public class ExcludeTestNested + { + public int Id { get; set; } + } + + + [Exclude(Feature.Metadata)] + public class ExcludeMetadata : IReturn + { + public int Id { get; set; } + } + + [Restrict(LocalhostOnly = true)] + public class RestrictLocalhost : IReturn + { + public int Id { get; set; } + } + + [Restrict(InternalOnly = true)] + public class RestrictInternal : IReturn + { + public int Id { get; set; } + } + + [Restrict(ExternalOnly = true)] + public class RestrictExternal : IReturn + { + public int Id { get; set; } + } + + public class IgnoreInMetadataConfig : IReturn + { + public int Id { get; set; } + } + + public class HelloTuple : IReturn + { + public Tuple Tuple2 { get; set; } + public Tuple Tuple3 { get; set; } + + public List> Tuples2 { get; set; } + public List> Tuples3 { get; set; } + } + + public class HelloAuthenticated : IReturn, IHasSessionId + { + public string SessionId { get; set; } + public int Version { get; set; } + } + + public class HelloAuthenticatedResponse + { + public int Version { get; set; } + public string SessionId { get; set; } + public string UserName { get; set; } + public string Email { get; set; } + public bool IsAuthenticated { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } +} + + diff --git a/tests/Check.ServiceModel/CustomMethodRoutes.cs b/tests/Check.ServiceModel/CustomMethodRoutes.cs new file mode 100644 index 00000000000..2abb6869b4e --- /dev/null +++ b/tests/Check.ServiceModel/CustomMethodRoutes.cs @@ -0,0 +1,18 @@ +using System; +using ServiceStack; + +namespace Check.ServiceModel +{ + public class Organization + { + public string Name { get; set; } + public Guid Id { get; set; } + } + + [Route("/organizations/{Id}", Verbs = "GET")] + public class GetOrganizationRequest : IReturn + { + public Guid Id { get; set; } + public bool IncludeAddresses { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/DynamicallyRegisteredService.cs b/tests/Check.ServiceModel/DynamicallyRegisteredService.cs new file mode 100644 index 00000000000..8ff35f51cd9 --- /dev/null +++ b/tests/Check.ServiceModel/DynamicallyRegisteredService.cs @@ -0,0 +1,26 @@ +using ServiceStack; + +namespace Check.ServiceModel +{ + [Route("/dynamically/registered/{Name}")] + public class DynamicallyRegistered + { + public string Name { get; set; } + } + + public class DynamicallyRegisteredService : Service + { + public object Any(DynamicallyRegistered request) + { + return request; + } + } + + public class DynamicallyRegisteredPlugin : IPlugin + { + public void Register(IAppHost appHost) + { + appHost.RegisterServicesInAssembly(GetType().Assembly); + } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/Echoes.cs b/tests/Check.ServiceModel/Echoes.cs new file mode 100644 index 00000000000..f82a625a38e --- /dev/null +++ b/tests/Check.ServiceModel/Echoes.cs @@ -0,0 +1,52 @@ +using ServiceStack; + +namespace Check.ServiceModel +{ + public class AsyncTest : IReturn { } + + /// + /// The Echo interface. + /// + public interface IEcho + { + /// + /// Gets or sets the sentence to echo. + /// + string Sentence { get; set; } + } + + /// + /// The Echo. + /// + public class Echo : IEcho + { + /// + /// Gets or sets the sentence. + /// + public string Sentence { get; set; } + } + + /// + /// The Echoes operation endpoints. + /// + [Api("Echoes a sentence")] + [Route("/echoes", "POST", Summary = @"Echoes a sentence.")] + public class Echoes : IReturn + { + /// + /// Gets or sets the sentence to echo. + /// + [ApiMember(Name = "Sentence", + DataType = "string", + Description = "The sentence to echo.", + IsRequired = true, + ParameterType = "form")] + public string Sentence { get; set; } + } + + public class CachedEcho : IReturn + { + public bool Reload { get; set; } + public string Sentence { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/Errors.cs b/tests/Check.ServiceModel/Errors.cs new file mode 100644 index 00000000000..c1ddef5463a --- /dev/null +++ b/tests/Check.ServiceModel/Errors.cs @@ -0,0 +1,31 @@ +using ServiceStack; + +namespace Check.ServiceModel +{ + public class CustomHttpError + { + public int StatusCode { get; set; } + public string StatusDescription { get; set; } + } + public class CustomHttpErrorResponse + { + public string Custom { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomFieldHttpError { } + public class CustomFieldHttpErrorResponse + { + public string Custom { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/alwaysthrows")] + public class AlwaysThrows : IReturn { } + + [Route("/alwaysthrowsfilterattribute")] + public class AlwaysThrowsFilterAttribute : IReturn { } + + [Route("/alwaysthrowsglobalfilter")] + public class AlwaysThrowsGlobalFilter : IReturn { } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/MetadataTest.cs b/tests/Check.ServiceModel/MetadataTest.cs new file mode 100644 index 00000000000..dd72c3d5d80 --- /dev/null +++ b/tests/Check.ServiceModel/MetadataTest.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Check.ServiceModel.Types; +using ServiceStack; + +namespace Check.ServiceModel +{ + public class MetadataTest : IReturn + { + public int Id { get; set; } + } + + public class MetadataTestResponse + { + public int Id { get; set; } + public List Results { get; set; } + } + + public class MetadataTestChild + { + public string Name { get; set; } + + public List Results { get; set; } + } + + public class MetadataTestNestedChild + { + public string Name { get; set; } + } + + + [Route("/example", "GET", Summary = @"")] + [DataContract] + public class GetExample : IReturn + { + } + + [DataContract] + public class GetExampleResponse : IHasResponseStatus + { + [DataMember(Order = 1, IsRequired = false)] + public ResponseStatus ResponseStatus { get; set; } + + [ApiMember] + [DataMember(Order = 2, IsRequired = false)] + public MenuExample MenuExample1 { get; set; } + } + + [DataContract] + public class MenuExample + { + [ApiMember] + [DataMember(Order = 1, IsRequired = false)] + public MenuItemExample MenuItemExample1 { get; set; } + } + + //[DataContract] + public class MenuItemExample + { + [ApiMember] + [DataMember(Order = 1, IsRequired = false)] + public string Name1 { get; set; } + + public MenuItemExampleItem MenuItemExampleItem { get; set; } + } + + public class MenuItemExampleItem + { + [ApiMember] + [DataMember(Order = 1, IsRequired = false)] + public string Name1 { get; set; } + } + + [ServiceStack.DataAnnotations.ExcludeMetadata] + public class ExcludeMetadataType + { + public int Id { get; set; } + } + + public class ExcludeMetadataProperty + { + public int Id { get; set; } + [ServiceStack.DataAnnotations.ExcludeMetadata] + public int ExcludedProperty { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/NativeTypeIssues.cs b/tests/Check.ServiceModel/NativeTypeIssues.cs new file mode 100644 index 00000000000..8bf7fae4653 --- /dev/null +++ b/tests/Check.ServiceModel/NativeTypeIssues.cs @@ -0,0 +1,42 @@ +using System.ComponentModel.DataAnnotations; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceModel +{ + [ExcludeMetadata] + public abstract class Issue221Base + { + public T Id { get; set; } + + protected Issue221Base(T id) + { + Id = id; + } + } + + [ExcludeMetadata] + public class Issue221Long : Issue221Base + { + public Issue221Long(long id) : base(id) + { + } + } + + + public class TestAttributeExport : IReturn + { + [Display(AutoGenerateField = true, AutoGenerateFilter = true, ShortName = "UnitMeasKey")] + public int UnitMeasKey { get; set; } + + [Display(AutoGenerateField = false)] + public int AutoGenerateFieldOff { get; set; } + } + + public class RecursiveNode : IReturn + { + public int Id { get; set; } + public string Text { get; set; } + public RecursiveNode[] Children { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/Properties/AssemblyInfo.cs b/tests/Check.ServiceModel/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..009207cac5e --- /dev/null +++ b/tests/Check.ServiceModel/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Check.ServiceModel")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Check.ServiceModel")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("17cf727f-f5bf-40b8-a6e2-132f27b0f4e3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/Check.ServiceModel/QueryPosts.cs b/tests/Check.ServiceModel/QueryPosts.cs new file mode 100644 index 00000000000..04c1f5f709e --- /dev/null +++ b/tests/Check.ServiceModel/QueryPosts.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using Check.ServiceModel.Types; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceModel +{ + [Route("/posts", "GET")] + public partial class QueryPosts + : QueryDb, IReturn>, IGet + { + public QueryPosts() + { + Ids = new int[]{}; + OrganizationIds = new List{}; + Types = new HashSet{}; + AnyTechnologyIds = new HashSet{}; + Is = new string[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual int? OrganizationId { get; set; } + public virtual List OrganizationIds { get; set; } + public virtual HashSet Types { get; set; } + public virtual HashSet AnyTechnologyIds { get; set; } + public virtual string[] Is { get; set; } + } + + public partial class Post + { + public Post() + { + TechnologyIds = new int[]{}; + Labels = new string[]{}; + RefUserIds = new int[]{}; + RefLinks = new string[]{}; + MuteUserIds = new int[]{}; + } + + public virtual long Id { get; set; } + public virtual int OrganizationId { get; set; } + public virtual int UserId { get; set; } + public virtual PostType Type { get; set; } + public virtual int CategoryId { get; set; } + public virtual string Title { get; set; } + public virtual string Slug { get; set; } + public virtual string Url { get; set; } + public virtual string ImageUrl { get; set; } + [StringLength(int.MaxValue)] + public virtual string Content { get; set; } + + [StringLength(int.MaxValue)] + public virtual string ContentHtml { get; set; } + + public virtual long? PinCommentId { get; set; } + public virtual int[] TechnologyIds { get; set; } + public virtual DateTime? FromDate { get; set; } + public virtual DateTime? ToDate { get; set; } + public virtual string Location { get; set; } + public virtual string MetaType { get; set; } + public virtual string Meta { get; set; } + public virtual bool Approved { get; set; } + public virtual long UpVotes { get; set; } + public virtual long DownVotes { get; set; } + public virtual long Points { get; set; } + public virtual long Views { get; set; } + public virtual long Favorites { get; set; } + public virtual int Subscribers { get; set; } + public virtual int ReplyCount { get; set; } + public virtual int CommentsCount { get; set; } + public virtual int WordCount { get; set; } + public virtual int ReportCount { get; set; } + public virtual int LinksCount { get; set; } + public virtual int LinkedToCount { get; set; } + public virtual int Score { get; set; } + public virtual int Rank { get; set; } + public virtual string[] Labels { get; set; } + public virtual int[] RefUserIds { get; set; } + public virtual string[] RefLinks { get; set; } + public virtual int[] MuteUserIds { get; set; } + public virtual DateTime? LastCommentDate { get; set; } + public virtual long? LastCommentId { get; set; } + public virtual int? LastCommentUserId { get; set; } + public virtual DateTime? Deleted { get; set; } + public virtual string DeletedBy { get; set; } + public virtual DateTime? Locked { get; set; } + public virtual string LockedBy { get; set; } + public virtual DateTime? Hidden { get; set; } + public virtual string HiddenBy { get; set; } + public virtual string Status { get; set; } + public virtual DateTime? StatusDate { get; set; } + public virtual string StatusBy { get; set; } + public virtual bool Archived { get; set; } + public virtual DateTime? Bumped { get; set; } + public virtual DateTime Created { get; set; } + public virtual string CreatedBy { get; set; } + public virtual DateTime Modified { get; set; } + public virtual string ModifiedBy { get; set; } + public virtual long? RefId { get; set; } + public virtual string RefSource { get; set; } + public virtual string RefUrn { get; set; } + } + + public enum PostType + { + Announcement, + Post, + Showcase, + Question, + Request, + } + + [Route("/echo/types")] + public partial class EchoTypes + : IReturn + { + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual Guid Guid { get; set; } + public virtual Char Char { get; set; } + } + +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/ReturnData.cs b/tests/Check.ServiceModel/ReturnData.cs new file mode 100644 index 00000000000..751f5d5a8f8 --- /dev/null +++ b/tests/Check.ServiceModel/ReturnData.cs @@ -0,0 +1,23 @@ +using System.IO; +using ServiceStack; + +namespace Check.ServiceModel +{ + [Route("/return/string")] + public class ReturnString : IReturn + { + public string Data { get; set; } + } + + [Route("/return/bytes")] + public class ReturnBytes : IReturn + { + public byte[] Data { get; set; } + } + + [Route("/return/stream")] + public class ReturnStream : IReturn + { + public byte[] Data { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/Rockstar.cs b/tests/Check.ServiceModel/Rockstar.cs new file mode 100644 index 00000000000..ae0e6379714 --- /dev/null +++ b/tests/Check.ServiceModel/Rockstar.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; +using ServiceStack; + +namespace Check.ServiceModel +{ + public class Rockstar + { + [Description("Идентификатор")] + public int Id { get; set; } + [Description("Фамилия")] + public string FirstName { get; set; } + [Description("Имя")] + public string LastName { get; set; } + [Description("Возраст")] + public int? Age { get; set; } + } + + public enum LivingStatus + { + Alive, + Dead + } + +} diff --git a/tests/Check.ServiceModel/SwaggerTest.cs b/tests/Check.ServiceModel/SwaggerTest.cs new file mode 100644 index 00000000000..7ea1ac6ccb8 --- /dev/null +++ b/tests/Check.ServiceModel/SwaggerTest.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceModel +{ + [Route("/{Version}/userdata", "GET")] + public class SwaggerVersionTest + { + public string Version { get; set; } + } + + [Route("/swagger/range")] + public class SwaggerRangeTest + { + public string IntRange { get; set; } + + public string DoubleRange { get; set; } + } + + public enum MyColorDesc + { + [Description("The color Red")] + Red = 10, + [Description("The color Green")] + Green = 20, + [Description("The color Blue")] + Blue = 30, + } + + public enum MyColorBasic + { + [Description("Basic color Red")] + Red, + [Description("Basic color Green")] + Green, + [Description("Basic color Blue")] + Blue + } + + [Flags] + public enum MyColorFlags + { + [Description("Flag color Red")] + Red = 10, + [Description("Flag color Green")] + Green = 20, + [Description("Flag color Blue")] + Blue = 30, + } + + [Route("/swagger/desc")] + public class SwaggerDescTest + { + [ApiMember(Description = "Color Description", + ParameterType = "path", DataType = "string", IsRequired = true)] + [ApiAllowableValues("Name", typeof(MyColorBasic))] //Enum + [DataMember] + public string Name { get; set; } + + [ApiMember] + // [ApiAllowableValues("ColorBasic", typeof(MyColorDesc))] //Enum + [DataMember] + public MyColorBasic ColorBasic { get; set; } + + [ApiMember] + // [ApiAllowableValues("NColorBasic", typeof(MyColorDesc))] //Enum + [DataMember] + public MyColorBasic? NColorBasic { get; set; } + + + [ApiMember] + [ApiAllowableValues("ColorDesc", typeof(MyColorDesc))] //Enum + [DataMember] + public MyColorDesc ColorDesc { get; set; } + + + [ApiMember] + [ApiAllowableValues("NColorDesc", typeof(MyColorDesc))] //Enum + [DataMember] + public MyColorDesc? NColorDesc { get; set; } + + + [ApiMember] + [ApiAllowableValues("ColorFlags", typeof(MyColorFlags))] //Enum + [DataMember] + public MyColorFlags ColorFlags { get; set; } + } + + [Route("/swagger/search", "POST")] + public class SwaggerSearch : IReturn + { + public List Filters { get; set; } + } + + public class SearchFilter + { + [ApiMember(Name = "Field")] + public string Field { get; set; } + + [ApiMember(Name = "Values")] + public List Values { get; set; } + + [ApiMember(Name = "Type")] + public string Type { get; set; } + } +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/TechStacks.cs b/tests/Check.ServiceModel/TechStacks.cs new file mode 100644 index 00000000000..2c94bdcc5c2 --- /dev/null +++ b/tests/Check.ServiceModel/TechStacks.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace Check.ServiceModel +{ + public interface IRegisterStats + { + string GetStatsId(); + } + + [Route("/technology/{Slug}")] + public class GetTechnology : IReturn, IRegisterStats + { + public string Slug { get; set; } + + public long Id + { + set => Slug = value.ToString(); + } + + public string GetStatsId() + { + return "/tech/" + Slug; + } + } + + public class GetTechnologyResponse + { + public DateTime Created { get; set; } + + public Technology Technology { get; set; } + + public List TechnologyStacks { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public enum TechnologyTier + { + [Description("Programming Languages")] + ProgrammingLanguage, + + [Description("Client Libraries")] + Client, + + [Description("HTTP Server Technologies")] + Http, + + [Description("Server Libraries")] + Server, + + [Description("Databases and NoSQL Datastores")] + Data, + + [Description("Server Software")] + SoftwareInfrastructure, + + [Description("Operating Systems")] + OperatingSystem, + + [Description("Cloud/Hardware Infrastructure")] + HardwareInfrastructure, + + [Description("3rd Party APIs/Services")] + ThirdPartyServices, + } + + public class Technology : TechnologyBase {} + + public abstract class TechnologyBase + { + [AutoIncrement] + public long Id { get; set; } + + public string Name { get; set; } + public string VendorName { get; set; } + public string VendorUrl { get; set; } + public string ProductUrl { get; set; } + public string LogoUrl { get; set; } + public string Description { get; set; } + + public DateTime Created { get; set; } + public string CreatedBy { get; set; } + public DateTime LastModified { get; set; } + public string LastModifiedBy { get; set; } + public string OwnerId { get; set; } + + [Index] + public string Slug { get; set; } + + public bool LogoApproved { get; set; } + public bool IsLocked { get; set; } + + public TechnologyTier Tier { get; set; } + + public DateTime? LastStatusUpdate { get; set; } + + public int? OrganizationId { get; set; } + + public long? CommentsPostId { get; set; } + + [Default(0)] + public int ViewCount { get; set; } + + [Default(0)] + public int FavCount { get; set; } + } + + public class TechnologyStack : TechnologyStackBase {} + + public abstract class TechnologyStackBase + { + [AutoIncrement] + public long Id { get; set; } + + public string Name { get; set; } + public string VendorName { get; set; } + public string Description { get; set; } + public string AppUrl { get; set; } + public string ScreenshotUrl { get; set; } + + public DateTime Created { get; set; } + public string CreatedBy { get; set; } + public DateTime LastModified { get; set; } + public string LastModifiedBy { get; set; } + + public bool IsLocked { get; set; } + + public string OwnerId { get; set; } + + [Index] + public string Slug { get; set; } + + [StringLength(StringLengthAttribute.MaxText)] + public string Details { get; set; } + + [StringLength(StringLengthAttribute.MaxText)] + public string DetailsHtml { get; set; } + + public DateTime? LastStatusUpdate { get; set; } + + public int? OrganizationId { get; set; } + + public long? CommentsPostId { get; set; } + + [Default(0)] + public int ViewCount { get; set; } + + [Default(0)] + public int FavCount { get; set; } + } + +} \ No newline at end of file diff --git a/tests/Check.ServiceModel/ThrowHttpError.cs b/tests/Check.ServiceModel/ThrowHttpError.cs new file mode 100644 index 00000000000..6d17695af06 --- /dev/null +++ b/tests/Check.ServiceModel/ThrowHttpError.cs @@ -0,0 +1,55 @@ +using ServiceStack; + +namespace Check.ServiceModel +{ + [Route("/throwhttperror/{Status}")] + public class ThrowHttpError + { + public int Status { get; set; } + public string Message { get; set; } + } + + public class ThrowHttpErrorResponse { } + + [Route("/throw404")] + [Route("/throw404/{Message}")] + public class Throw404 + { + public string Message { get; set; } + } + + [Route("/return404")] + public class Return404 { } + + [Route("/return404result")] + public class Return404Result { } + + [Route("/throw/{Type}")] + public class ThrowType : IReturn + { + public string Type { get; set; } + public string Message { get; set; } + } + + public class ThrowTypeResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throwvalidation")] + public class ThrowValidation : IReturn + { + public int Age { get; set; } + public string Required { get; set; } + public string Email { get; set; } + } + + public class ThrowValidationResponse + { + public int Age { get; set; } + public string Required { get; set; } + public string Email { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } +} \ No newline at end of file diff --git a/tests/CheckCoreApi/CheckCoreApi.csproj b/tests/CheckCoreApi/CheckCoreApi.csproj new file mode 100644 index 00000000000..b87587e471d --- /dev/null +++ b/tests/CheckCoreApi/CheckCoreApi.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + diff --git a/tests/CheckCoreApi/Program.cs b/tests/CheckCoreApi/Program.cs new file mode 100644 index 00000000000..a82b7f2398b --- /dev/null +++ b/tests/CheckCoreApi/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using ServiceStack; + +namespace CheckCoreApi +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { + webBuilder.UseModularStartup(); + }); + } +} \ No newline at end of file diff --git a/tests/CheckCoreApi/Properties/launchSettings.json b/tests/CheckCoreApi/Properties/launchSettings.json new file mode 100644 index 00000000000..3ab4a5f66b4 --- /dev/null +++ b/tests/CheckCoreApi/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:37093", + "sslPort": 44355 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "CheckCoreApi": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/tests/CheckCoreApi/Startup.cs b/tests/CheckCoreApi/Startup.cs new file mode 100644 index 00000000000..3244a92be43 --- /dev/null +++ b/tests/CheckCoreApi/Startup.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using ServiceStack; + +namespace CheckCoreApi +{ + public class Startup : ModularStartup + { + // This method gets called by the runtime. Use this method to add services to the container. + public new void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseServiceStack(new AppHost + { + PathBase = "/api", + AppSettings = new NetCoreAppSettings(Configuration) + }); + + app.Run(async context => { + context.Response.Redirect("/api/metadata"); + }); + } + } + + public class AppHost : AppHostBase + { + public AppHost() : base(nameof(CheckCoreApi), typeof(MyServices).Assembly) { } + public override void Configure(Container container) + { + } + } + + [Route("/hello/{Name}")] + public class Hello : IReturn + { + public string Name { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class MyServices : Service + { + public object Any(Hello request) => new HelloResponse { + Result = $"Hello, {request.Name}!" + }; + } +} \ No newline at end of file diff --git a/tests/CheckCoreApi/appsettings.Development.json b/tests/CheckCoreApi/appsettings.Development.json new file mode 100644 index 00000000000..8983e0fc1c5 --- /dev/null +++ b/tests/CheckCoreApi/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/tests/CheckCoreApi/appsettings.json b/tests/CheckCoreApi/appsettings.json new file mode 100644 index 00000000000..d9d9a9bff6f --- /dev/null +++ b/tests/CheckCoreApi/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/tests/CheckCoreApi/wwwroot/index.html b/tests/CheckCoreApi/wwwroot/index.html new file mode 100644 index 00000000000..7ddff7cbb0f --- /dev/null +++ b/tests/CheckCoreApi/wwwroot/index.html @@ -0,0 +1,12 @@ + + + + + Home + + + +

Home Page

+ + + diff --git a/tests/CheckGrpc/CheckGrpc.csproj b/tests/CheckGrpc/CheckGrpc.csproj new file mode 100644 index 00000000000..ab0fd5ab290 --- /dev/null +++ b/tests/CheckGrpc/CheckGrpc.csproj @@ -0,0 +1,37 @@ + + + + net6.0 + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/CheckGrpc/MyServices.cs b/tests/CheckGrpc/MyServices.cs new file mode 100644 index 00000000000..38ceed7fcd9 --- /dev/null +++ b/tests/CheckGrpc/MyServices.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using ServiceStack; +using CheckGrpc.ServiceModel; +using System.Runtime.Serialization; + +namespace CheckGrpc.ServiceModel +{ + [Route("/hello")] + [Route("/hello/{Name}")] + [DataContract] + public class Hello : IReturn + { + [DataMember(Order = 1)] + public string Name { get; set; } + } + + [DataContract] + public class HelloResponse + { + [DataMember(Order = 1)] + public string Result { get; set; } + + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class HelloAllTypes : IReturn + { + [DataMember(Order = 1)] + public string Name { get; set; } + [DataMember(Order = 2)] + public AllTypes AllTypes { get; set; } + [DataMember(Order = 3)] + public AllCollectionTypes AllCollectionTypes { get; set; } + } + + [DataContract] + public class HelloAllTypesResponse + { + [DataMember(Order = 1)] + public string Result { get; set; } + [DataMember(Order = 2)] + public AllTypes AllTypes { get; set; } + [DataMember(Order = 3)] + public AllCollectionTypes AllCollectionTypes { get; set; } + [DataMember(Order = 4)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class AllTypes : IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public int? NullableId { get; set; } + [DataMember(Order = 3)] + public byte Byte { get; set; } + [DataMember(Order = 4)] + public short Short { get; set; } + [DataMember(Order = 5)] + public int Int { get; set; } + [DataMember(Order = 6)] + public long Long { get; set; } + [DataMember(Order = 7)] + public UInt16 UShort { get; set; } + [DataMember(Order = 8)] + public uint UInt { get; set; } + [DataMember(Order = 9)] + public ulong ULong { get; set; } + [DataMember(Order = 10)] + public float Float { get; set; } + [DataMember(Order = 11)] + public double Double { get; set; } + [DataMember(Order = 12)] + public decimal Decimal { get; set; } + [DataMember(Order = 13)] + public string String { get; set; } + [DataMember(Order = 14)] + public DateTime DateTime { get; set; } + [DataMember(Order = 15)] + public TimeSpan TimeSpan { get; set; } + [DataMember(Order = 16)] + public DateTimeOffset DateTimeOffset { get; set; } + [DataMember(Order = 17)] + public Guid Guid { get; set; } + [DataMember(Order = 18)] + public Char Char { get; set; } + [DataMember(Order = 19)] + public KeyValuePair KeyValuePair { get; set; } + [DataMember(Order = 20)] + public DateTime? NullableDateTime { get; set; } + [DataMember(Order = 21)] + public TimeSpan? NullableTimeSpan { get; set; } + [DataMember(Order = 22)] + public List StringList { get; set; } + [DataMember(Order = 23)] + public string[] StringArray { get; set; } + [DataMember(Order = 24)] + public Dictionary StringMap { get; set; } + [DataMember(Order = 25)] + public Dictionary IntStringMap { get; set; } + [DataMember(Order = 26)] + public SubType SubType { get; set; } + [DataMember(Order = 27)] + public Point Point { get; set; } + + [DataMember(Name = "aliasedName", Order = 28)] + public string OriginalName { get; set; } + } + + [DataContract] + public class AllCollectionTypes + { + [DataMember(Order = 1)] + public int[] IntArray { get; set; } + [DataMember(Order = 2)] + public List IntList { get; set; } + + [DataMember(Order = 3)] + public string[] StringArray { get; set; } + [DataMember(Order = 4)] + public List StringList { get; set; } + + [DataMember(Order = 5)] + public Poco[] PocoArray { get; set; } + [DataMember(Order = 6)] + public List PocoList { get; set; } + + [DataMember(Order = 7)] + public byte?[] NullableByteArray { get; set; } + [DataMember(Order = 8)] + public List NullableByteList { get; set; } + + [DataMember(Order = 9)] + public DateTime?[] NullableDateTimeArray { get; set; } + [DataMember(Order = 10)] + public List NullableDateTimeList { get; set; } + +// [DataMember(Order = 11)] +// public Dictionary> PocoLookup { get; set; } +// [DataMember(Order = 12)] +// public Dictionary>> PocoLookupMap { get; set; } + } + + [DataContract] + public class Poco + { + [DataMember(Order = 1)] + public string Name { get; set; } + } + + [DataContract] + public class SubType + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string Name { get; set; } + } + + [DataContract] + public struct Point + { + public Point(double x=0, double y=0) : this() + { + X = x; + Y = y; + } + + public Point(string point) : this() + { + var parts = point.Split(','); + X = double.Parse(parts[0]); + Y = double.Parse(parts[1]); + } + + [DataMember(Order = 1)] + public double X { get; set; } + [DataMember(Order = 2)] + public double Y { get; set; } + + public override string ToString() + { + return X.ToString(System.Globalization.CultureInfo.InvariantCulture) + "," + Y.ToString(System.Globalization.CultureInfo.InvariantCulture); + } + } + +} + +namespace CheckGrpc.ServiceInterface +{ + public class MyServices : Service + { + public object Any(Hello request) + { + return new HelloResponse { Result = $"Hello, {request.Name}!" }; + } + + public object Any(HelloAllTypes request) + { + return new HelloAllTypesResponse + { + AllTypes = request.AllTypes, + AllCollectionTypes = request.AllCollectionTypes, + Result = request.Name + }; + } + + public object Any(AllTypes request) + { + return request; + } + } +} \ No newline at end of file diff --git a/tests/CheckGrpc/Program.cs b/tests/CheckGrpc/Program.cs new file mode 100644 index 00000000000..aaf77979398 --- /dev/null +++ b/tests/CheckGrpc/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using ServiceStack; + +namespace CheckGrpc +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { + webBuilder.UseModularStartup(); + }); + } +} \ No newline at end of file diff --git a/tests/CheckGrpc/Properties/launchSettings.json b/tests/CheckGrpc/Properties/launchSettings.json new file mode 100644 index 00000000000..f966f159deb --- /dev/null +++ b/tests/CheckGrpc/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "MyApp": { + "commandName": "Project", + "launchBrowser": false, + "applicationUrl": "https://localhost:5002", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/tests/CheckGrpc/Protos/protobuf-net/bcl.proto b/tests/CheckGrpc/Protos/protobuf-net/bcl.proto new file mode 100644 index 00000000000..8df1762245f --- /dev/null +++ b/tests/CheckGrpc/Protos/protobuf-net/bcl.proto @@ -0,0 +1,76 @@ +// The types in here indicate how protobuf-net represents certain types when using protobuf-net specific +// library features. Note that it is not *required* to use any of these types, and cross-platform code +// should usually avoid them completely (ideally starting from a .proto schema) + +// Some of these are ugly, sorry. The TimeSpan / DateTime dates here pre-date the introduction of Timestamp +// and Duration, and the "well known" types should be preferred when possible. Guids are particularly +// awkward - it turns out that there are multiple guid representations, and I accidentally used one that +// I can only call... "crazy-endian". Just make sure you check the order! + +// It should not be necessary to use bcl.proto from code that uses protobuf-net + +syntax = "proto3"; + +option csharp_namespace = "ProtoBuf.Bcl"; + +package bcl; + +message TimeSpan { + sint64 value = 1; // the size of the timespan (in units of the selected scale) + TimeSpanScale scale = 2; // the scale of the timespan [default = DAYS] + enum TimeSpanScale { + DAYS = 0; + HOURS = 1; + MINUTES = 2; + SECONDS = 3; + MILLISECONDS = 4; + TICKS = 5; + + MINMAX = 15; // dubious + } +} + +message DateTime { + sint64 value = 1; // the offset (in units of the selected scale) from 1970/01/01 + TimeSpanScale scale = 2; // the scale of the timespan [default = DAYS] + DateTimeKind kind = 3; // the kind of date/time being represented [default = UNSPECIFIED] + enum TimeSpanScale { + DAYS = 0; + HOURS = 1; + MINUTES = 2; + SECONDS = 3; + MILLISECONDS = 4; + TICKS = 5; + + MINMAX = 15; // dubious + } + enum DateTimeKind + { + // The time represented is not specified as either local time or Coordinated Universal Time (UTC). + UNSPECIFIED = 0; + // The time represented is UTC. + UTC = 1; + // The time represented is local time. + LOCAL = 2; + } +} + +message NetObjectProxy { + int32 existingObjectKey = 1; // for a tracked object, the key of the **first** time this object was seen + int32 newObjectKey = 2; // for a tracked object, a **new** key, the first time this object is seen + int32 existingTypeKey = 3; // for dynamic typing, the key of the **first** time this type was seen + int32 newTypeKey = 4; // for dynamic typing, a **new** key, the first time this type is seen + string typeName = 8; // for dynamic typing, the name of the type (only present along with newTypeKey) + bytes payload = 10; // the new string/value (only present along with newObjectKey) +} + +message Guid { + fixed64 lo = 1; // the first 8 bytes of the guid (note:crazy-endian) + fixed64 hi = 2; // the second 8 bytes of the guid (note:crazy-endian) +} + +message Decimal { + uint64 lo = 1; // the first 64 bits of the underlying value + uint32 hi = 2; // the last 32 bis of the underlying value + uint32 signScale = 3; // the number of decimal digits (bits 1-16), and the sign (bit 0) +} \ No newline at end of file diff --git a/tests/CheckGrpc/Protos/services.proto b/tests/CheckGrpc/Protos/services.proto new file mode 100644 index 00000000000..353733c544f --- /dev/null +++ b/tests/CheckGrpc/Protos/services.proto @@ -0,0 +1,178 @@ +/* Options: +Date: 2019-11-15 17:53:42 +Version: 5.71 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: https://localhost:5001 + +//GlobalNamespace: +//AddDescriptionAsComments: True +*/ + +syntax = "proto3"; +import "protobuf-net/bcl.proto"; // schema for protobuf-net's handling of core .NET types + +option csharp_namespace = "CheckGrpc"; + +service GrpcServices { + + rpc GetAllTypes(AllTypes) returns (AllTypes) {} + + rpc PostAllTypes(AllTypes) returns (AllTypes) {} + + rpc PutAllTypes(AllTypes) returns (AllTypes) {} + + rpc DeleteAllTypes(AllTypes) returns (AllTypes) {} + + rpc PatchAllTypes(AllTypes) returns (AllTypes) {} + + rpc GetHello(Hello) returns (HelloResponse) {} + + rpc PostHello(Hello) returns (HelloResponse) {} + + rpc PutHello(Hello) returns (HelloResponse) {} + + rpc DeleteHello(Hello) returns (HelloResponse) {} + + rpc PatchHello(Hello) returns (HelloResponse) {} + + rpc GetHelloAllTypes(HelloAllTypes) returns (HelloAllTypesResponse) {} + + rpc PostHelloAllTypes(HelloAllTypes) returns (HelloAllTypesResponse) {} + + rpc PutHelloAllTypes(HelloAllTypes) returns (HelloAllTypesResponse) {} + + rpc DeleteHelloAllTypes(HelloAllTypes) returns (HelloAllTypesResponse) {} + + rpc PatchHelloAllTypes(HelloAllTypes) returns (HelloAllTypesResponse) {} + + rpc ServerStreamFiles(StreamFiles) returns (stream FileContent) {} + + rpc ServerStreamServerEvents(StreamServerEvents) returns (stream StreamServerEventsResponse) {} +} + +message AllCollectionTypes { + repeated int32 IntArray = 1 [packed = false]; + repeated int32 IntList = 2 [packed = false]; + repeated string StringArray = 3; + repeated string StringList = 4; + repeated Poco PocoArray = 5; + repeated Poco PocoList = 6; + repeated uint32 NullableByteArray = 7; + repeated uint32 NullableByteList = 8; + repeated .bcl.DateTime NullableDateTimeArray = 9; + repeated .bcl.DateTime NullableDateTimeList = 10; +} +message AllTypes { + int32 Id = 1; + int32 NullableId = 2; + uint32 Byte = 3; + int32 Short = 4; + int32 Int = 5; + int64 Long = 6; + uint32 UShort = 7; + uint32 UInt = 8; + uint64 ULong = 9; + float Float = 10; + double Double = 11; + .bcl.Decimal Decimal = 12; + string String = 13; + .bcl.DateTime DateTime = 14; + .bcl.TimeSpan TimeSpan = 15; + DateTimeOffset DateTimeOffset = 16; + .bcl.Guid Guid = 17; // default value could not be applied: 00000000-0000-0000-0000-000000000000 + uint32 Char = 18; + KeyValuePair_String_String KeyValuePair = 19; + .bcl.DateTime NullableDateTime = 20; + .bcl.TimeSpan NullableTimeSpan = 21; + repeated string StringList = 22; + repeated string StringArray = 23; + map StringMap = 24; + map IntStringMap = 25; + SubType SubType = 26; + Point Point = 27; + string aliasedName = 28; +} +message DateTimeOffset { +} +message FileContent { + string Name = 1; + string Type = 2; + int32 Length = 3; + bytes Body = 4; + ResponseStatus ResponseStatus = 5; +} +message Hello { + string Name = 1; +} +message HelloAllTypes { + string Name = 1; + AllTypes AllTypes = 2; + AllCollectionTypes AllCollectionTypes = 3; +} +message HelloAllTypesResponse { + string Result = 1; + AllTypes AllTypes = 2; + AllCollectionTypes AllCollectionTypes = 3; + ResponseStatus ResponseStatus = 4; +} +message HelloResponse { + string Result = 1; + ResponseStatus ResponseStatus = 2; +} +message KeyValuePair_String_String { + string Key = 1; + string Value = 2; +} +message Poco { + string Name = 1; +} +message Point { + double X = 1; + double Y = 2; +} +message ResponseError { + string ErrorCode = 1; + string FieldName = 2; + string Message = 3; + map Meta = 4; +} +message ResponseStatus { + string ErrorCode = 1; + string Message = 2; + string StackTrace = 3; + repeated ResponseError Errors = 4; + map Meta = 5; +} +message StreamFiles { + repeated string Paths = 1; +} +message StreamServerEvents { + repeated string Channels = 1; +} +message StreamServerEventsResponse { + int64 EventId = 1; + string Channel = 2; + string Selector = 4; + string Json = 5; + string Op = 6; + string Target = 7; + string CssSelector = 8; + map Meta = 9; + string UserId = 10; + string DisplayName = 11; + string ProfileUrl = 12; + bool IsAuthenticated = 13; + repeated string Channels = 14; + int64 CreatedAt = 15; + string Id = 21; + string UnRegisterUrl = 22; + string UpdateSubscriberUrl = 23; + string HeartbeatUrl = 24; + int64 HeartbeatIntervalMs = 25; + int64 IdleTimeoutMs = 26; + ResponseStatus ResponseStatus = 30; +} +message SubType { + int32 Id = 1; + string Name = 2; +} \ No newline at end of file diff --git a/tests/CheckGrpc/Startup.cs b/tests/CheckGrpc/Startup.cs new file mode 100644 index 00000000000..39378757879 --- /dev/null +++ b/tests/CheckGrpc/Startup.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CheckGrpc.ServiceInterface; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using ServiceStack; + +namespace CheckGrpc +{ + public class Startup : ModularStartup + { + // This method gets called by the runtime. Use this method to add services to the container. + public new void ConfigureServices(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseServiceStack(new AppHost + { + AppSettings = new NetCoreAppSettings(Configuration) + }); + } + } + + public class AppHost : AppHostBase + { + public AppHost() : base("MyApp", typeof(MyServices).Assembly) { } + + // Configure your AppHost with the necessary configuration and dependencies your App needs + public override void Configure(Container container) + { + SetConfig(new HostConfig + { +// DefaultRedirectPath = "/metadata", + DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), false) + }); + + RegisterService(); + + Plugins.Add(new SharpPagesFeature()); + Plugins.Add(new GrpcFeature(App)); + } + } +} diff --git a/tests/CheckGrpc/appsettings.Development.json b/tests/CheckGrpc/appsettings.Development.json new file mode 100644 index 00000000000..78ea571517c --- /dev/null +++ b/tests/CheckGrpc/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "DebugMode": true, + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Grpc": "Information", + "Microsoft": "Information" + } + } +} \ No newline at end of file diff --git a/tests/CheckGrpc/appsettings.json b/tests/CheckGrpc/appsettings.json new file mode 100644 index 00000000000..406949d26e3 --- /dev/null +++ b/tests/CheckGrpc/appsettings.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + } +} \ No newline at end of file diff --git a/tests/CheckGrpc/wwwroot/_layout.html b/tests/CheckGrpc/wwwroot/_layout.html new file mode 100644 index 00000000000..adeb967a616 --- /dev/null +++ b/tests/CheckGrpc/wwwroot/_layout.html @@ -0,0 +1,47 @@ + + + + + + {{ title }} - CheckGrpc + + + + +
+ +
+
+
+ {{ page }} +
+
+ +
+
+ © 2019 - CheckGrpc - Privacy +
+
+ +{{ scripts | raw }} + + + diff --git a/tests/CheckGrpc/wwwroot/css/site.css b/tests/CheckGrpc/wwwroot/css/site.css new file mode 100644 index 00000000000..e679a8ea7fb --- /dev/null +++ b/tests/CheckGrpc/wwwroot/css/site.css @@ -0,0 +1,71 @@ +/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +for details on configuring this project to bundle and minify static web assets. */ + +a.navbar-brand { + white-space: normal; + text-align: center; + word-break: break-all; +} + +/* Provide sufficient contrast against white background */ +a { + color: #0366d6; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.nav-pills .nav-link.active, .nav-pills .show > .nav-link { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +/* Sticky footer styles +-------------------------------------------------- */ +html { + font-size: 14px; +} +@media (min-width: 768px) { + html { + font-size: 16px; + } +} + +.border-top { + border-top: 1px solid #e5e5e5; +} +.border-bottom { + border-bottom: 1px solid #e5e5e5; +} + +.box-shadow { + box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); +} + +button.accept-policy { + font-size: 1rem; + line-height: inherit; +} + +/* Sticky footer styles +-------------------------------------------------- */ +html { + position: relative; + min-height: 100%; +} + +body { + /* Margin bottom by footer height */ + margin-bottom: 60px; +} +.footer { + position: absolute; + bottom: 0; + width: 100%; + white-space: nowrap; + line-height: 60px; /* Vertically center the text there */ +} diff --git a/tests/CheckGrpc/wwwroot/error.html b/tests/CheckGrpc/wwwroot/error.html new file mode 100644 index 00000000000..3dfaf01b20e --- /dev/null +++ b/tests/CheckGrpc/wwwroot/error.html @@ -0,0 +1,23 @@ + + +

Error.

+

An error occurred while processing your request.

+ +{{#if Request.Id}} +

+ Request ID: {{ Request.Id }} +

+{{/if}} + +

Development Mode

+

+ Swapping to the Development environment displays detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

diff --git a/tests/CheckGrpc/wwwroot/favicon.ico b/tests/CheckGrpc/wwwroot/favicon.ico new file mode 100644 index 00000000000..a3a799985c4 Binary files /dev/null and b/tests/CheckGrpc/wwwroot/favicon.ico differ diff --git a/tests/CheckGrpc/wwwroot/index.html b/tests/CheckGrpc/wwwroot/index.html new file mode 100644 index 00000000000..c5e43a99dcd --- /dev/null +++ b/tests/CheckGrpc/wwwroot/index.html @@ -0,0 +1,8 @@ + + +
+

Welcome

+

Learn about building Web apps with ASP.NET Core.

+
diff --git a/tests/CheckGrpc/wwwroot/privacy.html b/tests/CheckGrpc/wwwroot/privacy.html new file mode 100644 index 00000000000..99d6bd840ce --- /dev/null +++ b/tests/CheckGrpc/wwwroot/privacy.html @@ -0,0 +1,7 @@ + + +

{{ title }}

+ +

Use this page to detail your site's privacy policy.

diff --git a/tests/CheckHttpListener/AnalyzeManyTestFixtures.cs b/tests/CheckHttpListener/AnalyzeManyTestFixtures.cs new file mode 100644 index 00000000000..2ae62ffcd3c --- /dev/null +++ b/tests/CheckHttpListener/AnalyzeManyTestFixtures.cs @@ -0,0 +1,34 @@ +namespace CheckHttpListener +{ + public class AnalyzeTestSideEffects_ManyTestFixtures01 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures02 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures03 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures04 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures05 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures06 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures07 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures08 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures09 : AnalyzeTestSideEffects_ManyTests + { + } + public class AnalyzeTestSideEffects_ManyTestFixtures10 : AnalyzeTestSideEffects_ManyTests + { + } + +} \ No newline at end of file diff --git a/tests/CheckHttpListener/AnalyzeTestSideEffects.cs b/tests/CheckHttpListener/AnalyzeTestSideEffects.cs new file mode 100644 index 00000000000..926f60ea9f9 --- /dev/null +++ b/tests/CheckHttpListener/AnalyzeTestSideEffects.cs @@ -0,0 +1,440 @@ +using System.Data; +using System.Diagnostics; +using Funq; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Caching; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace CheckHttpListener +{ + public class Config + { + public static string ListeningOn = "http://localhost:3000/"; + } + + [Route("/analyze")] + [Route("/analyze/{Id}")] + [Route("/analyze/{Id}/{Type}")] + public class Analyze : IReturn + { + public int Id { get; set; } + public string Type { get; set; } + } + + [Route("/analyze-01")] + public class Analyze01 { } + [Route("/analyze-02")] + public class Analyze02 { } + [Route("/analyze-03")] + public class Analyze03 { } + [Route("/analyze-04")] + public class Analyze04 { } + [Route("/analyze-05")] + public class Analyze05 { } + [Route("/analyze-06")] + public class Analyze06 { } + [Route("/analyze-07")] + public class Analyze07 { } + [Route("/analyze-08")] + public class Analyze08 { } + [Route("/analyze-09")] + public class Analyze09 { } + [Route("/analyze-10")] + public class Analyze10 { } + + public class AnalyzeServices : Service + { + public object Any(Analyze request) + { + return Db.Single(q => q.Type == request.Type); + } + + public object Any(Analyze02 request) + { + return request; + } + + public object Any(Analyze03 request) + { + return request; + } + + public object Any(Analyze04 request) + { + return request; + } + + public object Any(Analyze05 request) + { + return request; + } + + public object Any(Analyze06 request) + { + return request; + } + + public object Any(Analyze07 request) + { + return request; + } + + public object Any(Analyze08 request) + { + return request; + } + + public object Any(Analyze09 request) + { + return request; + } + + public object Any(Analyze10 request) + { + return request; + } + } + + public class AnalyzeAppHost : AppHostHttpListenerBase + { + public AnalyzeAppHost() : base("Analyze Tests", typeof(AnalyzeServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.RegisterAs(); + + container.Resolve().InitSchema(); + + using (var cache = container.Resolve()) + { + cache.Set("key:test", new Analyze { Id = 1 }); + } + + using (var cache = container.Resolve()) + { + var test = cache.Get("key:test"); + test.Id.PrintDump(); + } + } + } + + [TestFixture] + public class AnalyzeAppHostRestartSideEffects + { + [Test] + public void Restart_AppHosts() + { + for (int i = 0; i < 100; i++) + { + var sw = Stopwatch.StartNew(); + using (var appHost = new AnalyzeAppHost()) + { + appHost.Init(); + var db = appHost.TryResolve().Open(); + + appHost.Start(Config.ListeningOn); + db.Dispose(); + } + "starting #1 took {0}ms".Print(sw.ElapsedMilliseconds); + } + } + } + + + [TestFixture] + public class AnalyzeTestSideEffectsBase + { + private static int TestCount = 0; + + private AnalyzeAppHost AppHost; + public IDbConnection DbConnection; + public IServiceClient ServiceClient; + private Stopwatch sw; + + private void Acquire() + { + sw = Stopwatch.StartNew(); + } + + private void Release() + { + "Test {0} {1}ms".Print(TestCount++, sw.ElapsedMilliseconds); + sw = null; + } + + [TearDown] + public void OnTestFixtureTearDown() + { + "Disposing Fixture: #{0}".Print(TestCount); + if (AppHost != null) + { + AppHost.Stop(); + AppHost.Dispose(); + AppHost = null; + } + + if (DbConnection != null) + { + DbConnection.Close(); + DbConnection.Dispose(); + DbConnection = null; + } + + Release(); + } + + [SetUp] + public void OnTestSetup() + { + Acquire(); + + AppHost = new AnalyzeAppHost(); + AppHost.Init(); + + AppHost.Start(Config.ListeningOn); + + DbConnection = AppHost.Container.TryResolve().Open(); + + DbConnection.DropAndCreateTable(); + + //MockSiteVisitDatabase.DropAndCreateDummyDatabaseSchema(DbConnection); + 10.Times(i => DbConnection.Insert(new Analyze { Id = i, Type = "Type" + i })); + + //IdGenerator = AppHost.Container.TryResolve(); + + //TestData = new DbHelper(DbConnection, IdGenerator); + + //LocationHelper = new LocationHelper(DbConnection, IdGenerator); + //TimeSeriesHelper = new TimeSeriesHelper(DbConnection, IdGenerator); + + ServiceClient = new JsonServiceClient(Config.ListeningOn); + } + } + + public class AnalyzeTestSideEffects_ManyTests : AnalyzeTestSideEffectsBase + { + public void Test(int i) + { + var request = new Analyze { Type = "Type" + i }; + var response = ServiceClient.Get(request); + + Assert.That(response.Id, Is.EqualTo(i)); + } + + [Test] + public void Test00() { Test(0); } + [Test] + public void Test01() { Test(1); } + [Test] + public void Test02() { Test(2); } + [Test] + public void Test03() { Test(3); } + [Test] + public void Test04() { Test(4); } + [Test] + public void Test05() { Test(5); } + [Test] + public void Test06() { Test(6); } + [Test] + public void Test07() { Test(7); } + [Test] + public void Test08() { Test(8); } + [Test] + public void Test09() { Test(9); } + [Test] + public void Test10() { Test(0); } + + [Test] + public void Test11() { Test(1); } + [Test] + public void Test12() { Test(2); } + [Test] + public void Test13() { Test(3); } + [Test] + public void Test14() { Test(4); } + [Test] + public void Test15() { Test(5); } + [Test] + public void Test16() { Test(6); } + [Test] + public void Test17() { Test(7); } + [Test] + public void Test18() { Test(8); } + [Test] + public void Test19() { Test(9); } + [Test] + public void Test20() { Test(0); } + + [Test] + public void Test21() { Test(1); } + [Test] + public void Test22() { Test(2); } + [Test] + public void Test23() { Test(3); } + [Test] + public void Test24() { Test(4); } + [Test] + public void Test25() { Test(5); } + [Test] + public void Test26() { Test(6); } + [Test] + public void Test27() { Test(7); } + [Test] + public void Test28() { Test(8); } + [Test] + public void Test29() { Test(9); } + [Test] + public void Test30() { Test(0); } + + [Test] + public void Test31() { Test(1); } + [Test] + public void Test32() { Test(2); } + [Test] + public void Test33() { Test(3); } + [Test] + public void Test34() { Test(4); } + [Test] + public void Test35() { Test(5); } + [Test] + public void Test36() { Test(6); } + [Test] + public void Test37() { Test(7); } + [Test] + public void Test38() { Test(8); } + [Test] + public void Test39() { Test(9); } + [Test] + public void Test40() { Test(0); } + + [Test] + public void Test41() { Test(1); } + [Test] + public void Test42() { Test(2); } + [Test] + public void Test43() { Test(3); } + [Test] + public void Test44() { Test(4); } + [Test] + public void Test45() { Test(5); } + [Test] + public void Test46() { Test(6); } + [Test] + public void Test47() { Test(7); } + [Test] + public void Test48() { Test(8); } + [Test] + public void Test49() { Test(9); } + [Test] + public void Test50() { Test(0); } + + [Test] + public void Test51() { Test(1); } + [Test] + public void Test52() { Test(2); } + [Test] + public void Test53() { Test(3); } + [Test] + public void Test54() { Test(4); } + [Test] + public void Test55() { Test(5); } + [Test] + public void Test56() { Test(6); } + [Test] + public void Test57() { Test(7); } + [Test] + public void Test58() { Test(8); } + [Test] + public void Test59() { Test(9); } + [Test] + public void Test60() { Test(0); } + + [Test] + public void Test61() { Test(1); } + [Test] + public void Test62() { Test(2); } + [Test] + public void Test63() { Test(3); } + [Test] + public void Test64() { Test(4); } + [Test] + public void Test65() { Test(5); } + [Test] + public void Test66() { Test(6); } + [Test] + public void Test67() { Test(7); } + [Test] + public void Test68() { Test(8); } + [Test] + public void Test69() { Test(9); } + [Test] + public void Test70() { Test(0); } + + [Test] + public void Test71() { Test(1); } + [Test] + public void Test72() { Test(2); } + [Test] + public void Test73() { Test(3); } + [Test] + public void Test74() { Test(4); } + [Test] + public void Test75() { Test(5); } + [Test] + public void Test76() { Test(6); } + [Test] + public void Test77() { Test(7); } + [Test] + public void Test78() { Test(8); } + [Test] + public void Test79() { Test(9); } + [Test] + public void Test80() { Test(0); } + + [Test] + public void Test81() { Test(1); } + [Test] + public void Test82() { Test(2); } + [Test] + public void Test83() { Test(3); } + [Test] + public void Test84() { Test(4); } + [Test] + public void Test85() { Test(5); } + [Test] + public void Test86() { Test(6); } + [Test] + public void Test87() { Test(7); } + [Test] + public void Test88() { Test(8); } + [Test] + public void Test89() { Test(9); } + [Test] + public void Test90() { Test(0); } + + [Test] + public void Test91() { Test(1); } + [Test] + public void Test92() { Test(2); } + [Test] + public void Test93() { Test(3); } + [Test] + public void Test94() { Test(4); } + [Test] + public void Test95() { Test(5); } + [Test] + public void Test96() { Test(6); } + [Test] + public void Test97() { Test(7); } + [Test] + public void Test98() { Test(8); } + [Test] + public void Test99() { Test(9); } + } +} \ No newline at end of file diff --git a/tests/CheckHttpListener/App.config b/tests/CheckHttpListener/App.config new file mode 100644 index 00000000000..7d68974a2d7 --- /dev/null +++ b/tests/CheckHttpListener/App.config @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckHttpListener/CheckHttpListener.csproj b/tests/CheckHttpListener/CheckHttpListener.csproj new file mode 100644 index 00000000000..17e0f097b24 --- /dev/null +++ b/tests/CheckHttpListener/CheckHttpListener.csproj @@ -0,0 +1,151 @@ + + + + + Debug + AnyCPU + {F709A373-6FD5-4415-B2ED-2520EA7CC568} + Exe + Properties + CheckHttpListener + CheckHttpListener + v4.7.2 + 512 + ..\..\src\ + true + + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {5e258282-86a6-4780-ab25-5e458f2e6f70} + ServiceStack.Api.OpenApi + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416db-c143-4028-a0c3-cf41892d18d3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} + ServiceStack.Server + + + {680a1709-25eb-4d52-a87f-ee03ffd94baa} + ServiceStack + + + {9982317F-831C-478B-9CC3-57F888BCD97A} + Check.ServiceInterface + + + {213EF4BA-786A-432F-B147-5702B18DE3CC} + Check.ServiceModel + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckHttpListener/IntegrationTests.cs b/tests/CheckHttpListener/IntegrationTests.cs new file mode 100644 index 00000000000..33d1dfbbe0c --- /dev/null +++ b/tests/CheckHttpListener/IntegrationTests.cs @@ -0,0 +1,111 @@ +using System.Threading.Tasks; +using Check.ServiceModel; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Text; + +namespace CheckHttpListener +{ + public class IntegrationTests + { + [Test] + public void Can_send_QueryPosts() + { + var client = new JsonServiceClient("https://techstacks.io"); + // var client = new JsonServiceClient("https://localhost:5001"); + + var response = client.Send(new QueryPosts { + Ids = new[] { 1001, 6860, 6848 }, + OrderByDesc = "Points", + Take = 3, + }); + response.PrintDump(); + } + + [Route("/testauth")] + public partial class TestAuth + : IReturn + { + } + + public partial class TestAuthResponse + { + public virtual string UserId { get; set; } + public virtual string SessionId { get; set; } + public virtual string UserName { get; set; } + public virtual string DisplayName { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + static string TestUrl = "http://test.servicestack.net"; + // static string TestUrl = "https://localhost:5001"; + + [Test] + public void Can_authenticate_via_HTTP_BasicAuth() + { + var client = new JsonServiceClient(TestUrl) { + UserName = "test", + Password = "test", + AlwaysSendBasicAuthHeader = true + }; + + var response = client.Get(new TestAuth()); + response.PrintDump(); + } + + [ValidateIsAuthenticated] + [Route("/secured")] + public class Secured : IReturn + { + public string Name { get; set; } + } + + public class SecuredResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/jwt-invalidate")] + public class InvalidateLastAccessToken : IReturn {} + + [Test] + public async Task Does_fetch_AccessToken_using_RefreshTokenCookies_ServiceClient() + { + await AssertDoesGetAccessTokenUsingRefreshTokenCookie(new JsonServiceClient(TestUrl)); + } + + [Test] + public async Task Does_fetch_AccessToken_using_RefreshTokenCookies_HttpClient() + { + await AssertDoesGetAccessTokenUsingRefreshTokenCookie(new JsonHttpClient(TestUrl)); + } + + private static async Task AssertDoesGetAccessTokenUsingRefreshTokenCookie(IJsonServiceClient client) + { + var authResponse = await client.PostAsync(new Authenticate { + provider = "credentials", + UserName = "test", + Password = "test", + }); + + var initialAccessToken = client.GetTokenCookie(); + var initialRefreshToken = client.GetRefreshTokenCookie(); + Assert.That(initialAccessToken, Is.Not.Null); + Assert.That(initialRefreshToken, Is.Not.Null); + + var request = new Secured {Name = "test"}; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + client.Post(new InvalidateLastAccessToken()); + // JwtAuthProvider.PrintDump(initialAccessToken); + // JwtAuthProvider.PrintDump(initialRefreshToken); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + var latestAccessToken = client.GetTokenCookie(); + Assert.That(latestAccessToken, Is.Not.EqualTo(initialAccessToken)); + } + } +} \ No newline at end of file diff --git a/tests/CheckHttpListener/Program.cs b/tests/CheckHttpListener/Program.cs new file mode 100644 index 00000000000..9a1a451a85d --- /dev/null +++ b/tests/CheckHttpListener/Program.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Web.UI.WebControls; +using Check.ServiceInterface; +using Check.ServiceModel; +using Funq; +using ServiceStack; +// using ServiceStack.Admin; +using ServiceStack.Api.OpenApi; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.Formats; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace CheckHttpListener +{ + public class AppSelfHost : AppSelfHostBase + { + public static Rockstar[] SeedRockstars = new[] { + new Rockstar { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27 }, + new Rockstar { Id = 2, FirstName = "Jim", LastName = "Morrison", Age = 27 }, + new Rockstar { Id = 3, FirstName = "Kurt", LastName = "Cobain", Age = 27 }, + new Rockstar { Id = 4, FirstName = "Elvis", LastName = "Presley", Age = 42 }, + new Rockstar { Id = 5, FirstName = "David", LastName = "Grohl", Age = 44 }, + new Rockstar { Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48 }, + new Rockstar { Id = 7, FirstName = "Michael", LastName = "Jackson", Age = 50 }, + }; + + public AppSelfHost() + : base("DocuRec Services", typeof(TestService).Assembly, typeof(TechStacksService).Assembly) + { } + + public override void Configure(Container container) + { + container.Register( + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + using (var db = container.Resolve().Open()) + { + db.DropAndCreateTable(); + db.InsertAll(SeedRockstars); + } + + Plugins.Add(new SharpPagesFeature()); + + Plugins.Add(new OpenApiFeature()); + + Plugins.Add(new AutoQueryFeature { MaxLimit = 100 }); + // Plugins.Add(new AdminFeature()); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new[] { new BasicAuthProvider(AppSettings) }) + { + //ServiceRoutes = new Dictionary { + // { typeof(AuthenticateService), new[] { "/api/auth", "/api/auth/{provider}" } }, + //} + }); + + Plugins.Add(new RequestLogsFeature()); + + SetConfig(new HostConfig + { +// HandlerFactoryPath = "api", + CompressFilesWithExtensions = { "js", "css" }, + // (optional), only compress .js or .css files > 10k + CompressFilesLargerThanBytes = 10 * 1024, + DebugMode = false + }); + + ContentTypes.Register("text/x-custom+csv", new CsvFormat().SerializeToStream, null); + } + + public override string ResolvePathInfo(IRequest request, string originalPathInfo) => + base.ResolvePathInfo(request, originalPathInfo.Replace("/testsite", "/TestSite")); + +// public override RouteAttribute[] GetRouteAttributes(Type requestType) +// { +// var routes = base.GetRouteAttributes(requestType); +// routes.Each(x => x.Path = "/api" + x.Path); +// return routes; +// } + } + + [Route("/query/rockstars")] + public class QueryRockstars : QueryDb { } + + //public class Hello { } + + public class TestService : Service + { + //public object Any(Hello request) + //{ + // return request; + //} + } + + internal class Program + { + private static void Main(string[] args) + { + var baseUrl = "http://localhost:8000/"; + var appHost = new AppSelfHost() + .Init() + .Start(baseUrl); + + Console.WriteLine(baseUrl); + Process.Start(baseUrl); + Console.ReadLine(); + } + } +} \ No newline at end of file diff --git a/tests/CheckHttpListener/Properties/AssemblyInfo.cs b/tests/CheckHttpListener/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..32bb5c1b3d5 --- /dev/null +++ b/tests/CheckHttpListener/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CheckHttpListener")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CheckHttpListener")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d51c0e58-0fe7-41cd-871b-ae7ef316797d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/CheckHttpListener/RequestInfoTests.cs b/tests/CheckHttpListener/RequestInfoTests.cs new file mode 100644 index 00000000000..8d9fe5bb659 --- /dev/null +++ b/tests/CheckHttpListener/RequestInfoTests.cs @@ -0,0 +1,96 @@ +using System.Net; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Host.Handlers; + +namespace CheckHttpListener +{ + public class RequestInfoServices : Service + { + } + + public partial class RequestInfoTests + { + public string BaseUrl = "http://127.0.0.1:2222/"; + + private RequestInfoResponse GetRequestInfoForPath(string path) + { + var url = BaseUrl.CombineWith(path).AddQueryParam("debug", "requestinfo"); + var json = url.GetJsonFromUrl(); + var info = json.FromJson(); + return info; + } + + private void AssertHasContent(string pathInfo, string accept, string containsContent) + { + var url = BaseUrl.CombineWith(pathInfo); + var content = url.GetStringFromUrl(accept: accept); + Assert.That(content, Does.Contain(containsContent)); + } + + [Test] + public void Does_return_expected_content() + { + AssertHasContent("metadata", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("metadata/", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("dir", MimeTypes.Html, "

dir/index.html

"); + AssertHasContent("dir/", MimeTypes.Html, "

dir/index.html

"); + AssertHasContent("dir/sub", MimeTypes.Html, "

dir/sub/index.html

"); + AssertHasContent("dir/sub/", MimeTypes.Html, "

dir/sub/index.html

"); + AssertHasContent("swagger-ui", MimeTypes.Html, "Swagger UI"); + AssertHasContent("swagger-ui/", MimeTypes.Html, "Swagger UI"); + } + + [Test] + public void Does_have_correct_path_info() + { + Assert.That(GetRequestInfoForPath("dir/").PathInfo, Is.EqualTo("/dir/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("swagger-ui/").PathInfo, Is.EqualTo("/swagger-ui/")); + } + } + + public partial class RequestInfoTests + { + private void DoesRedirectToRemoveTrailingSlash(string dirWIthoutSlash) + { + BaseUrl.CombineWith(dirWIthoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWIthoutSlash + "/"))); + }); + } + + private void DoesRedirectToAddTrailingSlash(string dirWithoutSlash) + { + BaseUrl.CombineWith(dirWithoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWithoutSlash.TrimEnd('/')))); + }); + } + + [Test] + public void Does_redirect_dirs_without_trailing_slash() + { + DoesRedirectToRemoveTrailingSlash("dir"); + DoesRedirectToRemoveTrailingSlash("dir/sub"); + DoesRedirectToRemoveTrailingSlash("swagger-ui"); + } + + [Test] + public void Does_redirect_metadata_page_to_without_slash() + { + DoesRedirectToAddTrailingSlash("metadata/"); + } + } +} \ No newline at end of file diff --git a/tests/CheckHttpListener/default.html b/tests/CheckHttpListener/default.html new file mode 100644 index 00000000000..e3153590534 --- /dev/null +++ b/tests/CheckHttpListener/default.html @@ -0,0 +1,14 @@ + + + Title + + +

Heading

+

+ Body! +

+ + /api/types/typescript + + + diff --git a/tests/CheckHttpListener/dir/index.html b/tests/CheckHttpListener/dir/index.html new file mode 100644 index 00000000000..31063146576 --- /dev/null +++ b/tests/CheckHttpListener/dir/index.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

dir/index.html

+ + + \ No newline at end of file diff --git a/tests/CheckHttpListener/dir/sub/index.html b/tests/CheckHttpListener/dir/sub/index.html new file mode 100644 index 00000000000..e9fa3e179b7 --- /dev/null +++ b/tests/CheckHttpListener/dir/sub/index.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

dir/sub/index.html

+ + + \ No newline at end of file diff --git a/tests/CheckHttpListener/js/jquery-1.7.1.min.js b/tests/CheckHttpListener/js/jquery-1.7.1.min.js new file mode 100644 index 00000000000..198b3ff07d8 --- /dev/null +++ b/tests/CheckHttpListener/js/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/tests/CheckIIS/AppHost.cs b/tests/CheckIIS/AppHost.cs new file mode 100644 index 00000000000..1d78c0a9703 --- /dev/null +++ b/tests/CheckIIS/AppHost.cs @@ -0,0 +1,59 @@ +using Funq; +using ServiceStack; + +namespace CheckIIS +{ + public class AppHost : AppHostBase + { + public AppHost() + : base(nameof(MyServices), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + DebugMode = true, + // EnableAutoHtmlResponses = false, + }); + + Plugins.Add(new ServerEventsFeature()); + Plugins.Add(new SoapFormat()); + } + } + + [Route("/hello")] + [Route("/hello/{Name}")] + public class Hello : IReturn + { + public string Name { get; set; } + } + public class HelloResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class AddInts : IReturn + { + public int A { get; set; } + public int B { get; set; } + } + + public class AddIntsResponse + { + public int Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + + public class MyServices : Service + { + public object Any(Hello request) => new HelloResponse + { + Result = $"Hi, {request.Name}!" + }; + + public object Any(AddInts request) => new AddIntsResponse { + Result = request.A + request.B + }; + } +} \ No newline at end of file diff --git a/tests/CheckIIS/App_Start/BundleConfig.cs b/tests/CheckIIS/App_Start/BundleConfig.cs new file mode 100644 index 00000000000..2e476a3d99f --- /dev/null +++ b/tests/CheckIIS/App_Start/BundleConfig.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Optimization; +using System.Web.UI; + +namespace CheckIIS +{ + public class BundleConfig + { + // For more information on Bundling, visit https://go.microsoft.com/fwlink/?LinkID=303951 + public static void RegisterBundles(BundleCollection bundles) + { + bundles.Add(new ScriptBundle("~/bundles/WebFormsJs").Include( + "~/Scripts/WebForms/WebForms.js", + "~/Scripts/WebForms/WebUIValidation.js", + "~/Scripts/WebForms/MenuStandards.js", + "~/Scripts/WebForms/Focus.js", + "~/Scripts/WebForms/GridView.js", + "~/Scripts/WebForms/DetailsView.js", + "~/Scripts/WebForms/TreeView.js", + "~/Scripts/WebForms/WebParts.js")); + + // Order is very important for these files to work, they have explicit dependencies + bundles.Add(new ScriptBundle("~/bundles/MsAjaxJs").Include( + "~/Scripts/WebForms/MsAjax/MicrosoftAjax.js", + "~/Scripts/WebForms/MsAjax/MicrosoftAjaxApplicationServices.js", + "~/Scripts/WebForms/MsAjax/MicrosoftAjaxTimer.js", + "~/Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js")); + + // Use the Development version of Modernizr to develop with and learn from. Then, when you’re + // ready for production, use the build tool at https://modernizr.com to pick only the tests you need + bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( + "~/Scripts/modernizr-*")); + } + } +} \ No newline at end of file diff --git a/tests/CheckIIS/App_Start/RouteConfig.cs b/tests/CheckIIS/App_Start/RouteConfig.cs new file mode 100644 index 00000000000..d7ab9b81b82 --- /dev/null +++ b/tests/CheckIIS/App_Start/RouteConfig.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.Routing; +using Microsoft.AspNet.FriendlyUrls; + +namespace CheckIIS +{ + public static class RouteConfig + { + public static void RegisterRoutes(RouteCollection routes) + { + var settings = new FriendlyUrlSettings(); + settings.AutoRedirectMode = RedirectMode.Permanent; + routes.EnableFriendlyUrls(settings); + } + } +} diff --git a/tests/CheckIIS/Bundle.config b/tests/CheckIIS/Bundle.config new file mode 100644 index 00000000000..de5e842af84 --- /dev/null +++ b/tests/CheckIIS/Bundle.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/CheckIIS/CheckIIS.csproj b/tests/CheckIIS/CheckIIS.csproj new file mode 100644 index 00000000000..34ef8df855e --- /dev/null +++ b/tests/CheckIIS/CheckIIS.csproj @@ -0,0 +1,179 @@ + + + + + Debug + AnyCPU + + + 2.0 + {4EB53207-13DA-47B2-A638-A4EC1534FE47} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + CheckIIS + CheckIIS + v4.7.2 + true + + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + true + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default.aspx + ASPXCodeBehind + + + Default.aspx + + + Global.asax + + + + Site.Master + ASPXCodeBehind + + + Site.Master + + + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416db-c143-4028-a0c3-cf41892d18d3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {680a1709-25eb-4d52-a87f-ee03ffd94baa} + ServiceStack + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 0 + / + http://localhost:58784/ + False + False + + + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckIIS/Content/Site.css b/tests/CheckIIS/Content/Site.css new file mode 100644 index 00000000000..a9f861550b3 --- /dev/null +++ b/tests/CheckIIS/Content/Site.css @@ -0,0 +1,31 @@ +/* Move down content because we have a fixed navbar that is 50px tall */ +body { + padding-top: 50px; + padding-bottom: 20px; +} + +/* Wrapping element */ +/* Set some basic padding to keep content from hitting the edges */ +.body-content { + padding-left: 15px; + padding-right: 15px; +} + +/* Set widths on the form inputs since otherwise they're 100% wide */ +input, +select, +textarea { + max-width: 280px; +} + + +/* Responsive: Portrait tablets and up */ +@media screen and (min-width: 768px) { + .jumbotron { + margin-top: 20px; + } + + .body-content { + padding: 0; + } +} diff --git a/tests/CheckIIS/Default.aspx b/tests/CheckIIS/Default.aspx new file mode 100644 index 00000000000..85583edb217 --- /dev/null +++ b/tests/CheckIIS/Default.aspx @@ -0,0 +1,42 @@ +<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CheckIIS._Default" %> + + + +
+

ASP.NET

+

ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS, and JavaScript.

+

Learn more »

+
+ +
+
+

Getting started

+

+ ASP.NET Web Forms lets you build dynamic websites using a familiar drag-and-drop, event-driven model. + A design surface and hundreds of controls and components let you rapidly build sophisticated, powerful UI-driven sites with data access. +

+

+ Learn more » +

+
+
+

Get more libraries

+

+ NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects. +

+

+ Learn more » +

+
+
+

Web Hosting

+

+ You can easily find a web hosting company that offers the right mix of features and price for your applications. +

+

+ Learn more » +

+
+
+ +
diff --git a/tests/CheckIIS/Default.aspx.cs b/tests/CheckIIS/Default.aspx.cs new file mode 100644 index 00000000000..0b5ba21e7ed --- /dev/null +++ b/tests/CheckIIS/Default.aspx.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace CheckIIS +{ + public partial class _Default : Page + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/tests/CheckIIS/Default.aspx.designer.cs b/tests/CheckIIS/Default.aspx.designer.cs new file mode 100644 index 00000000000..d01453c8944 --- /dev/null +++ b/tests/CheckIIS/Default.aspx.designer.cs @@ -0,0 +1,17 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CheckIIS +{ + + + public partial class _Default + { + } +} diff --git a/tests/CheckIIS/Global.asax b/tests/CheckIIS/Global.asax new file mode 100644 index 00000000000..a7e8f5023e3 --- /dev/null +++ b/tests/CheckIIS/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CheckIIS.Global" Language="C#" %> diff --git a/tests/CheckIIS/Global.asax.cs b/tests/CheckIIS/Global.asax.cs new file mode 100644 index 00000000000..917699a2e19 --- /dev/null +++ b/tests/CheckIIS/Global.asax.cs @@ -0,0 +1,162 @@ +using System; +using System.Threading; +using ServiceStack; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Web.Hosting; + +namespace CheckIIS +{ + public class SimpleMessage + { + public string MyMsg { get; set; } + public IList Gifts { get; set; } + } + + public class LongMessage + { + public string Msg { get; set; } + } + + public class Global : System.Web.HttpApplication + { + protected void Application_Start(object sender, EventArgs e) + { + new AppHost().Init(); + + TestCase6(); + } + + private void TestCase1() + { + HostingEnvironment.QueueBackgroundWorkItem(LongMessage_SWithSleep2Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwaySleep2Async); + } + + private void TestCase2() + { + HostingEnvironment.QueueBackgroundWorkItem(LongMessage_SWithSleep2Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay2Async); + } + + private void TestCase3() + { + HostingEnvironment.QueueBackgroundWorkItem(LongMessage_SWithSleep200Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay200Async); + } + + private void TestCase4() + { + HostingEnvironment.QueueBackgroundWorkItem(LongMessage_SWithSleep2Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay1Async); + } + + private void TestCase5() + { + HostingEnvironment.QueueBackgroundWorkItem(LongMessage_SWithSleep2Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay1Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay2Async); + } + + private void TestCase6() + { + HostingEnvironment.QueueBackgroundWorkItem(LongMessage_SWithSleep2Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay1Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay2Async); + HostingEnvironment.QueueBackgroundWorkItem(GiftAwayDelay1Async); + } + + public async Task GiftAwayDelay200Async(CancellationToken cancellationToken) + { + await GiftAwayAsync(true, 200, cancellationToken); + } + public async Task GiftAwayDelay2Async(CancellationToken cancellationToken) + { + await GiftAwayAsync(true, 2, cancellationToken); + } + public async Task GiftAwayDelay1Async(CancellationToken cancellationToken) + { + await GiftAwayAsync(true, 1, cancellationToken); + } + public async Task GiftAwaySleep2Async(CancellationToken cancellationToken) + { + await GiftAwayAsync(false, 2, cancellationToken); + } + public async Task GiftAwaySleep200Async(CancellationToken cancellationToken) + { + await GiftAwayAsync(false, 200, cancellationToken); + } + public async Task GiftAwaySleep1Async(CancellationToken cancellationToken) + { + await GiftAwayAsync(false, 1, cancellationToken); + } + public async Task GiftAwayAsync(bool delay, int waitInMs, CancellationToken cancellationToken) + { + var serverEvents = HostContext.TryResolve(); + + var myGifts = new List + { + "On the first day of Christmas my true love gave to me: a Partridge in a Pear Tree.", + "On the second day of Christmas my true love gave to me: two Turtle Doves, and a Partridge in a Pear Tree.", + "On the third day of Christmas my true love gave to me: three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.", + "On the fourth day of Christmas my true love gave to me: four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.", + "On the fifth day of Christmas my true love gave to me: five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree." + }; + var msg = new SimpleMessage + { + MyMsg = "song", + Gifts = myGifts + }; + + while (true) + { + if (delay) + { + await Task.Delay(waitInMs); + } + else + { + Thread.Sleep(waitInMs); + } + await serverEvents.NotifyAllAsync("cmd.bombard", msg); + } + + } + + public async Task LongMessage_SWithSleep1Async(CancellationToken cancellationToken) + { + await LongMessage_SAsync(false, 1, cancellationToken); + } + public async Task LongMessage_SWithSleep2Async(CancellationToken cancellationToken) + { + await LongMessage_SAsync(false, 2, cancellationToken); + } + public async Task LongMessage_SWithSleep200Async(CancellationToken cancellationToken) + { + await LongMessage_SAsync(false, 200, cancellationToken); + } + public async Task LongMessage_SAsync(bool delay, int waitInMs, CancellationToken cancellationToken) + { + const int msgSize = 420 * 1024; + var serverEvents = HostContext.TryResolve(); + var stuff = new LongMessage + { + Msg = $"size{msgSize}-{new string('S', msgSize)}" + }; + + while (true) + { + if (delay) + { + await Task.Delay(waitInMs); + } + else + { + Thread.Sleep(waitInMs); + } + await serverEvents.NotifyAllAsync("cmd.MS", stuff, cancellationToken); + } + } + + } +} \ No newline at end of file diff --git a/tests/CheckIIS/Properties/AssemblyInfo.cs b/tests/CheckIIS/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..3c06d539740 --- /dev/null +++ b/tests/CheckIIS/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CheckIIS")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CheckIIS")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4eb53207-13da-47b2-a638-a4ec1534fe47")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "CheckIIS")] diff --git a/tests/CheckIIS/Site.Master b/tests/CheckIIS/Site.Master new file mode 100644 index 00000000000..3997ba85fd8 --- /dev/null +++ b/tests/CheckIIS/Site.Master @@ -0,0 +1,71 @@ +<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="CheckIIS.SiteMaster" %> + + + + + + + + <%: Page.Title %> - My ASP.NET Application + + + <%: Scripts.Render("~/bundles/modernizr") %> + + + + + + + +
+ + + <%--To learn more about bundling scripts in ScriptManager see https://go.microsoft.com/fwlink/?LinkID=301884 --%> + <%--Framework Scripts--%> + + + + + + + + + + + + + <%--Site Scripts--%> + + + + +
+ + +
+
+

© <%: DateTime.Now.Year %> - My ASP.NET Application

+
+
+ + + + diff --git a/tests/CheckIIS/Site.Master.cs b/tests/CheckIIS/Site.Master.cs new file mode 100644 index 00000000000..4880fc267d1 --- /dev/null +++ b/tests/CheckIIS/Site.Master.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace CheckIIS +{ + public partial class SiteMaster : MasterPage + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/tests/CheckIIS/Site.Master.designer.cs b/tests/CheckIIS/Site.Master.designer.cs new file mode 100644 index 00000000000..5e239ee20f1 --- /dev/null +++ b/tests/CheckIIS/Site.Master.designer.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CheckIIS +{ + + + public partial class SiteMaster + { + + /// + /// HeadContent control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder HeadContent; + + /// + /// MainContent control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder MainContent; + } +} diff --git a/tests/CheckIIS/Web.config b/tests/CheckIIS/Web.config new file mode 100644 index 00000000000..e1ad2ad1fe6 --- /dev/null +++ b/tests/CheckIIS/Web.config @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckIIS/default.html b/tests/CheckIIS/default.html new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/CheckIIS/default.html @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/CheckIIS/sse.html b/tests/CheckIIS/sse.html new file mode 100644 index 00000000000..4486ae5e847 --- /dev/null +++ b/tests/CheckIIS/sse.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + +

Errors

+
+ + + \ No newline at end of file diff --git a/tests/CheckIdentity/AppHost.cs b/tests/CheckIdentity/AppHost.cs new file mode 100644 index 00000000000..87ec906127d --- /dev/null +++ b/tests/CheckIdentity/AppHost.cs @@ -0,0 +1,63 @@ +using CheckIdentity.ServiceInterface; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.Text; +[assembly: HostingStartup(typeof(CheckIdentity.TestStartupServices))] + +namespace CheckIdentity +{ + public class AppHost : AppHostBase + { + public AppHost() + : base(nameof(CheckIdentity), typeof(MyServices).Assembly) {} + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + AdminAuthSecret = "secretz" + }); + + Plugins.Add(new AuthFeature(IdentityAuth.For(options => { + options.IncludeRegisterService = true; + options.IncludeAssignRoleServices = true; + }))); + } + } + + public class TestStartupServices : IHostingStartup + { + public void Configure(IWebHostBuilder builder) + { + builder.ConfigureServices(services => { + $"{nameof(TestStartupServices)}.Configure(services)".Print(); + }); + // kills the app? + // builder.Configure(app => { + // $"{nameof(TestStartupServices)}.Configure(app)".Print(); + // }); + } + } + + // public class TestStartupApp : IConfigureApp + // { + // public void Configure(IApplicationBuilder app) + // { + // $"{nameof(TestStartupApp)}.Configure(app)".Print(); + // } + // } + + public static class AppExt + { + public static WebApplicationBuilder AddModularStartup(this WebApplicationBuilder builder) + where THost : AppHostBase + { + builder.Services.AddModularStartup(builder.Configuration); + return builder; + } + } + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Data/CheckIdentityIdentityDbContext.cs b/tests/CheckIdentity/Areas/Identity/Data/CheckIdentityIdentityDbContext.cs new file mode 100644 index 00000000000..ea6cada2ad3 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Data/CheckIdentityIdentityDbContext.cs @@ -0,0 +1,26 @@ +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Threading.Tasks; +// using Microsoft.AspNetCore.Identity; +// using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +// using Microsoft.EntityFrameworkCore; +// +// namespace CheckIdentity.Areas.Identity.Data +// { +// public class CheckIdentityIdentityDbContext : IdentityDbContext +// { +// public CheckIdentityIdentityDbContext(DbContextOptions options) +// : base(options) +// { +// } +// +// protected override void OnModelCreating(ModelBuilder builder) +// { +// base.OnModelCreating(builder); +// // Customize the ASP.NET Identity model and override the defaults if needed. +// // For example, you can rename the ASP.NET Identity table names and more. +// // Add your customizations after calling base.OnModelCreating(builder); +// } +// } +// } diff --git a/tests/CheckIdentity/Areas/Identity/IdentityHostingStartup.cs b/tests/CheckIdentity/Areas/Identity/IdentityHostingStartup.cs new file mode 100644 index 00000000000..7f59675fce5 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/IdentityHostingStartup.cs @@ -0,0 +1,27 @@ +// using System; +// using CheckIdentity.Areas.Identity.Data; +// using Microsoft.AspNetCore.Hosting; +// using Microsoft.AspNetCore.Identity; +// using Microsoft.AspNetCore.Identity.UI; +// using Microsoft.EntityFrameworkCore; +// using Microsoft.Extensions.Configuration; +// using Microsoft.Extensions.DependencyInjection; +// +// [assembly: HostingStartup(typeof(CheckIdentity.Areas.Identity.IdentityHostingStartup))] +// namespace CheckIdentity.Areas.Identity +// { +// public class IdentityHostingStartup : IHostingStartup +// { +// public void Configure(IWebHostBuilder builder) +// { +// builder.ConfigureServices((context, services) => { +// services.AddDbContext(options => +// options.UseSqlite( +// context.Configuration.GetConnectionString("DefaultConnection"))); +// +// services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) +// .AddEntityFrameworkStores(); +// }); +// } +// } +// } \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/AccessDenied.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/AccessDenied.cshtml new file mode 100644 index 00000000000..017f6ff4d16 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/AccessDenied.cshtml @@ -0,0 +1,10 @@ +@page +@model AccessDeniedModel +@{ + ViewData["Title"] = "Access denied"; +} + +
+

@ViewData["Title"]

+

You do not have access to this resource.

+
diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs new file mode 100644 index 00000000000..27c0a9a50d3 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/AccessDenied.cshtml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + public class AccessDeniedModel : PageModel + { + public void OnGet() + { + + } + } +} + diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmail.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmail.cshtml new file mode 100644 index 00000000000..26deba2041e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmail.cshtml @@ -0,0 +1,7 @@ +@page +@model ConfirmEmailModel +@{ + ViewData["Title"] = "Confirm email"; +} + +

@ViewData["Title"]

\ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs new file mode 100644 index 00000000000..a6f90dd9f05 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ConfirmEmailModel : PageModel + { + private readonly UserManager _userManager; + + public ConfirmEmailModel(UserManager userManager) + { + _userManager = userManager; + } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGetAsync(string userId, string code) + { + if (userId == null || code == null) + { + return RedirectToPage("/Index"); + } + + var user = await _userManager.FindByIdAsync(userId); + if (user == null) + { + return NotFound($"Unable to load user with ID '{userId}'."); + } + + code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); + var result = await _userManager.ConfirmEmailAsync(user, code); + StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml new file mode 100644 index 00000000000..98d57c88d02 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml @@ -0,0 +1,8 @@ +@page +@model ConfirmEmailChangeModel +@{ + ViewData["Title"] = "Confirm email change"; +} + +

@ViewData["Title"]

+ \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml.cs new file mode 100644 index 00000000000..de2f84745a8 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ConfirmEmailChangeModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + + public ConfirmEmailChangeModel(UserManager userManager, SignInManager signInManager) + { + _userManager = userManager; + _signInManager = signInManager; + } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGetAsync(string userId, string email, string code) + { + if (userId == null || email == null || code == null) + { + return RedirectToPage("/Index"); + } + + var user = await _userManager.FindByIdAsync(userId); + if (user == null) + { + return NotFound($"Unable to load user with ID '{userId}'."); + } + + code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); + var result = await _userManager.ChangeEmailAsync(user, email, code); + if (!result.Succeeded) + { + StatusMessage = "Error changing email."; + return Page(); + } + + // In our UI email and user name are one and the same, so when we update the email + // we need to update the user name. + var setUserNameResult = await _userManager.SetUserNameAsync(user, email); + if (!setUserNameResult.Succeeded) + { + StatusMessage = "Error changing user name."; + return Page(); + } + + await _signInManager.RefreshSignInAsync(user); + StatusMessage = "Thank you for confirming your email change."; + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ExternalLogin.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ExternalLogin.cshtml new file mode 100644 index 00000000000..f7dc967d634 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ExternalLogin.cshtml @@ -0,0 +1,33 @@ +@page +@model ExternalLoginModel +@{ + ViewData["Title"] = "Register"; +} + +

@ViewData["Title"]

+

Associate your @Model.ProviderDisplayName account.

+
+ +

+ You've successfully authenticated with @Model.ProviderDisplayName. + Please enter an email address for this site below and click the Register button to finish + logging in. +

+ +
+
+
+
+
+ + + +
+ + +
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs new file mode 100644 index 00000000000..bd53a73ed07 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ExternalLoginModel : PageModel + { + private readonly SignInManager _signInManager; + private readonly UserManager _userManager; + private readonly IEmailSender _emailSender; + private readonly ILogger _logger; + + public ExternalLoginModel( + SignInManager signInManager, + UserManager userManager, + ILogger logger, + IEmailSender emailSender) + { + _signInManager = signInManager; + _userManager = userManager; + _logger = logger; + _emailSender = emailSender; + } + + [BindProperty] + public InputModel Input { get; set; } + + public string ProviderDisplayName { get; set; } + + public string ReturnUrl { get; set; } + + [TempData] + public string ErrorMessage { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + } + + public IActionResult OnGetAsync() + { + return RedirectToPage("./Login"); + } + + public IActionResult OnPost(string provider, string returnUrl = null) + { + // Request a redirect to the external login provider. + var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl }); + var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); + return new ChallengeResult(provider, properties); + } + + public async Task OnGetCallbackAsync(string returnUrl = null, string remoteError = null) + { + returnUrl = returnUrl ?? Url.Content("~/"); + if (remoteError != null) + { + ErrorMessage = $"Error from external provider: {remoteError}"; + return RedirectToPage("./Login", new {ReturnUrl = returnUrl }); + } + var info = await _signInManager.GetExternalLoginInfoAsync(); + if (info == null) + { + ErrorMessage = "Error loading external login information."; + return RedirectToPage("./Login", new { ReturnUrl = returnUrl }); + } + + // Sign in the user with this external login provider if the user already has a login. + var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor : true); + if (result.Succeeded) + { + _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider); + return LocalRedirect(returnUrl); + } + if (result.IsLockedOut) + { + return RedirectToPage("./Lockout"); + } + else + { + // If the user does not have an account, then ask the user to create an account. + ReturnUrl = returnUrl; + ProviderDisplayName = info.ProviderDisplayName; + if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email)) + { + Input = new InputModel + { + Email = info.Principal.FindFirstValue(ClaimTypes.Email) + }; + } + return Page(); + } + } + + public async Task OnPostConfirmationAsync(string returnUrl = null) + { + returnUrl = returnUrl ?? Url.Content("~/"); + // Get the information about the user from the external login provider + var info = await _signInManager.GetExternalLoginInfoAsync(); + if (info == null) + { + ErrorMessage = "Error loading external login information during confirmation."; + return RedirectToPage("./Login", new { ReturnUrl = returnUrl }); + } + + if (ModelState.IsValid) + { + var user = new IdentityUser { UserName = Input.Email, Email = Input.Email }; + + var result = await _userManager.CreateAsync(user); + if (result.Succeeded) + { + result = await _userManager.AddLoginAsync(user, info); + if (result.Succeeded) + { + _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider); + + var userId = await _userManager.GetUserIdAsync(user); + var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = Url.Page( + "/Account/ConfirmEmail", + pageHandler: null, + values: new { area = "Identity", userId = userId, code = code }, + protocol: Request.Scheme); + + await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", + $"Please confirm your account by clicking here."); + + // If account confirmation is required, we need to show the link if we don't have a real email sender + if (_userManager.Options.SignIn.RequireConfirmedAccount) + { + return RedirectToPage("./RegisterConfirmation", new { Email = Input.Email }); + } + + await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider); + + return LocalRedirect(returnUrl); + } + } + foreach (var error in result.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + } + + ProviderDisplayName = info.ProviderDisplayName; + ReturnUrl = returnUrl; + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPassword.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPassword.cshtml new file mode 100644 index 00000000000..94f46b2863e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPassword.cshtml @@ -0,0 +1,26 @@ +@page +@model ForgotPasswordModel +@{ + ViewData["Title"] = "Forgot your password?"; +} + +

@ViewData["Title"]

+

Enter your email.

+
+
+
+
+
+
+ + + +
+ + +
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs new file mode 100644 index 00000000000..8818797ab59 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text.Encodings.Web; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ForgotPasswordModel : PageModel + { + private readonly UserManager _userManager; + private readonly IEmailSender _emailSender; + + public ForgotPasswordModel(UserManager userManager, IEmailSender emailSender) + { + _userManager = userManager; + _emailSender = emailSender; + } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + } + + public async Task OnPostAsync() + { + if (ModelState.IsValid) + { + var user = await _userManager.FindByEmailAsync(Input.Email); + if (user == null || !(await _userManager.IsEmailConfirmedAsync(user))) + { + // Don't reveal that the user does not exist or is not confirmed + return RedirectToPage("./ForgotPasswordConfirmation"); + } + + // For more information on how to enable account confirmation and password reset please + // visit https://go.microsoft.com/fwlink/?LinkID=532713 + var code = await _userManager.GeneratePasswordResetTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = Url.Page( + "/Account/ResetPassword", + pageHandler: null, + values: new { area = "Identity", code }, + protocol: Request.Scheme); + + await _emailSender.SendEmailAsync( + Input.Email, + "Reset Password", + $"Please reset your password by clicking here."); + + return RedirectToPage("./ForgotPasswordConfirmation"); + } + + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml new file mode 100644 index 00000000000..1a1b7f96594 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml @@ -0,0 +1,11 @@ +@page +@model ForgotPasswordConfirmation +@{ + ViewData["Title"] = "Forgot password confirmation"; +} + +

@ViewData["Title"]

+

+ Please check your email to reset your password. +

+ diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs new file mode 100644 index 00000000000..89fbaa0bbf5 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ForgotPasswordConfirmation : PageModel + { + public void OnGet() + { + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Lockout.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Lockout.cshtml new file mode 100644 index 00000000000..4eded88208c --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Lockout.cshtml @@ -0,0 +1,10 @@ +@page +@model LockoutModel +@{ + ViewData["Title"] = "Locked out"; +} + +
+

@ViewData["Title"]

+

This account has been locked out, please try again later.

+
diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Lockout.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Lockout.cshtml.cs new file mode 100644 index 00000000000..dea12fa4a68 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Lockout.cshtml.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class LockoutModel : PageModel + { + public void OnGet() + { + + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Login.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Login.cshtml new file mode 100644 index 00000000000..72a567fae2a --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Login.cshtml @@ -0,0 +1,85 @@ +@page +@model LoginModel + +@{ + ViewData["Title"] = "Log in"; +} + +

@ViewData["Title"]

+
+
+
+
+

Use a local account to log in.

+
+
+
+ + + +
+
+ + + +
+
+
+ +
+
+
+ +
+ + +
+
+
+
+

Use another service to log in.

+
+ @{ + if ((Model.ExternalLogins?.Count ?? 0) == 0) + { +
+

+ There are no external authentication services configured. See this article + for details on setting up this ASP.NET application to support logging in via external services. +

+
+ } + else + { +
+
+

+ @foreach (var provider in Model.ExternalLogins) + { + + } +

+
+ + } + } +
+
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Login.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Login.cshtml.cs new file mode 100644 index 00000000000..d672a9a2f59 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Login.cshtml.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class LoginModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public LoginModel(SignInManager signInManager, + ILogger logger, + UserManager userManager) + { + _userManager = userManager; + _signInManager = signInManager; + _logger = logger; + } + + [BindProperty] + public InputModel Input { get; set; } + + public IList ExternalLogins { get; set; } + + public string ReturnUrl { get; set; } + + [TempData] + public string ErrorMessage { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + + [Required] + [DataType(DataType.Password)] + public string Password { get; set; } + + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } + } + + public async Task OnGetAsync(string returnUrl = null) + { + if (!string.IsNullOrEmpty(ErrorMessage)) + { + ModelState.AddModelError(string.Empty, ErrorMessage); + } + + returnUrl ??= Url.Content("~/"); + + // Clear the existing external cookie to ensure a clean login process + await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); + + ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); + + ReturnUrl = returnUrl; + } + + public async Task OnPostAsync(string returnUrl = null) + { + returnUrl ??= Url.Content("~/"); + + ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); + + if (ModelState.IsValid) + { + // This doesn't count login failures towards account lockout + // To enable password failures to trigger account lockout, set lockoutOnFailure: true + var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false); + if (result.Succeeded) + { + _logger.LogInformation("User logged in."); + return LocalRedirect(returnUrl); + } + if (result.RequiresTwoFactor) + { + return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe }); + } + if (result.IsLockedOut) + { + _logger.LogWarning("User account locked out."); + return RedirectToPage("./Lockout"); + } + else + { + ModelState.AddModelError(string.Empty, "Invalid login attempt."); + return Page(); + } + } + + // If we got this far, something failed, redisplay form + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWith2fa.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWith2fa.cshtml new file mode 100644 index 00000000000..780b4ec39a4 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWith2fa.cshtml @@ -0,0 +1,41 @@ +@page +@model LoginWith2faModel +@{ + ViewData["Title"] = "Two-factor authentication"; +} + +

@ViewData["Title"]

+
+

Your login is protected with an authenticator app. Enter your authenticator code below.

+
+
+
+ +
+
+ + + +
+
+
+ +
+
+
+ +
+ +
+
+

+ Don't have access to your authenticator device? You can + log in with a recovery code. +

+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs new file mode 100644 index 00000000000..3a2d3aaadbc --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class LoginWith2faModel : PageModel + { + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public LoginWith2faModel(SignInManager signInManager, ILogger logger) + { + _signInManager = signInManager; + _logger = logger; + } + + [BindProperty] + public InputModel Input { get; set; } + + public bool RememberMe { get; set; } + + public string ReturnUrl { get; set; } + + public class InputModel + { + [Required] + [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Text)] + [Display(Name = "Authenticator code")] + public string TwoFactorCode { get; set; } + + [Display(Name = "Remember this machine")] + public bool RememberMachine { get; set; } + } + + public async Task OnGetAsync(bool rememberMe, string returnUrl = null) + { + // Ensure the user has gone through the username & password screen first + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + + if (user == null) + { + throw new InvalidOperationException($"Unable to load two-factor authentication user."); + } + + ReturnUrl = returnUrl; + RememberMe = rememberMe; + + return Page(); + } + + public async Task OnPostAsync(bool rememberMe, string returnUrl = null) + { + if (!ModelState.IsValid) + { + return Page(); + } + + returnUrl = returnUrl ?? Url.Content("~/"); + + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + if (user == null) + { + throw new InvalidOperationException($"Unable to load two-factor authentication user."); + } + + var authenticatorCode = Input.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty); + + var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, rememberMe, Input.RememberMachine); + + if (result.Succeeded) + { + _logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", user.Id); + return LocalRedirect(returnUrl); + } + else if (result.IsLockedOut) + { + _logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id); + return RedirectToPage("./Lockout"); + } + else + { + _logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", user.Id); + ModelState.AddModelError(string.Empty, "Invalid authenticator code."); + return Page(); + } + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml new file mode 100644 index 00000000000..d866adb3074 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml @@ -0,0 +1,29 @@ +@page +@model LoginWithRecoveryCodeModel +@{ + ViewData["Title"] = "Recovery code verification"; +} + +

@ViewData["Title"]

+
+

+ You have requested to log in with a recovery code. This login will not be remembered until you provide + an authenticator app code at log in or disable 2FA and log in again. +

+
+
+
+
+
+ + + +
+ + +
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs new file mode 100644 index 00000000000..4f635f4e309 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class LoginWithRecoveryCodeModel : PageModel + { + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public LoginWithRecoveryCodeModel(SignInManager signInManager, ILogger logger) + { + _signInManager = signInManager; + _logger = logger; + } + + [BindProperty] + public InputModel Input { get; set; } + + public string ReturnUrl { get; set; } + + public class InputModel + { + [BindProperty] + [Required] + [DataType(DataType.Text)] + [Display(Name = "Recovery Code")] + public string RecoveryCode { get; set; } + } + + public async Task OnGetAsync(string returnUrl = null) + { + // Ensure the user has gone through the username & password screen first + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + if (user == null) + { + throw new InvalidOperationException($"Unable to load two-factor authentication user."); + } + + ReturnUrl = returnUrl; + + return Page(); + } + + public async Task OnPostAsync(string returnUrl = null) + { + if (!ModelState.IsValid) + { + return Page(); + } + + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + if (user == null) + { + throw new InvalidOperationException($"Unable to load two-factor authentication user."); + } + + var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty); + + var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode); + + if (result.Succeeded) + { + _logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", user.Id); + return LocalRedirect(returnUrl ?? Url.Content("~/")); + } + if (result.IsLockedOut) + { + _logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id); + return RedirectToPage("./Lockout"); + } + else + { + _logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", user.Id); + ModelState.AddModelError(string.Empty, "Invalid recovery code entered."); + return Page(); + } + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Logout.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Logout.cshtml new file mode 100644 index 00000000000..eca33c64052 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Logout.cshtml @@ -0,0 +1,21 @@ +@page +@model LogoutModel +@{ + ViewData["Title"] = "Log out"; +} + +
+

@ViewData["Title"]

+ @{ + if (User.Identity.IsAuthenticated) + { +
+ + + } + else + { +

You have successfully logged out of the application.

+ } + } +
\ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Logout.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Logout.cshtml.cs new file mode 100644 index 00000000000..c7d7cc91f4a --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Logout.cshtml.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class LogoutModel : PageModel + { + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public LogoutModel(SignInManager signInManager, ILogger logger) + { + _signInManager = signInManager; + _logger = logger; + } + + public void OnGet() + { + } + + public async Task OnPost(string returnUrl = null) + { + await _signInManager.SignOutAsync(); + _logger.LogInformation("User logged out."); + if (returnUrl != null) + { + return LocalRedirect(returnUrl); + } + else + { + return RedirectToPage(); + } + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml new file mode 100644 index 00000000000..31a2ea59a81 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml @@ -0,0 +1,36 @@ +@page +@model ChangePasswordModel +@{ + ViewData["Title"] = "Change password"; + ViewData["ActivePage"] = ManageNavPages.ChangePassword; +} + +

@ViewData["Title"]

+ +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+ + +
+
+ +@section Scripts { + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs new file mode 100644 index 00000000000..90d755664c6 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class ChangePasswordModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public ChangePasswordModel( + UserManager userManager, + SignInManager signInManager, + ILogger logger) + { + _userManager = userManager; + _signInManager = signInManager; + _logger = logger; + } + + [BindProperty] + public InputModel Input { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + public class InputModel + { + [Required] + [DataType(DataType.Password)] + [Display(Name = "Current password")] + public string OldPassword { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var hasPassword = await _userManager.HasPasswordAsync(user); + if (!hasPassword) + { + return RedirectToPage("./SetPassword"); + } + + return Page(); + } + + public async Task OnPostAsync() + { + if (!ModelState.IsValid) + { + return Page(); + } + + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var changePasswordResult = await _userManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword); + if (!changePasswordResult.Succeeded) + { + foreach (var error in changePasswordResult.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + return Page(); + } + + await _signInManager.RefreshSignInAsync(user); + _logger.LogInformation("User changed their password successfully."); + StatusMessage = "Your password has been changed."; + + return RedirectToPage(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml new file mode 100644 index 00000000000..c95ab92de7e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml @@ -0,0 +1,33 @@ +@page +@model DeletePersonalDataModel +@{ + ViewData["Title"] = "Delete Personal Data"; + ViewData["ActivePage"] = ManageNavPages.PersonalData; +} + +

@ViewData["Title"]

+ + + +
+
+
+ @if (Model.RequirePassword) + { +
+ + + +
+ } + + +
+ +@section Scripts { + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs new file mode 100644 index 00000000000..cfe07660e49 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs @@ -0,0 +1,83 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class DeletePersonalDataModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public DeletePersonalDataModel( + UserManager userManager, + SignInManager signInManager, + ILogger logger) + { + _userManager = userManager; + _signInManager = signInManager; + _logger = logger; + } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Required] + [DataType(DataType.Password)] + public string Password { get; set; } + } + + public bool RequirePassword { get; set; } + + public async Task OnGet() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + RequirePassword = await _userManager.HasPasswordAsync(user); + return Page(); + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + RequirePassword = await _userManager.HasPasswordAsync(user); + if (RequirePassword) + { + if (!await _userManager.CheckPasswordAsync(user, Input.Password)) + { + ModelState.AddModelError(string.Empty, "Incorrect password."); + return Page(); + } + } + + var result = await _userManager.DeleteAsync(user); + var userId = await _userManager.GetUserIdAsync(user); + if (!result.Succeeded) + { + throw new InvalidOperationException($"Unexpected error occurred deleting user with ID '{userId}'."); + } + + await _signInManager.SignOutAsync(); + + _logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId); + + return Redirect("~/"); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml new file mode 100644 index 00000000000..96df7522c7c --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml @@ -0,0 +1,25 @@ +@page +@model Disable2faModel +@{ + ViewData["Title"] = "Disable two-factor authentication (2FA)"; + ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; +} + + +

@ViewData["Title"]

+ + + +
+
+ + +
diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs new file mode 100644 index 00000000000..a19bc3eedfc --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class Disable2faModel : PageModel + { + private readonly UserManager _userManager; + private readonly ILogger _logger; + + public Disable2faModel( + UserManager userManager, + ILogger logger) + { + _userManager = userManager; + _logger = logger; + } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGet() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + if (!await _userManager.GetTwoFactorEnabledAsync(user)) + { + throw new InvalidOperationException($"Cannot disable 2FA for user with ID '{_userManager.GetUserId(User)}' as it's not currently enabled."); + } + + return Page(); + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var disable2faResult = await _userManager.SetTwoFactorEnabledAsync(user, false); + if (!disable2faResult.Succeeded) + { + throw new InvalidOperationException($"Unexpected error occurred disabling 2FA for user with ID '{_userManager.GetUserId(User)}'."); + } + + _logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User)); + StatusMessage = "2fa has been disabled. You can reenable 2fa when you setup an authenticator app"; + return RedirectToPage("./TwoFactorAuthentication"); + } + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml new file mode 100644 index 00000000000..87470c2f0b1 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml @@ -0,0 +1,12 @@ +@page +@model DownloadPersonalDataModel +@{ + ViewData["Title"] = "Download Your Data"; + ViewData["ActivePage"] = ManageNavPages.PersonalData; +} + +

@ViewData["Title"]

+ +@section Scripts { + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs new file mode 100644 index 00000000000..04f6047f037 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class DownloadPersonalDataModel : PageModel + { + private readonly UserManager _userManager; + private readonly ILogger _logger; + + public DownloadPersonalDataModel( + UserManager userManager, + ILogger logger) + { + _userManager = userManager; + _logger = logger; + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + _logger.LogInformation("User with ID '{UserId}' asked for their personal data.", _userManager.GetUserId(User)); + + // Only include personal data for download + var personalData = new Dictionary(); + var personalDataProps = typeof(IdentityUser).GetProperties().Where( + prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute))); + foreach (var p in personalDataProps) + { + personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null"); + } + + var logins = await _userManager.GetLoginsAsync(user); + foreach (var l in logins) + { + personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey); + } + + Response.Headers.Add("Content-Disposition", "attachment; filename=PersonalData.json"); + return new FileContentResult(JsonSerializer.SerializeToUtf8Bytes(personalData), "application/json"); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Email.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Email.cshtml new file mode 100644 index 00000000000..8ff8e39e3e1 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Email.cshtml @@ -0,0 +1,43 @@ +@page +@model EmailModel +@{ + ViewData["Title"] = "Manage Email"; + ViewData["ActivePage"] = ManageNavPages.Email; +} + +

@ViewData["Title"]

+ +
+
+
+
+
+ + @if (Model.IsEmailConfirmed) + { +
+ +
+ +
+
+ } + else + { + + + } +
+
+ + + +
+ + +
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Email.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Email.cshtml.cs new file mode 100644 index 00000000000..69f3db3ab58 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Email.cshtml.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; +using System.Text.Encodings.Web; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public partial class EmailModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + private readonly IEmailSender _emailSender; + + public EmailModel( + UserManager userManager, + SignInManager signInManager, + IEmailSender emailSender) + { + _userManager = userManager; + _signInManager = signInManager; + _emailSender = emailSender; + } + + public string Username { get; set; } + + public string Email { get; set; } + + public bool IsEmailConfirmed { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + [Display(Name = "New email")] + public string NewEmail { get; set; } + } + + private async Task LoadAsync(IdentityUser user) + { + var email = await _userManager.GetEmailAsync(user); + Email = email; + + Input = new InputModel + { + NewEmail = email, + }; + + IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user); + } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + await LoadAsync(user); + return Page(); + } + + public async Task OnPostChangeEmailAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + if (!ModelState.IsValid) + { + await LoadAsync(user); + return Page(); + } + + var email = await _userManager.GetEmailAsync(user); + if (Input.NewEmail != email) + { + var userId = await _userManager.GetUserIdAsync(user); + var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = Url.Page( + "/Account/ConfirmEmailChange", + pageHandler: null, + values: new { userId = userId, email = Input.NewEmail, code = code }, + protocol: Request.Scheme); + await _emailSender.SendEmailAsync( + Input.NewEmail, + "Confirm your email", + $"Please confirm your account by clicking here."); + + StatusMessage = "Confirmation link to change email sent. Please check your email."; + return RedirectToPage(); + } + + StatusMessage = "Your email is unchanged."; + return RedirectToPage(); + } + + public async Task OnPostSendVerificationEmailAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + if (!ModelState.IsValid) + { + await LoadAsync(user); + return Page(); + } + + var userId = await _userManager.GetUserIdAsync(user); + var email = await _userManager.GetEmailAsync(user); + var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = Url.Page( + "/Account/ConfirmEmail", + pageHandler: null, + values: new { area = "Identity", userId = userId, code = code }, + protocol: Request.Scheme); + await _emailSender.SendEmailAsync( + email, + "Confirm your email", + $"Please confirm your account by clicking here."); + + StatusMessage = "Verification email sent. Please check your email."; + return RedirectToPage(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml new file mode 100644 index 00000000000..6ea85104ae4 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml @@ -0,0 +1,53 @@ +@page +@model EnableAuthenticatorModel +@{ + ViewData["Title"] = "Configure authenticator app"; + ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; +} + + +

@ViewData["Title"]

+
+

To use an authenticator app go through the following steps:

+
    +
  1. +

    + Download a two-factor authenticator app like Microsoft Authenticator for + Android and + iOS or + Google Authenticator for + Android and + iOS. +

    +
  2. +
  3. +

    Scan the QR Code or enter this key @Model.SharedKey into your two factor authenticator app. Spaces and casing do not matter.

    + +
    +
    +
  4. +
  5. +

    + Once you have scanned the QR code or input the key above, your two factor authentication app will provide you + with a unique code. Enter the code in the confirmation box below. +

    +
    +
    +
    +
    + + + +
    + +
    + +
    +
    +
  6. +
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs new file mode 100644 index 00000000000..56ea2ca28fd --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs @@ -0,0 +1,156 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using System.Text; +using System.Text.Encodings.Web; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class EnableAuthenticatorModel : PageModel + { + private readonly UserManager _userManager; + private readonly ILogger _logger; + private readonly UrlEncoder _urlEncoder; + + private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6"; + + public EnableAuthenticatorModel( + UserManager userManager, + ILogger logger, + UrlEncoder urlEncoder) + { + _userManager = userManager; + _logger = logger; + _urlEncoder = urlEncoder; + } + + public string SharedKey { get; set; } + + public string AuthenticatorUri { get; set; } + + [TempData] + public string[] RecoveryCodes { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Required] + [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Text)] + [Display(Name = "Verification Code")] + public string Code { get; set; } + } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + await LoadSharedKeyAndQrCodeUriAsync(user); + + return Page(); + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + if (!ModelState.IsValid) + { + await LoadSharedKeyAndQrCodeUriAsync(user); + return Page(); + } + + // Strip spaces and hypens + var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty); + + var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync( + user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); + + if (!is2faTokenValid) + { + ModelState.AddModelError("Input.Code", "Verification code is invalid."); + await LoadSharedKeyAndQrCodeUriAsync(user); + return Page(); + } + + await _userManager.SetTwoFactorEnabledAsync(user, true); + var userId = await _userManager.GetUserIdAsync(user); + _logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId); + + StatusMessage = "Your authenticator app has been verified."; + + if (await _userManager.CountRecoveryCodesAsync(user) == 0) + { + var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); + RecoveryCodes = recoveryCodes.ToArray(); + return RedirectToPage("./ShowRecoveryCodes"); + } + else + { + return RedirectToPage("./TwoFactorAuthentication"); + } + } + + private async Task LoadSharedKeyAndQrCodeUriAsync(IdentityUser user) + { + // Load the authenticator key & QR code URI to display on the form + var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user); + if (string.IsNullOrEmpty(unformattedKey)) + { + await _userManager.ResetAuthenticatorKeyAsync(user); + unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user); + } + + SharedKey = FormatKey(unformattedKey); + + var email = await _userManager.GetEmailAsync(user); + AuthenticatorUri = GenerateQrCodeUri(email, unformattedKey); + } + + private string FormatKey(string unformattedKey) + { + var result = new StringBuilder(); + int currentPosition = 0; + while (currentPosition + 4 < unformattedKey.Length) + { + result.Append(unformattedKey.Substring(currentPosition, 4)).Append(" "); + currentPosition += 4; + } + if (currentPosition < unformattedKey.Length) + { + result.Append(unformattedKey.Substring(currentPosition)); + } + + return result.ToString().ToLowerInvariant(); + } + + private string GenerateQrCodeUri(string email, string unformattedKey) + { + return string.Format( + AuthenticatorUriFormat, + _urlEncoder.Encode("CheckIdentity"), + _urlEncoder.Encode(email), + unformattedKey); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml new file mode 100644 index 00000000000..d7a3c42e2fc --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml @@ -0,0 +1,53 @@ +@page +@model ExternalLoginsModel +@{ + ViewData["Title"] = "Manage your external logins"; + ViewData["ActivePage"] = ManageNavPages.ExternalLogins; +} + + +@if (Model.CurrentLogins?.Count > 0) +{ +

Registered Logins

+
+ + @foreach (var login in Model.CurrentLogins) + { + + + + + } + +
@login.ProviderDisplayName + @if (Model.ShowRemoveButton) + { +
+
+ + + +
+
+ } + else + { + @:   + } +
+} +@if (Model.OtherLogins?.Count > 0) +{ +

Add another service to log in.

+
+ +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml.cs new file mode 100644 index 00000000000..e0f5446502e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class ExternalLoginsModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + + public ExternalLoginsModel( + UserManager userManager, + SignInManager signInManager) + { + _userManager = userManager; + _signInManager = signInManager; + } + + public IList CurrentLogins { get; set; } + + public IList OtherLogins { get; set; } + + public bool ShowRemoveButton { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID 'user.Id'."); + } + + CurrentLogins = await _userManager.GetLoginsAsync(user); + OtherLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()) + .Where(auth => CurrentLogins.All(ul => auth.Name != ul.LoginProvider)) + .ToList(); + ShowRemoveButton = user.PasswordHash != null || CurrentLogins.Count > 1; + return Page(); + } + + public async Task OnPostRemoveLoginAsync(string loginProvider, string providerKey) + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID 'user.Id'."); + } + + var result = await _userManager.RemoveLoginAsync(user, loginProvider, providerKey); + if (!result.Succeeded) + { + StatusMessage = "The external login was not removed."; + return RedirectToPage(); + } + + await _signInManager.RefreshSignInAsync(user); + StatusMessage = "The external login was removed."; + return RedirectToPage(); + } + + public async Task OnPostLinkLoginAsync(string provider) + { + // Clear the existing external cookie to ensure a clean login process + await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); + + // Request a redirect to the external login provider to link a login for the current user + var redirectUrl = Url.Page("./ExternalLogins", pageHandler: "LinkLoginCallback"); + var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); + return new ChallengeResult(provider, properties); + } + + public async Task OnGetLinkLoginCallbackAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID 'user.Id'."); + } + + var info = await _signInManager.GetExternalLoginInfoAsync(user.Id); + if (info == null) + { + throw new InvalidOperationException($"Unexpected error occurred loading external login info for user with ID '{user.Id}'."); + } + + var result = await _userManager.AddLoginAsync(user, info); + if (!result.Succeeded) + { + StatusMessage = "The external login was not added. External logins can only be associated with one account."; + return RedirectToPage(); + } + + // Clear the existing external cookie to ensure a clean login process + await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); + + StatusMessage = "The external login was added."; + return RedirectToPage(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml new file mode 100644 index 00000000000..284ab59b5d4 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml @@ -0,0 +1,27 @@ +@page +@model GenerateRecoveryCodesModel +@{ + ViewData["Title"] = "Generate two-factor authentication (2FA) recovery codes"; + ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; +} + + +

@ViewData["Title"]

+ +
+
+ +
+
\ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml.cs new file mode 100644 index 00000000000..7c046bbb46f --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class GenerateRecoveryCodesModel : PageModel + { + private readonly UserManager _userManager; + private readonly ILogger _logger; + + public GenerateRecoveryCodesModel( + UserManager userManager, + ILogger logger) + { + _userManager = userManager; + _logger = logger; + } + + [TempData] + public string[] RecoveryCodes { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var isTwoFactorEnabled = await _userManager.GetTwoFactorEnabledAsync(user); + if (!isTwoFactorEnabled) + { + var userId = await _userManager.GetUserIdAsync(user); + throw new InvalidOperationException($"Cannot generate recovery codes for user with ID '{userId}' because they do not have 2FA enabled."); + } + + return Page(); + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var isTwoFactorEnabled = await _userManager.GetTwoFactorEnabledAsync(user); + var userId = await _userManager.GetUserIdAsync(user); + if (!isTwoFactorEnabled) + { + throw new InvalidOperationException($"Cannot generate recovery codes for user with ID '{userId}' as they do not have 2FA enabled."); + } + + var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); + RecoveryCodes = recoveryCodes.ToArray(); + + _logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", userId); + StatusMessage = "You have generated new recovery codes."; + return RedirectToPage("./ShowRecoveryCodes"); + } + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Index.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Index.cshtml new file mode 100644 index 00000000000..2a18fdb9603 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Index.cshtml @@ -0,0 +1,30 @@ +@page +@model IndexModel +@{ + ViewData["Title"] = "Profile"; + ViewData["ActivePage"] = ManageNavPages.Index; +} + +

@ViewData["Title"]

+ +
+
+
+
+
+ + +
+
+ + + +
+ +
+
+
+ +@section Scripts { + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs new file mode 100644 index 00000000000..107f1688ca3 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public partial class IndexModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + + public IndexModel( + UserManager userManager, + SignInManager signInManager) + { + _userManager = userManager; + _signInManager = signInManager; + } + + public string Username { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Phone] + [Display(Name = "Phone number")] + public string PhoneNumber { get; set; } + } + + private async Task LoadAsync(IdentityUser user) + { + var userName = await _userManager.GetUserNameAsync(user); + var phoneNumber = await _userManager.GetPhoneNumberAsync(user); + + Username = userName; + + Input = new InputModel + { + PhoneNumber = phoneNumber + }; + } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + await LoadAsync(user); + return Page(); + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + if (!ModelState.IsValid) + { + await LoadAsync(user); + return Page(); + } + + var phoneNumber = await _userManager.GetPhoneNumberAsync(user); + if (Input.PhoneNumber != phoneNumber) + { + var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber); + if (!setPhoneResult.Succeeded) + { + StatusMessage = "Unexpected error when trying to set phone number."; + return RedirectToPage(); + } + } + + await _signInManager.RefreshSignInAsync(user); + StatusMessage = "Your profile has been updated"; + return RedirectToPage(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ManageNavPages.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ManageNavPages.cs new file mode 100644 index 00000000000..02102c0370e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ManageNavPages.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public static class ManageNavPages + { + public static string Index => "Index"; + + public static string Email => "Email"; + + public static string ChangePassword => "ChangePassword"; + + public static string DownloadPersonalData => "DownloadPersonalData"; + + public static string DeletePersonalData => "DeletePersonalData"; + + public static string ExternalLogins => "ExternalLogins"; + + public static string PersonalData => "PersonalData"; + + public static string TwoFactorAuthentication => "TwoFactorAuthentication"; + + public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index); + + public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email); + + public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword); + + public static string DownloadPersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DownloadPersonalData); + + public static string DeletePersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DeletePersonalData); + + public static string ExternalLoginsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ExternalLogins); + + public static string PersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, PersonalData); + + public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication); + + private static string PageNavClass(ViewContext viewContext, string page) + { + var activePage = viewContext.ViewData["ActivePage"] as string + ?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName); + return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null; + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml new file mode 100644 index 00000000000..d64bd826cf5 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml @@ -0,0 +1,27 @@ +@page +@model PersonalDataModel +@{ + ViewData["Title"] = "Personal Data"; + ViewData["ActivePage"] = ManageNavPages.PersonalData; +} + +

@ViewData["Title"]

+ +
+
+

Your account contains personal data that you have given us. This page allows you to download or delete that data.

+

+ Deleting this data will permanently remove your account, and this cannot be recovered. +

+
+ +
+

+ Delete +

+
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml.cs new file mode 100644 index 00000000000..d4eca656937 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/PersonalData.cshtml.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class PersonalDataModel : PageModel + { + private readonly UserManager _userManager; + private readonly ILogger _logger; + + public PersonalDataModel( + UserManager userManager, + ILogger logger) + { + _userManager = userManager; + _logger = logger; + } + + public async Task OnGet() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + return Page(); + } + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml new file mode 100644 index 00000000000..081c82461f6 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml @@ -0,0 +1,24 @@ +@page +@model ResetAuthenticatorModel +@{ + ViewData["Title"] = "Reset authenticator key"; + ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; +} + + +

@ViewData["Title"]

+ +
+
+ +
+
\ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml.cs new file mode 100644 index 00000000000..619d9819b91 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class ResetAuthenticatorModel : PageModel + { + UserManager _userManager; + private readonly SignInManager _signInManager; + ILogger _logger; + + public ResetAuthenticatorModel( + UserManager userManager, + SignInManager signInManager, + ILogger logger) + { + _userManager = userManager; + _signInManager = signInManager; + _logger = logger; + } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGet() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + return Page(); + } + + public async Task OnPostAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + await _userManager.SetTwoFactorEnabledAsync(user, false); + await _userManager.ResetAuthenticatorKeyAsync(user); + _logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", user.Id); + + await _signInManager.RefreshSignInAsync(user); + StatusMessage = "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key."; + + return RedirectToPage("./EnableAuthenticator"); + } + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml new file mode 100644 index 00000000000..f1817aad06c --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml @@ -0,0 +1,35 @@ +@page +@model SetPasswordModel +@{ + ViewData["Title"] = "Set password"; + ViewData["ActivePage"] = ManageNavPages.ChangePassword; +} + +

Set your password

+ +

+ You do not have a local username/password for this site. Add a local + account so you can log in without an external login. +

+
+
+
+
+
+ + + +
+
+ + + +
+ +
+
+
+ +@section Scripts { + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml.cs new file mode 100644 index 00000000000..055916c88b0 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class SetPasswordModel : PageModel + { + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + + public SetPasswordModel( + UserManager userManager, + SignInManager signInManager) + { + _userManager = userManager; + _signInManager = signInManager; + } + + [BindProperty] + public InputModel Input { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + public class InputModel + { + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } + + public async Task OnGetAsync() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var hasPassword = await _userManager.HasPasswordAsync(user); + + if (hasPassword) + { + return RedirectToPage("./ChangePassword"); + } + + return Page(); + } + + public async Task OnPostAsync() + { + if (!ModelState.IsValid) + { + return Page(); + } + + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + var addPasswordResult = await _userManager.AddPasswordAsync(user, Input.NewPassword); + if (!addPasswordResult.Succeeded) + { + foreach (var error in addPasswordResult.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + return Page(); + } + + await _signInManager.RefreshSignInAsync(user); + StatusMessage = "Your password has been set."; + + return RedirectToPage(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml new file mode 100644 index 00000000000..23fa27ba5d5 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml @@ -0,0 +1,25 @@ +@page +@model ShowRecoveryCodesModel +@{ + ViewData["Title"] = "Recovery codes"; + ViewData["ActivePage"] = "TwoFactorAuthentication"; +} + + +

@ViewData["Title"]

+ +
+
+ @for (var row = 0; row < Model.RecoveryCodes.Length; row += 2) + { + @Model.RecoveryCodes[row] @Model.RecoveryCodes[row + 1]
+ } +
+
\ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml.cs new file mode 100644 index 00000000000..30682e4dc30 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class ShowRecoveryCodesModel : PageModel + { + [TempData] + public string[] RecoveryCodes { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + public IActionResult OnGet() + { + if (RecoveryCodes == null || RecoveryCodes.Length == 0) + { + return RedirectToPage("./TwoFactorAuthentication"); + } + + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml new file mode 100644 index 00000000000..a1729eba376 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml @@ -0,0 +1,57 @@ +@page +@model TwoFactorAuthenticationModel +@{ + ViewData["Title"] = "Two-factor authentication (2FA)"; + ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; +} + + +

@ViewData["Title"]

+@if (Model.Is2faEnabled) +{ + if (Model.RecoveryCodesLeft == 0) + { +
+ You have no recovery codes left. +

You must generate a new set of recovery codes before you can log in with a recovery code.

+
+ } + else if (Model.RecoveryCodesLeft == 1) + { +
+ You have 1 recovery code left. +

You can generate a new set of recovery codes.

+
+ } + else if (Model.RecoveryCodesLeft <= 3) + { +
+ You have @Model.RecoveryCodesLeft recovery codes left. +

You should generate a new set of recovery codes.

+
+ } + + if (Model.IsMachineRemembered) + { +
+ +
+ } + Disable 2FA + Reset recovery codes +} + +
Authenticator app
+@if (!Model.HasAuthenticator) +{ + Add authenticator app +} +else +{ + Setup authenticator app + Reset authenticator app +} + +@section Scripts { + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml.cs new file mode 100644 index 00000000000..9af5639d186 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account.Manage +{ + public class TwoFactorAuthenticationModel : PageModel + { + private const string AuthenicatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}"; + + private readonly UserManager _userManager; + private readonly SignInManager _signInManager; + private readonly ILogger _logger; + + public TwoFactorAuthenticationModel( + UserManager userManager, + SignInManager signInManager, + ILogger logger) + { + _userManager = userManager; + _signInManager = signInManager; + _logger = logger; + } + + public bool HasAuthenticator { get; set; } + + public int RecoveryCodesLeft { get; set; } + + [BindProperty] + public bool Is2faEnabled { get; set; } + + public bool IsMachineRemembered { get; set; } + + [TempData] + public string StatusMessage { get; set; } + + public async Task OnGet() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + HasAuthenticator = await _userManager.GetAuthenticatorKeyAsync(user) != null; + Is2faEnabled = await _userManager.GetTwoFactorEnabledAsync(user); + IsMachineRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user); + RecoveryCodesLeft = await _userManager.CountRecoveryCodesAsync(user); + + return Page(); + } + + public async Task OnPost() + { + var user = await _userManager.GetUserAsync(User); + if (user == null) + { + return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); + } + + await _signInManager.ForgetTwoFactorClientAsync(); + StatusMessage = "The current browser has been forgotten. When you login again from this browser you will be prompted for your 2fa code."; + return RedirectToPage(); + } + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_Layout.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_Layout.cshtml new file mode 100644 index 00000000000..3d882cc4810 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_Layout.cshtml @@ -0,0 +1,29 @@ +@{ + if (ViewData.TryGetValue("ParentLayout", out var parentLayout)) + { + Layout = (string)parentLayout; + } + else + { + Layout = "/Areas/Identity/Pages/_Layout.cshtml"; + } +} + +

Manage your account

+ +
+

Change your account settings

+
+
+
+ +
+
+ @RenderBody() +
+
+
+ +@section Scripts { + @RenderSection("Scripts", required: false) +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml new file mode 100644 index 00000000000..c29c9e58d1e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml @@ -0,0 +1,15 @@ +@inject SignInManager SignInManager +@{ + var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any(); +} + diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml new file mode 100644 index 00000000000..208a42475ab --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml @@ -0,0 +1,10 @@ +@model string + +@if (!String.IsNullOrEmpty(Model)) +{ + var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; + +} \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml new file mode 100644 index 00000000000..53e69923261 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml @@ -0,0 +1 @@ +@using CheckIdentity.Areas.Identity.Pages.Account.Manage diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Register.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/Register.cshtml new file mode 100644 index 00000000000..96e6a9a5302 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Register.cshtml @@ -0,0 +1,67 @@ +@page +@model RegisterModel +@{ + ViewData["Title"] = "Register"; +} + +

@ViewData["Title"]

+ +
+
+
+

Create a new account.

+
+
+
+ + + +
+
+ + + +
+
+ + + +
+ +
+
+
+
+

Use another service to register.

+
+ @{ + if ((Model.ExternalLogins?.Count ?? 0) == 0) + { +
+

+ There are no external authentication services configured. See this article + for details on setting up this ASP.NET application to support logging in via external services. +

+
+ } + else + { +
+
+

+ @foreach (var provider in Model.ExternalLogins) + { + + } +

+
+
+ } + } +
+
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/Register.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/Register.cshtml.cs new file mode 100644 index 00000000000..3f4187ce248 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/Register.cshtml.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class RegisterModel : PageModel + { + private readonly SignInManager _signInManager; + private readonly UserManager _userManager; + private readonly ILogger _logger; + private readonly IEmailSender _emailSender; + + public RegisterModel( + UserManager userManager, + SignInManager signInManager, + ILogger logger, + IEmailSender emailSender) + { + _userManager = userManager; + _signInManager = signInManager; + _logger = logger; + _emailSender = emailSender; + } + + [BindProperty] + public InputModel Input { get; set; } + + public string ReturnUrl { get; set; } + + public IList ExternalLogins { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string Email { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } + + public async Task OnGetAsync(string returnUrl = null) + { + ReturnUrl = returnUrl; + ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); + } + + public async Task OnPostAsync(string returnUrl = null) + { + returnUrl ??= Url.Content("~/"); + ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); + if (ModelState.IsValid) + { + var user = new IdentityUser { UserName = Input.Email, Email = Input.Email }; + var result = await _userManager.CreateAsync(user, Input.Password); + if (result.Succeeded) + { + _logger.LogInformation("User created a new account with password."); + + var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = Url.Page( + "/Account/ConfirmEmail", + pageHandler: null, + values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl }, + protocol: Request.Scheme); + + await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", + $"Please confirm your account by clicking here."); + + if (_userManager.Options.SignIn.RequireConfirmedAccount) + { + return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl }); + } + else + { + await _signInManager.SignInAsync(user, isPersistent: false); + return LocalRedirect(returnUrl); + } + } + foreach (var error in result.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + } + + // If we got this far, something failed, redisplay form + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml new file mode 100644 index 00000000000..c7c5d905b2b --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml @@ -0,0 +1,22 @@ +@page +@model RegisterConfirmationModel +@{ + ViewData["Title"] = "Register confirmation"; +} + +

@ViewData["Title"]

+@{ + if (@Model.DisplayConfirmAccountLink) + { +

+ This app does not currently have a real email sender registered, see these docs for how to configure a real email sender. + Normally this would be emailed: Click here to confirm your account +

+ } + else + { +

+ Please check your email to confirm your account. +

+ } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs new file mode 100644 index 00000000000..9c870ea00f0 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Authorization; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class RegisterConfirmationModel : PageModel + { + private readonly UserManager _userManager; + private readonly IEmailSender _sender; + + public RegisterConfirmationModel(UserManager userManager, IEmailSender sender) + { + _userManager = userManager; + _sender = sender; + } + + public string Email { get; set; } + + public bool DisplayConfirmAccountLink { get; set; } + + public string EmailConfirmationUrl { get; set; } + + public async Task OnGetAsync(string email, string returnUrl = null) + { + if (email == null) + { + return RedirectToPage("/Index"); + } + + var user = await _userManager.FindByEmailAsync(email); + if (user == null) + { + return NotFound($"Unable to load user with email '{email}'."); + } + + Email = email; + // Once you add a real email sender, you should remove this code that lets you confirm the account + DisplayConfirmAccountLink = true; + if (DisplayConfirmAccountLink) + { + var userId = await _userManager.GetUserIdAsync(user); + var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + EmailConfirmationUrl = Url.Page( + "/Account/ConfirmEmail", + pageHandler: null, + values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl }, + protocol: Request.Scheme); + } + + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml new file mode 100644 index 00000000000..16d11e9d8eb --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml @@ -0,0 +1,26 @@ +@page +@model ResendEmailConfirmationModel +@{ + ViewData["Title"] = "Resend email confirmation"; +} + +

@ViewData["Title"]

+

Enter your email.

+
+
+
+
+
+
+ + + +
+ +
+
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml.cs new file mode 100644 index 00000000000..38159886315 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml.cs @@ -0,0 +1,73 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; + +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ResendEmailConfirmationModel : PageModel + { + private readonly UserManager _userManager; + private readonly IEmailSender _emailSender; + + public ResendEmailConfirmationModel(UserManager userManager, IEmailSender emailSender) + { + _userManager = userManager; + _emailSender = emailSender; + } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + } + + public void OnGet() + { + } + + public async Task OnPostAsync() + { + if (!ModelState.IsValid) + { + return Page(); + } + + var user = await _userManager.FindByEmailAsync(Input.Email); + if (user == null) + { + ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email."); + return Page(); + } + + var userId = await _userManager.GetUserIdAsync(user); + var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = Url.Page( + "/Account/ConfirmEmail", + pageHandler: null, + values: new { userId = userId, code = code }, + protocol: Request.Scheme); + await _emailSender.SendEmailAsync( + Input.Email, + "Confirm your email", + $"Please confirm your account by clicking here."); + + ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email."); + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPassword.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPassword.cshtml new file mode 100644 index 00000000000..27bc951b039 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPassword.cshtml @@ -0,0 +1,37 @@ +@page +@model ResetPasswordModel +@{ + ViewData["Title"] = "Reset password"; +} + +

@ViewData["Title"]

+

Reset your password.

+
+
+
+
+
+ +
+ + + +
+
+ + + +
+
+ + + +
+ +
+
+
+ +@section Scripts { + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPassword.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPassword.cshtml.cs new file mode 100644 index 00000000000..67b46cfe286 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPassword.cshtml.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.WebUtilities; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ResetPasswordModel : PageModel + { + private readonly UserManager _userManager; + + public ResetPasswordModel(UserManager userManager) + { + _userManager = userManager; + } + + [BindProperty] + public InputModel Input { get; set; } + + public class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + public string Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + + public string Code { get; set; } + } + + public IActionResult OnGet(string code = null) + { + if (code == null) + { + return BadRequest("A code must be supplied for password reset."); + } + else + { + Input = new InputModel + { + Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)) + }; + return Page(); + } + } + + public async Task OnPostAsync() + { + if (!ModelState.IsValid) + { + return Page(); + } + + var user = await _userManager.FindByEmailAsync(Input.Email); + if (user == null) + { + // Don't reveal that the user does not exist + return RedirectToPage("./ResetPasswordConfirmation"); + } + + var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password); + if (result.Succeeded) + { + return RedirectToPage("./ResetPasswordConfirmation"); + } + + foreach (var error in result.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + return Page(); + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml new file mode 100644 index 00000000000..c52552f3e6d --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml @@ -0,0 +1,10 @@ +@page +@model ResetPasswordConfirmationModel +@{ + ViewData["Title"] = "Reset password confirmation"; +} + +

@ViewData["Title"]

+

+ Your password has been reset. Please click here to log in. +

diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml.cs new file mode 100644 index 00000000000..5348bd601a8 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages.Account +{ + [AllowAnonymous] + public class ResetPasswordConfirmationModel : PageModel + { + public void OnGet() + { + + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/_StatusMessage.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/_StatusMessage.cshtml new file mode 100644 index 00000000000..e996841309e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/_StatusMessage.cshtml @@ -0,0 +1,10 @@ +@model string + +@if (!String.IsNullOrEmpty(Model)) +{ + var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; + +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Account/_ViewImports.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Account/_ViewImports.cshtml new file mode 100644 index 00000000000..9623a03c0bd --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Account/_ViewImports.cshtml @@ -0,0 +1 @@ +@using CheckIdentity.Areas.Identity.Pages.Account \ No newline at end of file diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Error.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/Error.cshtml new file mode 100644 index 00000000000..b1f3143a42e --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Error.cshtml @@ -0,0 +1,23 @@ +@page +@model ErrorModel +@{ + ViewData["Title"] = "Error"; +} + +

Error.

+

An error occurred while processing your request.

+ +@if (Model.ShowRequestId) +{ +

+ Request ID: @Model.RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. +

diff --git a/tests/CheckIdentity/Areas/Identity/Pages/Error.cshtml.cs b/tests/CheckIdentity/Areas/Identity/Pages/Error.cshtml.cs new file mode 100644 index 00000000000..55b6c9e9dfb --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/Error.cshtml.cs @@ -0,0 +1,21 @@ +using System.Diagnostics; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace CheckIdentity.Areas.Identity.Pages +{ + [AllowAnonymous] + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public class ErrorModel : PageModel + { + public string RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } + } +} diff --git a/tests/CheckIdentity/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml new file mode 100644 index 00000000000..9e26f3b82a1 --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/tests/CheckIdentity/Areas/Identity/Pages/_ViewImports.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/_ViewImports.cshtml new file mode 100644 index 00000000000..0c6cf57fbca --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@using Microsoft.AspNetCore.Identity +@using CheckIdentity.Areas.Identity +@using CheckIdentity.Areas.Identity.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/tests/CheckIdentity/Areas/Identity/Pages/_ViewStart.cshtml b/tests/CheckIdentity/Areas/Identity/Pages/_ViewStart.cshtml new file mode 100644 index 00000000000..2909abd3ecc --- /dev/null +++ b/tests/CheckIdentity/Areas/Identity/Pages/_ViewStart.cshtml @@ -0,0 +1,4 @@ + +@{ + Layout = "/Pages/Shared/_Layout.cshtml"; +} diff --git a/tests/CheckIdentity/CheckIdentity.csproj b/tests/CheckIdentity/CheckIdentity.csproj new file mode 100644 index 00000000000..5539e6ac466 --- /dev/null +++ b/tests/CheckIdentity/CheckIdentity.csproj @@ -0,0 +1,40 @@ + + + + net6.0 + enable + enable + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + + + + + diff --git a/tests/CheckIdentity/Configure.OpenApi.cs b/tests/CheckIdentity/Configure.OpenApi.cs new file mode 100644 index 00000000000..33210aebaac --- /dev/null +++ b/tests/CheckIdentity/Configure.OpenApi.cs @@ -0,0 +1,14 @@ +using ServiceStack; +using ServiceStack.Api.OpenApi; + +[assembly: HostingStartup(typeof(MyApp.ConfigureOpenApi))] + +namespace MyApp; + +public class ConfigureOpenApi : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) => builder + .ConfigureAppHost(appHost => { + appHost.Plugins.Add(new OpenApiFeature()); + }); +} diff --git a/tests/CheckIdentity/Data/ApplicationDbContext.cs b/tests/CheckIdentity/Data/ApplicationDbContext.cs new file mode 100644 index 00000000000..369229d78e9 --- /dev/null +++ b/tests/CheckIdentity/Data/ApplicationDbContext.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace CheckIdentity.Data +{ + public class ApplicationDbContext : IdentityDbContext + { + public ApplicationDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + // Customize the ASP.NET Identity model and override the defaults if needed. + // For example, you can rename the ASP.NET Identity table names and more. + // Add your customizations after calling base.OnModelCreating(builder); + } + } +} + diff --git a/tests/CheckIdentity/Data/Migrations/20210919091112_InitialCreate.Designer.cs b/tests/CheckIdentity/Data/Migrations/20210919091112_InitialCreate.Designer.cs new file mode 100644 index 00000000000..57a1a5d0a00 --- /dev/null +++ b/tests/CheckIdentity/Data/Migrations/20210919091112_InitialCreate.Designer.cs @@ -0,0 +1,271 @@ +// +using System; +using CheckIdentity.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckIdentity.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20210919091112_InitialCreate")] + partial class InitialCreate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0-rc.1.21452.10"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/tests/CheckIdentity/Data/Migrations/20210919091112_InitialCreate.cs b/tests/CheckIdentity/Data/Migrations/20210919091112_InitialCreate.cs new file mode 100644 index 00000000000..947af0be918 --- /dev/null +++ b/tests/CheckIdentity/Data/Migrations/20210919091112_InitialCreate.cs @@ -0,0 +1,219 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CheckIdentity.Migrations +{ + public partial class InitialCreate : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "INTEGER", nullable: false), + PasswordHash = table.Column(type: "TEXT", nullable: true), + SecurityStamp = table.Column(type: "TEXT", nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), + PhoneNumber = table.Column(type: "TEXT", nullable: true), + PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), + TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), + LockoutEnd = table.Column(type: "TEXT", nullable: true), + LockoutEnabled = table.Column(type: "INTEGER", nullable: false), + AccessFailedCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + RoleId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "TEXT", maxLength: 128, nullable: false), + ProviderKey = table.Column(type: "TEXT", maxLength: 128, nullable: false), + ProviderDisplayName = table.Column(type: "TEXT", nullable: true), + UserId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + RoleId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + LoginProvider = table.Column(type: "TEXT", maxLength: 128, nullable: false), + Name = table.Column(type: "TEXT", maxLength: 128, nullable: false), + Value = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/tests/CheckIdentity/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/tests/CheckIdentity/Data/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 00000000000..c12b8eddc33 --- /dev/null +++ b/tests/CheckIdentity/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,269 @@ +// +using System; +using CheckIdentity.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckIdentity.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0-rc.1.21452.10"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/tests/CheckIdentity/Pages/Error.cshtml b/tests/CheckIdentity/Pages/Error.cshtml new file mode 100644 index 00000000000..6f92b956557 --- /dev/null +++ b/tests/CheckIdentity/Pages/Error.cshtml @@ -0,0 +1,26 @@ +@page +@model ErrorModel +@{ + ViewData["Title"] = "Error"; +} + +

Error.

+

An error occurred while processing your request.

+ +@if (Model.ShowRequestId) +{ +

+ Request ID: @Model.RequestId +

+} + +

Development Mode

+

+ Swapping to the Development environment displays detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

diff --git a/tests/CheckIdentity/Pages/Error.cshtml.cs b/tests/CheckIdentity/Pages/Error.cshtml.cs new file mode 100644 index 00000000000..f0ae3ec6647 --- /dev/null +++ b/tests/CheckIdentity/Pages/Error.cshtml.cs @@ -0,0 +1,30 @@ +using System.Diagnostics; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Pages +{ + +[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] +[IgnoreAntiforgeryToken] +public class ErrorModel : PageModel +{ + public string? RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + private readonly ILogger _logger; + + public ErrorModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } +} + +} diff --git a/tests/CheckIdentity/Pages/Index.cshtml b/tests/CheckIdentity/Pages/Index.cshtml new file mode 100644 index 00000000000..36b1baaf0c4 --- /dev/null +++ b/tests/CheckIdentity/Pages/Index.cshtml @@ -0,0 +1,74 @@ +@page +@model IndexModel +@{ +ViewData["Title"] = "Home page"; +} + + + + +
+

Welcome

+

Learn about building Web apps with ASP.NET Core.

+ +

Sign In using credentials

+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com + as@if.com +
+
+
+ + diff --git a/tests/CheckIdentity/Pages/Index.cshtml.cs b/tests/CheckIdentity/Pages/Index.cshtml.cs new file mode 100644 index 00000000000..5a62e9203d1 --- /dev/null +++ b/tests/CheckIdentity/Pages/Index.cshtml.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Pages +{ + +public class IndexModel : PageModel +{ + private readonly ILogger _logger; + + public IndexModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + + } +} + +} diff --git a/tests/CheckIdentity/Pages/Privacy.cshtml b/tests/CheckIdentity/Pages/Privacy.cshtml new file mode 100644 index 00000000000..46ba96612ec --- /dev/null +++ b/tests/CheckIdentity/Pages/Privacy.cshtml @@ -0,0 +1,8 @@ +@page +@model PrivacyModel +@{ + ViewData["Title"] = "Privacy Policy"; +} +

@ViewData["Title"]

+ +

Use this page to detail your site's privacy policy.

diff --git a/tests/CheckIdentity/Pages/Privacy.cshtml.cs b/tests/CheckIdentity/Pages/Privacy.cshtml.cs new file mode 100644 index 00000000000..3673247aeec --- /dev/null +++ b/tests/CheckIdentity/Pages/Privacy.cshtml.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace CheckIdentity.Pages +{ + +public class PrivacyModel : PageModel +{ + private readonly ILogger _logger; + + public PrivacyModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + } +} + +} diff --git a/tests/CheckIdentity/Pages/Shared/_Layout.cshtml b/tests/CheckIdentity/Pages/Shared/_Layout.cshtml new file mode 100644 index 00000000000..a0a2db840e4 --- /dev/null +++ b/tests/CheckIdentity/Pages/Shared/_Layout.cshtml @@ -0,0 +1,51 @@ + + + + + + @ViewData["Title"] - MyApp + + + + +
+ +
+
+
+ @RenderBody() +
+
+ + + + + + + +@await RenderSectionAsync("Scripts", required: false) + + diff --git a/tests/CheckIdentity/Pages/Shared/_LoginPartial.cshtml b/tests/CheckIdentity/Pages/Shared/_LoginPartial.cshtml new file mode 100644 index 00000000000..9f617b34312 --- /dev/null +++ b/tests/CheckIdentity/Pages/Shared/_LoginPartial.cshtml @@ -0,0 +1,27 @@ +@using Microsoft.AspNetCore.Identity + +@inject SignInManager SignInManager +@inject UserManager UserManager + + diff --git a/tests/CheckIdentity/Pages/Shared/_ValidationScriptsPartial.cshtml b/tests/CheckIdentity/Pages/Shared/_ValidationScriptsPartial.cshtml new file mode 100644 index 00000000000..5a16d80a9aa --- /dev/null +++ b/tests/CheckIdentity/Pages/Shared/_ValidationScriptsPartial.cshtml @@ -0,0 +1,2 @@ + + diff --git a/tests/CheckIdentity/Pages/_ViewImports.cshtml b/tests/CheckIdentity/Pages/_ViewImports.cshtml new file mode 100644 index 00000000000..13211ddb26f --- /dev/null +++ b/tests/CheckIdentity/Pages/_ViewImports.cshtml @@ -0,0 +1,3 @@ +@using CheckIdentity +@namespace CheckIdentity.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/tests/CheckIdentity/Pages/_ViewStart.cshtml b/tests/CheckIdentity/Pages/_ViewStart.cshtml new file mode 100644 index 00000000000..a5f10045db9 --- /dev/null +++ b/tests/CheckIdentity/Pages/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_Layout"; +} diff --git a/tests/CheckIdentity/Program.cs b/tests/CheckIdentity/Program.cs new file mode 100644 index 00000000000..79072503f9a --- /dev/null +++ b/tests/CheckIdentity/Program.cs @@ -0,0 +1,63 @@ +using CheckIdentity; +using CheckIdentity.Data; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.IdentityModel.Tokens; +using ServiceStack; +using ServiceStack.Auth; + +var builder = WebApplication.CreateBuilder(args); +//builder.Services.AddModularStartup(builder.Configuration); + +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.Services.AddDbContext(options => + options.UseSqlite(connectionString)); +//builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services + .AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddRoles() + .AddEntityFrameworkStores(); + +builder.Services + .AddAuthentication() + .AddJwtBearer(x => { + // secretKey contains a secret passphrase only your server knows + x.TokenValidationParameters = new TokenValidationParameters { + IssuerSigningKey = new SymmetricSecurityKey("mysupers3cr3tsharedkey!".ToUtf8Bytes()), + ValidAudience = "ExampleAudience", + ValidIssuer = "ExampleIssuer", + }.UseStandardJwtClaims(); + }); + +builder.Services.ConfigureNonBreakingSameSiteCookies(builder.Environment); + + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseCookiePolicy().UseJwtCookie(IdentityAuth.TokenCookie); +app.UseAuthentication(); +app.UseAuthorization(); + +app.UseServiceStack(new AppHost()); + +app.MapRazorPages(); + +app.Run(); diff --git a/tests/CheckIdentity/Properties/launchSettings.json b/tests/CheckIdentity/Properties/launchSettings.json new file mode 100644 index 00000000000..40f29bac67f --- /dev/null +++ b/tests/CheckIdentity/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:36642", + "sslPort": 44346 + } + }, + "profiles": { + "CheckIdentity": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/tests/CheckIdentity/README.txt b/tests/CheckIdentity/README.txt new file mode 100644 index 00000000000..bfab300b776 --- /dev/null +++ b/tests/CheckIdentity/README.txt @@ -0,0 +1,18 @@ +https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-5.0&tabs=netcore-cli + +dotnet tool install -g dotnet-aspnet-codegenerator + +dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design +dotnet add package Microsoft.EntityFrameworkCore.Design +dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore +dotnet add package Microsoft.AspNetCore.Identity.UI +dotnet add package Microsoft.EntityFrameworkCore.SqlServer +dotnet add package Microsoft.EntityFrameworkCore.Tools + +dotnet aspnet-codegenerator identity -h + +dotnet aspnet-codegenerator identity --useDefaultUI + +dotnet tool install --global dotnet-ef +dotnet ef migrations add InitialCreate +dotnet ef database update \ No newline at end of file diff --git a/tests/CheckIdentity/ScaffoldingReadMe.txt b/tests/CheckIdentity/ScaffoldingReadMe.txt new file mode 100644 index 00000000000..6e6208dc29e --- /dev/null +++ b/tests/CheckIdentity/ScaffoldingReadMe.txt @@ -0,0 +1,3 @@ +Support for ASP.NET Core Identity was added to your project. + +For setup and configuration information, see https://go.microsoft.com/fwlink/?linkid=2116645. diff --git a/tests/CheckIdentity/ServiceInterface/MyServices.cs b/tests/CheckIdentity/ServiceInterface/MyServices.cs new file mode 100644 index 00000000000..18f9a90c63d --- /dev/null +++ b/tests/CheckIdentity/ServiceInterface/MyServices.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using CheckIdentity.ServiceModel; +using Microsoft.AspNetCore.Identity; +using ServiceStack; + +namespace CheckIdentity.ServiceInterface +{ + public class MyServices : Service + { + HelloResponse CreateResponse(object request, string name) => + new() { Result = $"{request.GetType().Name}, {name}!" }; + + public object Any(Hello request) => CreateResponse(request, request.Name); + public object Any(HelloAuth request) => CreateResponse(request, request.Name); + public object Any(HelloRole request) => CreateResponse(request, request.Name); + } + + [ValidateIsAdmin] + public class CreateRole : IReturn + { + public string Role { get; set; } + } + + + [ValidateIsAdmin] + public class DeleteUser : IReturn + { + public string UserName { get; set; } + } + + public class AdminServices : Service + { + private readonly UserManager userManager; + private readonly RoleManager roleManager; + public AdminServices(UserManager userManager, RoleManager roleManager) + { + this.userManager = userManager; + this.roleManager = roleManager; + } + + public async Task PostAsync(CreateRole request) + { + await roleManager.CreateAsync(new IdentityRole(request.Role)); + return request; + } + + public async Task PostAsync(DeleteUser request) + { + var userName = request.UserName ?? throw new ArgumentNullException(nameof(request.UserName)); + var user = await userManager.FindByEmailAsync(userName); + if (user != null) + { + await userManager.DeleteAsync(user); + } + return request; + } + } + +} diff --git a/tests/CheckIdentity/ServiceModel/Hello.cs b/tests/CheckIdentity/ServiceModel/Hello.cs new file mode 100644 index 00000000000..8c7f075b117 --- /dev/null +++ b/tests/CheckIdentity/ServiceModel/Hello.cs @@ -0,0 +1,30 @@ +using ServiceStack; + +namespace CheckIdentity.ServiceModel +{ + [Route("/hello")] + [Route("/hello/{Name}")] + public class Hello : IReturn, IGet + { + public string Name { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + } + + [ValidateIsAuthenticated] + [Route("/helloauth/{Name}")] + public class HelloAuth : IReturn, IGet + { + public string Name { get; set; } + } + + [ValidateHasRole("TheRole")] + [Route("/hellorole/{Name}")] + public class HelloRole : IReturn, IGet + { + public string Name { get; set; } + } +} diff --git a/tests/CheckIdentity/Tests/AuthTests.cs b/tests/CheckIdentity/Tests/AuthTests.cs new file mode 100644 index 00000000000..9217ee78294 --- /dev/null +++ b/tests/CheckIdentity/Tests/AuthTests.cs @@ -0,0 +1,190 @@ +using System.Collections.Generic; +using CheckIdentity.ServiceInterface; +using CheckIdentity.ServiceModel; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.Text; + +namespace CheckIdentity.Tests +{ + public class AuthTests + { + const string BaseUri = "https://localhost:5001/"; + const string Password = "testTest1!"; + public IServiceClient CreateClient() => new JsonServiceClient(BaseUri); + + public (IServiceClient, T) CreateClient(IReturn request) + { + var client = new JsonServiceClient(BaseUri); + var response = client.Send(request); + return (client, response); + } + + private IServiceClient CreateAdminClient() + { + var client = CreateClient(); + client.AddHeader(HttpHeaders.XParamOverridePrefix + "authsecret", "secretz"); + return client; + } + + private static Authenticate CreateAuthenticateUser() + { + return new Authenticate { + provider = "credentials", + UserName = "as@if.com", + Password = Password, + RememberMe = true, + }; + } + + [Test] + public void Can_credentials_auth_with_IdentityCredentialsAuthProvider_and_populate_JWTs() + { + var (client, response) = CreateClient(CreateAuthenticateUser()); + response.PrintDump(); + Assert.That(response.UserId, Is.Not.Empty); + Assert.That(response.UserName, Is.Not.Empty); + Assert.That(response.DisplayName, Is.Not.Empty); + Assert.That(response.BearerToken, Is.Not.Empty); + Assert.That(response.ProfileUrl, Is.Not.Empty); + + var obj = JwtAuthProviderReader.ExtractPayload(response.BearerToken); + obj.PrintDump(); + Assert.That(obj["name"], Is.EqualTo("as@if.com")); + + var authResponse = client.Post(new HelloAuth { Name = "as@if.com" }); + Assert.That(authResponse.Result, Is.EqualTo("HelloAuth, as@if.com!")); + } + + [Test] + public void Can_credentials_auth_with_Admin_User() + { + var client = CreateAdminClient(); + + var response = client.Post(new Authenticate { + provider = "credentials", + UserName = Keywords.AuthSecret, + RememberMe = true, + }); + + response.PrintDump(); + Assert.That(response.UserId, Is.Not.Empty); + Assert.That(response.UserName, Is.Not.Empty); + Assert.That(response.DisplayName, Is.Not.Empty); + Assert.That(response.BearerToken, Is.Not.Empty); + Assert.That(response.ProfileUrl, Is.Not.Empty); + + var obj = JwtAuthProviderReader.ExtractPayload(response.BearerToken); + obj.PrintDump(); + Assert.That(obj["name"], Is.EqualTo("authsecret")); + + var authResponse = client.Post(new HelloAuth { Name = "authsecret" }); + Assert.That(authResponse.Result, Is.EqualTo("HelloAuth, authsecret!")); + } + + [Test] + public void Can_authenticate_with_Admin_User() + { + var client = CreateAdminClient(); + + var response = client.Post(new HelloAuth { Name = "Admin" }); + + Assert.That(response.Result, Is.EqualTo("HelloAuth, Admin!")); + } + + [Test] + public void Can_authenticate_with_User_with_Role() + { + var (client, authResponse) = CreateClient(CreateAuthenticateUser()); + + var response = client.Send(new HelloRole { Name = "as@if.com" }); + + Assert.That(response.Result, Is.EqualTo("HelloRole, as@if.com!")); + } + + [Test] + public void Can_Assign_Roles() + { + var client = CreateAdminClient(); + + var response = client.Post(new AssignRoles { + UserName = "as@if.com", + Roles = new List { "TheRole" }, + }); + + Assert.That(response.AllRoles, Is.EquivalentTo(new[]{ "TheRole" })); + } + + [Test] + public void Can_Create_Role() + { + var client = CreateAdminClient(); + var response = client.Post(new CreateRole { Role = "TheRole" }); + response.PrintDump(); + } + + [Test] + public void Can_Delete_user() + { + var client = CreateAdminClient(); + var response = client.Post(new DeleteUser { UserName = "new@user.com" }); + response.PrintDump(); + } + + [Test] + public void Can_register_new_user() + { + var client = CreateClient(); + + var response = client.Post(new Register { + Email = "new@user.com", + Password = Password, + ConfirmPassword = Password, + FirstName = "New", + LastName = "User", + DisplayName = "New User", + }); + + response.PrintDump(); + } + + [Test] + public void Does_validate_min_password() + { + var client = CreateClient(); + + try + { + var response = client.Post(new Register { + Email = "weak@password.com", + Password = "weak", + ConfirmPassword = "weak", + FirstName = "Weak", + LastName = "Password", + DisplayName = "Weak Password", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + var status = e.GetResponseStatus(); + status.PrintDump(); + Assert.That(status.ErrorCode, Is.EqualTo("PasswordTooShort")); + Assert.That(status.Message, Is.EqualTo("Passwords must be at least 6 characters.")); + + var errors = status.Errors; + Assert.That(errors[0].ErrorCode, Is.EqualTo("PasswordTooShort")); + Assert.That(errors[0].Message, Is.EqualTo("Passwords must be at least 6 characters.")); + Assert.That(errors[1].ErrorCode, Is.EqualTo("PasswordRequiresNonAlphanumeric")); + Assert.That(errors[1].Message, Is.EqualTo("Passwords must have at least one non alphanumeric character.")); + Assert.That(errors[2].ErrorCode, Is.EqualTo("PasswordRequiresDigit")); + Assert.That(errors[2].Message, Is.EqualTo("Passwords must have at least one digit ('0'-'9').")); + Assert.That(errors[3].ErrorCode, Is.EqualTo("PasswordRequiresUpper")); + Assert.That(errors[3].Message, Is.EqualTo("Passwords must have at least one uppercase ('A'-'Z').")); + } + } + + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/app.db b/tests/CheckIdentity/app.db new file mode 100644 index 00000000000..8f7395a588d Binary files /dev/null and b/tests/CheckIdentity/app.db differ diff --git a/tests/CheckIdentity/appsettings.Development.json b/tests/CheckIdentity/appsettings.Development.json new file mode 100644 index 00000000000..770d3e93146 --- /dev/null +++ b/tests/CheckIdentity/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/tests/CheckIdentity/appsettings.json b/tests/CheckIdentity/appsettings.json new file mode 100644 index 00000000000..e94cdd2f713 --- /dev/null +++ b/tests/CheckIdentity/appsettings.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "DefaultConnection": "DataSource=app.db;Cache=Shared", + "CheckIdentityIdentityDbContextConnection": "Server=(localdb)\\mssqllocaldb;Database=CheckIdentity;Trusted_Connection=True;MultipleActiveResultSets=true" + } +} \ No newline at end of file diff --git a/tests/CheckIdentity/wwwroot/css/site.css b/tests/CheckIdentity/wwwroot/css/site.css new file mode 100644 index 00000000000..41726e4ac2a --- /dev/null +++ b/tests/CheckIdentity/wwwroot/css/site.css @@ -0,0 +1,65 @@ +/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +for details on configuring this project to bundle and minify static web assets. */ + +a.navbar-brand { + white-space: normal; + text-align: center; + word-break: break-all; +} + +a { + color: #0077cc; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.nav-pills .nav-link.active, .nav-pills .show > .nav-link { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +html { + font-size: 14px; +} +@media (min-width: 768px) { + html { + font-size: 16px; + } +} + +.border-top { + border-top: 1px solid #e5e5e5; +} +.border-bottom { + border-bottom: 1px solid #e5e5e5; +} + +.box-shadow { + box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); +} + +button.accept-policy { + font-size: 1rem; + line-height: inherit; +} + +html { + position: relative; + min-height: 100%; +} + +body { + margin-bottom: 60px; +} +.footer { + position: absolute; + bottom: 0; + width: 100%; + white-space: nowrap; + line-height: 60px; +} diff --git a/tests/CheckIdentity/wwwroot/favicon.ico b/tests/CheckIdentity/wwwroot/favicon.ico new file mode 100644 index 00000000000..63e859b476e Binary files /dev/null and b/tests/CheckIdentity/wwwroot/favicon.ico differ diff --git a/tests/CheckIdentity/wwwroot/js/site.js b/tests/CheckIdentity/wwwroot/js/site.js new file mode 100644 index 00000000000..ac49c186418 --- /dev/null +++ b/tests/CheckIdentity/wwwroot/js/site.js @@ -0,0 +1,4 @@ +// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +// for details on configuring this project to bundle and minify static web assets. + +// Write your JavaScript code. diff --git a/tests/CheckMvc/App_Start/FilterConfig.cs b/tests/CheckMvc/App_Start/FilterConfig.cs new file mode 100644 index 00000000000..7d50264335a --- /dev/null +++ b/tests/CheckMvc/App_Start/FilterConfig.cs @@ -0,0 +1,13 @@ +using System.Web; +using System.Web.Mvc; + +namespace CheckMvc +{ + public class FilterConfig + { + public static void RegisterGlobalFilters(GlobalFilterCollection filters) + { + filters.Add(new HandleErrorAttribute()); + } + } +} \ No newline at end of file diff --git a/tests/CheckMvc/App_Start/RouteConfig.cs b/tests/CheckMvc/App_Start/RouteConfig.cs new file mode 100644 index 00000000000..1e616597e54 --- /dev/null +++ b/tests/CheckMvc/App_Start/RouteConfig.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; + +namespace CheckMvc +{ + public class RouteConfig + { + public static void RegisterRoutes(RouteCollection routes) + { + routes.IgnoreRoute("api/{*pathInfo}"); + routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" }); + + routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + + routes.MapRoute( + name: "Default", + url: "{controller}/{action}/{id}", + defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } + ); + } + } +} \ No newline at end of file diff --git a/tests/CheckMvc/App_Start/WebApiConfig.cs b/tests/CheckMvc/App_Start/WebApiConfig.cs new file mode 100644 index 00000000000..494a35bb9fd --- /dev/null +++ b/tests/CheckMvc/App_Start/WebApiConfig.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Http; + +namespace CheckMvc +{ + public static class WebApiConfig + { + public static void Register(HttpConfiguration config) + { + config.Routes.MapHttpRoute( + name: "DefaultApi", + routeTemplate: "api/{controller}/{id}", + defaults: new { id = RouteParameter.Optional } + ); + } + } +} diff --git a/tests/CheckMvc/CheckMvc.csproj b/tests/CheckMvc/CheckMvc.csproj new file mode 100644 index 00000000000..a9a1522a632 --- /dev/null +++ b/tests/CheckMvc/CheckMvc.csproj @@ -0,0 +1,234 @@ + + + + + + Debug + AnyCPU + + + 2.0 + {50971470-179A-45D1-92C9-748DEFCBD9E5} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + CheckMvc + CheckMvc + v4.7.2 + false + true + + + + + ..\..\src\ + true + true + + + + + 4.0 + + + + + + 3.0 + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global.asax + + + + + + + + + + + + + + + + Web.config + + + Web.config + + + + + + + + + + {5e258282-86a6-4780-ab25-5e458f2e6f70} + ServiceStack.Api.OpenApi + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416db-c143-4028-a0c3-cf41892d18d3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {672f2dfe-4ee8-498b-b449-23e9e7f6961c} + ServiceStack.Mvc + + + {22f8d050-2c96-4993-b221-da16ebc61f31} + ServiceStack.NetFramework + + + {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} + ServiceStack.Server + + + {680a1709-25eb-4d52-a87f-ee03ffd94baa} + ServiceStack + + + {9982317F-831C-478B-9CC3-57F888BCD97A} + Check.ServiceInterface + + + {F709A373-6FD5-4415-B2ED-2520EA7CC568} + CheckHttpListener + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + + + True + True + 49435 + / + http://localhost:49435/ + False + False + + + False + + + + + + + \ No newline at end of file diff --git a/tests/CheckMvc/CheckWebGlobalNamespace.dtos.cs b/tests/CheckMvc/CheckWebGlobalNamespace.dtos.cs new file mode 100644 index 00000000000..77b4091e1cf --- /dev/null +++ b/tests/CheckMvc/CheckWebGlobalNamespace.dtos.cs @@ -0,0 +1,2597 @@ +/* Options: +Date: 2019-10-04 18:16:41 +Version: 5.70 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:55799 + +GlobalNamespace: dtos +//MakePartial: True +//MakeVirtual: True +//MakeInternal: False +//MakeDataContractsExtensible: False +//AddReturnMarker: True +//AddDescriptionAsComments: True +//AddDataContractAttributes: False +//AddIndexesToDataMembers: False +//AddGeneratedCodeAttributes: False +//AddResponseStatus: False +//AddImplicitVersion: +//InitializeCollections: True +//ExportValueTypes: False +//IncludeTypes: +//ExcludeTypes: +//AddNamespaces: +//AddDefaultXmlNamespace: http://schemas.servicestack.net/types +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; +using System.IO; +using dtos; + + +namespace dtos +{ + + [Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE")] + [Route("/api/acsprofiles/{profileId}")] + [References(typeof(Check.ServiceInterface.acsprofileResponse))] + [Serializable] + public partial class ACSProfile + : IReturn, IHasVersion, IHasSessionId + { + public virtual string profileId { get; set; } + [StringLength(20)] + public virtual string shortName { get; set; } + + [StringLength(60)] + public virtual string longName { get; set; } + + [StringLength(20)] + public virtual string regionId { get; set; } + + [StringLength(20)] + public virtual string groupId { get; set; } + + [StringLength(12)] + public virtual string deviceID { get; set; } + + public virtual DateTime lastUpdated { get; set; } + public virtual bool enabled { get; set; } + public virtual int Version { get; set; } + public virtual string SessionId { get; set; } + } + + [Serializable] + public partial class acsprofileResponse + { + public virtual string profileId { get; set; } + } + + [Route("/anontype")] + [Serializable] + public partial class AnonType + { + } + + [Serializable] + public partial class ArrayElementInDictionary + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class BatchThrows + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class BatchThrowsAsync + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class BatchThrowsResponse + { + public virtual string Result { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/changerequest/{Id}")] + [Serializable] + public partial class ChangeRequest + : IReturn + { + public virtual string Id { get; set; } + } + + [Serializable] + public partial class ChangeRequestResponse + { + public virtual string ContentType { get; set; } + public virtual string Header { get; set; } + public virtual string QueryString { get; set; } + public virtual string Form { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/compress/{Path*}")] + [Serializable] + public partial class CompressFile + { + public virtual string Path { get; set; } + } + + [Route("/jwt")] + [Serializable] + public partial class CreateJwt + : AuthUserSession, IReturn, IMeta + { + public virtual DateTime? JwtExpiry { get; set; } + } + + [Serializable] + public partial class CreateJwtResponse + { + public virtual string Token { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/jwt-refresh")] + [Serializable] + public partial class CreateRefreshJwt + : IReturn + { + public virtual string UserAuthId { get; set; } + public virtual DateTime? JwtExpiry { get; set; } + } + + [Serializable] + public partial class CreateRefreshJwtResponse + { + public virtual string Token { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Serializable] + public partial class CustomRockstar + { + [AutoQueryViewerField(Title="Name")] + public virtual string FirstName { get; set; } + + [AutoQueryViewerField(HideInSummary=true)] + public virtual string LastName { get; set; } + + public virtual int? Age { get; set; } + [AutoQueryViewerField(Title="Album")] + public virtual string RockstarAlbumName { get; set; } + + [AutoQueryViewerField(Title="Genre")] + public virtual string RockstarGenreName { get; set; } + } + + [Serializable] + public partial class CustomUserSession + : AuthUserSession, IMeta + { + [DataMember] + public virtual string CustomName { get; set; } + + [DataMember] + public virtual string CustomInfo { get; set; } + } + + [Serializable] + public partial class DiscoverTypes + : IReturn + { + public DiscoverTypes() + { + ElementInDictionary = new Dictionary{}; + } + + public virtual Dictionary ElementInDictionary { get; set; } + } + + [Serializable] + public partial class FallbackRoute + { + public virtual string PathInfo { get; set; } + } + + [Route("/files/{Path*}")] + [Serializable] + public partial class GetFile + { + public virtual string Path { get; set; } + } + + [Route("/Request1/", "GET")] + [Serializable] + public partial class GetRequest1 + : IReturn>, IGet + { + } + + [Route("/Request3", "GET")] + [Serializable] + public partial class GetRequest2 + : IReturn, IGet + { + } + + [Route("/timestamp", "GET")] + [Serializable] + public partial class GetTimestamp + : IReturn + { + } + + [Serializable] + public partial class GetUserSession + : IReturn + { + } + + public partial interface IFilterRockstars + { + } + + [Route("/info/{Id}")] + [Serializable] + public partial class Info + { + public virtual string Id { get; set; } + } + + [Route("/Routing/LeadPost.aspx")] + [Serializable] + public partial class LegacyLeadPost + { + public virtual string LeadType { get; set; } + public virtual int MyId { get; set; } + } + + [Route("/matchroute/html")] + [Serializable] + public partial class MatchesHtml + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/matchregex/{Id}")] + [Serializable] + public partial class MatchesId + { + public virtual int Id { get; set; } + } + + [Route("/matchroute/json")] + [Serializable] + public partial class MatchesJson + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/matchlast/{Id}")] + [Serializable] + public partial class MatchesLastInt + { + public virtual int Id { get; set; } + } + + [Route("/matchlast/{Slug}")] + [Serializable] + public partial class MatchesNotLastInt + { + public virtual string Slug { get; set; } + } + + [Route("/matchregex/{Slug}")] + [Serializable] + public partial class MatchesSlug + { + public virtual string Slug { get; set; } + } + + [Serializable] + public partial class MetadataRequest + : IReturn + { + public virtual MetadataType MetadataType { get; set; } + } + + [Serializable] + public partial class Movie + { + public Movie() + { + Genres = new List{}; + } + + public virtual int Id { get; set; } + public virtual string ImdbId { get; set; } + public virtual string Title { get; set; } + public virtual string Rating { get; set; } + public virtual decimal Score { get; set; } + public virtual string Director { get; set; } + public virtual DateTime ReleaseDate { get; set; } + public virtual string TagLine { get; set; } + public virtual List Genres { get; set; } + } + + [Route("/namedconnection")] + [Serializable] + public partial class NamedConnection + { + public virtual string EmailAddresses { get; set; } + } + + [Serializable] + public partial class NativeTypesTestService + { + + [Serializable] + public partial class HelloInService + { + public virtual string Name { get; set; } + } + } + + [Serializable] + public partial class NoRepeat + : IReturn + { + public virtual Guid Id { get; set; } + } + + [Serializable] + public partial class NoRepeatResponse + { + public virtual Guid Id { get; set; } + } + + [Serializable] + public partial class ObjectDesign + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class ObjectDesignResponse + { + public virtual ObjectDesign data { get; set; } + } + + [Route("/code/object", "GET")] + [Serializable] + public partial class ObjectId + : IReturn + { + public virtual string objectName { get; set; } + } + + [Serializable] + public partial class PgRockstar + : Rockstar + { + } + + [AutoQueryViewer(Description="Use this option to search for Rockstars!", Title="Search for Rockstars")] + [Serializable] + public partial class QueryCustomRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Serializable] + public partial class QueryCustomRockstarsFilter + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Route("/querydata/rockstars")] + [Serializable] + public partial class QueryDataRockstars + : QueryData, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Route("/query-custom/rockstars")] + [Serializable] + public partial class QueryFieldRockstars + : QueryDb, IReturn>, IMeta + { + public QueryFieldRockstars() + { + FirstNames = new string[]{}; + FirstNameBetween = new string[]{}; + FirstNameContainsMulti = new string[]{}; + } + + public virtual string FirstName { get; set; } + public virtual string[] FirstNames { get; set; } + public virtual int? Age { get; set; } + public virtual string FirstNameCaseInsensitive { get; set; } + public virtual string FirstNameStartsWith { get; set; } + public virtual string LastNameEndsWith { get; set; } + public virtual string[] FirstNameBetween { get; set; } + public virtual string OrLastName { get; set; } + public virtual string[] FirstNameContainsMulti { get; set; } + } + + [Serializable] + public partial class QueryFieldRockstarsDynamic + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Serializable] + public partial class QueryGetRockstars + : QueryDb, IReturn>, IMeta + { + public QueryGetRockstars() + { + Ids = new int[]{}; + Ages = new List{}; + FirstNames = new List{}; + IdsBetween = new int[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual List Ages { get; set; } + public virtual List FirstNames { get; set; } + public virtual int[] IdsBetween { get; set; } + } + + [Serializable] + public partial class QueryGetRockstarsDynamic + : QueryDb, IReturn>, IMeta + { + } + + [Route("/movies")] + [Serializable] + public partial class QueryMovies + : QueryDb, IReturn>, IMeta + { + public QueryMovies() + { + Ids = new int[]{}; + ImdbIds = new string[]{}; + Ratings = new string[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual string[] ImdbIds { get; set; } + public virtual string[] Ratings { get; set; } + } + + [Route("/OrRockstars")] + [Serializable] + public partial class QueryOrRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + public virtual string FirstName { get; set; } + } + + [Serializable] + public partial class QueryOverridedCustomRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Serializable] + public partial class QueryOverridedRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Route("/pgsql/pgrockstars")] + [Serializable] + public partial class QueryPostgresPgRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Route("/pgsql/rockstars")] + [Serializable] + public partial class QueryPostgresRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Route("/query/requestlogs")] + [Route("/query/requestlogs/{Date}")] + [Serializable] + public partial class QueryRequestLogs + : QueryData, IReturn>, IMeta + { + public virtual DateTime? Date { get; set; } + public virtual bool ViewErrors { get; set; } + } + + [Route("/customrockstars")] + [Serializable] + public partial class QueryRockstarAlbums + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + public virtual string RockstarAlbumName { get; set; } + } + + [Serializable] + public partial class QueryRockstarAlbumsImplicit + : QueryDb, IReturn>, IMeta + { + } + + [Serializable] + public partial class QueryRockstarAlbumsLeftJoin + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + public virtual string AlbumName { get; set; } + } + + [Route("/query/rockstars")] + [Serializable] + public partial class QueryRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Route("/query/rockstars/cached")] + [Serializable] + public partial class QueryRockstarsCached + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Serializable] + public partial class QueryRockstarsConventions + : QueryDb, IReturn>, IMeta + { + public QueryRockstarsConventions() + { + Ids = new int[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual int? AgeOlderThan { get; set; } + public virtual int? AgeGreaterThanOrEqualTo { get; set; } + public virtual int? AgeGreaterThan { get; set; } + public virtual int? GreaterThanAge { get; set; } + public virtual string FirstNameStartsWith { get; set; } + public virtual string LastNameEndsWith { get; set; } + public virtual string LastNameContains { get; set; } + public virtual string RockstarAlbumNameContains { get; set; } + public virtual int? RockstarIdAfter { get; set; } + public virtual int? RockstarIdOnOrAfter { get; set; } + } + + [Serializable] + public partial class QueryRockstarsFilter + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Serializable] + public partial class QueryRockstarsIFilter + : QueryDb, IReturn>, IMeta, IFilterRockstars + { + public virtual int? Age { get; set; } + } + + [Route("/query/rockstar-references")] + [Serializable] + public partial class QueryRockstarsWithReferences + : QueryDb, IReturn>, IMeta + { + public virtual int? Age { get; set; } + } + + [Serializable] + public partial class QueryUnknownRockstars + : QueryDb, IReturn>, IMeta + { + public virtual int UnknownInt { get; set; } + public virtual string UnknownProperty { get; set; } + } + + [Serializable] + public partial class ReturnedDto + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class RockstarAlbum + { + public virtual int Id { get; set; } + public virtual int RockstarId { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class RockstarReference + { + public RockstarReference() + { + Albums = new List{}; + } + + public virtual int Id { get; set; } + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual int? Age { get; set; } + public virtual List Albums { get; set; } + } + + [Route("/movies/search")] + [Serializable] + public partial class SearchMovies + : QueryDb, IReturn>, IMeta + { + } + + [Serializable] + public partial class StreamMovies + : QueryDb, IReturn>, IMeta + { + public StreamMovies() + { + Ratings = new string[]{}; + } + + public virtual string[] Ratings { get; set; } + } + + [Route("/test/errorview")] + [Serializable] + public partial class TestErrorView + { + public virtual string Id { get; set; } + } + + [Route("/testexecproc")] + [Serializable] + public partial class TestExecProc + { + } + + [Serializable] + public partial class TestMiniverView + { + } + + [Serializable] + public partial class TimestampData + { + public virtual long Timestamp { get; set; } + } + + [Serializable] + public partial class TodayErrorLogs + : QueryData, IReturn>, IMeta + { + } + + [AutoQueryViewer(Name="Today\'s Logs", Title="Logs from Today")] + [Serializable] + public partial class TodayLogs + : QueryData, IReturn>, IMeta + { + } + + [Serializable] + public partial class YesterdayErrorLogs + : QueryData, IReturn>, IMeta + { + } + + [Serializable] + public partial class YesterdayLogs + : QueryData, IReturn>, IMeta + { + } + + [Route("/alwaysthrows")] + [Serializable] + public partial class AlwaysThrows + : IReturn + { + } + + [Route("/alwaysthrowsfilterattribute")] + [Serializable] + public partial class AlwaysThrowsFilterAttribute + : IReturn + { + } + + [Route("/alwaysthrowsglobalfilter")] + [Serializable] + public partial class AlwaysThrowsGlobalFilter + : IReturn + { + } + + [Serializable] + public partial class AsyncTest + : IReturn + { + } + + [Serializable] + public partial class CachedEcho + : IReturn + { + public virtual bool Reload { get; set; } + public virtual string Sentence { get; set; } + } + + [Serializable] + public partial class CustomFieldHttpError + : IReturn + { + } + + [Serializable] + public partial class CustomFieldHttpErrorResponse + { + public virtual string Custom { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Serializable] + public partial class CustomHttpError + : IReturn + { + public virtual int StatusCode { get; set; } + public virtual string StatusDescription { get; set; } + } + + [Serializable] + public partial class CustomHttpErrorResponse + { + public virtual string Custom { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/dynamically/registered/{Name}")] + [Serializable] + public partial class DynamicallyRegistered + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class Echo + : IEcho + { + public virtual string Sentence { get; set; } + } + + /// + ///Echoes a sentence + /// + [Route("/echoes", "POST")] + [Api(Description="Echoes a sentence")] + [Serializable] + public partial class Echoes + : IReturn + { + /// + ///The sentence to echo. + /// + [ApiMember(DataType="string", Description="The sentence to echo.", IsRequired=true, Name="Sentence", ParameterType="form")] + public virtual string Sentence { get; set; } + } + + [Serializable] + public partial class ExcludeMetadataProperty + { + public virtual int Id { get; set; } + } + + [Route("/example", "GET")] + [DataContract] + [Serializable] + public partial class GetExample + : IReturn + { + } + + [DataContract] + [Serializable] + public partial class GetExampleResponse + { + [DataMember(Order=1)] + public virtual ResponseStatus ResponseStatus { get; set; } + + [DataMember(Order=2)] + [ApiMember] + public virtual MenuExample MenuExample1 { get; set; } + } + + public partial interface IEcho + { + string Sentence { get; set; } + } + + [DataContract] + [Serializable] + public partial class MenuExample + { + [DataMember(Order=1)] + [ApiMember] + public virtual MenuItemExample MenuItemExample1 { get; set; } + } + + [Serializable] + public partial class MenuItemExample + { + [DataMember(Order=1)] + [ApiMember] + public virtual string Name1 { get; set; } + + public virtual MenuItemExampleItem MenuItemExampleItem { get; set; } + } + + [Serializable] + public partial class MenuItemExampleItem + { + [DataMember(Order=1)] + [ApiMember] + public virtual string Name1 { get; set; } + } + + [Serializable] + public partial class MetadataTest + : IReturn + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class MetadataTestChild + { + public MetadataTestChild() + { + Results = new List{}; + } + + public virtual string Name { get; set; } + public virtual List Results { get; set; } + } + + [Serializable] + public partial class MetadataTestNestedChild + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class MetadataTestResponse + { + public MetadataTestResponse() + { + Results = new List{}; + } + + public virtual int Id { get; set; } + public virtual List Results { get; set; } + } + + [Serializable] + public partial class OnlyDefinedInGenericType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class OnlyDefinedInGenericTypeFrom + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class OnlyDefinedInGenericTypeInto + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class QueryPocoBase + : QueryDb, IReturn>, IMeta + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class QueryPocoIntoBase + : QueryDb, IReturn>, IMeta + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class RecursiveNode + : IReturn + { + public RecursiveNode() + { + Children = new RecursiveNode[]{}; + } + + public virtual int Id { get; set; } + public virtual string Text { get; set; } + public virtual RecursiveNode[] Children { get; set; } + } + + [Route("/return404")] + [Serializable] + public partial class Return404 + { + } + + [Route("/return404result")] + [Serializable] + public partial class Return404Result + { + } + + [Route("/return/bytes")] + [Serializable] + public partial class ReturnBytes + : IReturn + { + public ReturnBytes() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/stream")] + [Serializable] + public partial class ReturnStream + : IReturn + { + public ReturnStream() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/string")] + [Serializable] + public partial class ReturnString + : IReturn + { + public virtual string Data { get; set; } + } + + [Serializable] + public partial class Rockstar + { + /// + ///Идентификатор + /// + public virtual int Id { get; set; } + /// + ///Фамилия + /// + public virtual string FirstName { get; set; } + /// + ///Имя + /// + public virtual string LastName { get; set; } + /// + ///Возраст + /// + public virtual int? Age { get; set; } + } + + [Route("/swagger/range")] + [Serializable] + public partial class SwaggerRangeTest + { + public virtual string IntRange { get; set; } + public virtual string DoubleRange { get; set; } + } + + [Route("/{Version}/userdata", "GET")] + [Serializable] + public partial class SwaggerVersionTest + { + public virtual string Version { get; set; } + } + + [Serializable] + public partial class TestAttributeExport + : IReturn + { + public virtual int UnitMeasKey { get; set; } + } + + [Route("/throw404")] + [Route("/throw404/{Message}")] + [Serializable] + public partial class Throw404 + { + public virtual string Message { get; set; } + } + + [Route("/throwhttperror/{Status}")] + [Serializable] + public partial class ThrowHttpError + : IReturn + { + public virtual int Status { get; set; } + public virtual string Message { get; set; } + } + + [Serializable] + public partial class ThrowHttpErrorResponse + { + } + + [Route("/throw/{Type}")] + [Serializable] + public partial class ThrowType + : IReturn + { + public virtual string Type { get; set; } + public virtual string Message { get; set; } + } + + [Serializable] + public partial class ThrowTypeResponse + { + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throwvalidation")] + [Serializable] + public partial class ThrowValidation + : IReturn + { + public virtual int Age { get; set; } + public virtual string Required { get; set; } + public virtual string Email { get; set; } + } + + [Serializable] + public partial class ThrowValidationResponse + { + public virtual int Age { get; set; } + public virtual string Required { get; set; } + public virtual string Email { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + /// + ///AllowedAttributes Description + /// + [Route("/allowed-attributes", "GET")] + [Api(Description="AllowedAttributes Description")] + [ApiResponse(Description="Your request was not understood", StatusCode=400)] + [DataContract] + [Serializable] + public partial class AllowedAttributes + { + [DataMember] + [Required] + public virtual int Id { get; set; } + + /// + ///Range Description + /// + [DataMember(Name="Aliased")] + [ApiMember(DataType="double", Description="Range Description", IsRequired=true, ParameterType="path")] + public virtual double Range { get; set; } + } + + [Serializable] + public partial class ArrayResult + { + public virtual string Result { get; set; } + } + + public enum EnumAsInt + { + Value1 = 1000, + Value2 = 2000, + Value3 = 3000, + } + + [Flags] + public enum EnumFlags + { + Value0 = 0, + [EnumMember(Value="Value 1")] + Value1 = 1, + Value2 = 2, + Value3 = 4, + Value123 = 7, + } + + public enum EnumStyle + { + lower, + UPPER, + PascalCase, + camelCase, + camelUPPER, + PascalUPPER, + } + + public enum EnumStyleMembers + { + [EnumMember(Value="lower")] + Lower, + [EnumMember(Value="UPPER")] + Upper, + PascalCase, + [EnumMember(Value="camelCase")] + CamelCase, + [EnumMember(Value="camelUPPER")] + CamelUpper, + [EnumMember(Value="PascalUPPER")] + PascalUpper, + } + + public enum EnumType + { + Value1, + Value2, + Value3, + } + + [Flags] + public enum EnumTypeFlags + { + Value1 = 0, + Value2 = 1, + Value3 = 2, + } + + public enum EnumWithValues + { + None, + [EnumMember(Value="Member 1")] + Value1, + Value2, + } + + [Route("/hello")] + [Route("/hello/{Name}")] + [Serializable] + public partial class Hello + : IReturn + { + [Required] + public virtual string Name { get; set; } + + public virtual string Title { get; set; } + } + + /// + ///Description for HelloACodeGenTest + /// + [Serializable] + public partial class HelloACodeGenTest + : IReturn + { + public HelloACodeGenTest() + { + SecondFields = new List{}; + } + + /// + ///Description for FirstField + /// + public virtual int FirstField { get; set; } + public virtual List SecondFields { get; set; } + } + + [DataContract] + [Serializable] + public partial class HelloACodeGenTestResponse + { + /// + ///Description for FirstResult + /// + [DataMember] + public virtual int FirstResult { get; set; } + + /// + ///Description for SecondResult + /// + [DataMember] + [ApiMember(Description="Description for SecondResult")] + public virtual int SecondResult { get; set; } + } + + [Serializable] + public partial class HelloAllTypes + : IReturn + { + public virtual string Name { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + [Serializable] + public partial class HelloAllTypesResponse + { + public virtual string Result { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + /// + ///Description on HelloAll type + /// + [DataContract] + [Serializable] + public partial class HelloAnnotated + : IReturn + { + [DataMember] + public virtual string Name { get; set; } + } + + /// + ///Description on HelloAllResponse type + /// + [DataContract] + [Serializable] + public partial class HelloAnnotatedResponse + { + [DataMember] + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloArray + : IReturn + { + public HelloArray() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + /// + ///Multi Line Class + /// + [Api(Description="Multi \r\nLine \r\nClass")] + [Serializable] + public partial class HelloAttributeStringTest + { + /// + ///Multi Line Property + /// + [ApiMember(Description="Multi \r\nLine \r\nProperty")] + public virtual string Overflow { get; set; } + + /// + ///Some \ escaped chars + /// + [ApiMember(Description="Some \\ escaped \t \n chars")] + public virtual string EscapedChars { get; set; } + } + + [Serializable] + public partial class HelloBase + { + public HelloBase() + { + Items = new List{}; + Counts = new List{}; + } + + public virtual List Items { get; set; } + public virtual List Counts { get; set; } + } + + [Serializable] + public partial class HelloExisting + : IReturn + { + public HelloExisting() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + [Serializable] + public partial class HelloExistingResponse + { + public HelloExistingResponse() + { + ArrayResults = new ArrayResult[]{}; + ListResults = new List{}; + } + + public virtual HelloList HelloList { get; set; } + public virtual HelloArray HelloArray { get; set; } + public virtual ArrayResult[] ArrayResults { get; set; } + public virtual List ListResults { get; set; } + } + + [Serializable] + public partial class HelloList + : IReturn> + { + public HelloList() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + [Serializable] + public partial class HelloResponse + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloReturnList + : IReturn> + { + public HelloReturnList() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + [Serializable] + public partial class HelloString + : IReturn + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class HelloVoid + : IReturnVoid + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class HelloWithAlternateReturnResponse + : HelloWithReturnResponse + { + public virtual string AltResult { get; set; } + } + + [DataContract] + [Serializable] + public partial class HelloWithDataContract + : IReturn + { + [DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Name { get; set; } + + [DataMember(Name="id", Order=2, EmitDefaultValue=false)] + public virtual int Id { get; set; } + } + + [DataContract] + [Serializable] + public partial class HelloWithDataContractResponse + { + [DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Result { get; set; } + } + + /// + ///Description on HelloWithDescription type + /// + [Serializable] + public partial class HelloWithDescription + : IReturn + { + public virtual string Name { get; set; } + } + + /// + ///Description on HelloWithDescriptionResponse type + /// + [Serializable] + public partial class HelloWithDescriptionResponse + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloWithEnum + { + public virtual EnumType EnumProp { get; set; } + public virtual EnumTypeFlags EnumTypeFlags { get; set; } + public virtual EnumWithValues EnumWithValues { get; set; } + public virtual EnumType? NullableEnumProp { get; set; } + public virtual EnumFlags EnumFlags { get; set; } + public virtual EnumAsInt EnumAsInt { get; set; } + public virtual EnumStyle EnumStyle { get; set; } + public virtual EnumStyleMembers EnumStyleMembers { get; set; } + } + + [Serializable] + public partial class HelloWithEnumList + { + public HelloWithEnumList() + { + EnumProp = new List{}; + EnumWithValues = new List{}; + NullableEnumProp = new List>{}; + EnumFlags = new List{}; + EnumStyle = new List{}; + } + + public virtual List EnumProp { get; set; } + public virtual List EnumWithValues { get; set; } + public virtual List> NullableEnumProp { get; set; } + public virtual List EnumFlags { get; set; } + public virtual List EnumStyle { get; set; } + } + + [Serializable] + public partial class HelloWithEnumMap + { + public HelloWithEnumMap() + { + EnumProp = new Dictionary{}; + EnumWithValues = new Dictionary{}; + NullableEnumProp = new Dictionary, Nullable>{}; + EnumFlags = new Dictionary{}; + EnumStyle = new Dictionary{}; + } + + public virtual Dictionary EnumProp { get; set; } + public virtual Dictionary EnumWithValues { get; set; } + public virtual Dictionary, Nullable> NullableEnumProp { get; set; } + public virtual Dictionary EnumFlags { get; set; } + public virtual Dictionary EnumStyle { get; set; } + } + + [Serializable] + public partial class HelloWithGenericInheritance + : HelloBase + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloWithGenericInheritance2 + : HelloBase + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloWithInheritance + : HelloBase, IReturn + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class HelloWithInheritanceResponse + : HelloResponseBase + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloWithListInheritance + : List + { + } + + [Serializable] + public partial class HelloWithNestedClass + : IReturn + { + public virtual string Name { get; set; } + public virtual HelloWithNestedClass.NestedClass NestedClassProp { get; set; } + + [Serializable] + public partial class NestedClass + { + public virtual string Value { get; set; } + } + } + + [Serializable] + public partial class HelloWithNestedInheritance + : HelloBase + { + + [Serializable] + public partial class Item + { + public virtual string Value { get; set; } + } + } + + [Serializable] + public partial class HelloWithReturn + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/helloroute")] + [Serializable] + public partial class HelloWithRoute + : IReturn + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class HelloWithRouteResponse + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloWithType + : IReturn + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class HelloWithTypeResponse + { + public virtual HelloType Result { get; set; } + } + + [Serializable] + public partial class InheritedItem + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class ListResult + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class OnlyInReturnListArg + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class RestrictedAttributes + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual Hello Hello { get; set; } + } + + [Serializable] + public partial class AllCollectionTypes + { + public AllCollectionTypes() + { + IntArray = new int[]{}; + IntList = new List{}; + StringArray = new string[]{}; + StringList = new List{}; + PocoArray = new Poco[]{}; + PocoList = new List{}; + NullableByteArray = new Nullable[]{}; + NullableByteList = new List>{}; + NullableDateTimeArray = new Nullable[]{}; + NullableDateTimeList = new List>{}; + PocoLookup = new Dictionary>{}; + PocoLookupMap = new Dictionary>>{}; + } + + public virtual int[] IntArray { get; set; } + public virtual List IntList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual List StringList { get; set; } + public virtual Poco[] PocoArray { get; set; } + public virtual List PocoList { get; set; } + public virtual Nullable[] NullableByteArray { get; set; } + public virtual List> NullableByteList { get; set; } + public virtual Nullable[] NullableDateTimeArray { get; set; } + public virtual List> NullableDateTimeList { get; set; } + public virtual Dictionary> PocoLookup { get; set; } + public virtual Dictionary>> PocoLookupMap { get; set; } + } + + [Serializable] + public partial class AllTypes + : IReturn + { + public AllTypes() + { + StringList = new List{}; + StringArray = new string[]{}; + StringMap = new Dictionary{}; + IntStringMap = new Dictionary{}; + } + + public virtual int Id { get; set; } + public virtual int? NullableId { get; set; } + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual Guid Guid { get; set; } + public virtual Char Char { get; set; } + public virtual KeyValuePair KeyValuePair { get; set; } + public virtual DateTime? NullableDateTime { get; set; } + public virtual TimeSpan? NullableTimeSpan { get; set; } + public virtual List StringList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual Dictionary StringMap { get; set; } + public virtual Dictionary IntStringMap { get; set; } + public virtual SubType SubType { get; set; } + public virtual string Point { get; set; } + [DataMember(Name="aliasedName")] + public virtual string OriginalName { get; set; } + } + + [Serializable] + public partial class EmptyClass + { + } + + [Serializable] + public partial class EnumRequest + : IReturn, IPut + { + public virtual ScopeType Operator { get; set; } + } + + [Serializable] + public partial class EnumResponse + { + public virtual ScopeType Operator { get; set; } + } + + [Serializable] + public partial class ExcludeTest1 + : IReturn + { + } + + [Serializable] + public partial class ExcludeTest2 + : IReturn + { + public virtual ExcludeTestNested ExcludeTestNested { get; set; } + } + + [Serializable] + public partial class ExcludeTestNested + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloAuthenticated + : IReturn, IHasSessionId + { + public virtual string SessionId { get; set; } + public virtual int Version { get; set; } + } + + [Serializable] + public partial class HelloAuthenticatedResponse + { + public virtual int Version { get; set; } + public virtual string SessionId { get; set; } + public virtual string UserName { get; set; } + public virtual string Email { get; set; } + public virtual bool IsAuthenticated { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Serializable] + public partial class HelloBase + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloBuiltin + { + public virtual DayOfWeek DayOfWeek { get; set; } + public virtual ShortDays ShortDays { get; set; } + } + + [Serializable] + public partial class HelloDelete + : IReturn, IDelete + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloDictionary + : IReturn> + { + public virtual string Key { get; set; } + public virtual string Value { get; set; } + } + + [Serializable] + public partial class HelloGet + : IReturn, IGet + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloImplementsInterface + : IReturn, ImplementsPoco + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class HelloInnerTypes + : IReturn + { + } + + [Serializable] + public partial class HelloInnerTypesResponse + { + public HelloInnerTypesResponse() + { + InnerList = new List{}; + } + + public virtual TypesGroup.InnerType InnerType { get; set; } + public virtual TypesGroup.InnerEnum InnerEnum { get; set; } + public virtual List InnerList { get; set; } + } + + [Serializable] + public partial class HelloInterface + { + public virtual IPoco Poco { get; set; } + public virtual IEmptyInterface EmptyInterface { get; set; } + public virtual EmptyClass EmptyClass { get; set; } + public virtual string Value { get; set; } + } + + [Serializable] + public partial class HelloPatch + : IReturn, IPatch + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloPost + : HelloBase, IReturn, IPost + { + } + + [Serializable] + public partial class HelloPut + : IReturn, IPut + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloReserved + { + public virtual string Class { get; set; } + public virtual string Type { get; set; } + public virtual string extension { get; set; } + } + + [Serializable] + public partial class HelloResponseBase + { + public virtual int RefId { get; set; } + } + + [Serializable] + public partial class HelloReturnVoid + : IReturnVoid + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class HelloSession + : IReturn + { + } + + [Serializable] + public partial class HelloSessionResponse + { + public virtual AuthUserSession Result { get; set; } + } + + [Serializable] + public partial class HelloStruct + : IReturn + { + public virtual string Point { get; set; } + public virtual string NullablePoint { get; set; } + } + + [Serializable] + public partial class HelloTuple + : IReturn + { + public HelloTuple() + { + Tuples2 = new List>{}; + Tuples3 = new List>{}; + } + + public virtual Tuple Tuple2 { get; set; } + public virtual Tuple Tuple3 { get; set; } + public virtual List> Tuples2 { get; set; } + public virtual List> Tuples3 { get; set; } + } + + [Serializable] + public partial class HelloType + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloVerbResponse + { + public virtual string Result { get; set; } + } + + [Serializable] + public partial class HelloWithReturnResponse + { + public virtual string Result { get; set; } + } + + public partial interface IEmptyInterface + { + } + + public partial interface ImplementsPoco + { + string Name { get; set; } + } + + public partial interface IPoco + { + string Name { get; set; } + } + + [Serializable] + public partial class Poco + { + public virtual string Name { get; set; } + } + + [DataContract] + [Serializable] + public partial class QueryResponseTemplate + : IMeta + { + public QueryResponseTemplate() + { + Results = new List{}; + Meta = new Dictionary{}; + } + + [DataMember(Order=1)] + public virtual int Offset { get; set; } + + [DataMember(Order=2)] + public virtual int Total { get; set; } + + [DataMember(Order=3)] + public virtual List Results { get; set; } + + [DataMember(Order=4)] + public virtual Dictionary Meta { get; set; } + + [DataMember(Order=5)] + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Serializable] + public partial class QueryTemplate + : IReturn> + { + } + + [Serializable] + public partial class Request1 + : IReturn + { + public virtual TypeA Test { get; set; } + } + + [Serializable] + public partial class Request1Response + { + public virtual TypeA Test { get; set; } + } + + [Serializable] + public partial class Request2 + : IReturn + { + public virtual TypeA Test { get; set; } + } + + [Serializable] + public partial class Request2Response + { + public virtual TypeA Test { get; set; } + } + + [Serializable] + public partial class RestrictInternal + : IReturn + { + public virtual int Id { get; set; } + } + + [Serializable] + public partial class RestrictLocalhost + : IReturn + { + public virtual int Id { get; set; } + } + + [DataContract] + public enum ScopeType + { + Global = 1, + Sale = 2, + } + + [DataContract] + public enum ShortDays + { + [EnumMember(Value="MON")] + Monday, + [EnumMember(Value="TUE")] + Tuesday, + [EnumMember(Value="WED")] + Wednesday, + [EnumMember(Value="THU")] + Thursday, + [EnumMember(Value="FRI")] + Friday, + [EnumMember(Value="SAT")] + Saturday, + [EnumMember(Value="SUN")] + Sunday, + } + + [Serializable] + public partial class SubType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class TypeA + { + public TypeA() + { + Bar = new List{}; + } + + public virtual List Bar { get; set; } + } + + [Serializable] + public partial class TypeB + { + public virtual string Foo { get; set; } + } + + [Serializable] + public partial class TypesGroup + { + + [Serializable] + public partial class InnerType + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } + + [Serializable] + public partial class InnerTypeItem + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } + + public enum InnerEnum + { + Foo, + Bar, + Baz, + } + } + + [Route("/surveys/{surveyId}/sendouts/{sendoutId}/respondents", "POST")] + [Serializable] + public partial class AddRespondentRequest + : IReturn + { + public AddRespondentRequest() + { + backgroundData = new Dictionary{}; + } + + /// + ///Remarks: SurveyId of requested Survey. + /// + [ApiMember(DataType="integer", Description="Remarks: SurveyId of requested Survey.", Format="int32", IsRequired=true, Name="surveyId", ParameterType="path")] + public virtual int surveyId { get; set; } + + /// + ///Remarks: SendoutId of Sendout to which a respondent is added. + /// + [ApiMember(DataType="integer", Description="Remarks: SendoutId of Sendout to which a respondent is added.", Format="int32", IsRequired=true, Name="sendoutId", ParameterType="path")] + public virtual int sendoutId { get; set; } + + /// + ///Remarks: Valid email address, SMS recipient or login identifier. + /// + [ApiMember(DataType="string", Description="Remarks: Valid email address, SMS recipient or login identifier.", Name="contactDetails", ParameterType="query")] + public virtual string contactDetails { get; set; } + + /// + ///Remarks: Indicates whether Netigate should send the survey link to the respondent, or if you distribute it yourself. + /// + [ApiMember(DataType="boolean", Description="Remarks: Indicates whether Netigate should send the survey link to the respondent, or if you distribute it yourself.", Name="sendMail", ParameterType="query")] + public virtual bool sendMail { get; set; } + + /// + ///Remarks: Key = BGDataLabelId, Value = respondent's background data (not empty or null) + /// + [ApiMember(Description="Remarks: Key = BGDataLabelId, Value = respondent\'s background data (not empty or null)", Name="backgroundData", ParameterType="query")] + public virtual Dictionary backgroundData { get; set; } + } + + [Serializable] + public partial class AddRespondentResponse + { + public virtual int RespondentId { get; set; } + public virtual string Email { get; set; } + public virtual string Password { get; set; } + public virtual string SurveyURL { get; set; } + } + + [Route("/defaultview/action")] + [Serializable] + public partial class DefaultViewActionAttr + { + } + + [Route("/defaultview/class")] + [Serializable] + public partial class DefaultViewAttr + { + } + + [Route("/gzip/{FileName}")] + [Serializable] + public partial class DownloadGzipFile + : IReturn + { + public virtual string FileName { get; set; } + } + + [Route("/lists", "GET")] + [Serializable] + public partial class GetLists + : IReturn + { + public virtual string Id { get; set; } + } + + /// + ///Api GET Id + /// + [Route("/swaggerexamples/{Id}", "GET")] + [Api(Description="Api GET Id")] + [Serializable] + public partial class GetSwaggerExample + : IReturn + { + public virtual int Id { get; set; } + public virtual string Get { get; set; } + } + + /// + ///Api GET All + /// + [Route("/swaggerexamples", "GET")] + [Api(Description="Api GET All")] + [Serializable] + public partial class GetSwaggerExamples + : IReturn + { + public virtual string Get { get; set; } + } + + [Route("/httpresult-dto")] + [Serializable] + public partial class HttpResultDto + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/index")] + [Serializable] + public partial class IndexPage + { + public virtual string PathInfo { get; set; } + } + + [Serializable] + public partial class InProcRequest1 + { + } + + [Serializable] + public partial class InProcRequest2 + { + } + + [Route("/match/{Language*}")] + [Serializable] + public partial class MatchLang + : IReturn + { + public virtual string Language { get; set; } + } + + [Route("/match/{Language}/{Name*}")] + [Serializable] + public partial class MatchName + : IReturn + { + public virtual string Language { get; set; } + public virtual string Name { get; set; } + } + + public enum MyColor + { + Red, + Green, + Blue, + } + + public enum MyEnum + { + A, + B, + C, + } + + [Route("/plain-dto")] + [Serializable] + public partial class PlainDto + : IReturn + { + public virtual string Name { get; set; } + } + + /// + ///Api POST + /// + [Route("/swaggerexamples", "POST")] + [Api(Description="Api POST")] + [Serializable] + public partial class PostSwaggerExamples + : IReturn + { + public virtual string Post { get; set; } + } + + /// + ///Api PUT Id + /// + [Route("/swaggerexamples/{Id}", "PUT")] + [Api(Description="Api PUT Id")] + [Serializable] + public partial class PutSwaggerExample + : IReturn + { + public virtual int Id { get; set; } + public virtual string Get { get; set; } + } + + [Route("/query/alltypes")] + [Serializable] + public partial class QueryAllTypes + : QueryDb, IReturn>, IMeta + { + } + + [Route("/reqlogstest/{Name}")] + [Serializable] + public partial class RequestLogsTest + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/return/text")] + [Serializable] + public partial class ReturnText + { + public virtual string Text { get; set; } + } + + [Route("/set-cache")] + [Serializable] + public partial class SetCache + : IReturn + { + public virtual string ETag { get; set; } + public virtual TimeSpan? Age { get; set; } + public virtual TimeSpan? MaxAge { get; set; } + public virtual DateTime? Expires { get; set; } + public virtual DateTime? LastModified { get; set; } + public virtual CacheControl? CacheControl { get; set; } + } + + [Route("/swagger-complex", "POST")] + [Serializable] + public partial class SwaggerComplex + : IReturn + { + public SwaggerComplex() + { + ArrayString = new string[]{}; + ArrayInt = new int[]{}; + ListString = new List{}; + ListInt = new List{}; + DictionaryString = new Dictionary{}; + } + + [DataMember] + [ApiMember] + public virtual bool IsRequired { get; set; } + + [DataMember] + [ApiMember(IsRequired=true)] + public virtual string[] ArrayString { get; set; } + + [DataMember] + [ApiMember] + public virtual int[] ArrayInt { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListString { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListInt { get; set; } + + [DataMember] + [ApiMember] + public virtual Dictionary DictionaryString { get; set; } + } + + [Serializable] + public partial class SwaggerComplexResponse + { + public SwaggerComplexResponse() + { + ArrayString = new string[]{}; + ArrayInt = new int[]{}; + ListString = new List{}; + ListInt = new List{}; + DictionaryString = new Dictionary{}; + } + + [DataMember] + [ApiMember] + public virtual bool IsRequired { get; set; } + + [DataMember] + [ApiMember(IsRequired=true)] + public virtual string[] ArrayString { get; set; } + + [DataMember] + [ApiMember] + public virtual int[] ArrayInt { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListString { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListInt { get; set; } + + [DataMember] + [ApiMember] + public virtual Dictionary DictionaryString { get; set; } + } + + [Route("/swagger/model")] + [Serializable] + public partial class SwaggerModel + : IReturn + { + public virtual int Int { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + } + + [Route("/swagger/multiattrtest", "POST")] + [ApiResponse(Description="Code 1", StatusCode=400)] + [ApiResponse(Description="Code 2", StatusCode=402)] + [ApiResponse(Description="Code 3", StatusCode=401)] + [Serializable] + public partial class SwaggerMultiApiResponseTest + : IReturnVoid + { + } + + [Serializable] + public partial class SwaggerNestedModel + { + /// + ///NestedProperty description + /// + [ApiMember(Description="NestedProperty description")] + public virtual bool NestedProperty { get; set; } + } + + [Serializable] + public partial class SwaggerNestedModel2 + { + /// + ///NestedProperty2 description + /// + [ApiMember(Description="NestedProperty2 description")] + public virtual bool NestedProperty2 { get; set; } + + /// + ///MultipleValues description + /// + [ApiMember(Description="MultipleValues description")] + public virtual string MultipleValues { get; set; } + + /// + ///TestRange description + /// + [ApiMember(Description="TestRange description")] + public virtual int TestRange { get; set; } + } + + [Route("/swaggerpost/{Required1}", "GET")] + [Route("/swaggerpost/{Required1}/{Optional1}", "GET")] + [Route("/swaggerpost", "POST")] + [Serializable] + public partial class SwaggerPostTest + : IReturn + { + [ApiMember(Verb="POST")] + [ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}", Verb="GET")] + [ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET")] + public virtual string Required1 { get; set; } + + [ApiMember(Verb="POST")] + [ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET")] + public virtual string Optional1 { get; set; } + } + + [Route("/swaggerpost2/{Required1}/{Required2}", "GET")] + [Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", "GET")] + [Route("/swaggerpost2", "POST")] + [Serializable] + public partial class SwaggerPostTest2 + : IReturn + { + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET")] + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET")] + public virtual string Required1 { get; set; } + + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET")] + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET")] + public virtual string Required2 { get; set; } + + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET")] + public virtual string Optional1 { get; set; } + } + + /// + ///SwaggerTest Service Description + /// + [Route("/swagger", "GET")] + [Route("/swagger/{Name}", "GET")] + [Route("/swagger/{Name}", "POST")] + [Api(Description="SwaggerTest Service Description")] + [ApiResponse(Description="Your request was not understood", StatusCode=400)] + [ApiResponse(Description="Oops, something broke", StatusCode=500)] + [DataContract] + [Serializable] + public partial class SwaggerTest + { + public SwaggerTest() + { + MyDateBetween = new DateTime[]{}; + } + + /// + ///Color Description + /// + [DataMember] + [ApiMember(DataType="string", Description="Color Description", IsRequired=true, ParameterType="path")] + public virtual string Name { get; set; } + + [DataMember] + [ApiMember] + public virtual MyColor Color { get; set; } + + /// + ///Aliased Description + /// + [DataMember(Name="Aliased")] + [ApiMember(DataType="string", Description="Aliased Description", IsRequired=true)] + public virtual string Original { get; set; } + + /// + ///Not Aliased Description + /// + [DataMember] + [ApiMember(DataType="string", Description="Not Aliased Description", IsRequired=true)] + public virtual string NotAliased { get; set; } + + /// + ///Format as password + /// + [DataMember] + [ApiMember(DataType="password", Description="Format as password")] + public virtual string Password { get; set; } + + [DataMember] + [ApiMember(AllowMultiple=true)] + public virtual DateTime[] MyDateBetween { get; set; } + + /// + ///Nested model 1 + /// + [DataMember] + [ApiMember(DataType="SwaggerNestedModel", Description="Nested model 1")] + public virtual SwaggerNestedModel NestedModel1 { get; set; } + + /// + ///Nested model 2 + /// + [DataMember] + [ApiMember(DataType="SwaggerNestedModel2", Description="Nested model 2")] + public virtual SwaggerNestedModel2 NestedModel2 { get; set; } + } + + [Route("/swaggertest2", "POST")] + [Serializable] + public partial class SwaggerTest2 + { + [ApiMember] + public virtual MyEnum MyEnumProperty { get; set; } + + [ApiMember(DataType="string", IsRequired=true, Name="Token", ParameterType="header")] + public virtual string Token { get; set; } + } + + [Route("/test/html")] + [Serializable] + public partial class TestHtml + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/test/html2")] + [Serializable] + public partial class TestHtml2 + { + public virtual string Name { get; set; } + } + + [Route("/restrict/mq")] + [Serializable] + public partial class TestMqRestriction + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/views/request")] + [Serializable] + public partial class ViewRequest + : IReturn + { + public virtual string Name { get; set; } + } + + [Serializable] + public partial class ViewResponse + { + public virtual string Result { get; set; } + } +} + diff --git a/tests/CheckMvc/Controllers/HomeController.cs b/tests/CheckMvc/Controllers/HomeController.cs new file mode 100644 index 00000000000..46a8c0de742 --- /dev/null +++ b/tests/CheckMvc/Controllers/HomeController.cs @@ -0,0 +1,75 @@ +using System; +using System.Web.Mvc; +using dtos; +using ServiceStack; +using ServiceStack.Mvc; + +namespace CheckMvc.Controllers +{ + public class HomeViewModel + { + public string Name { get; set; } + public long Counter { get; set; } + public string Json { get; set; } + } + + public class TestObj + { + public int Id { get; set; } + public DateTime CurrentDate { get; set; } + } + + public class HomeController : ServiceStackController + { + public ActionResult Index() + { + return View(GetViewModel("Index")); + } + + private HomeViewModel GetViewModel(string name) + { + return new HomeViewModel + { + Name = name, + //Counter = Redis.IncrementValue("counter:" + name), + Json = new TestObj + { + Id = 1, + CurrentDate = DateTime.Now + }.ToJson() + }; + } + + public ActionResult About() + { + return View(GetViewModel("About")); + } + + public ActionResult Contact() + { + try + { + var request = new TestGateway {Name = "MVC"}; + var gateway = HostContext.AppHost.GetServiceGateway(HostContext.GetCurrentRequest()); + var response = gateway.Send(request); + //within above call the validator throws exception + } + catch (WebServiceException ex) + { + // no longer reaches here + if (ex.ResponseStatus.ErrorCode == "NotFound") + return HttpNotFound(); + throw; + } + + return View(GetViewModel("Contact")); + } + + public ActionResult Hello() + { + var uri = new GetExample().ToAbsoluteUri(); + ViewBag.Message = uri; + return View(); + } + } +} \ No newline at end of file diff --git a/tests/CheckMvc/Global.asax b/tests/CheckMvc/Global.asax new file mode 100644 index 00000000000..f931f263f3f --- /dev/null +++ b/tests/CheckMvc/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CheckMvc.MvcApplication" Language="C#" %> diff --git a/tests/CheckMvc/Global.asax.cs b/tests/CheckMvc/Global.asax.cs new file mode 100644 index 00000000000..5d4df731ead --- /dev/null +++ b/tests/CheckMvc/Global.asax.cs @@ -0,0 +1,179 @@ +using System; +using System.Configuration; +using System.Data; +using System.IO; +using System.Runtime.Serialization; +using System.Web.Mvc; +using System.Web.Routing; +using Check.ServiceInterface; +using Funq; +using ServiceStack; +using ServiceStack.Api.OpenApi; +using ServiceStack.Data; +using ServiceStack.MiniProfiler; +using ServiceStack.Mvc; +//using ServiceStack.OrmLite; // ref source packages +using ServiceStack.Redis; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace CheckMvc +{ + public class AppHost : AppHostBase + { + public AppHost() + : base("Check MVC", typeof(ErrorsService).Assembly, typeof(SmrImportServices).Assembly) {} + + public override void Configure(Container container) + { + //Set MVC to use the same Funq IOC as ServiceStack + ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container)); + + Plugins.Add(new MiniProfilerFeature()); + +// container.Register(c => +// new RedisManagerPool()); + +// container.Register(c => c.Resolve().GetCacheClient()); + + SetConfig(new HostConfig { DebugMode = true }); + + Plugins.Add(new SharpPagesFeature()); + + Plugins.Add(new OpenApiFeature()); + } + } + + public class TestGateway : IReturn + { + public string Name { get; set; } + } + + public class TestGatewayResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class TestGatewayService : Service + { + public object Any(TestGateway request) => + throw HttpError.NotFound("NotFound"); + } + + public class SmrImportServices : Service + { + public object Post(AddSmrImportRequest request) + { + return request; + } + } + + [ServiceStack.Route("/addsmrimportrequest/{Year}/{Month}/{ScheduledDay}/{ScheduledMonth}/{ScheduledYear}/{ScheduledHour}/{ScheduledMinutes}/{AuditUserName}/{AuditIpAddress}", + Verbs = "OPTIONS POST")] + [DataContract] + public class AddSmrImportRequest : QueryBase, IRequiresRequestStream, IReturn + { + [DataMember(IsRequired = true, Order = 1)] + public int Year { get; set; } + + [DataMember(IsRequired = true, Order = 2)] + public short Month { get; set; } + + [DataMember(IsRequired = true, Order = 3)] + public short ScheduledDay { get; set; } + + [DataMember(IsRequired = true, Order = 4)] + public short ScheduledMonth { get; set; } + + [DataMember(IsRequired = true, Order = 5)] + public int ScheduledYear { get; set; } + + [DataMember(IsRequired = true, Order = 6)] + public short ScheduledHour { get; set; } + + [DataMember(IsRequired = true, Order = 7)] + public short ScheduledMinutes { get; set; } + + [DataMember(IsRequired = true, Order = 8)] + public string AuditUserName { get; set; } + + [DataMember(IsRequired = true, Order = 9)] + public string AuditIpAddress { get; set; } + + public Stream RequestStream { get; set; } + } + + [ServiceStack.Route("/urlcheck")] + [ServiceStack.Route("/urlcheck/{Name}")] + public class UrlCheck : IReturn + { + public string Name { get; set; } + } + + public class UrlCheckResponse + { + public string Result { get; set; } + } + + public class MyServices : Service + { + public object Any(UrlCheck request) + { + return new UrlCheckResponse { + Result = request.ToAbsoluteUri() + }; + } + } + + // Note: For instructions on enabling IIS6 or IIS7 classic mode, + // visit http://go.microsoft.com/?LinkId=9394801 + public class MvcApplication : System.Web.HttpApplication + { + public static IDbConnectionFactory DbFactory; + + protected void Application_Start() + { +// DbFactory = new OrmLiteConnectionFactory( +// ConfigurationManager.AppSettings["connectionString"], +// SqlServerDialect.Provider); + + JsConfig.Init(new ServiceStack.Text.Config { + TextCase = TextCase.CamelCase, + DateHandler = DateHandler.ISO8601, + }); + + AreaRegistration.RegisterAllAreas(); + + //WebApiConfig.Register(GlobalConfiguration.Configuration); + FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); + RouteConfig.RegisterRoutes(RouteTable.Routes); + + new AppHost().Init(); + } + + protected void Application_BeginRequest(object src, EventArgs e) + { + if (Request.IsLocal) + Profiler.Start(); + } + + protected void Application_EndRequest(object src, EventArgs e) + { + Profiler.Stop(); + } + } + + public abstract class ControllerBase : Controller + { + private IDbConnection db; + public IDbConnection Db => db ?? (db = MvcApplication.DbFactory.OpenDbConnection()); + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + db?.Close(); + } + } +} \ No newline at end of file diff --git a/tests/RazorRockstars.Console/MRootPage.md b/tests/CheckMvc/MRootPage.md similarity index 88% rename from tests/RazorRockstars.Console/MRootPage.md rename to tests/CheckMvc/MRootPage.md index 3ae595a1190..52ede7bbf44 100644 --- a/tests/RazorRockstars.Console/MRootPage.md +++ b/tests/CheckMvc/MRootPage.md @@ -1,23 +1,25 @@ -@var Title = "Root Page" - +@var Title = "Root Page" + ^
- -**view this page in: ** -[json](?format=json), -[xml](?format=xml), -[jsv](?format=jsv), -[csv](?format=csv) - -### Other Pages - - - [/rockstars](/rockstars) - - [/TypedModelNoController](/TypedModelNoController) - - [/NoModelNoController](/NoModelNoController) - -^
- -### All Rockstars - -source files for this demo - + +**view this page in:** +[json](?format=json), +[xml](?format=xml), +[jsv](?format=jsv), +[csv](?format=csv) + +### Other Pages + + - [/rockstars](/rockstars) + - [/TypedModelNoController](/TypedModelNoController) + - [/NoModelNoController](/NoModelNoController) + +^ + +### All Rockstars + +source files for this demo + +Time is: @DateTime.UtcNow + \ No newline at end of file diff --git a/tests/CheckMvc/Properties/AssemblyInfo.cs b/tests/CheckMvc/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..9869dba2cb0 --- /dev/null +++ b/tests/CheckMvc/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CheckMvc")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CheckMvc")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4bf62f3a-b833-40e8-bc7e-608cc478f421")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/CheckMvc/RequestInfoTests.cs b/tests/CheckMvc/RequestInfoTests.cs new file mode 100644 index 00000000000..d6a97e83e09 --- /dev/null +++ b/tests/CheckMvc/RequestInfoTests.cs @@ -0,0 +1,96 @@ +using ServiceStack; +using ServiceStack.Host.Handlers; +using System.Net; +using NUnit.Framework; + +namespace CheckMvc +{ + public class RequestInfoServices : Service + { + } + + public partial class RequestInfoTests + { + public string BaseUrl = "http://localhost:49435/api/v1/"; + + private RequestInfoResponse GetRequestInfoForPath(string path) + { + var url = BaseUrl.CombineWith(path).AddQueryParam("debug", "requestinfo"); + var json = url.GetJsonFromUrl(); + var info = json.FromJson(); + return info; + } + + private void AssertHasContent(string pathInfo, string accept, string containsContent) + { + var url = BaseUrl.CombineWith(pathInfo); + var content = url.GetStringFromUrl(accept: accept); + Assert.That(content, Does.Contain(containsContent)); + } + + [Test] + public void Does_return_expected_content() + { + AssertHasContent("metadata", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("metadata/", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("dir", MimeTypes.Html, "

dir/index.html

"); + AssertHasContent("dir/", MimeTypes.Html, "

dir/index.html

"); + AssertHasContent("dir/sub", MimeTypes.Html, "

dir/sub/index.html

"); + AssertHasContent("dir/sub/", MimeTypes.Html, "

dir/sub/index.html

"); + AssertHasContent("swagger-ui", MimeTypes.Html, "Swagger UI"); + AssertHasContent("swagger-ui/", MimeTypes.Html, "Swagger UI"); + } + + [Test] + public void Does_have_correct_path_info() + { + Assert.That(GetRequestInfoForPath("dir/").PathInfo, Is.EqualTo("/dir/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("swagger-ui/").PathInfo, Is.EqualTo("/swagger-ui/")); + } + } + + public partial class RequestInfoTests + { + private void DoesRedirectToRemoveTrailingSlash(string dirWIthoutSlash) + { + BaseUrl.CombineWith(dirWIthoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWIthoutSlash + "/"))); + }); + } + + private void DoesRedirectToAddTrailingSlash(string dirWithoutSlash) + { + BaseUrl.CombineWith(dirWithoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWithoutSlash.TrimEnd('/')))); + }); + } + + [Test] + public void Does_redirect_dirs_without_trailing_slash() + { + DoesRedirectToRemoveTrailingSlash("dir"); + DoesRedirectToRemoveTrailingSlash("dir/sub"); + DoesRedirectToRemoveTrailingSlash("swagger-ui"); + } + + [Test] + public void Does_redirect_metadata_page_to_without_slash() + { + DoesRedirectToAddTrailingSlash("metadata/"); + } + } +} \ No newline at end of file diff --git a/tests/CheckMvc/StackApis.dtos.cs b/tests/CheckMvc/StackApis.dtos.cs new file mode 100644 index 00000000000..30f9d77ee1f --- /dev/null +++ b/tests/CheckMvc/StackApis.dtos.cs @@ -0,0 +1,156 @@ +/* Options: +Date: 2019-10-04 22:16:42 +Version: 5.00 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://stackapis.netcore.io + +//GlobalNamespace: +//MakePartial: True +//MakeVirtual: True +//MakeInternal: False +//MakeDataContractsExtensible: False +//AddReturnMarker: True +//AddDescriptionAsComments: True +//AddDataContractAttributes: False +//AddIndexesToDataMembers: False +//AddGeneratedCodeAttributes: False +//AddResponseStatus: False +//AddImplicitVersion: +//InitializeCollections: True +//ExportValueTypes: False +//IncludeTypes: +//ExcludeTypes: +//AddNamespaces: +//AddDefaultXmlNamespace: http://schemas.servicestack.net/types +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; +using StackApis.ServiceModel.Types; +using StackApis.ServiceModel; + + +namespace StackApis.ServiceModel +{ + + /// + ///Get a list of Answers for a Question + /// + [Route("/answers/{QuestionId}")] + public partial class GetAnswers + : IReturn + { + public virtual int QuestionId { get; set; } + } + + public partial class GetAnswersResponse + { + public virtual Answer Ansnwer { get; set; } + } + + [Route("/admin/stats", "GET")] + public partial class GetStats + : IReturn + { + } + + public partial class GetStatsResponse + { + public GetStatsResponse() + { + TagCounts = new Dictionary{}; + } + + public virtual long QuestionsCount { get; set; } + public virtual long AnswersCount { get; set; } + public virtual Dictionary TagCounts { get; set; } + public virtual long TopQuestionScore { get; set; } + public virtual long TopQuestionViews { get; set; } + public virtual long TopAnswerScore { get; set; } + } + + [Route("/questions/search")] + public partial class SearchQuestions + : IReturn + { + public SearchQuestions() + { + Tags = new List{}; + } + + public virtual List Tags { get; set; } + public virtual string UserId { get; set; } + } + + public partial class SearchQuestionsResponse + { + public SearchQuestionsResponse() + { + Results = new List{}; + } + + public virtual List Results { get; set; } + } + + [Route("/questions")] + [AutoQueryViewer(DefaultSearchField="Title", DefaultSearchText="ServiceStack", DefaultSearchType="Contains", Description="Find ServiceStack Questions on StackOverflow", IconUrl="material-icons:cast", Title="Explore StackOverflow Questions")] + public partial class StackOverflowQuery + : QueryDb, IReturn>, IMeta + { + public virtual int? ScoreGreaterThan { get; set; } + } +} + +namespace StackApis.ServiceModel.Types +{ + + public partial class Answer + { + public virtual int AnswerId { get; set; } + public virtual User Owner { get; set; } + public virtual bool IsAccepted { get; set; } + public virtual int Score { get; set; } + public virtual int LastActivityDate { get; set; } + public virtual int LastEditDate { get; set; } + public virtual int CreationDate { get; set; } + public virtual int QuestionId { get; set; } + } + + public partial class Question + { + public Question() + { + Tags = new string[]{}; + } + + public virtual int QuestionId { get; set; } + public virtual string Title { get; set; } + public virtual int Score { get; set; } + public virtual int ViewCount { get; set; } + public virtual bool IsAnswered { get; set; } + public virtual int AnswerCount { get; set; } + public virtual string Link { get; set; } + public virtual string[] Tags { get; set; } + public virtual User Owner { get; set; } + public virtual int LastActivityDate { get; set; } + public virtual int CreationDate { get; set; } + public virtual int LastEditDate { get; set; } + public virtual int? AcceptedAnswerId { get; set; } + } + + public partial class User + { + public virtual int Reputation { get; set; } + public virtual int Userid { get; set; } + public virtual string UserType { get; set; } + public virtual int AcceptRate { get; set; } + public virtual string ProfileImage { get; set; } + public virtual string DisplayName { get; set; } + public virtual string Link { get; set; } + } +} + diff --git a/tests/CheckMvc/TestGlobalNamespace.dtos.cs b/tests/CheckMvc/TestGlobalNamespace.dtos.cs new file mode 100644 index 00000000000..9e148b3172b --- /dev/null +++ b/tests/CheckMvc/TestGlobalNamespace.dtos.cs @@ -0,0 +1,1400 @@ +/* Options: +Date: 2019-10-04 15:16:43 +Version: 5.7 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://test.servicestack.net + +GlobalNamespace: testdtos +//MakePartial: True +//MakeVirtual: True +//MakeInternal: False +//MakeDataContractsExtensible: False +//AddReturnMarker: True +//AddDescriptionAsComments: True +//AddDataContractAttributes: False +//AddIndexesToDataMembers: False +//AddGeneratedCodeAttributes: False +//AddResponseStatus: False +//AddImplicitVersion: +//InitializeCollections: True +//ExportValueTypes: False +//IncludeTypes: +//ExcludeTypes: +//AddNamespaces: +//AddDefaultXmlNamespace: http://schemas.servicestack.net/types +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; +using System.IO; +using testdtos; + + +namespace testdtos +{ + + public enum ExternalEnum + { + Foo, + Bar, + Baz, + } + + public enum ExternalEnum2 + { + Uno, + Due, + Tre, + } + + public enum ExternalEnum3 + { + Un, + Deux, + Trois, + } + + public partial class ExternalOperation + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ExternalEnum ExternalEnum { get; set; } + } + + public partial class ExternalOperation2 + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class ExternalOperation2Response + { + public virtual ExternalType ExternalType { get; set; } + } + + public partial class ExternalOperation3 + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class ExternalOperation4 + { + public virtual int Id { get; set; } + } + + public partial class ExternalOperationResponse + { + public virtual string Result { get; set; } + } + + public partial class ExternalReturnTypeResponse + { + public virtual ExternalEnum3 ExternalEnum3 { get; set; } + } + + public partial class ExternalType + { + public virtual ExternalEnum2 ExternalEnum2 { get; set; } + } + + public partial class Account + { + public virtual string Name { get; set; } + } + + [Route("/jwt")] + public partial class CreateJwt + : AuthUserSession, IReturn, IMeta + { + public virtual DateTime? JwtExpiry { get; set; } + } + + public partial class CreateJwtResponse + { + public virtual string Token { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/jwt-refresh")] + public partial class CreateRefreshJwt + : IReturn + { + public virtual string UserAuthId { get; set; } + public virtual DateTime? JwtExpiry { get; set; } + } + + public partial class CreateRefreshJwtResponse + { + public virtual string Token { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/custom")] + [Route("/custom/{Data}")] + public partial class CustomRoute + : IReturn + { + public virtual string Data { get; set; } + } + + public partial class CustomUserSession + : AuthUserSession, IMeta + { + [DataMember] + public virtual string CustomName { get; set; } + + [DataMember] + public virtual string CustomInfo { get; set; } + } + + public partial class DummyTypes + { + public DummyTypes() + { + HelloResponses = new List{}; + } + + public virtual List HelloResponses { get; set; } + } + + [Route("/echo/collections")] + public partial class EchoCollections + : IReturn + { + public EchoCollections() + { + StringList = new List{}; + StringArray = new string[]{}; + StringMap = new Dictionary{}; + IntStringMap = new Dictionary{}; + } + + public virtual List StringList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual Dictionary StringMap { get; set; } + public virtual Dictionary IntStringMap { get; set; } + } + + [Route("/echo/complex")] + public partial class EchoComplexTypes + : IReturn + { + public EchoComplexTypes() + { + SubTypes = new List{}; + SubTypeMap = new Dictionary{}; + StringMap = new Dictionary{}; + IntStringMap = new Dictionary{}; + } + + public virtual SubType SubType { get; set; } + public virtual List SubTypes { get; set; } + public virtual Dictionary SubTypeMap { get; set; } + public virtual Dictionary StringMap { get; set; } + public virtual Dictionary IntStringMap { get; set; } + } + + [Route("/echo/types")] + public partial class EchoTypes + : IReturn + { + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual Guid Guid { get; set; } + public virtual Char Char { get; set; } + } + + public partial class GetAccount + : IReturn + { + public virtual string Account { get; set; } + } + + public partial class GetProject + : IReturn + { + public virtual string Account { get; set; } + public virtual string Project { get; set; } + } + + [Route("/Request1", "GET")] + public partial class GetRequest1 + : IReturn>, IGet + { + } + + [Route("/Request2", "GET")] + public partial class GetRequest2 + : IReturn>, IGet + { + } + + [Route("/session")] + public partial class GetSession + : IReturn + { + } + + public partial class GetSessionResponse + { + public virtual CustomUserSession Result { get; set; } + public virtual UnAuthInfo UnAuthInfo { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/Stuff")] + [DataContract(Namespace="http://schemas.servicestack.net/types")] + public partial class GetStuff + : IReturn + { + [DataMember] + [ApiMember(DataType="DateTime", Name="Summary Date")] + public virtual DateTime? SummaryDate { get; set; } + + [DataMember] + [ApiMember(DataType="DateTime", Name="Summary End Date")] + public virtual DateTime? SummaryEndDate { get; set; } + + [DataMember] + [ApiMember(DataType="string", Name="Symbol")] + public virtual string Symbol { get; set; } + + [DataMember] + [ApiMember(DataType="string", Name="Email")] + public virtual string Email { get; set; } + + [DataMember] + [ApiMember(DataType="bool", Name="Is Enabled")] + public virtual bool? IsEnabled { get; set; } + } + + [DataContract(Namespace="http://schemas.servicestack.net/types")] + public partial class GetStuffResponse + { + [DataMember] + public virtual DateTime? SummaryDate { get; set; } + + [DataMember] + public virtual DateTime? SummaryEndDate { get; set; } + + [DataMember] + public virtual string Symbol { get; set; } + + [DataMember] + public virtual string Email { get; set; } + + [DataMember] + public virtual bool? IsEnabled { get; set; } + } + + public partial class HelloAuth + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/hello-image/{Name}")] + public partial class HelloImage + : IReturn + { + public virtual string Name { get; set; } + public virtual string Format { get; set; } + public virtual int? Width { get; set; } + public virtual int? Height { get; set; } + public virtual int? FontSize { get; set; } + public virtual string FontFamily { get; set; } + public virtual string Foreground { get; set; } + public virtual string Background { get; set; } + } + + [Route("/image-bytes")] + public partial class ImageAsBytes + : IReturn + { + public virtual string Format { get; set; } + } + + [Route("/image-custom")] + public partial class ImageAsCustomResult + : IReturn + { + public virtual string Format { get; set; } + } + + [Route("/image-file")] + public partial class ImageAsFile + : IReturn + { + public virtual string Format { get; set; } + } + + [Route("/image-redirect")] + public partial class ImageAsRedirect + { + public virtual string Format { get; set; } + } + + [Route("/image-stream")] + public partial class ImageAsStream + : IReturn + { + public virtual string Format { get; set; } + } + + [Route("/image-response")] + public partial class ImageWriteToResponse + : IReturn + { + public virtual string Format { get; set; } + } + + [Route("/ping")] + public partial class Ping + : IReturn + { + } + + public partial class PingResponse + { + public PingResponse() + { + Responses = new Dictionary{}; + } + + public virtual Dictionary Responses { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class PingService + { + + [Route("/reset-connections")] + public partial class ResetConnections + { + } + } + + public partial class Project + { + public virtual string Account { get; set; } + public virtual string Name { get; set; } + } + + public partial class RequiresAdmin + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class ReturnedDto + { + public virtual int Id { get; set; } + } + + [Route("/return/html")] + public partial class ReturnHtml + { + public virtual string Text { get; set; } + } + + [Route("/return/text")] + public partial class ReturnText + { + public virtual string Text { get; set; } + } + + public partial class RootPathRoutes + { + public virtual string Path { get; set; } + } + + public partial class SendDefault + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class SendGet + : IReturn, IGet + { + public virtual int Id { get; set; } + } + + public partial class SendPost + : IReturn, IPost + { + public virtual int Id { get; set; } + } + + public partial class SendPut + : IReturn, IPut + { + public virtual int Id { get; set; } + } + + [Route("/sendrestget/{Id}", "GET")] + public partial class SendRestGet + : IReturn, IGet + { + public virtual int Id { get; set; } + } + + public partial class SendReturnVoid + : IReturnVoid + { + public virtual int Id { get; set; } + } + + public partial class SendVerbResponse + { + public virtual int Id { get; set; } + public virtual string PathInfo { get; set; } + public virtual string RequestMethod { get; set; } + } + + [Route("/testauth")] + public partial class TestAuth + : IReturn + { + } + + public partial class TestAuthResponse + { + public virtual string UserId { get; set; } + public virtual string SessionId { get; set; } + public virtual string UserName { get; set; } + public virtual string DisplayName { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/testdata/AllCollectionTypes")] + public partial class TestDataAllCollectionTypes + : IReturn + { + } + + [Route("/testdata/AllTypes")] + public partial class TestDataAllTypes + : IReturn + { + } + + [Route("/null-response")] + public partial class TestNullResponse + { + } + + [Route("/void-response")] + public partial class TestVoidResponse + { + } + + [Route("/textfile-test")] + public partial class TextFileTest + { + public virtual bool AsAttachment { get; set; } + } + + public partial class UnAuthInfo + { + public virtual string CustomInfo { get; set; } + } + + [Route("/session/edit/{CustomName}")] + public partial class UpdateSession + : IReturn + { + public virtual string CustomName { get; set; } + } + + [Route("/logs")] + public partial class ViewLogs + : IReturn + { + public virtual bool Clear { get; set; } + } + + [Route("/wait/{ForMs}")] + public partial class Wait + : IReturn + { + public virtual int ForMs { get; set; } + } + + /// + ///AllowedAttributes Description + /// + [Route("/allowed-attributes", "GET")] + [Api(Description="AllowedAttributes Description")] + [ApiResponse(Description="Your request was not understood", StatusCode=400)] + [DataContract] + public partial class AllowedAttributes + { + /// + ///Range Description + /// + [DataMember(Name="Aliased")] + [ApiMember(DataType="double", Description="Range Description", IsRequired=true, ParameterType="path")] + public virtual double Range { get; set; } + } + + public partial class ArrayResult + { + public virtual string Result { get; set; } + } + + public partial class Channel + { + public virtual string Name { get; set; } + public virtual string Value { get; set; } + } + + public partial class CustomHttpError + : IReturn + { + public virtual int StatusCode { get; set; } + public virtual string StatusDescription { get; set; } + } + + public partial class CustomHttpErrorResponse + { + public virtual string Custom { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class Device + { + public Device() + { + Channels = new List{}; + } + + public virtual long Id { get; set; } + public virtual string Type { get; set; } + public virtual long TimeStamp { get; set; } + public virtual List Channels { get; set; } + } + + public partial class EmptyClass + { + } + + [Flags] + public enum EnumFlags + { + Value1 = 1, + Value2 = 2, + Value3 = 4, + } + + public partial class EnumRequest + : IReturn, IPut + { + public virtual ScopeType Operator { get; set; } + } + + public partial class EnumResponse + { + public virtual ScopeType Operator { get; set; } + } + + public enum EnumType + { + Value1, + Value2, + } + + [Route("/example", "GET")] + [DataContract] + public partial class GetExample + : IReturn + { + } + + [DataContract] + public partial class GetExampleResponse + { + [DataMember(Order=1)] + public virtual ResponseStatus ResponseStatus { get; set; } + + [DataMember(Order=2)] + [ApiMember] + public virtual MenuExample MenuExample1 { get; set; } + } + + [Route("/randomids")] + public partial class GetRandomIds + : IReturn + { + public virtual int? Take { get; set; } + } + + public partial class GetRandomIdsResponse + { + public GetRandomIdsResponse() + { + Results = new List{}; + } + + public virtual List Results { get; set; } + } + + [Route("/hello")] + [Route("/hello/{Name}")] + public partial class Hello + : IReturn + { + [Required] + public virtual string Name { get; set; } + + public virtual string Title { get; set; } + } + + [Route("/all-types")] + public partial class HelloAllTypes + : IReturn + { + public virtual string Name { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + public partial class HelloAllTypesResponse + { + public virtual string Result { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + /// + ///Description on HelloAll type + /// + [DataContract] + public partial class HelloAnnotated + : IReturn + { + [DataMember] + public virtual string Name { get; set; } + } + + /// + ///Description on HelloAllResponse type + /// + [DataContract] + public partial class HelloAnnotatedResponse + { + [DataMember] + public virtual string Result { get; set; } + } + + public partial class HelloArray + : IReturn + { + public HelloArray() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + public partial class HelloBase + { + public HelloBase() + { + Items = new List{}; + Counts = new List{}; + } + + public virtual List Items { get; set; } + public virtual List Counts { get; set; } + } + + public partial class HelloBuiltin + { + public virtual DayOfWeek DayOfWeek { get; set; } + } + + public partial class HelloDateTime + : IReturn + { + public virtual DateTime DateTime { get; set; } + } + + public partial class HelloDelete + : IReturn, IDelete + { + public virtual int Id { get; set; } + } + + public partial class HelloGet + : IReturn, IGet + { + public virtual int Id { get; set; } + } + + public partial class HelloInnerTypes + : IReturn + { + } + + public partial class HelloInnerTypesResponse + { + public virtual TypesGroup.InnerType InnerType { get; set; } + public virtual TypesGroup.InnerEnum InnerEnum { get; set; } + } + + public partial class HelloInterface + { + public virtual IPoco Poco { get; set; } + public virtual IEmptyInterface EmptyInterface { get; set; } + public virtual EmptyClass EmptyClass { get; set; } + } + + public partial class HelloList + : IReturn> + { + public HelloList() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + public partial class HelloPatch + : IReturn, IPatch + { + public virtual int Id { get; set; } + } + + public partial class HelloPost + : HelloBase, IReturn, IPost + { + } + + public partial class HelloPut + : IReturn, IPut + { + public virtual int Id { get; set; } + } + + public partial class HelloResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloReturnVoid + : IReturnVoid + { + public virtual int Id { get; set; } + } + + public partial class HelloString + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/hellotypes/{Name}")] + public partial class HelloTypes + : IReturn + { + public virtual string String { get; set; } + public virtual bool Bool { get; set; } + public virtual int Int { get; set; } + } + + public partial class HelloVerbResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloVoid + { + public virtual string Name { get; set; } + } + + public partial class HelloWithAlternateReturnResponse + : HelloWithReturnResponse + { + public virtual string AltResult { get; set; } + } + + [DataContract] + public partial class HelloWithDataContract + : IReturn + { + [DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Name { get; set; } + + [DataMember(Name="id", Order=2, EmitDefaultValue=false)] + public virtual int Id { get; set; } + } + + [DataContract] + public partial class HelloWithDataContractResponse + { + [DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Result { get; set; } + } + + /// + ///Description on HelloWithDescription type + /// + public partial class HelloWithDescription + : IReturn + { + public virtual string Name { get; set; } + } + + /// + ///Description on HelloWithDescriptionResponse type + /// + public partial class HelloWithDescriptionResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithEnum + { + public virtual EnumType EnumProp { get; set; } + public virtual EnumType? NullableEnumProp { get; set; } + public virtual EnumFlags EnumFlags { get; set; } + } + + public partial class HelloWithGenericInheritance + : HelloBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithGenericInheritance2 + : HelloBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithInheritance + : HelloBase, IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithInheritanceResponse + : HelloResponseBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithNestedClass + : IReturn + { + public virtual string Name { get; set; } + public virtual HelloWithNestedClass.NestedClass NestedClassProp { get; set; } + + public partial class NestedClass + { + public virtual string Value { get; set; } + } + } + + public partial class HelloWithNestedInheritance + : HelloBase + { + + public partial class Item + { + public virtual string Value { get; set; } + } + } + + public partial class HelloWithReturn + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/helloroute")] + public partial class HelloWithRoute + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithRouteResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithType + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithTypeResponse + { + public virtual HelloType Result { get; set; } + } + + [Route("/hellozip")] + [DataContract] + public partial class HelloZip + : IReturn + { + public HelloZip() + { + Test = new List{}; + } + + [DataMember] + public virtual string Name { get; set; } + + [DataMember] + public virtual List Test { get; set; } + } + + [DataContract] + public partial class HelloZipResponse + { + [DataMember] + public virtual string Result { get; set; } + } + + public partial interface IEmptyInterface + { + } + + public partial interface IPoco + { + string Name { get; set; } + } + + public partial class ListResult + { + public virtual string Result { get; set; } + } + + public partial class Logger + { + public Logger() + { + Devices = new List{}; + } + + public virtual long Id { get; set; } + public virtual List Devices { get; set; } + } + + [DataContract] + public partial class MenuExample + { + [DataMember(Order=1)] + [ApiMember] + public virtual MenuItemExample MenuItemExample1 { get; set; } + } + + public partial class MenuItemExample + { + [DataMember(Order=1)] + [ApiMember] + public virtual string Name1 { get; set; } + + public virtual MenuItemExampleItem MenuItemExampleItem { get; set; } + } + + public partial class MenuItemExampleItem + { + [DataMember(Order=1)] + [ApiMember] + public virtual string Name1 { get; set; } + } + + [Route("/metadatatest")] + public partial class MetadataTest + : IReturn + { + public virtual int Id { get; set; } + } + + [Route("/metadatatest-array")] + public partial class MetadataTestArray + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class MetadataTestChild + { + public MetadataTestChild() + { + Results = new List{}; + } + + public virtual string Name { get; set; } + public virtual List Results { get; set; } + } + + public partial class MetadataTestNestedChild + { + public virtual string Name { get; set; } + } + + public partial class MetadataTestResponse + { + public MetadataTestResponse() + { + Results = new List{}; + } + + public virtual int Id { get; set; } + public virtual List Results { get; set; } + } + + public partial class OnlyDefinedInGenericType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class OnlyDefinedInGenericTypeFrom + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class OnlyDefinedInGenericTypeInto + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class QueryPocoBase + : QueryDb, IReturn>, IMeta + { + public virtual int Id { get; set; } + } + + public partial class QueryPocoIntoBase + : QueryDb, IReturn>, IMeta + { + public virtual int Id { get; set; } + } + + [Route("/rockstars", "GET")] + public partial class QueryRockstars + : QueryDb, IReturn>, IMeta + { + } + + [Route("/requires-role")] + public partial class RequiresRole + : IReturn + { + } + + public partial class RequiresRoleResponse + { + public virtual string Result { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class RestrictedAttributes + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual Hello Hello { get; set; } + } + + [Route("/return/bytes")] + public partial class ReturnBytes + : IReturn + { + public ReturnBytes() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/stream")] + public partial class ReturnStream + : IReturn + { + public ReturnStream() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/string")] + public partial class ReturnString + : IReturn + { + public virtual string Data { get; set; } + } + + public partial class Rockstar + { + public virtual int Id { get; set; } + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual int? Age { get; set; } + } + + [DataContract] + public enum ScopeType + { + Global = 1, + Sale = 2, + } + + [Route("/sendjson")] + public partial class SendJson + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Route("/sendraw")] + public partial class SendRaw + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual string ContentType { get; set; } + } + + [Route("/sendtext")] + public partial class SendText + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual string ContentType { get; set; } + } + + public partial class StoreLogs + : IReturn + { + public StoreLogs() + { + Loggers = new List{}; + } + + public virtual List Loggers { get; set; } + } + + public partial class StoreLogsResponse + { + public StoreLogsResponse() + { + ExistingLogs = new List{}; + } + + public virtual List ExistingLogs { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/rockstars", "POST")] + public partial class StoreRockstars + : List, IReturn + { + } + + [Route("/throw404")] + [Route("/throw404/{Message}")] + public partial class Throw404 + { + public virtual string Message { get; set; } + } + + [Route("/throwbusinesserror")] + public partial class ThrowBusinessError + : IReturn + { + } + + public partial class ThrowBusinessErrorResponse + { + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throwcustom400")] + [Route("/throwcustom400/{Message}")] + public partial class ThrowCustom400 + { + public virtual string Message { get; set; } + } + + [Route("/throwhttperror/{Status}")] + public partial class ThrowHttpError + { + public virtual int? Status { get; set; } + public virtual string Message { get; set; } + } + + [Route("/throw/{Type}")] + public partial class ThrowType + : IReturn + { + public virtual string Type { get; set; } + public virtual string Message { get; set; } + } + + public partial class ThrowTypeResponse + { + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throwvalidation")] + public partial class ThrowValidation + : IReturn + { + public virtual int Age { get; set; } + public virtual string Required { get; set; } + public virtual string Email { get; set; } + } + + public partial class ThrowValidationResponse + { + public virtual int Age { get; set; } + public virtual string Required { get; set; } + public virtual string Email { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class TypesGroup + { + + public partial class InnerType + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } + + public enum InnerEnum + { + Foo, + Bar, + Baz, + } + } + + public partial class AllCollectionTypes + { + public AllCollectionTypes() + { + IntArray = new int[]{}; + IntList = new List{}; + StringArray = new string[]{}; + StringList = new List{}; + PocoArray = new Poco[]{}; + PocoList = new List{}; + PocoLookup = new Dictionary>{}; + PocoLookupMap = new Dictionary>>{}; + } + + public virtual int[] IntArray { get; set; } + public virtual List IntList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual List StringList { get; set; } + public virtual Poco[] PocoArray { get; set; } + public virtual List PocoList { get; set; } + public virtual Dictionary> PocoLookup { get; set; } + public virtual Dictionary>> PocoLookupMap { get; set; } + } + + public partial class AllTypes + { + public AllTypes() + { + StringList = new List{}; + StringArray = new string[]{}; + StringMap = new Dictionary{}; + IntStringMap = new Dictionary{}; + } + + public virtual int Id { get; set; } + public virtual int? NullableId { get; set; } + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual Guid Guid { get; set; } + public virtual Char Char { get; set; } + public virtual KeyValuePair KeyValuePair { get; set; } + public virtual DateTime? NullableDateTime { get; set; } + public virtual TimeSpan? NullableTimeSpan { get; set; } + public virtual List StringList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual Dictionary StringMap { get; set; } + public virtual Dictionary IntStringMap { get; set; } + public virtual SubType SubType { get; set; } + } + + public partial class HelloBase + { + public virtual int Id { get; set; } + } + + public partial class HelloResponseBase + { + public virtual int RefId { get; set; } + } + + public partial class HelloType + { + public virtual string Result { get; set; } + } + + public partial class HelloWithReturnResponse + { + public virtual string Result { get; set; } + } + + public partial class Poco + { + public virtual string Name { get; set; } + } + + public partial class SubType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } +} + diff --git a/tests/CheckMvc/TypeScript.dtos.d.ts b/tests/CheckMvc/TypeScript.dtos.d.ts new file mode 100644 index 00000000000..44d7470ae15 --- /dev/null +++ b/tests/CheckMvc/TypeScript.dtos.d.ts @@ -0,0 +1,2420 @@ +/* Options: +Date: 2017-11-22 18:17:56 +Version: 5.00 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:55799 + +GlobalNamespace: dtos +//MakePropertiesOptional: True +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ + + +declare module dtos +{ + + interface IReturn + { + } + + interface IReturnVoid + { + } + + interface IMeta + { + meta?: { [index:string]: string; }; + } + + interface IGet + { + } + + interface IPost + { + } + + interface IPut + { + } + + interface IDelete + { + } + + interface IPatch + { + } + + interface IHasSessionId + { + sessionId?: string; + } + + interface IHasVersion + { + version?: number; + } + + interface QueryBase + { + // @DataMember(Order=1) + skip?: number; + + // @DataMember(Order=2) + take?: number; + + // @DataMember(Order=3) + orderBy?: string; + + // @DataMember(Order=4) + orderByDesc?: string; + + // @DataMember(Order=5) + include?: string; + + // @DataMember(Order=6) + fields?: string; + + // @DataMember(Order=7) + meta?: { [index:string]: string; }; + } + + interface QueryData extends QueryBase + { + } + + interface RequestLogEntry + { + id?: number; + dateTime?: string; + statusCode?: number; + statusDescription?: string; + httpMethod?: string; + absoluteUri?: string; + pathInfo?: string; + requestBody?: string; + requestDto?: Object; + userAuthId?: string; + sessionId?: string; + ipAddress?: string; + forwardedFor?: string; + referer?: string; + headers?: { [index:string]: string; }; + formData?: { [index:string]: string; }; + items?: { [index:string]: string; }; + session?: Object; + responseDto?: Object; + errorResponse?: Object; + exceptionSource?: string; + exceptionData?: any; + requestDuration?: string; + } + + // @DataContract + interface ResponseError + { + // @DataMember(Order=1, EmitDefaultValue=false) + errorCode?: string; + + // @DataMember(Order=2, EmitDefaultValue=false) + fieldName?: string; + + // @DataMember(Order=3, EmitDefaultValue=false) + message?: string; + + // @DataMember(Order=4, EmitDefaultValue=false) + meta?: { [index:string]: string; }; + } + + // @DataContract + interface ResponseStatus + { + // @DataMember(Order=1) + errorCode?: string; + + // @DataMember(Order=2) + message?: string; + + // @DataMember(Order=3) + stackTrace?: string; + + // @DataMember(Order=4) + errors?: ResponseError[]; + + // @DataMember(Order=5) + meta?: { [index:string]: string; }; + } + + interface QueryDb_1 extends QueryBase + { + } + + interface Rockstar + { + /** + * Идентификатор + */ + id?: number; + /** + * Фамилия + */ + firstName?: string; + /** + * Имя + */ + lastName?: string; + /** + * Возраст + */ + age?: number; + } + + interface ObjectDesign + { + id?: number; + } + + interface MetadataTestNestedChild + { + name?: string; + } + + interface MetadataTestChild + { + name?: string; + results?: MetadataTestNestedChild[]; + } + + interface MenuItemExampleItem + { + // @DataMember(Order=1) + // @ApiMember() + name1?: string; + } + + interface MenuItemExample + { + // @DataMember(Order=1) + // @ApiMember() + name1?: string; + + menuItemExampleItem?: MenuItemExampleItem; + } + + // @DataContract + interface MenuExample + { + // @DataMember(Order=1) + // @ApiMember() + menuItemExample1?: MenuItemExample; + } + + interface MetadataTypeName + { + name?: string; + namespace?: string; + genericArgs?: string[]; + } + + interface MetadataRoute + { + path?: string; + verbs?: string; + notes?: string; + summary?: string; + } + + interface MetadataDataContract + { + name?: string; + namespace?: string; + } + + interface MetadataDataMember + { + name?: string; + order?: number; + isRequired?: boolean; + emitDefaultValue?: boolean; + } + + interface MetadataAttribute + { + name?: string; + constructorArgs?: MetadataPropertyType[]; + args?: MetadataPropertyType[]; + } + + interface MetadataPropertyType + { + name?: string; + type?: string; + isValueType?: boolean; + isSystemType?: boolean; + isEnum?: boolean; + typeNamespace?: string; + genericArgs?: string[]; + value?: string; + description?: string; + dataMember?: MetadataDataMember; + readOnly?: boolean; + paramType?: string; + displayType?: string; + isRequired?: boolean; + allowableValues?: string[]; + allowableMin?: number; + allowableMax?: number; + attributes?: MetadataAttribute[]; + } + + interface MetadataType + { + name?: string; + namespace?: string; + genericArgs?: string[]; + inherits?: MetadataTypeName; + implements?: MetadataTypeName[]; + displayType?: string; + description?: string; + returnVoidMarker?: boolean; + isNested?: boolean; + isEnum?: boolean; + isEnumInt?: boolean; + isInterface?: boolean; + isAbstract?: boolean; + returnMarkerTypeName?: MetadataTypeName; + routes?: MetadataRoute[]; + dataContract?: MetadataDataContract; + properties?: MetadataPropertyType[]; + attributes?: MetadataAttribute[]; + innerTypes?: MetadataTypeName[]; + enumNames?: string[]; + enumValues?: string[]; + meta?: { [index:string]: string; }; + } + + interface AutoQueryConvention + { + name?: string; + value?: string; + types?: string; + } + + interface AutoQueryViewerConfig + { + serviceBaseUrl?: string; + serviceName?: string; + serviceDescription?: string; + serviceIconUrl?: string; + formats?: string[]; + maxLimit?: number; + isPublic?: boolean; + onlyShowAnnotatedServices?: boolean; + implicitConventions?: AutoQueryConvention[]; + defaultSearchField?: string; + defaultSearchType?: string; + defaultSearchText?: string; + brandUrl?: string; + brandImageUrl?: string; + textColor?: string; + linkColor?: string; + backgroundColor?: string; + backgroundImageUrl?: string; + iconUrl?: string; + meta?: { [index:string]: string; }; + } + + interface AutoQueryViewerUserInfo + { + isAuthenticated?: boolean; + queryCount?: number; + meta?: { [index:string]: string; }; + } + + interface AutoQueryOperation + { + request?: string; + from?: string; + to?: string; + meta?: { [index:string]: string; }; + } + + interface NativeTypesTestService + { + } + + interface NestedClass + { + value?: string; + } + + interface ListResult + { + result?: string; + } + + interface OnlyInReturnListArg + { + result?: string; + } + + interface ArrayResult + { + result?: string; + } + + type EnumType = "Value1" | "Value2"; + + type EnumWithValues = "Value1" | "Value2"; + + // @Flags() + enum EnumFlags + { + Value1 = 1, + Value2 = 2, + Value3 = 4, + } + + interface Poco + { + name?: string; + } + + interface AllCollectionTypes + { + intArray?: number[]; + intList?: number[]; + stringArray?: string[]; + stringList?: string[]; + pocoArray?: Poco[]; + pocoList?: Poco[]; + nullableByteArray?: Uint8Array; + nullableByteList?: number[]; + nullableDateTimeArray?: string[]; + nullableDateTimeList?: string[]; + pocoLookup?: { [index:string]: Poco[]; }; + pocoLookupMap?: { [index:string]: { [index:string]: Poco; }[]; }; + } + + interface KeyValuePair + { + key?: TKey; + value?: TValue; + } + + interface SubType + { + id?: number; + name?: string; + } + + interface HelloBase + { + id?: number; + } + + interface HelloResponseBase + { + refId?: number; + } + + interface HelloBase_1 + { + items?: T[]; + counts?: number[]; + } + + interface Item + { + value?: string; + } + + interface InheritedItem + { + name?: string; + } + + interface HelloWithReturnResponse + { + result?: string; + } + + interface HelloType + { + result?: string; + } + + interface IAuthTokens + { + provider?: string; + userId?: string; + accessToken?: string; + accessTokenSecret?: string; + refreshToken?: string; + refreshTokenExpiry?: string; + requestToken?: string; + requestTokenSecret?: string; + items?: { [index:string]: string; }; + } + + // @DataContract + interface AuthUserSession + { + // @DataMember(Order=1) + referrerUrl?: string; + + // @DataMember(Order=2) + id?: string; + + // @DataMember(Order=3) + userAuthId?: string; + + // @DataMember(Order=4) + userAuthName?: string; + + // @DataMember(Order=5) + userName?: string; + + // @DataMember(Order=6) + twitterUserId?: string; + + // @DataMember(Order=7) + twitterScreenName?: string; + + // @DataMember(Order=8) + facebookUserId?: string; + + // @DataMember(Order=9) + facebookUserName?: string; + + // @DataMember(Order=10) + firstName?: string; + + // @DataMember(Order=11) + lastName?: string; + + // @DataMember(Order=12) + displayName?: string; + + // @DataMember(Order=13) + company?: string; + + // @DataMember(Order=14) + email?: string; + + // @DataMember(Order=15) + primaryEmail?: string; + + // @DataMember(Order=16) + phoneNumber?: string; + + // @DataMember(Order=17) + birthDate?: string; + + // @DataMember(Order=18) + birthDateRaw?: string; + + // @DataMember(Order=19) + address?: string; + + // @DataMember(Order=20) + address2?: string; + + // @DataMember(Order=21) + city?: string; + + // @DataMember(Order=22) + state?: string; + + // @DataMember(Order=23) + country?: string; + + // @DataMember(Order=24) + culture?: string; + + // @DataMember(Order=25) + fullName?: string; + + // @DataMember(Order=26) + gender?: string; + + // @DataMember(Order=27) + language?: string; + + // @DataMember(Order=28) + mailAddress?: string; + + // @DataMember(Order=29) + nickname?: string; + + // @DataMember(Order=30) + postalCode?: string; + + // @DataMember(Order=31) + timeZone?: string; + + // @DataMember(Order=32) + requestTokenSecret?: string; + + // @DataMember(Order=33) + createdAt?: string; + + // @DataMember(Order=34) + lastModified?: string; + + // @DataMember(Order=35) + roles?: string[]; + + // @DataMember(Order=36) + permissions?: string[]; + + // @DataMember(Order=37) + isAuthenticated?: boolean; + + // @DataMember(Order=38) + fromToken?: boolean; + + // @DataMember(Order=39) + profileUrl?: string; + + // @DataMember(Order=40) + sequence?: string; + + // @DataMember(Order=41) + tag?: number; + + // @DataMember(Order=42) + authProvider?: string; + + // @DataMember(Order=43) + providerOAuthAccess?: IAuthTokens[]; + + // @DataMember(Order=44) + meta?: { [index:string]: string; }; + } + + interface IPoco + { + name?: string; + } + + interface IEmptyInterface + { + } + + interface EmptyClass + { + } + + interface ImplementsPoco + { + name?: string; + } + + interface TypeB + { + foo?: string; + } + + interface TypeA + { + bar?: TypeB[]; + } + + interface InnerType + { + id?: number; + name?: string; + } + + type InnerEnum = "Foo" | "Bar" | "Baz"; + + interface InnerTypeItem + { + id?: number; + name?: string; + } + + type DayOfWeek = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday"; + + // @DataContract + type ScopeType = "Global" | "Sale"; + + interface Tuple_2 + { + item1?: T1; + item2?: T2; + } + + interface Tuple_3 + { + item1?: T1; + item2?: T2; + item3?: T3; + } + + interface IEcho + { + sentence?: string; + } + + type MyColor = "Red" | "Green" | "Blue"; + + interface SwaggerNestedModel + { + /** + * NestedProperty description + */ + // @ApiMember(Description="NestedProperty description") + nestedProperty?: boolean; + } + + interface SwaggerNestedModel2 + { + /** + * NestedProperty2 description + */ + // @ApiMember(Description="NestedProperty2 description") + nestedProperty2?: boolean; + + /** + * MultipleValues description + */ + // @ApiMember(Description="MultipleValues description") + multipleValues?: string; + + /** + * TestRange description + */ + // @ApiMember(Description="TestRange description") + testRange?: number; + } + + type MyEnum = "A" | "B" | "C"; + + // @DataContract + interface UserApiKey + { + // @DataMember(Order=1) + key?: string; + + // @DataMember(Order=2) + keyType?: string; + + // @DataMember(Order=3) + expiryDate?: string; + } + + interface PgRockstar extends Rockstar + { + } + + interface QueryDb_2 extends QueryBase + { + } + + interface CustomRockstar + { + // @AutoQueryViewerField(Title="Name") + firstName?: string; + + // @AutoQueryViewerField(HideInSummary=true) + lastName?: string; + + age?: number; + // @AutoQueryViewerField(Title="Album") + rockstarAlbumName?: string; + + // @AutoQueryViewerField(Title="Genre") + rockstarGenreName?: string; + } + + interface IFilterRockstars + { + } + + interface Movie + { + id?: number; + imdbId?: string; + title?: string; + rating?: string; + score?: number; + director?: string; + releaseDate?: string; + tagLine?: string; + genres?: string[]; + } + + interface RockstarAlbum + { + id?: number; + rockstarId?: number; + name?: string; + } + + interface RockstarReference + { + id?: number; + firstName?: string; + lastName?: string; + age?: number; + albums?: RockstarAlbum[]; + } + + interface OnlyDefinedInGenericType + { + id?: number; + name?: string; + } + + interface OnlyDefinedInGenericTypeFrom + { + id?: number; + name?: string; + } + + interface OnlyDefinedInGenericTypeInto + { + id?: number; + name?: string; + } + + interface TypesGroup + { + } + + // @DataContract + interface QueryResponse + { + // @DataMember(Order=1) + offset?: number; + + // @DataMember(Order=2) + total?: number; + + // @DataMember(Order=3) + results?: T[]; + + // @DataMember(Order=4) + meta?: { [index:string]: string; }; + + // @DataMember(Order=5) + responseStatus?: ResponseStatus; + } + + // @DataContract + interface UpdateEventSubscriberResponse + { + // @DataMember(Order=1) + responseStatus?: ResponseStatus; + } + + interface ChangeRequestResponse + { + contentType?: string; + header?: string; + queryString?: string; + form?: string; + responseStatus?: ResponseStatus; + } + + interface CustomHttpErrorResponse + { + custom?: string; + responseStatus?: ResponseStatus; + } + + // @Route("/alwaysthrows") + interface AlwaysThrows extends IReturn + { + } + + // @Route("/alwaysthrowsfilterattribute") + interface AlwaysThrowsFilterAttribute extends IReturn + { + } + + // @Route("/alwaysthrowsglobalfilter") + interface AlwaysThrowsGlobalFilter extends IReturn + { + } + + interface CustomFieldHttpErrorResponse + { + custom?: string; + responseStatus?: ResponseStatus; + } + + interface NoRepeatResponse + { + id?: string; + } + + interface BatchThrowsResponse + { + result?: string; + responseStatus?: ResponseStatus; + } + + interface ObjectDesignResponse + { + data?: ObjectDesign; + } + + interface MetadataTestResponse + { + id?: number; + results?: MetadataTestChild[]; + } + + // @DataContract + interface GetExampleResponse + { + // @DataMember(Order=1) + responseStatus?: ResponseStatus; + + // @DataMember(Order=2) + // @ApiMember() + menuExample1?: MenuExample; + } + + interface AutoQueryMetadataResponse + { + config?: AutoQueryViewerConfig; + userInfo?: AutoQueryViewerUserInfo; + operations?: AutoQueryOperation[]; + types?: MetadataType[]; + responseStatus?: ResponseStatus; + meta?: { [index:string]: string; }; + } + + // @DataContract + interface HelloACodeGenTestResponse + { + /** + * Description for FirstResult + */ + // @DataMember + firstResult?: number; + + /** + * Description for SecondResult + */ + // @DataMember + // @ApiMember(Description="Description for SecondResult") + secondResult?: number; + } + + interface HelloResponse + { + result?: string; + } + + /** + * Description on HelloAllResponse type + */ + // @DataContract + interface HelloAnnotatedResponse + { + // @DataMember + result?: string; + } + + interface HelloList extends IReturn> + { + names?: string[]; + } + + interface HelloArray extends IReturn> + { + names?: string[]; + } + + interface HelloExistingResponse + { + helloList?: HelloList; + helloArray?: HelloArray; + arrayResults?: ArrayResult[]; + listResults?: ListResult[]; + } + + interface AllTypes extends IReturn + { + id?: number; + nullableId?: number; + byte?: number; + short?: number; + int?: number; + long?: number; + uShort?: number; + uInt?: number; + uLong?: number; + float?: number; + double?: number; + decimal?: number; + string?: string; + dateTime?: string; + timeSpan?: string; + dateTimeOffset?: string; + guid?: string; + char?: string; + keyValuePair?: KeyValuePair; + nullableDateTime?: string; + nullableTimeSpan?: string; + stringList?: string[]; + stringArray?: string[]; + stringMap?: { [index:string]: string; }; + intStringMap?: { [index:number]: string; }; + subType?: SubType; + point?: string; + // @DataMember(Name="aliasedName") + originalName?: string; + } + + interface HelloAllTypesResponse + { + result?: string; + allTypes?: AllTypes; + allCollectionTypes?: AllCollectionTypes; + } + + // @DataContract + interface HelloWithDataContractResponse + { + // @DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false) + result?: string; + } + + /** + * Description on HelloWithDescriptionResponse type + */ + interface HelloWithDescriptionResponse + { + result?: string; + } + + interface HelloWithInheritanceResponse extends HelloResponseBase + { + result?: string; + } + + interface HelloWithAlternateReturnResponse extends HelloWithReturnResponse + { + altResult?: string; + } + + interface HelloWithRouteResponse + { + result?: string; + } + + interface HelloWithTypeResponse + { + result?: HelloType; + } + + interface HelloStruct extends IReturn + { + point?: string; + nullablePoint?: string; + } + + interface HelloSessionResponse + { + result?: AuthUserSession; + } + + interface HelloImplementsInterface extends IReturn, ImplementsPoco + { + name?: string; + } + + interface Request1Response + { + test?: TypeA; + } + + interface Request2Response + { + test?: TypeA; + } + + interface HelloInnerTypesResponse + { + innerType?: InnerType; + innerEnum?: InnerEnum; + innerList?: InnerTypeItem[]; + } + + interface CustomUserSession extends AuthUserSession + { + // @DataMember + customName?: string; + + // @DataMember + customInfo?: string; + } + + // @DataContract + interface QueryResponseTemplate + { + // @DataMember(Order=1) + offset?: number; + + // @DataMember(Order=2) + total?: number; + + // @DataMember(Order=3) + results?: T[]; + + // @DataMember(Order=4) + meta?: { [index:string]: string; }; + + // @DataMember(Order=5) + responseStatus?: ResponseStatus; + } + + interface HelloVerbResponse + { + result?: string; + } + + interface EnumResponse + { + operator?: ScopeType; + } + + interface ExcludeTestNested + { + id?: number; + } + + interface RestrictLocalhost extends IReturn + { + id?: number; + } + + interface RestrictInternal extends IReturn + { + id?: number; + } + + interface HelloTuple extends IReturn + { + tuple2?: Tuple_2; + tuple3?: Tuple_3; + tuples2?: Tuple_2[]; + tuples3?: Tuple_3[]; + } + + interface HelloAuthenticatedResponse + { + version?: number; + sessionId?: string; + userName?: string; + email?: string; + isAuthenticated?: boolean; + responseStatus?: ResponseStatus; + } + + interface Echo + { + sentence?: string; + } + + interface ThrowHttpErrorResponse + { + } + + interface ThrowTypeResponse + { + responseStatus?: ResponseStatus; + } + + interface ThrowValidationResponse + { + age?: number; + required?: string; + email?: string; + responseStatus?: ResponseStatus; + } + + interface acsprofileResponse + { + profileId?: string; + } + + interface ReturnedDto + { + id?: number; + } + + // @Route("/matchroute/html") + interface MatchesHtml extends IReturn + { + name?: string; + } + + // @Route("/matchroute/json") + interface MatchesJson extends IReturn + { + name?: string; + } + + interface TimestampData + { + timestamp?: number; + } + + // @Route("/test/html") + interface TestHtml extends IReturn + { + name?: string; + } + + interface SwaggerComplexResponse + { + // @DataMember + // @ApiMember() + isRequired?: boolean; + + // @DataMember + // @ApiMember(IsRequired=true) + arrayString?: string[]; + + // @DataMember + // @ApiMember() + arrayInt?: number[]; + + // @DataMember + // @ApiMember() + listString?: string[]; + + // @DataMember + // @ApiMember() + listInt?: number[]; + + // @DataMember + // @ApiMember() + dictionaryString?: { [index:string]: string; }; + } + + /** + * Api GET All + */ + // @Route("/swaggerexamples", "GET") + // @Api(Description="Api GET All") + interface GetSwaggerExamples extends IReturn + { + get?: string; + } + + /** + * Api GET Id + */ + // @Route("/swaggerexamples/{Id}", "GET") + // @Api(Description="Api GET Id") + interface GetSwaggerExample extends IReturn + { + id?: number; + get?: string; + } + + /** + * Api POST + */ + // @Route("/swaggerexamples", "POST") + // @Api(Description="Api POST") + interface PostSwaggerExamples extends IReturn + { + post?: string; + } + + /** + * Api PUT Id + */ + // @Route("/swaggerexamples/{Id}", "PUT") + // @Api(Description="Api PUT Id") + interface PutSwaggerExample extends IReturn + { + id?: number; + get?: string; + } + + // @Route("/lists", "GET") + interface GetLists extends IReturn + { + id?: string; + } + + // @DataContract + interface AuthenticateResponse + { + // @DataMember(Order=1) + userId?: string; + + // @DataMember(Order=2) + sessionId?: string; + + // @DataMember(Order=3) + userName?: string; + + // @DataMember(Order=4) + displayName?: string; + + // @DataMember(Order=5) + referrerUrl?: string; + + // @DataMember(Order=6) + bearerToken?: string; + + // @DataMember(Order=7) + refreshToken?: string; + + // @DataMember(Order=8) + responseStatus?: ResponseStatus; + + // @DataMember(Order=9) + meta?: { [index:string]: string; }; + } + + // @DataContract + interface AssignRolesResponse + { + // @DataMember(Order=1) + allRoles?: string[]; + + // @DataMember(Order=2) + allPermissions?: string[]; + + // @DataMember(Order=3) + responseStatus?: ResponseStatus; + } + + // @DataContract + interface UnAssignRolesResponse + { + // @DataMember(Order=1) + allRoles?: string[]; + + // @DataMember(Order=2) + allPermissions?: string[]; + + // @DataMember(Order=3) + responseStatus?: ResponseStatus; + } + + // @DataContract + interface GetApiKeysResponse + { + // @DataMember(Order=1) + results?: UserApiKey[]; + + // @DataMember(Order=2) + responseStatus?: ResponseStatus; + } + + // @DataContract + interface RegisterResponse + { + // @DataMember(Order=1) + userId?: string; + + // @DataMember(Order=2) + sessionId?: string; + + // @DataMember(Order=3) + userName?: string; + + // @DataMember(Order=4) + referrerUrl?: string; + + // @DataMember(Order=5) + bearerToken?: string; + + // @DataMember(Order=6) + refreshToken?: string; + + // @DataMember(Order=7) + responseStatus?: ResponseStatus; + + // @DataMember(Order=8) + meta?: { [index:string]: string; }; + } + + // @Route("/anontype") + interface AnonType + { + } + + // @Route("/query/requestlogs") + // @Route("/query/requestlogs/{Date}") + interface QueryRequestLogs extends QueryData, IReturn>, IMeta + { + date?: string; + viewErrors?: boolean; + } + + interface TodayLogs extends QueryData, IReturn>, IMeta + { + } + + interface TodayErrorLogs extends QueryData, IReturn>, IMeta + { + } + + interface YesterdayLogs extends QueryData, IReturn>, IMeta + { + } + + interface YesterdayErrorLogs extends QueryData, IReturn>, IMeta + { + } + + // @Route("/query/rockstars") + interface QueryRockstars extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + interface GetEventSubscribers extends IReturn, IGet + { + channels?: string[]; + } + + // @Route("/event-subscribers/{Id}", "POST") + // @DataContract + interface UpdateEventSubscriber extends IReturn, IPost + { + // @DataMember(Order=1) + id?: string; + + // @DataMember(Order=2) + subscribeChannels?: string[]; + + // @DataMember(Order=3) + unsubscribeChannels?: string[]; + } + + // @Route("/changerequest/{Id}") + interface ChangeRequest extends IReturn + { + id?: string; + } + + // @Route("/compress/{Path*}") + interface CompressFile + { + path?: string; + } + + // @Route("/Routing/LeadPost.aspx") + interface LegacyLeadPost + { + leadType?: string; + myId?: number; + } + + // @Route("/info/{Id}") + interface Info + { + id?: string; + } + + interface CustomHttpError extends IReturn + { + statusCode?: number; + statusDescription?: string; + } + + interface CustomFieldHttpError extends IReturn + { + } + + interface FallbackRoute + { + pathInfo?: string; + } + + interface NoRepeat extends IReturn + { + id?: string; + } + + interface BatchThrows extends IReturn + { + id?: number; + name?: string; + } + + interface BatchThrowsAsync extends IReturn + { + id?: number; + name?: string; + } + + // @Route("/code/object", "GET") + interface ObjectId extends IReturn + { + objectName?: string; + } + + interface MetadataTest extends IReturn + { + id?: number; + } + + // @Route("/example", "GET") + // @DataContract + interface GetExample extends IReturn + { + } + + interface MetadataRequest extends IReturn + { + metadataType?: MetadataType; + } + + interface ExcludeMetadataProperty + { + id?: number; + } + + // @Route("/namedconnection") + interface NamedConnection + { + emailAddresses?: string; + } + + /** + * Description for HelloACodeGenTest + */ + interface HelloACodeGenTest extends IReturn + { + /** + * Description for FirstField + */ + firstField?: number; + secondFields?: string[]; + } + + interface HelloInService extends IReturn + { + name?: string; + } + + // @Route("/hello") + // @Route("/hello/{Name}") + interface Hello extends IReturn + { + // @Required() + name: string; + + title?: string; + } + + /** + * Description on HelloAll type + */ + // @DataContract + interface HelloAnnotated extends IReturn + { + // @DataMember + name?: string; + } + + interface HelloWithNestedClass extends IReturn + { + name?: string; + nestedClassProp?: NestedClass; + } + + interface HelloReturnList extends IReturn> + { + names?: string[]; + } + + interface HelloExisting extends IReturn + { + names?: string[]; + } + + interface HelloWithEnum + { + enumProp?: EnumType; + enumWithValues?: EnumWithValues; + nullableEnumProp?: EnumType; + enumFlags?: EnumFlags; + } + + interface RestrictedAttributes + { + id?: number; + name?: string; + hello?: Hello; + } + + /** + * AllowedAttributes Description + */ + // @Route("/allowed-attributes", "GET") + // @Api(Description="AllowedAttributes Description") + // @ApiResponse(Description="Your request was not understood", StatusCode=400) + // @DataContract + interface AllowedAttributes + { + // @DataMember + // @Required() + id: number; + + /** + * Range Description + */ + // @DataMember(Name="Aliased") + // @ApiMember(DataType="double", Description="Range Description", IsRequired=true, ParameterType="path") + range?: number; + } + + /** + * Multi Line Class + */ + // @Api(Description="Multi Line Class") + interface HelloMultiline + { + /** + * Multi Line Property + */ + // @ApiMember(Description="Multi Line Property") + overflow?: string; + } + + interface HelloAllTypes extends IReturn + { + name?: string; + allTypes?: AllTypes; + allCollectionTypes?: AllCollectionTypes; + } + + interface HelloString extends IReturn + { + name?: string; + } + + interface HelloVoid extends IReturnVoid + { + name?: string; + } + + // @DataContract + interface HelloWithDataContract extends IReturn + { + // @DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false) + name?: string; + + // @DataMember(Name="id", Order=2, EmitDefaultValue=false) + id?: number; + } + + /** + * Description on HelloWithDescription type + */ + interface HelloWithDescription extends IReturn + { + name?: string; + } + + interface HelloWithInheritance extends HelloBase, IReturn + { + name?: string; + } + + interface HelloWithGenericInheritance extends HelloBase_1 + { + result?: string; + } + + interface HelloWithGenericInheritance2 extends HelloBase_1 + { + result?: string; + } + + interface HelloWithNestedInheritance extends HelloBase_1 + { + } + + interface HelloWithListInheritance extends Array + { + } + + interface HelloWithReturn extends IReturn + { + name?: string; + } + + // @Route("/helloroute") + interface HelloWithRoute extends IReturn + { + name?: string; + } + + interface HelloWithType extends IReturn + { + name?: string; + } + + interface HelloSession extends IReturn + { + } + + interface HelloInterface + { + poco?: IPoco; + emptyInterface?: IEmptyInterface; + emptyClass?: EmptyClass; + value?: string; + } + + interface Request1 extends IReturn + { + test?: TypeA; + } + + interface Request2 extends IReturn + { + test?: TypeA; + } + + interface HelloInnerTypes extends IReturn + { + } + + interface GetUserSession extends IReturn + { + } + + interface QueryTemplate extends IReturn> + { + } + + interface HelloReserved + { + class?: string; + type?: string; + extension?: string; + } + + interface HelloDictionary extends IReturn + { + key?: string; + value?: string; + } + + interface HelloBuiltin + { + dayOfWeek?: DayOfWeek; + } + + interface HelloGet extends IReturn, IGet + { + id?: number; + } + + interface HelloPost extends HelloBase, IReturn, IPost + { + } + + interface HelloPut extends IReturn, IPut + { + id?: number; + } + + interface HelloDelete extends IReturn, IDelete + { + id?: number; + } + + interface HelloPatch extends IReturn, IPatch + { + id?: number; + } + + interface HelloReturnVoid extends IReturnVoid + { + id?: number; + } + + interface EnumRequest extends IReturn, IPut + { + operator?: ScopeType; + } + + interface ExcludeTest1 extends IReturn + { + } + + interface ExcludeTest2 extends IReturn + { + excludeTestNested?: ExcludeTestNested; + } + + interface HelloAuthenticated extends IReturn, IHasSessionId + { + sessionId?: string; + version?: number; + } + + /** + * Echoes a sentence + */ + // @Route("/echoes", "POST") + // @Api(Description="Echoes a sentence") + interface Echoes extends IReturn + { + /** + * The sentence to echo. + */ + // @ApiMember(DataType="string", Description="The sentence to echo.", IsRequired=true, Name="Sentence", ParameterType="form") + sentence?: string; + } + + interface CachedEcho extends IReturn + { + reload?: boolean; + sentence?: string; + } + + interface AsyncTest extends IReturn + { + } + + // @Route("/throwhttperror/{Status}") + interface ThrowHttpError extends IReturn + { + status?: number; + message?: string; + } + + // @Route("/throw404") + // @Route("/throw404/{Message}") + interface Throw404 + { + message?: string; + } + + // @Route("/return404") + interface Return404 + { + } + + // @Route("/return404result") + interface Return404Result + { + } + + // @Route("/throw/{Type}") + interface ThrowType extends IReturn + { + type?: string; + message?: string; + } + + // @Route("/throwvalidation") + interface ThrowValidation extends IReturn + { + age?: number; + required?: string; + email?: string; + } + + // @Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE") + // @Route("/api/acsprofiles/{profileId}") + interface ACSProfile extends IReturn, IHasVersion, IHasSessionId + { + profileId?: string; + // @Required() + // @StringLength(20) + shortName: string; + + // @StringLength(60) + longName?: string; + + // @StringLength(20) + regionId?: string; + + // @StringLength(20) + groupId?: string; + + // @StringLength(12) + deviceID?: string; + + lastUpdated?: string; + enabled?: boolean; + version?: number; + sessionId?: string; + } + + // @Route("/return/string") + interface ReturnString extends IReturn + { + data?: string; + } + + // @Route("/return/bytes") + interface ReturnBytes extends IReturn + { + data?: Uint8Array; + } + + // @Route("/return/stream") + interface ReturnStream extends IReturn + { + data?: Uint8Array; + } + + // @Route("/Request1/", "GET") + interface GetRequest1 extends IReturn>, IGet + { + } + + // @Route("/Request3", "GET") + interface GetRequest2 extends IReturn, IGet + { + } + + // @Route("/matchlast/{Id}") + interface MatchesLastInt + { + id?: number; + } + + // @Route("/matchlast/{Slug}") + interface MatchesNotLastInt + { + slug?: string; + } + + // @Route("/matchregex/{Id}") + interface MatchesId + { + id?: number; + } + + // @Route("/matchregex/{Slug}") + interface MatchesSlug + { + slug?: string; + } + + // @Route("/{Version}/userdata", "GET") + interface SwaggerVersionTest + { + version?: string; + } + + // @Route("/test/errorview") + interface TestErrorView + { + id?: string; + } + + // @Route("/timestamp", "GET") + interface GetTimestamp extends IReturn + { + } + + interface TestMiniverView + { + } + + // @Route("/testexecproc") + interface TestExecProc + { + } + + // @Route("/files/{Path*}") + interface GetFile + { + path?: string; + } + + // @Route("/test/html2") + interface TestHtml2 + { + name?: string; + } + + // @Route("/views/request") + interface ViewRequest + { + name?: string; + } + + // @Route("/index") + interface IndexPage + { + pathInfo?: string; + } + + // @Route("/return/text") + interface ReturnText + { + text?: string; + } + + /** + * SwaggerTest Service Description + */ + // @Route("/swagger", "GET") + // @Route("/swagger/{Name}", "GET") + // @Route("/swagger/{Name}", "POST") + // @Api(Description="SwaggerTest Service Description") + // @ApiResponse(Description="Your request was not understood", StatusCode=400) + // @ApiResponse(Description="Oops, something broke", StatusCode=500) + // @DataContract + interface SwaggerTest + { + /** + * Color Description + */ + // @DataMember + // @ApiMember(DataType="string", Description="Color Description", IsRequired=true, ParameterType="path") + name?: string; + + // @DataMember + // @ApiMember() + color?: MyColor; + + /** + * Aliased Description + */ + // @DataMember(Name="Aliased") + // @ApiMember(DataType="string", Description="Aliased Description", IsRequired=true) + original?: string; + + /** + * Not Aliased Description + */ + // @DataMember + // @ApiMember(DataType="string", Description="Not Aliased Description", IsRequired=true) + notAliased?: string; + + /** + * Format as password + */ + // @DataMember + // @ApiMember(DataType="password", Description="Format as password") + password?: string; + + // @DataMember + // @ApiMember(AllowMultiple=true) + myDateBetween?: string[]; + + /** + * Nested model 1 + */ + // @DataMember + // @ApiMember(DataType="SwaggerNestedModel", Description="Nested model 1") + nestedModel1?: SwaggerNestedModel; + + /** + * Nested model 2 + */ + // @DataMember + // @ApiMember(DataType="SwaggerNestedModel2", Description="Nested model 2") + nestedModel2?: SwaggerNestedModel2; + } + + // @Route("/swaggertest2", "POST") + interface SwaggerTest2 + { + // @ApiMember() + myEnumProperty?: MyEnum; + + // @ApiMember(DataType="string", IsRequired=true, Name="Token", ParameterType="header") + token?: string; + } + + // @Route("/swagger-complex", "POST") + interface SwaggerComplex extends IReturn + { + // @DataMember + // @ApiMember() + isRequired?: boolean; + + // @DataMember + // @ApiMember(IsRequired=true) + arrayString?: string[]; + + // @DataMember + // @ApiMember() + arrayInt?: number[]; + + // @DataMember + // @ApiMember() + listString?: string[]; + + // @DataMember + // @ApiMember() + listInt?: number[]; + + // @DataMember + // @ApiMember() + dictionaryString?: { [index:string]: string; }; + } + + // @Route("/swaggerpost/{Required1}", "GET") + // @Route("/swaggerpost/{Required1}/{Optional1}", "GET") + // @Route("/swaggerpost", "POST") + interface SwaggerPostTest extends IReturn + { + // @ApiMember(Verb="POST") + // @ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}", Verb="GET") + // @ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET") + required1?: string; + + // @ApiMember(Verb="POST") + // @ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET") + optional1?: string; + } + + // @Route("/swaggerpost2/{Required1}/{Required2}", "GET") + // @Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", "GET") + // @Route("/swaggerpost2", "POST") + interface SwaggerPostTest2 extends IReturn + { + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET") + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET") + required1?: string; + + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET") + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET") + required2?: string; + + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET") + optional1?: string; + } + + // @Route("/swagger/multiattrtest", "POST") + // @ApiResponse(Description="Code 1", StatusCode=400) + // @ApiResponse(Description="Code 2", StatusCode=402) + // @ApiResponse(Description="Code 3", StatusCode=401) + interface SwaggerMultiApiResponseTest extends IReturnVoid + { + } + + // @Route("/dynamically/registered/{Name}") + interface DynamicallyRegistered + { + name?: string; + } + + // @Route("/auth") + // @Route("/auth/{provider}") + // @Route("/authenticate") + // @Route("/authenticate/{provider}") + // @DataContract + interface Authenticate extends IReturn, IPost, IMeta + { + // @DataMember(Order=1) + provider?: string; + + // @DataMember(Order=2) + state?: string; + + // @DataMember(Order=3) + oauth_token?: string; + + // @DataMember(Order=4) + oauth_verifier?: string; + + // @DataMember(Order=5) + userName?: string; + + // @DataMember(Order=6) + password?: string; + + // @DataMember(Order=7) + rememberMe?: boolean; + + // @DataMember(Order=8) + continue?: string; + + // @DataMember(Order=9) + nonce?: string; + + // @DataMember(Order=10) + uri?: string; + + // @DataMember(Order=11) + response?: string; + + // @DataMember(Order=12) + qop?: string; + + // @DataMember(Order=13) + nc?: string; + + // @DataMember(Order=14) + cnonce?: string; + + // @DataMember(Order=15) + useTokenCookie?: boolean; + + // @DataMember(Order=16) + accessToken?: string; + + // @DataMember(Order=17) + accessTokenSecret?: string; + + // @DataMember(Order=18) + meta?: { [index:string]: string; }; + } + + // @Route("/assignroles") + // @DataContract + interface AssignRoles extends IReturn, IPost + { + // @DataMember(Order=1) + userName?: string; + + // @DataMember(Order=2) + permissions?: string[]; + + // @DataMember(Order=3) + roles?: string[]; + } + + // @Route("/unassignroles") + // @DataContract + interface UnAssignRoles extends IReturn, IPost + { + // @DataMember(Order=1) + userName?: string; + + // @DataMember(Order=2) + permissions?: string[]; + + // @DataMember(Order=3) + roles?: string[]; + } + + // @Route("/apikeys") + // @Route("/apikeys/{Environment}") + // @DataContract + interface GetApiKeys extends IReturn, IGet + { + // @DataMember(Order=1) + environment?: string; + } + + // @Route("/apikeys/regenerate") + // @Route("/apikeys/regenerate/{Environment}") + // @DataContract + interface RegenerateApiKeys extends IReturn, IPost + { + // @DataMember(Order=1) + environment?: string; + } + + // @Route("/register") + // @DataContract + interface Register extends IReturn, IPost + { + // @DataMember(Order=1) + userName?: string; + + // @DataMember(Order=2) + firstName?: string; + + // @DataMember(Order=3) + lastName?: string; + + // @DataMember(Order=4) + displayName?: string; + + // @DataMember(Order=5) + email?: string; + + // @DataMember(Order=6) + password?: string; + + // @DataMember(Order=7) + autoLogin?: boolean; + + // @DataMember(Order=8) + continue?: string; + } + + // @Route("/pgsql/rockstars") + interface QueryPostgresRockstars extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + // @Route("/pgsql/pgrockstars") + interface QueryPostgresPgRockstars extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + interface QueryRockstarsConventions extends QueryDb_1, IReturn>, IMeta + { + ids?: number[]; + ageOlderThan?: number; + ageGreaterThanOrEqualTo?: number; + ageGreaterThan?: number; + greaterThanAge?: number; + firstNameStartsWith?: string; + lastNameEndsWith?: string; + lastNameContains?: string; + rockstarAlbumNameContains?: string; + rockstarIdAfter?: number; + rockstarIdOnOrAfter?: number; + } + + // @AutoQueryViewer(Description="Use this option to search for Rockstars!", Title="Search for Rockstars") + interface QueryCustomRockstars extends QueryDb_2, IReturn>, IMeta + { + age?: number; + } + + // @Route("/customrockstars") + interface QueryRockstarAlbums extends QueryDb_2, IReturn>, IMeta + { + age?: number; + rockstarAlbumName?: string; + } + + interface QueryRockstarAlbumsImplicit extends QueryDb_2, IReturn>, IMeta + { + } + + interface QueryRockstarAlbumsLeftJoin extends QueryDb_2, IReturn>, IMeta + { + age?: number; + albumName?: string; + } + + interface QueryOverridedRockstars extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + interface QueryOverridedCustomRockstars extends QueryDb_2, IReturn>, IMeta + { + age?: number; + } + + // @Route("/query-custom/rockstars") + interface QueryFieldRockstars extends QueryDb_1, IReturn>, IMeta + { + firstName?: string; + firstNames?: string[]; + age?: number; + firstNameCaseInsensitive?: string; + firstNameStartsWith?: string; + lastNameEndsWith?: string; + firstNameBetween?: string[]; + orLastName?: string; + firstNameContainsMulti?: string[]; + } + + interface QueryFieldRockstarsDynamic extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + interface QueryRockstarsFilter extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + interface QueryCustomRockstarsFilter extends QueryDb_2, IReturn>, IMeta + { + age?: number; + } + + interface QueryRockstarsIFilter extends QueryDb_1, IReturn>, IMeta, IFilterRockstars + { + age?: number; + } + + // @Route("/OrRockstars") + interface QueryOrRockstars extends QueryDb_1, IReturn>, IMeta + { + age?: number; + firstName?: string; + } + + interface QueryGetRockstars extends QueryDb_1, IReturn>, IMeta + { + ids?: number[]; + ages?: number[]; + firstNames?: string[]; + idsBetween?: number[]; + } + + interface QueryGetRockstarsDynamic extends QueryDb_1, IReturn>, IMeta + { + } + + // @Route("/movies/search") + interface SearchMovies extends QueryDb_1, IReturn>, IMeta + { + } + + // @Route("/movies") + interface QueryMovies extends QueryDb_1, IReturn>, IMeta + { + ids?: number[]; + imdbIds?: string[]; + ratings?: string[]; + } + + interface StreamMovies extends QueryDb_1, IReturn>, IMeta + { + ratings?: string[]; + } + + interface QueryUnknownRockstars extends QueryDb_1, IReturn>, IMeta + { + unknownInt?: number; + unknownProperty?: string; + } + + // @Route("/query/rockstar-references") + interface QueryRockstarsWithReferences extends QueryDb_1, IReturn>, IMeta + { + age?: number; + } + + interface QueryPocoBase extends QueryDb_1, IReturn>, IMeta + { + id?: number; + } + + interface QueryPocoIntoBase extends QueryDb_2, IReturn>, IMeta + { + id?: number; + } + + // @Route("/query/alltypes") + interface QueryAllTypes extends QueryDb_1, IReturn>, IMeta + { + } + + // @Route("/querydata/rockstars") + interface QueryDataRockstars extends QueryData, IReturn>, IMeta + { + age?: number; + } + +} diff --git a/tests/CheckMvc/TypeScript.dtos.js b/tests/CheckMvc/TypeScript.dtos.js new file mode 100644 index 00000000000..1504438b7f2 --- /dev/null +++ b/tests/CheckMvc/TypeScript.dtos.js @@ -0,0 +1,2731 @@ +"use strict"; +/* Options: +Date: 2019-02-11 10:08:04 +Version: 5.41 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:55799 + +//GlobalNamespace: +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var QueryBase = /** @class */ (function () { + function QueryBase(init) { + Object.assign(this, init); + } + return QueryBase; +}()); +exports.QueryBase = QueryBase; +var QueryData = /** @class */ (function (_super) { + __extends(QueryData, _super); + function QueryData(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return QueryData; +}(QueryBase)); +exports.QueryData = QueryData; +var RequestLogEntry = /** @class */ (function () { + function RequestLogEntry(init) { + Object.assign(this, init); + } + return RequestLogEntry; +}()); +exports.RequestLogEntry = RequestLogEntry; +// @DataContract +var ResponseError = /** @class */ (function () { + function ResponseError(init) { + Object.assign(this, init); + } + return ResponseError; +}()); +exports.ResponseError = ResponseError; +// @DataContract +var ResponseStatus = /** @class */ (function () { + function ResponseStatus(init) { + Object.assign(this, init); + } + return ResponseStatus; +}()); +exports.ResponseStatus = ResponseStatus; +var QueryDb_1 = /** @class */ (function (_super) { + __extends(QueryDb_1, _super); + function QueryDb_1(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return QueryDb_1; +}(QueryBase)); +exports.QueryDb_1 = QueryDb_1; +var Rockstar = /** @class */ (function () { + function Rockstar(init) { + Object.assign(this, init); + } + return Rockstar; +}()); +exports.Rockstar = Rockstar; +var ArrayElementInDictionary = /** @class */ (function () { + function ArrayElementInDictionary(init) { + Object.assign(this, init); + } + return ArrayElementInDictionary; +}()); +exports.ArrayElementInDictionary = ArrayElementInDictionary; +var ObjectDesign = /** @class */ (function () { + function ObjectDesign(init) { + Object.assign(this, init); + } + return ObjectDesign; +}()); +exports.ObjectDesign = ObjectDesign; +// @DataContract +var AuthUserSession = /** @class */ (function () { + function AuthUserSession(init) { + Object.assign(this, init); + } + return AuthUserSession; +}()); +exports.AuthUserSession = AuthUserSession; +var MetadataTestNestedChild = /** @class */ (function () { + function MetadataTestNestedChild(init) { + Object.assign(this, init); + } + return MetadataTestNestedChild; +}()); +exports.MetadataTestNestedChild = MetadataTestNestedChild; +var MetadataTestChild = /** @class */ (function () { + function MetadataTestChild(init) { + Object.assign(this, init); + } + return MetadataTestChild; +}()); +exports.MetadataTestChild = MetadataTestChild; +var MenuItemExampleItem = /** @class */ (function () { + function MenuItemExampleItem(init) { + Object.assign(this, init); + } + return MenuItemExampleItem; +}()); +exports.MenuItemExampleItem = MenuItemExampleItem; +var MenuItemExample = /** @class */ (function () { + function MenuItemExample(init) { + Object.assign(this, init); + } + return MenuItemExample; +}()); +exports.MenuItemExample = MenuItemExample; +// @DataContract +var MenuExample = /** @class */ (function () { + function MenuExample(init) { + Object.assign(this, init); + } + return MenuExample; +}()); +exports.MenuExample = MenuExample; +var MetadataTypeName = /** @class */ (function () { + function MetadataTypeName(init) { + Object.assign(this, init); + } + return MetadataTypeName; +}()); +exports.MetadataTypeName = MetadataTypeName; +var MetadataRoute = /** @class */ (function () { + function MetadataRoute(init) { + Object.assign(this, init); + } + return MetadataRoute; +}()); +exports.MetadataRoute = MetadataRoute; +var MetadataDataContract = /** @class */ (function () { + function MetadataDataContract(init) { + Object.assign(this, init); + } + return MetadataDataContract; +}()); +exports.MetadataDataContract = MetadataDataContract; +var MetadataDataMember = /** @class */ (function () { + function MetadataDataMember(init) { + Object.assign(this, init); + } + return MetadataDataMember; +}()); +exports.MetadataDataMember = MetadataDataMember; +var MetadataAttribute = /** @class */ (function () { + function MetadataAttribute(init) { + Object.assign(this, init); + } + return MetadataAttribute; +}()); +exports.MetadataAttribute = MetadataAttribute; +var MetadataPropertyType = /** @class */ (function () { + function MetadataPropertyType(init) { + Object.assign(this, init); + } + return MetadataPropertyType; +}()); +exports.MetadataPropertyType = MetadataPropertyType; +var MetadataType = /** @class */ (function () { + function MetadataType(init) { + Object.assign(this, init); + } + return MetadataType; +}()); +exports.MetadataType = MetadataType; +var AutoQueryConvention = /** @class */ (function () { + function AutoQueryConvention(init) { + Object.assign(this, init); + } + return AutoQueryConvention; +}()); +exports.AutoQueryConvention = AutoQueryConvention; +var AutoQueryViewerConfig = /** @class */ (function () { + function AutoQueryViewerConfig(init) { + Object.assign(this, init); + } + return AutoQueryViewerConfig; +}()); +exports.AutoQueryViewerConfig = AutoQueryViewerConfig; +var AutoQueryViewerUserInfo = /** @class */ (function () { + function AutoQueryViewerUserInfo(init) { + Object.assign(this, init); + } + return AutoQueryViewerUserInfo; +}()); +exports.AutoQueryViewerUserInfo = AutoQueryViewerUserInfo; +var AutoQueryOperation = /** @class */ (function () { + function AutoQueryOperation(init) { + Object.assign(this, init); + } + return AutoQueryOperation; +}()); +exports.AutoQueryOperation = AutoQueryOperation; +var RecursiveNode = /** @class */ (function () { + function RecursiveNode(init) { + Object.assign(this, init); + } + RecursiveNode.prototype.createResponse = function () { return new RecursiveNode(); }; + RecursiveNode.prototype.getTypeName = function () { return 'RecursiveNode'; }; + return RecursiveNode; +}()); +exports.RecursiveNode = RecursiveNode; +var NativeTypesTestService = /** @class */ (function () { + function NativeTypesTestService(init) { + Object.assign(this, init); + } + return NativeTypesTestService; +}()); +exports.NativeTypesTestService = NativeTypesTestService; +var NestedClass = /** @class */ (function () { + function NestedClass(init) { + Object.assign(this, init); + } + return NestedClass; +}()); +exports.NestedClass = NestedClass; +var ListResult = /** @class */ (function () { + function ListResult(init) { + Object.assign(this, init); + } + return ListResult; +}()); +exports.ListResult = ListResult; +var OnlyInReturnListArg = /** @class */ (function () { + function OnlyInReturnListArg(init) { + Object.assign(this, init); + } + return OnlyInReturnListArg; +}()); +exports.OnlyInReturnListArg = OnlyInReturnListArg; +var ArrayResult = /** @class */ (function () { + function ArrayResult(init) { + Object.assign(this, init); + } + return ArrayResult; +}()); +exports.ArrayResult = ArrayResult; +var EnumType; +(function (EnumType) { + EnumType["Value1"] = "Value1"; + EnumType["Value2"] = "Value2"; +})(EnumType = exports.EnumType || (exports.EnumType = {})); +var EnumWithValues; +(function (EnumWithValues) { + EnumWithValues["Value1"] = "1"; + EnumWithValues["Value2"] = "2"; +})(EnumWithValues = exports.EnumWithValues || (exports.EnumWithValues = {})); +// @Flags() +var EnumFlags; +(function (EnumFlags) { + EnumFlags[EnumFlags["Value0"] = 0] = "Value0"; + EnumFlags[EnumFlags["Value1"] = 1] = "Value1"; + EnumFlags[EnumFlags["Value2"] = 2] = "Value2"; + EnumFlags[EnumFlags["Value3"] = 3] = "Value3"; + EnumFlags[EnumFlags["Value123"] = 3] = "Value123"; +})(EnumFlags = exports.EnumFlags || (exports.EnumFlags = {})); +var EnumStyle; +(function (EnumStyle) { + EnumStyle["lower"] = "lower"; + EnumStyle["UPPER"] = "UPPER"; + EnumStyle["PascalCase"] = "PascalCase"; + EnumStyle["camelCase"] = "camelCase"; + EnumStyle["camelUPPER"] = "camelUPPER"; + EnumStyle["PascalUPPER"] = "PascalUPPER"; +})(EnumStyle = exports.EnumStyle || (exports.EnumStyle = {})); +var Poco = /** @class */ (function () { + function Poco(init) { + Object.assign(this, init); + } + return Poco; +}()); +exports.Poco = Poco; +var AllCollectionTypes = /** @class */ (function () { + function AllCollectionTypes(init) { + Object.assign(this, init); + } + return AllCollectionTypes; +}()); +exports.AllCollectionTypes = AllCollectionTypes; +var KeyValuePair = /** @class */ (function () { + function KeyValuePair(init) { + Object.assign(this, init); + } + return KeyValuePair; +}()); +exports.KeyValuePair = KeyValuePair; +var SubType = /** @class */ (function () { + function SubType(init) { + Object.assign(this, init); + } + return SubType; +}()); +exports.SubType = SubType; +var HelloBase = /** @class */ (function () { + function HelloBase(init) { + Object.assign(this, init); + } + return HelloBase; +}()); +exports.HelloBase = HelloBase; +var HelloResponseBase = /** @class */ (function () { + function HelloResponseBase(init) { + Object.assign(this, init); + } + return HelloResponseBase; +}()); +exports.HelloResponseBase = HelloResponseBase; +var HelloBase_1 = /** @class */ (function () { + function HelloBase_1(init) { + Object.assign(this, init); + } + return HelloBase_1; +}()); +exports.HelloBase_1 = HelloBase_1; +var Item = /** @class */ (function () { + function Item(init) { + Object.assign(this, init); + } + return Item; +}()); +exports.Item = Item; +var InheritedItem = /** @class */ (function () { + function InheritedItem(init) { + Object.assign(this, init); + } + return InheritedItem; +}()); +exports.InheritedItem = InheritedItem; +var HelloWithReturnResponse = /** @class */ (function () { + function HelloWithReturnResponse(init) { + Object.assign(this, init); + } + return HelloWithReturnResponse; +}()); +exports.HelloWithReturnResponse = HelloWithReturnResponse; +var HelloType = /** @class */ (function () { + function HelloType(init) { + Object.assign(this, init); + } + return HelloType; +}()); +exports.HelloType = HelloType; +var EmptyClass = /** @class */ (function () { + function EmptyClass(init) { + Object.assign(this, init); + } + return EmptyClass; +}()); +exports.EmptyClass = EmptyClass; +var TypeB = /** @class */ (function () { + function TypeB(init) { + Object.assign(this, init); + } + return TypeB; +}()); +exports.TypeB = TypeB; +var TypeA = /** @class */ (function () { + function TypeA(init) { + Object.assign(this, init); + } + return TypeA; +}()); +exports.TypeA = TypeA; +var InnerType = /** @class */ (function () { + function InnerType(init) { + Object.assign(this, init); + } + return InnerType; +}()); +exports.InnerType = InnerType; +var InnerEnum; +(function (InnerEnum) { + InnerEnum["Foo"] = "Foo"; + InnerEnum["Bar"] = "Bar"; + InnerEnum["Baz"] = "Baz"; +})(InnerEnum = exports.InnerEnum || (exports.InnerEnum = {})); +var InnerTypeItem = /** @class */ (function () { + function InnerTypeItem(init) { + Object.assign(this, init); + } + return InnerTypeItem; +}()); +exports.InnerTypeItem = InnerTypeItem; +var DayOfWeek; +(function (DayOfWeek) { + DayOfWeek["Sunday"] = "Sunday"; + DayOfWeek["Monday"] = "Monday"; + DayOfWeek["Tuesday"] = "Tuesday"; + DayOfWeek["Wednesday"] = "Wednesday"; + DayOfWeek["Thursday"] = "Thursday"; + DayOfWeek["Friday"] = "Friday"; + DayOfWeek["Saturday"] = "Saturday"; +})(DayOfWeek = exports.DayOfWeek || (exports.DayOfWeek = {})); +// @DataContract +var ShortDays; +(function (ShortDays) { + ShortDays["Monday"] = "MON"; + ShortDays["Tuesday"] = "TUE"; + ShortDays["Wednesday"] = "WED"; + ShortDays["Thursday"] = "THU"; + ShortDays["Friday"] = "FRI"; + ShortDays["Saturday"] = "SAT"; + ShortDays["Sunday"] = "SUN"; +})(ShortDays = exports.ShortDays || (exports.ShortDays = {})); +// @DataContract +var ScopeType; +(function (ScopeType) { + ScopeType["Global"] = "1"; + ScopeType["Sale"] = "2"; +})(ScopeType = exports.ScopeType || (exports.ScopeType = {})); +var Tuple_2 = /** @class */ (function () { + function Tuple_2(init) { + Object.assign(this, init); + } + return Tuple_2; +}()); +exports.Tuple_2 = Tuple_2; +var Tuple_3 = /** @class */ (function () { + function Tuple_3(init) { + Object.assign(this, init); + } + return Tuple_3; +}()); +exports.Tuple_3 = Tuple_3; +// @Flags() +var CacheControl; +(function (CacheControl) { + CacheControl[CacheControl["None"] = 0] = "None"; + CacheControl[CacheControl["Public"] = 1] = "Public"; + CacheControl[CacheControl["Private"] = 2] = "Private"; + CacheControl[CacheControl["MustRevalidate"] = 4] = "MustRevalidate"; + CacheControl[CacheControl["NoCache"] = 8] = "NoCache"; + CacheControl[CacheControl["NoStore"] = 16] = "NoStore"; + CacheControl[CacheControl["NoTransform"] = 32] = "NoTransform"; + CacheControl[CacheControl["ProxyRevalidate"] = 64] = "ProxyRevalidate"; +})(CacheControl = exports.CacheControl || (exports.CacheControl = {})); +var MyColor; +(function (MyColor) { + MyColor["Red"] = "Red"; + MyColor["Green"] = "Green"; + MyColor["Blue"] = "Blue"; +})(MyColor = exports.MyColor || (exports.MyColor = {})); +var SwaggerNestedModel = /** @class */ (function () { + function SwaggerNestedModel(init) { + Object.assign(this, init); + } + return SwaggerNestedModel; +}()); +exports.SwaggerNestedModel = SwaggerNestedModel; +var SwaggerNestedModel2 = /** @class */ (function () { + function SwaggerNestedModel2(init) { + Object.assign(this, init); + } + return SwaggerNestedModel2; +}()); +exports.SwaggerNestedModel2 = SwaggerNestedModel2; +var MyEnum; +(function (MyEnum) { + MyEnum["A"] = "A"; + MyEnum["B"] = "B"; + MyEnum["C"] = "C"; +})(MyEnum = exports.MyEnum || (exports.MyEnum = {})); +// @DataContract +var UserApiKey = /** @class */ (function () { + function UserApiKey(init) { + Object.assign(this, init); + } + return UserApiKey; +}()); +exports.UserApiKey = UserApiKey; +var PgRockstar = /** @class */ (function (_super) { + __extends(PgRockstar, _super); + function PgRockstar(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return PgRockstar; +}(Rockstar)); +exports.PgRockstar = PgRockstar; +var QueryDb_2 = /** @class */ (function (_super) { + __extends(QueryDb_2, _super); + function QueryDb_2(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return QueryDb_2; +}(QueryBase)); +exports.QueryDb_2 = QueryDb_2; +var CustomRockstar = /** @class */ (function () { + function CustomRockstar(init) { + Object.assign(this, init); + } + return CustomRockstar; +}()); +exports.CustomRockstar = CustomRockstar; +var Movie = /** @class */ (function () { + function Movie(init) { + Object.assign(this, init); + } + return Movie; +}()); +exports.Movie = Movie; +var RockstarAlbum = /** @class */ (function () { + function RockstarAlbum(init) { + Object.assign(this, init); + } + return RockstarAlbum; +}()); +exports.RockstarAlbum = RockstarAlbum; +var RockstarReference = /** @class */ (function () { + function RockstarReference(init) { + Object.assign(this, init); + } + return RockstarReference; +}()); +exports.RockstarReference = RockstarReference; +var OnlyDefinedInGenericType = /** @class */ (function () { + function OnlyDefinedInGenericType(init) { + Object.assign(this, init); + } + return OnlyDefinedInGenericType; +}()); +exports.OnlyDefinedInGenericType = OnlyDefinedInGenericType; +var OnlyDefinedInGenericTypeFrom = /** @class */ (function () { + function OnlyDefinedInGenericTypeFrom(init) { + Object.assign(this, init); + } + return OnlyDefinedInGenericTypeFrom; +}()); +exports.OnlyDefinedInGenericTypeFrom = OnlyDefinedInGenericTypeFrom; +var OnlyDefinedInGenericTypeInto = /** @class */ (function () { + function OnlyDefinedInGenericTypeInto(init) { + Object.assign(this, init); + } + return OnlyDefinedInGenericTypeInto; +}()); +exports.OnlyDefinedInGenericTypeInto = OnlyDefinedInGenericTypeInto; +var TypesGroup = /** @class */ (function () { + function TypesGroup(init) { + Object.assign(this, init); + } + return TypesGroup; +}()); +exports.TypesGroup = TypesGroup; +// @DataContract +var QueryResponse = /** @class */ (function () { + function QueryResponse(init) { + Object.assign(this, init); + } + return QueryResponse; +}()); +exports.QueryResponse = QueryResponse; +var ChangeRequestResponse = /** @class */ (function () { + function ChangeRequestResponse(init) { + Object.assign(this, init); + } + return ChangeRequestResponse; +}()); +exports.ChangeRequestResponse = ChangeRequestResponse; +var DiscoverTypes = /** @class */ (function () { + function DiscoverTypes(init) { + Object.assign(this, init); + } + DiscoverTypes.prototype.createResponse = function () { return new DiscoverTypes(); }; + DiscoverTypes.prototype.getTypeName = function () { return 'DiscoverTypes'; }; + return DiscoverTypes; +}()); +exports.DiscoverTypes = DiscoverTypes; +var CustomHttpErrorResponse = /** @class */ (function () { + function CustomHttpErrorResponse(init) { + Object.assign(this, init); + } + return CustomHttpErrorResponse; +}()); +exports.CustomHttpErrorResponse = CustomHttpErrorResponse; +// @Route("/alwaysthrows") +var AlwaysThrows = /** @class */ (function () { + function AlwaysThrows(init) { + Object.assign(this, init); + } + AlwaysThrows.prototype.createResponse = function () { return new AlwaysThrows(); }; + AlwaysThrows.prototype.getTypeName = function () { return 'AlwaysThrows'; }; + return AlwaysThrows; +}()); +exports.AlwaysThrows = AlwaysThrows; +// @Route("/alwaysthrowsfilterattribute") +var AlwaysThrowsFilterAttribute = /** @class */ (function () { + function AlwaysThrowsFilterAttribute(init) { + Object.assign(this, init); + } + AlwaysThrowsFilterAttribute.prototype.createResponse = function () { return new AlwaysThrowsFilterAttribute(); }; + AlwaysThrowsFilterAttribute.prototype.getTypeName = function () { return 'AlwaysThrowsFilterAttribute'; }; + return AlwaysThrowsFilterAttribute; +}()); +exports.AlwaysThrowsFilterAttribute = AlwaysThrowsFilterAttribute; +// @Route("/alwaysthrowsglobalfilter") +var AlwaysThrowsGlobalFilter = /** @class */ (function () { + function AlwaysThrowsGlobalFilter(init) { + Object.assign(this, init); + } + AlwaysThrowsGlobalFilter.prototype.createResponse = function () { return new AlwaysThrowsGlobalFilter(); }; + AlwaysThrowsGlobalFilter.prototype.getTypeName = function () { return 'AlwaysThrowsGlobalFilter'; }; + return AlwaysThrowsGlobalFilter; +}()); +exports.AlwaysThrowsGlobalFilter = AlwaysThrowsGlobalFilter; +var CustomFieldHttpErrorResponse = /** @class */ (function () { + function CustomFieldHttpErrorResponse(init) { + Object.assign(this, init); + } + return CustomFieldHttpErrorResponse; +}()); +exports.CustomFieldHttpErrorResponse = CustomFieldHttpErrorResponse; +var NoRepeatResponse = /** @class */ (function () { + function NoRepeatResponse(init) { + Object.assign(this, init); + } + return NoRepeatResponse; +}()); +exports.NoRepeatResponse = NoRepeatResponse; +var BatchThrowsResponse = /** @class */ (function () { + function BatchThrowsResponse(init) { + Object.assign(this, init); + } + return BatchThrowsResponse; +}()); +exports.BatchThrowsResponse = BatchThrowsResponse; +var ObjectDesignResponse = /** @class */ (function () { + function ObjectDesignResponse(init) { + Object.assign(this, init); + } + return ObjectDesignResponse; +}()); +exports.ObjectDesignResponse = ObjectDesignResponse; +var CreateJwtResponse = /** @class */ (function () { + function CreateJwtResponse(init) { + Object.assign(this, init); + } + return CreateJwtResponse; +}()); +exports.CreateJwtResponse = CreateJwtResponse; +var CreateRefreshJwtResponse = /** @class */ (function () { + function CreateRefreshJwtResponse(init) { + Object.assign(this, init); + } + return CreateRefreshJwtResponse; +}()); +exports.CreateRefreshJwtResponse = CreateRefreshJwtResponse; +var MetadataTestResponse = /** @class */ (function () { + function MetadataTestResponse(init) { + Object.assign(this, init); + } + return MetadataTestResponse; +}()); +exports.MetadataTestResponse = MetadataTestResponse; +// @DataContract +var GetExampleResponse = /** @class */ (function () { + function GetExampleResponse(init) { + Object.assign(this, init); + } + return GetExampleResponse; +}()); +exports.GetExampleResponse = GetExampleResponse; +var AutoQueryMetadataResponse = /** @class */ (function () { + function AutoQueryMetadataResponse(init) { + Object.assign(this, init); + } + return AutoQueryMetadataResponse; +}()); +exports.AutoQueryMetadataResponse = AutoQueryMetadataResponse; +var TestAttributeExport = /** @class */ (function () { + function TestAttributeExport(init) { + Object.assign(this, init); + } + TestAttributeExport.prototype.createResponse = function () { return new TestAttributeExport(); }; + TestAttributeExport.prototype.getTypeName = function () { return 'TestAttributeExport'; }; + return TestAttributeExport; +}()); +exports.TestAttributeExport = TestAttributeExport; +// @DataContract +var HelloACodeGenTestResponse = /** @class */ (function () { + function HelloACodeGenTestResponse(init) { + Object.assign(this, init); + } + return HelloACodeGenTestResponse; +}()); +exports.HelloACodeGenTestResponse = HelloACodeGenTestResponse; +var HelloResponse = /** @class */ (function () { + function HelloResponse(init) { + Object.assign(this, init); + } + return HelloResponse; +}()); +exports.HelloResponse = HelloResponse; +/** + * Description on HelloAllResponse type + */ +// @DataContract +var HelloAnnotatedResponse = /** @class */ (function () { + function HelloAnnotatedResponse(init) { + Object.assign(this, init); + } + return HelloAnnotatedResponse; +}()); +exports.HelloAnnotatedResponse = HelloAnnotatedResponse; +var HelloList = /** @class */ (function () { + function HelloList(init) { + Object.assign(this, init); + } + HelloList.prototype.createResponse = function () { return new Array(); }; + HelloList.prototype.getTypeName = function () { return 'HelloList'; }; + return HelloList; +}()); +exports.HelloList = HelloList; +var HelloArray = /** @class */ (function () { + function HelloArray(init) { + Object.assign(this, init); + } + HelloArray.prototype.createResponse = function () { return new Array(); }; + HelloArray.prototype.getTypeName = function () { return 'HelloArray'; }; + return HelloArray; +}()); +exports.HelloArray = HelloArray; +var HelloExistingResponse = /** @class */ (function () { + function HelloExistingResponse(init) { + Object.assign(this, init); + } + return HelloExistingResponse; +}()); +exports.HelloExistingResponse = HelloExistingResponse; +var AllTypes = /** @class */ (function () { + function AllTypes(init) { + Object.assign(this, init); + } + AllTypes.prototype.createResponse = function () { return new AllTypes(); }; + AllTypes.prototype.getTypeName = function () { return 'AllTypes'; }; + return AllTypes; +}()); +exports.AllTypes = AllTypes; +var HelloAllTypesResponse = /** @class */ (function () { + function HelloAllTypesResponse(init) { + Object.assign(this, init); + } + return HelloAllTypesResponse; +}()); +exports.HelloAllTypesResponse = HelloAllTypesResponse; +// @DataContract +var HelloWithDataContractResponse = /** @class */ (function () { + function HelloWithDataContractResponse(init) { + Object.assign(this, init); + } + return HelloWithDataContractResponse; +}()); +exports.HelloWithDataContractResponse = HelloWithDataContractResponse; +/** + * Description on HelloWithDescriptionResponse type + */ +var HelloWithDescriptionResponse = /** @class */ (function () { + function HelloWithDescriptionResponse(init) { + Object.assign(this, init); + } + return HelloWithDescriptionResponse; +}()); +exports.HelloWithDescriptionResponse = HelloWithDescriptionResponse; +var HelloWithInheritanceResponse = /** @class */ (function (_super) { + __extends(HelloWithInheritanceResponse, _super); + function HelloWithInheritanceResponse(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return HelloWithInheritanceResponse; +}(HelloResponseBase)); +exports.HelloWithInheritanceResponse = HelloWithInheritanceResponse; +var HelloWithAlternateReturnResponse = /** @class */ (function (_super) { + __extends(HelloWithAlternateReturnResponse, _super); + function HelloWithAlternateReturnResponse(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return HelloWithAlternateReturnResponse; +}(HelloWithReturnResponse)); +exports.HelloWithAlternateReturnResponse = HelloWithAlternateReturnResponse; +var HelloWithRouteResponse = /** @class */ (function () { + function HelloWithRouteResponse(init) { + Object.assign(this, init); + } + return HelloWithRouteResponse; +}()); +exports.HelloWithRouteResponse = HelloWithRouteResponse; +var HelloWithTypeResponse = /** @class */ (function () { + function HelloWithTypeResponse(init) { + Object.assign(this, init); + } + return HelloWithTypeResponse; +}()); +exports.HelloWithTypeResponse = HelloWithTypeResponse; +var HelloStruct = /** @class */ (function () { + function HelloStruct(init) { + Object.assign(this, init); + } + HelloStruct.prototype.createResponse = function () { return new HelloStruct(); }; + HelloStruct.prototype.getTypeName = function () { return 'HelloStruct'; }; + return HelloStruct; +}()); +exports.HelloStruct = HelloStruct; +var HelloSessionResponse = /** @class */ (function () { + function HelloSessionResponse(init) { + Object.assign(this, init); + } + return HelloSessionResponse; +}()); +exports.HelloSessionResponse = HelloSessionResponse; +var HelloImplementsInterface = /** @class */ (function () { + function HelloImplementsInterface(init) { + Object.assign(this, init); + } + HelloImplementsInterface.prototype.createResponse = function () { return new HelloImplementsInterface(); }; + HelloImplementsInterface.prototype.getTypeName = function () { return 'HelloImplementsInterface'; }; + return HelloImplementsInterface; +}()); +exports.HelloImplementsInterface = HelloImplementsInterface; +var Request1Response = /** @class */ (function () { + function Request1Response(init) { + Object.assign(this, init); + } + return Request1Response; +}()); +exports.Request1Response = Request1Response; +var Request2Response = /** @class */ (function () { + function Request2Response(init) { + Object.assign(this, init); + } + return Request2Response; +}()); +exports.Request2Response = Request2Response; +var HelloInnerTypesResponse = /** @class */ (function () { + function HelloInnerTypesResponse(init) { + Object.assign(this, init); + } + return HelloInnerTypesResponse; +}()); +exports.HelloInnerTypesResponse = HelloInnerTypesResponse; +var CustomUserSession = /** @class */ (function (_super) { + __extends(CustomUserSession, _super); + function CustomUserSession(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return CustomUserSession; +}(AuthUserSession)); +exports.CustomUserSession = CustomUserSession; +// @DataContract +var QueryResponseTemplate = /** @class */ (function () { + function QueryResponseTemplate(init) { + Object.assign(this, init); + } + return QueryResponseTemplate; +}()); +exports.QueryResponseTemplate = QueryResponseTemplate; +var HelloVerbResponse = /** @class */ (function () { + function HelloVerbResponse(init) { + Object.assign(this, init); + } + return HelloVerbResponse; +}()); +exports.HelloVerbResponse = HelloVerbResponse; +var EnumResponse = /** @class */ (function () { + function EnumResponse(init) { + Object.assign(this, init); + } + return EnumResponse; +}()); +exports.EnumResponse = EnumResponse; +var ExcludeTestNested = /** @class */ (function () { + function ExcludeTestNested(init) { + Object.assign(this, init); + } + return ExcludeTestNested; +}()); +exports.ExcludeTestNested = ExcludeTestNested; +var RestrictLocalhost = /** @class */ (function () { + function RestrictLocalhost(init) { + Object.assign(this, init); + } + RestrictLocalhost.prototype.createResponse = function () { return new RestrictLocalhost(); }; + RestrictLocalhost.prototype.getTypeName = function () { return 'RestrictLocalhost'; }; + return RestrictLocalhost; +}()); +exports.RestrictLocalhost = RestrictLocalhost; +var RestrictInternal = /** @class */ (function () { + function RestrictInternal(init) { + Object.assign(this, init); + } + RestrictInternal.prototype.createResponse = function () { return new RestrictInternal(); }; + RestrictInternal.prototype.getTypeName = function () { return 'RestrictInternal'; }; + return RestrictInternal; +}()); +exports.RestrictInternal = RestrictInternal; +var HelloTuple = /** @class */ (function () { + function HelloTuple(init) { + Object.assign(this, init); + } + HelloTuple.prototype.createResponse = function () { return new HelloTuple(); }; + HelloTuple.prototype.getTypeName = function () { return 'HelloTuple'; }; + return HelloTuple; +}()); +exports.HelloTuple = HelloTuple; +var HelloAuthenticatedResponse = /** @class */ (function () { + function HelloAuthenticatedResponse(init) { + Object.assign(this, init); + } + return HelloAuthenticatedResponse; +}()); +exports.HelloAuthenticatedResponse = HelloAuthenticatedResponse; +var Echo = /** @class */ (function () { + function Echo(init) { + Object.assign(this, init); + } + return Echo; +}()); +exports.Echo = Echo; +var ThrowHttpErrorResponse = /** @class */ (function () { + function ThrowHttpErrorResponse(init) { + Object.assign(this, init); + } + return ThrowHttpErrorResponse; +}()); +exports.ThrowHttpErrorResponse = ThrowHttpErrorResponse; +var ThrowTypeResponse = /** @class */ (function () { + function ThrowTypeResponse(init) { + Object.assign(this, init); + } + return ThrowTypeResponse; +}()); +exports.ThrowTypeResponse = ThrowTypeResponse; +var ThrowValidationResponse = /** @class */ (function () { + function ThrowValidationResponse(init) { + Object.assign(this, init); + } + return ThrowValidationResponse; +}()); +exports.ThrowValidationResponse = ThrowValidationResponse; +var acsprofileResponse = /** @class */ (function () { + function acsprofileResponse(init) { + Object.assign(this, init); + } + return acsprofileResponse; +}()); +exports.acsprofileResponse = acsprofileResponse; +var ReturnedDto = /** @class */ (function () { + function ReturnedDto(init) { + Object.assign(this, init); + } + return ReturnedDto; +}()); +exports.ReturnedDto = ReturnedDto; +// @Route("/matchroute/html") +var MatchesHtml = /** @class */ (function () { + function MatchesHtml(init) { + Object.assign(this, init); + } + MatchesHtml.prototype.createResponse = function () { return new MatchesHtml(); }; + MatchesHtml.prototype.getTypeName = function () { return 'MatchesHtml'; }; + return MatchesHtml; +}()); +exports.MatchesHtml = MatchesHtml; +// @Route("/matchroute/json") +var MatchesJson = /** @class */ (function () { + function MatchesJson(init) { + Object.assign(this, init); + } + MatchesJson.prototype.createResponse = function () { return new MatchesJson(); }; + MatchesJson.prototype.getTypeName = function () { return 'MatchesJson'; }; + return MatchesJson; +}()); +exports.MatchesJson = MatchesJson; +var TimestampData = /** @class */ (function () { + function TimestampData(init) { + Object.assign(this, init); + } + return TimestampData; +}()); +exports.TimestampData = TimestampData; +// @Route("/test/html") +var TestHtml = /** @class */ (function () { + function TestHtml(init) { + Object.assign(this, init); + } + TestHtml.prototype.createResponse = function () { return new TestHtml(); }; + TestHtml.prototype.getTypeName = function () { return 'TestHtml'; }; + return TestHtml; +}()); +exports.TestHtml = TestHtml; +var ViewResponse = /** @class */ (function () { + function ViewResponse(init) { + Object.assign(this, init); + } + return ViewResponse; +}()); +exports.ViewResponse = ViewResponse; +// @Route("/swagger/model") +var SwaggerModel = /** @class */ (function () { + function SwaggerModel(init) { + Object.assign(this, init); + } + SwaggerModel.prototype.createResponse = function () { return new SwaggerModel(); }; + SwaggerModel.prototype.getTypeName = function () { return 'SwaggerModel'; }; + return SwaggerModel; +}()); +exports.SwaggerModel = SwaggerModel; +// @Route("/plain-dto") +var PlainDto = /** @class */ (function () { + function PlainDto(init) { + Object.assign(this, init); + } + PlainDto.prototype.createResponse = function () { return new PlainDto(); }; + PlainDto.prototype.getTypeName = function () { return 'PlainDto'; }; + return PlainDto; +}()); +exports.PlainDto = PlainDto; +// @Route("/httpresult-dto") +var HttpResultDto = /** @class */ (function () { + function HttpResultDto(init) { + Object.assign(this, init); + } + HttpResultDto.prototype.createResponse = function () { return new HttpResultDto(); }; + HttpResultDto.prototype.getTypeName = function () { return 'HttpResultDto'; }; + return HttpResultDto; +}()); +exports.HttpResultDto = HttpResultDto; +// @Route("/restrict/mq") +var TestMqRestriction = /** @class */ (function () { + function TestMqRestriction(init) { + Object.assign(this, init); + } + TestMqRestriction.prototype.createResponse = function () { return new TestMqRestriction(); }; + TestMqRestriction.prototype.getTypeName = function () { return 'TestMqRestriction'; }; + return TestMqRestriction; +}()); +exports.TestMqRestriction = TestMqRestriction; +// @Route("/set-cache") +var SetCache = /** @class */ (function () { + function SetCache(init) { + Object.assign(this, init); + } + SetCache.prototype.createResponse = function () { return new SetCache(); }; + SetCache.prototype.getTypeName = function () { return 'SetCache'; }; + return SetCache; +}()); +exports.SetCache = SetCache; +var SwaggerComplexResponse = /** @class */ (function () { + function SwaggerComplexResponse(init) { + Object.assign(this, init); + } + return SwaggerComplexResponse; +}()); +exports.SwaggerComplexResponse = SwaggerComplexResponse; +/** + * Api GET All + */ +// @Route("/swaggerexamples", "GET") +// @Api(Description="Api GET All") +var GetSwaggerExamples = /** @class */ (function () { + function GetSwaggerExamples(init) { + Object.assign(this, init); + } + GetSwaggerExamples.prototype.createResponse = function () { return new GetSwaggerExamples(); }; + GetSwaggerExamples.prototype.getTypeName = function () { return 'GetSwaggerExamples'; }; + return GetSwaggerExamples; +}()); +exports.GetSwaggerExamples = GetSwaggerExamples; +/** + * Api GET Id + */ +// @Route("/swaggerexamples/{Id}", "GET") +// @Api(Description="Api GET Id") +var GetSwaggerExample = /** @class */ (function () { + function GetSwaggerExample(init) { + Object.assign(this, init); + } + GetSwaggerExample.prototype.createResponse = function () { return new GetSwaggerExample(); }; + GetSwaggerExample.prototype.getTypeName = function () { return 'GetSwaggerExample'; }; + return GetSwaggerExample; +}()); +exports.GetSwaggerExample = GetSwaggerExample; +/** + * Api POST + */ +// @Route("/swaggerexamples", "POST") +// @Api(Description="Api POST") +var PostSwaggerExamples = /** @class */ (function () { + function PostSwaggerExamples(init) { + Object.assign(this, init); + } + PostSwaggerExamples.prototype.createResponse = function () { return new PostSwaggerExamples(); }; + PostSwaggerExamples.prototype.getTypeName = function () { return 'PostSwaggerExamples'; }; + return PostSwaggerExamples; +}()); +exports.PostSwaggerExamples = PostSwaggerExamples; +/** + * Api PUT Id + */ +// @Route("/swaggerexamples/{Id}", "PUT") +// @Api(Description="Api PUT Id") +var PutSwaggerExample = /** @class */ (function () { + function PutSwaggerExample(init) { + Object.assign(this, init); + } + PutSwaggerExample.prototype.createResponse = function () { return new PutSwaggerExample(); }; + PutSwaggerExample.prototype.getTypeName = function () { return 'PutSwaggerExample'; }; + return PutSwaggerExample; +}()); +exports.PutSwaggerExample = PutSwaggerExample; +// @Route("/lists", "GET") +var GetLists = /** @class */ (function () { + function GetLists(init) { + Object.assign(this, init); + } + GetLists.prototype.createResponse = function () { return new GetLists(); }; + GetLists.prototype.getTypeName = function () { return 'GetLists'; }; + return GetLists; +}()); +exports.GetLists = GetLists; +// @DataContract +var AuthenticateResponse = /** @class */ (function () { + function AuthenticateResponse(init) { + Object.assign(this, init); + } + return AuthenticateResponse; +}()); +exports.AuthenticateResponse = AuthenticateResponse; +// @DataContract +var AssignRolesResponse = /** @class */ (function () { + function AssignRolesResponse(init) { + Object.assign(this, init); + } + return AssignRolesResponse; +}()); +exports.AssignRolesResponse = AssignRolesResponse; +// @DataContract +var UnAssignRolesResponse = /** @class */ (function () { + function UnAssignRolesResponse(init) { + Object.assign(this, init); + } + return UnAssignRolesResponse; +}()); +exports.UnAssignRolesResponse = UnAssignRolesResponse; +// @DataContract +var ConvertSessionToTokenResponse = /** @class */ (function () { + function ConvertSessionToTokenResponse(init) { + Object.assign(this, init); + } + return ConvertSessionToTokenResponse; +}()); +exports.ConvertSessionToTokenResponse = ConvertSessionToTokenResponse; +// @DataContract +var GetAccessTokenResponse = /** @class */ (function () { + function GetAccessTokenResponse(init) { + Object.assign(this, init); + } + return GetAccessTokenResponse; +}()); +exports.GetAccessTokenResponse = GetAccessTokenResponse; +// @DataContract +var GetApiKeysResponse = /** @class */ (function () { + function GetApiKeysResponse(init) { + Object.assign(this, init); + } + return GetApiKeysResponse; +}()); +exports.GetApiKeysResponse = GetApiKeysResponse; +// @DataContract +var RegenerateApiKeysResponse = /** @class */ (function () { + function RegenerateApiKeysResponse(init) { + Object.assign(this, init); + } + return RegenerateApiKeysResponse; +}()); +exports.RegenerateApiKeysResponse = RegenerateApiKeysResponse; +// @DataContract +var RegisterResponse = /** @class */ (function () { + function RegisterResponse(init) { + Object.assign(this, init); + } + return RegisterResponse; +}()); +exports.RegisterResponse = RegisterResponse; +// @Route("/anontype") +var AnonType = /** @class */ (function () { + function AnonType(init) { + Object.assign(this, init); + } + return AnonType; +}()); +exports.AnonType = AnonType; +// @Route("/query/requestlogs") +// @Route("/query/requestlogs/{Date}") +var QueryRequestLogs = /** @class */ (function (_super) { + __extends(QueryRequestLogs, _super); + function QueryRequestLogs(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRequestLogs.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRequestLogs.prototype.getTypeName = function () { return 'QueryRequestLogs'; }; + return QueryRequestLogs; +}(QueryData)); +exports.QueryRequestLogs = QueryRequestLogs; +// @AutoQueryViewer(Name="Today\'s Logs", Title="Logs from Today") +var TodayLogs = /** @class */ (function (_super) { + __extends(TodayLogs, _super); + function TodayLogs(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + TodayLogs.prototype.createResponse = function () { return new QueryResponse(); }; + TodayLogs.prototype.getTypeName = function () { return 'TodayLogs'; }; + return TodayLogs; +}(QueryData)); +exports.TodayLogs = TodayLogs; +var TodayErrorLogs = /** @class */ (function (_super) { + __extends(TodayErrorLogs, _super); + function TodayErrorLogs(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + TodayErrorLogs.prototype.createResponse = function () { return new QueryResponse(); }; + TodayErrorLogs.prototype.getTypeName = function () { return 'TodayErrorLogs'; }; + return TodayErrorLogs; +}(QueryData)); +exports.TodayErrorLogs = TodayErrorLogs; +var YesterdayLogs = /** @class */ (function (_super) { + __extends(YesterdayLogs, _super); + function YesterdayLogs(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + YesterdayLogs.prototype.createResponse = function () { return new QueryResponse(); }; + YesterdayLogs.prototype.getTypeName = function () { return 'YesterdayLogs'; }; + return YesterdayLogs; +}(QueryData)); +exports.YesterdayLogs = YesterdayLogs; +var YesterdayErrorLogs = /** @class */ (function (_super) { + __extends(YesterdayErrorLogs, _super); + function YesterdayErrorLogs(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + YesterdayErrorLogs.prototype.createResponse = function () { return new QueryResponse(); }; + YesterdayErrorLogs.prototype.getTypeName = function () { return 'YesterdayErrorLogs'; }; + return YesterdayErrorLogs; +}(QueryData)); +exports.YesterdayErrorLogs = YesterdayErrorLogs; +// @Route("/query/rockstars") +var QueryRockstars = /** @class */ (function (_super) { + __extends(QueryRockstars, _super); + function QueryRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstars.prototype.getTypeName = function () { return 'QueryRockstars'; }; + return QueryRockstars; +}(QueryDb_1)); +exports.QueryRockstars = QueryRockstars; +// @Route("/query/rockstars/cached") +var QueryRockstarsCached = /** @class */ (function (_super) { + __extends(QueryRockstarsCached, _super); + function QueryRockstarsCached(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarsCached.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarsCached.prototype.getTypeName = function () { return 'QueryRockstarsCached'; }; + return QueryRockstarsCached; +}(QueryDb_1)); +exports.QueryRockstarsCached = QueryRockstarsCached; +// @Route("/changerequest/{Id}") +var ChangeRequest = /** @class */ (function () { + function ChangeRequest(init) { + Object.assign(this, init); + } + ChangeRequest.prototype.createResponse = function () { return new ChangeRequestResponse(); }; + ChangeRequest.prototype.getTypeName = function () { return 'ChangeRequest'; }; + return ChangeRequest; +}()); +exports.ChangeRequest = ChangeRequest; +// @Route("/compress/{Path*}") +var CompressFile = /** @class */ (function () { + function CompressFile(init) { + Object.assign(this, init); + } + return CompressFile; +}()); +exports.CompressFile = CompressFile; +// @Route("/Routing/LeadPost.aspx") +var LegacyLeadPost = /** @class */ (function () { + function LegacyLeadPost(init) { + Object.assign(this, init); + } + return LegacyLeadPost; +}()); +exports.LegacyLeadPost = LegacyLeadPost; +// @Route("/info/{Id}") +var Info = /** @class */ (function () { + function Info(init) { + Object.assign(this, init); + } + return Info; +}()); +exports.Info = Info; +var CustomHttpError = /** @class */ (function () { + function CustomHttpError(init) { + Object.assign(this, init); + } + CustomHttpError.prototype.createResponse = function () { return new CustomHttpErrorResponse(); }; + CustomHttpError.prototype.getTypeName = function () { return 'CustomHttpError'; }; + return CustomHttpError; +}()); +exports.CustomHttpError = CustomHttpError; +var CustomFieldHttpError = /** @class */ (function () { + function CustomFieldHttpError(init) { + Object.assign(this, init); + } + CustomFieldHttpError.prototype.createResponse = function () { return new CustomFieldHttpErrorResponse(); }; + CustomFieldHttpError.prototype.getTypeName = function () { return 'CustomFieldHttpError'; }; + return CustomFieldHttpError; +}()); +exports.CustomFieldHttpError = CustomFieldHttpError; +var FallbackRoute = /** @class */ (function () { + function FallbackRoute(init) { + Object.assign(this, init); + } + return FallbackRoute; +}()); +exports.FallbackRoute = FallbackRoute; +var NoRepeat = /** @class */ (function () { + function NoRepeat(init) { + Object.assign(this, init); + } + NoRepeat.prototype.createResponse = function () { return new NoRepeatResponse(); }; + NoRepeat.prototype.getTypeName = function () { return 'NoRepeat'; }; + return NoRepeat; +}()); +exports.NoRepeat = NoRepeat; +var BatchThrows = /** @class */ (function () { + function BatchThrows(init) { + Object.assign(this, init); + } + BatchThrows.prototype.createResponse = function () { return new BatchThrowsResponse(); }; + BatchThrows.prototype.getTypeName = function () { return 'BatchThrows'; }; + return BatchThrows; +}()); +exports.BatchThrows = BatchThrows; +var BatchThrowsAsync = /** @class */ (function () { + function BatchThrowsAsync(init) { + Object.assign(this, init); + } + BatchThrowsAsync.prototype.createResponse = function () { return new BatchThrowsResponse(); }; + BatchThrowsAsync.prototype.getTypeName = function () { return 'BatchThrowsAsync'; }; + return BatchThrowsAsync; +}()); +exports.BatchThrowsAsync = BatchThrowsAsync; +// @Route("/code/object", "GET") +var ObjectId = /** @class */ (function () { + function ObjectId(init) { + Object.assign(this, init); + } + ObjectId.prototype.createResponse = function () { return new ObjectDesignResponse(); }; + ObjectId.prototype.getTypeName = function () { return 'ObjectId'; }; + return ObjectId; +}()); +exports.ObjectId = ObjectId; +// @Route("/jwt") +var CreateJwt = /** @class */ (function (_super) { + __extends(CreateJwt, _super); + function CreateJwt(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + CreateJwt.prototype.createResponse = function () { return new CreateJwtResponse(); }; + CreateJwt.prototype.getTypeName = function () { return 'CreateJwt'; }; + return CreateJwt; +}(AuthUserSession)); +exports.CreateJwt = CreateJwt; +// @Route("/jwt-refresh") +var CreateRefreshJwt = /** @class */ (function () { + function CreateRefreshJwt(init) { + Object.assign(this, init); + } + CreateRefreshJwt.prototype.createResponse = function () { return new CreateRefreshJwtResponse(); }; + CreateRefreshJwt.prototype.getTypeName = function () { return 'CreateRefreshJwt'; }; + return CreateRefreshJwt; +}()); +exports.CreateRefreshJwt = CreateRefreshJwt; +var MetadataTest = /** @class */ (function () { + function MetadataTest(init) { + Object.assign(this, init); + } + MetadataTest.prototype.createResponse = function () { return new MetadataTestResponse(); }; + MetadataTest.prototype.getTypeName = function () { return 'MetadataTest'; }; + return MetadataTest; +}()); +exports.MetadataTest = MetadataTest; +// @Route("/example", "GET") +// @DataContract +var GetExample = /** @class */ (function () { + function GetExample(init) { + Object.assign(this, init); + } + GetExample.prototype.createResponse = function () { return new GetExampleResponse(); }; + GetExample.prototype.getTypeName = function () { return 'GetExample'; }; + return GetExample; +}()); +exports.GetExample = GetExample; +var MetadataRequest = /** @class */ (function () { + function MetadataRequest(init) { + Object.assign(this, init); + } + MetadataRequest.prototype.createResponse = function () { return new AutoQueryMetadataResponse(); }; + MetadataRequest.prototype.getTypeName = function () { return 'MetadataRequest'; }; + return MetadataRequest; +}()); +exports.MetadataRequest = MetadataRequest; +var ExcludeMetadataProperty = /** @class */ (function () { + function ExcludeMetadataProperty(init) { + Object.assign(this, init); + } + return ExcludeMetadataProperty; +}()); +exports.ExcludeMetadataProperty = ExcludeMetadataProperty; +// @Route("/namedconnection") +var NamedConnection = /** @class */ (function () { + function NamedConnection(init) { + Object.assign(this, init); + } + return NamedConnection; +}()); +exports.NamedConnection = NamedConnection; +/** + * Description for HelloACodeGenTest + */ +var HelloACodeGenTest = /** @class */ (function () { + function HelloACodeGenTest(init) { + Object.assign(this, init); + } + HelloACodeGenTest.prototype.createResponse = function () { return new HelloACodeGenTestResponse(); }; + HelloACodeGenTest.prototype.getTypeName = function () { return 'HelloACodeGenTest'; }; + return HelloACodeGenTest; +}()); +exports.HelloACodeGenTest = HelloACodeGenTest; +var HelloInService = /** @class */ (function () { + function HelloInService(init) { + Object.assign(this, init); + } + HelloInService.prototype.createResponse = function () { return new HelloResponse(); }; + HelloInService.prototype.getTypeName = function () { return 'NativeTypesTestService.HelloInService'; }; + return HelloInService; +}()); +exports.HelloInService = HelloInService; +// @Route("/hello") +// @Route("/hello/{Name}") +var Hello = /** @class */ (function () { + function Hello(init) { + Object.assign(this, init); + } + Hello.prototype.createResponse = function () { return new HelloResponse(); }; + Hello.prototype.getTypeName = function () { return 'Hello'; }; + return Hello; +}()); +exports.Hello = Hello; +/** + * Description on HelloAll type + */ +// @DataContract +var HelloAnnotated = /** @class */ (function () { + function HelloAnnotated(init) { + Object.assign(this, init); + } + HelloAnnotated.prototype.createResponse = function () { return new HelloAnnotatedResponse(); }; + HelloAnnotated.prototype.getTypeName = function () { return 'HelloAnnotated'; }; + return HelloAnnotated; +}()); +exports.HelloAnnotated = HelloAnnotated; +var HelloWithNestedClass = /** @class */ (function () { + function HelloWithNestedClass(init) { + Object.assign(this, init); + } + HelloWithNestedClass.prototype.createResponse = function () { return new HelloResponse(); }; + HelloWithNestedClass.prototype.getTypeName = function () { return 'HelloWithNestedClass'; }; + return HelloWithNestedClass; +}()); +exports.HelloWithNestedClass = HelloWithNestedClass; +var HelloReturnList = /** @class */ (function () { + function HelloReturnList(init) { + Object.assign(this, init); + } + HelloReturnList.prototype.createResponse = function () { return new Array(); }; + HelloReturnList.prototype.getTypeName = function () { return 'HelloReturnList'; }; + return HelloReturnList; +}()); +exports.HelloReturnList = HelloReturnList; +var HelloExisting = /** @class */ (function () { + function HelloExisting(init) { + Object.assign(this, init); + } + HelloExisting.prototype.createResponse = function () { return new HelloExistingResponse(); }; + HelloExisting.prototype.getTypeName = function () { return 'HelloExisting'; }; + return HelloExisting; +}()); +exports.HelloExisting = HelloExisting; +var HelloWithEnum = /** @class */ (function () { + function HelloWithEnum(init) { + Object.assign(this, init); + } + return HelloWithEnum; +}()); +exports.HelloWithEnum = HelloWithEnum; +var RestrictedAttributes = /** @class */ (function () { + function RestrictedAttributes(init) { + Object.assign(this, init); + } + return RestrictedAttributes; +}()); +exports.RestrictedAttributes = RestrictedAttributes; +/** + * AllowedAttributes Description + */ +// @Route("/allowed-attributes", "GET") +// @Api(Description="AllowedAttributes Description") +// @ApiResponse(Description="Your request was not understood", StatusCode=400) +// @DataContract +var AllowedAttributes = /** @class */ (function () { + function AllowedAttributes(init) { + Object.assign(this, init); + } + return AllowedAttributes; +}()); +exports.AllowedAttributes = AllowedAttributes; +/** + * Multi Line Class + */ +// @Api(Description="Multi \r\nLine \r\nClass") +var HelloAttributeStringTest = /** @class */ (function () { + function HelloAttributeStringTest(init) { + Object.assign(this, init); + } + return HelloAttributeStringTest; +}()); +exports.HelloAttributeStringTest = HelloAttributeStringTest; +var HelloAllTypes = /** @class */ (function () { + function HelloAllTypes(init) { + Object.assign(this, init); + } + HelloAllTypes.prototype.createResponse = function () { return new HelloAllTypesResponse(); }; + HelloAllTypes.prototype.getTypeName = function () { return 'HelloAllTypes'; }; + return HelloAllTypes; +}()); +exports.HelloAllTypes = HelloAllTypes; +var HelloString = /** @class */ (function () { + function HelloString(init) { + Object.assign(this, init); + } + HelloString.prototype.createResponse = function () { return ''; }; + HelloString.prototype.getTypeName = function () { return 'HelloString'; }; + return HelloString; +}()); +exports.HelloString = HelloString; +var HelloVoid = /** @class */ (function () { + function HelloVoid(init) { + Object.assign(this, init); + } + HelloVoid.prototype.createResponse = function () { }; + HelloVoid.prototype.getTypeName = function () { return 'HelloVoid'; }; + return HelloVoid; +}()); +exports.HelloVoid = HelloVoid; +// @DataContract +var HelloWithDataContract = /** @class */ (function () { + function HelloWithDataContract(init) { + Object.assign(this, init); + } + HelloWithDataContract.prototype.createResponse = function () { return new HelloWithDataContractResponse(); }; + HelloWithDataContract.prototype.getTypeName = function () { return 'HelloWithDataContract'; }; + return HelloWithDataContract; +}()); +exports.HelloWithDataContract = HelloWithDataContract; +/** + * Description on HelloWithDescription type + */ +var HelloWithDescription = /** @class */ (function () { + function HelloWithDescription(init) { + Object.assign(this, init); + } + HelloWithDescription.prototype.createResponse = function () { return new HelloWithDescriptionResponse(); }; + HelloWithDescription.prototype.getTypeName = function () { return 'HelloWithDescription'; }; + return HelloWithDescription; +}()); +exports.HelloWithDescription = HelloWithDescription; +var HelloWithInheritance = /** @class */ (function (_super) { + __extends(HelloWithInheritance, _super); + function HelloWithInheritance(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + HelloWithInheritance.prototype.createResponse = function () { return new HelloWithInheritanceResponse(); }; + HelloWithInheritance.prototype.getTypeName = function () { return 'HelloWithInheritance'; }; + return HelloWithInheritance; +}(HelloBase)); +exports.HelloWithInheritance = HelloWithInheritance; +var HelloWithGenericInheritance = /** @class */ (function (_super) { + __extends(HelloWithGenericInheritance, _super); + function HelloWithGenericInheritance(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return HelloWithGenericInheritance; +}(HelloBase_1)); +exports.HelloWithGenericInheritance = HelloWithGenericInheritance; +var HelloWithGenericInheritance2 = /** @class */ (function (_super) { + __extends(HelloWithGenericInheritance2, _super); + function HelloWithGenericInheritance2(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return HelloWithGenericInheritance2; +}(HelloBase_1)); +exports.HelloWithGenericInheritance2 = HelloWithGenericInheritance2; +var HelloWithNestedInheritance = /** @class */ (function (_super) { + __extends(HelloWithNestedInheritance, _super); + function HelloWithNestedInheritance(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + return HelloWithNestedInheritance; +}(HelloBase_1)); +exports.HelloWithNestedInheritance = HelloWithNestedInheritance; +var HelloWithListInheritance = /** @class */ (function (_super) { + __extends(HelloWithListInheritance, _super); + function HelloWithListInheritance(init) { + var _this = _super.call(this) || this; + Object.assign(_this, init); + return _this; + } + return HelloWithListInheritance; +}(Array)); +exports.HelloWithListInheritance = HelloWithListInheritance; +var HelloWithReturn = /** @class */ (function () { + function HelloWithReturn(init) { + Object.assign(this, init); + } + HelloWithReturn.prototype.createResponse = function () { return new HelloWithAlternateReturnResponse(); }; + HelloWithReturn.prototype.getTypeName = function () { return 'HelloWithReturn'; }; + return HelloWithReturn; +}()); +exports.HelloWithReturn = HelloWithReturn; +// @Route("/helloroute") +var HelloWithRoute = /** @class */ (function () { + function HelloWithRoute(init) { + Object.assign(this, init); + } + HelloWithRoute.prototype.createResponse = function () { return new HelloWithRouteResponse(); }; + HelloWithRoute.prototype.getTypeName = function () { return 'HelloWithRoute'; }; + return HelloWithRoute; +}()); +exports.HelloWithRoute = HelloWithRoute; +var HelloWithType = /** @class */ (function () { + function HelloWithType(init) { + Object.assign(this, init); + } + HelloWithType.prototype.createResponse = function () { return new HelloWithTypeResponse(); }; + HelloWithType.prototype.getTypeName = function () { return 'HelloWithType'; }; + return HelloWithType; +}()); +exports.HelloWithType = HelloWithType; +var HelloSession = /** @class */ (function () { + function HelloSession(init) { + Object.assign(this, init); + } + HelloSession.prototype.createResponse = function () { return new HelloSessionResponse(); }; + HelloSession.prototype.getTypeName = function () { return 'HelloSession'; }; + return HelloSession; +}()); +exports.HelloSession = HelloSession; +var HelloInterface = /** @class */ (function () { + function HelloInterface(init) { + Object.assign(this, init); + } + return HelloInterface; +}()); +exports.HelloInterface = HelloInterface; +var Request1 = /** @class */ (function () { + function Request1(init) { + Object.assign(this, init); + } + Request1.prototype.createResponse = function () { return new Request1Response(); }; + Request1.prototype.getTypeName = function () { return 'Request1'; }; + return Request1; +}()); +exports.Request1 = Request1; +var Request2 = /** @class */ (function () { + function Request2(init) { + Object.assign(this, init); + } + Request2.prototype.createResponse = function () { return new Request2Response(); }; + Request2.prototype.getTypeName = function () { return 'Request2'; }; + return Request2; +}()); +exports.Request2 = Request2; +var HelloInnerTypes = /** @class */ (function () { + function HelloInnerTypes(init) { + Object.assign(this, init); + } + HelloInnerTypes.prototype.createResponse = function () { return new HelloInnerTypesResponse(); }; + HelloInnerTypes.prototype.getTypeName = function () { return 'HelloInnerTypes'; }; + return HelloInnerTypes; +}()); +exports.HelloInnerTypes = HelloInnerTypes; +var GetUserSession = /** @class */ (function () { + function GetUserSession(init) { + Object.assign(this, init); + } + GetUserSession.prototype.createResponse = function () { return new CustomUserSession(); }; + GetUserSession.prototype.getTypeName = function () { return 'GetUserSession'; }; + return GetUserSession; +}()); +exports.GetUserSession = GetUserSession; +var QueryTemplate = /** @class */ (function () { + function QueryTemplate(init) { + Object.assign(this, init); + } + QueryTemplate.prototype.createResponse = function () { return new QueryResponseTemplate(); }; + QueryTemplate.prototype.getTypeName = function () { return 'QueryTemplate'; }; + return QueryTemplate; +}()); +exports.QueryTemplate = QueryTemplate; +var HelloReserved = /** @class */ (function () { + function HelloReserved(init) { + Object.assign(this, init); + } + return HelloReserved; +}()); +exports.HelloReserved = HelloReserved; +var HelloDictionary = /** @class */ (function () { + function HelloDictionary(init) { + Object.assign(this, init); + } + HelloDictionary.prototype.createResponse = function () { return {}; }; + HelloDictionary.prototype.getTypeName = function () { return 'HelloDictionary'; }; + return HelloDictionary; +}()); +exports.HelloDictionary = HelloDictionary; +var HelloBuiltin = /** @class */ (function () { + function HelloBuiltin(init) { + Object.assign(this, init); + } + return HelloBuiltin; +}()); +exports.HelloBuiltin = HelloBuiltin; +var HelloGet = /** @class */ (function () { + function HelloGet(init) { + Object.assign(this, init); + } + HelloGet.prototype.createResponse = function () { return new HelloVerbResponse(); }; + HelloGet.prototype.getTypeName = function () { return 'HelloGet'; }; + return HelloGet; +}()); +exports.HelloGet = HelloGet; +var HelloPost = /** @class */ (function (_super) { + __extends(HelloPost, _super); + function HelloPost(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + HelloPost.prototype.createResponse = function () { return new HelloVerbResponse(); }; + HelloPost.prototype.getTypeName = function () { return 'HelloPost'; }; + return HelloPost; +}(HelloBase)); +exports.HelloPost = HelloPost; +var HelloPut = /** @class */ (function () { + function HelloPut(init) { + Object.assign(this, init); + } + HelloPut.prototype.createResponse = function () { return new HelloVerbResponse(); }; + HelloPut.prototype.getTypeName = function () { return 'HelloPut'; }; + return HelloPut; +}()); +exports.HelloPut = HelloPut; +var HelloDelete = /** @class */ (function () { + function HelloDelete(init) { + Object.assign(this, init); + } + HelloDelete.prototype.createResponse = function () { return new HelloVerbResponse(); }; + HelloDelete.prototype.getTypeName = function () { return 'HelloDelete'; }; + return HelloDelete; +}()); +exports.HelloDelete = HelloDelete; +var HelloPatch = /** @class */ (function () { + function HelloPatch(init) { + Object.assign(this, init); + } + HelloPatch.prototype.createResponse = function () { return new HelloVerbResponse(); }; + HelloPatch.prototype.getTypeName = function () { return 'HelloPatch'; }; + return HelloPatch; +}()); +exports.HelloPatch = HelloPatch; +var HelloReturnVoid = /** @class */ (function () { + function HelloReturnVoid(init) { + Object.assign(this, init); + } + HelloReturnVoid.prototype.createResponse = function () { }; + HelloReturnVoid.prototype.getTypeName = function () { return 'HelloReturnVoid'; }; + return HelloReturnVoid; +}()); +exports.HelloReturnVoid = HelloReturnVoid; +var EnumRequest = /** @class */ (function () { + function EnumRequest(init) { + Object.assign(this, init); + } + EnumRequest.prototype.createResponse = function () { return new EnumResponse(); }; + EnumRequest.prototype.getTypeName = function () { return 'EnumRequest'; }; + return EnumRequest; +}()); +exports.EnumRequest = EnumRequest; +var ExcludeTest1 = /** @class */ (function () { + function ExcludeTest1(init) { + Object.assign(this, init); + } + ExcludeTest1.prototype.createResponse = function () { return new ExcludeTestNested(); }; + ExcludeTest1.prototype.getTypeName = function () { return 'ExcludeTest1'; }; + return ExcludeTest1; +}()); +exports.ExcludeTest1 = ExcludeTest1; +var ExcludeTest2 = /** @class */ (function () { + function ExcludeTest2(init) { + Object.assign(this, init); + } + ExcludeTest2.prototype.createResponse = function () { return ''; }; + ExcludeTest2.prototype.getTypeName = function () { return 'ExcludeTest2'; }; + return ExcludeTest2; +}()); +exports.ExcludeTest2 = ExcludeTest2; +var HelloAuthenticated = /** @class */ (function () { + function HelloAuthenticated(init) { + Object.assign(this, init); + } + HelloAuthenticated.prototype.createResponse = function () { return new HelloAuthenticatedResponse(); }; + HelloAuthenticated.prototype.getTypeName = function () { return 'HelloAuthenticated'; }; + return HelloAuthenticated; +}()); +exports.HelloAuthenticated = HelloAuthenticated; +/** + * Echoes a sentence + */ +// @Route("/echoes", "POST") +// @Api(Description="Echoes a sentence") +var Echoes = /** @class */ (function () { + function Echoes(init) { + Object.assign(this, init); + } + Echoes.prototype.createResponse = function () { return new Echo(); }; + Echoes.prototype.getTypeName = function () { return 'Echoes'; }; + return Echoes; +}()); +exports.Echoes = Echoes; +var CachedEcho = /** @class */ (function () { + function CachedEcho(init) { + Object.assign(this, init); + } + CachedEcho.prototype.createResponse = function () { return new Echo(); }; + CachedEcho.prototype.getTypeName = function () { return 'CachedEcho'; }; + return CachedEcho; +}()); +exports.CachedEcho = CachedEcho; +var AsyncTest = /** @class */ (function () { + function AsyncTest(init) { + Object.assign(this, init); + } + AsyncTest.prototype.createResponse = function () { return new Echo(); }; + AsyncTest.prototype.getTypeName = function () { return 'AsyncTest'; }; + return AsyncTest; +}()); +exports.AsyncTest = AsyncTest; +// @Route("/throwhttperror/{Status}") +var ThrowHttpError = /** @class */ (function () { + function ThrowHttpError(init) { + Object.assign(this, init); + } + ThrowHttpError.prototype.createResponse = function () { return new ThrowHttpErrorResponse(); }; + ThrowHttpError.prototype.getTypeName = function () { return 'ThrowHttpError'; }; + return ThrowHttpError; +}()); +exports.ThrowHttpError = ThrowHttpError; +// @Route("/throw404") +// @Route("/throw404/{Message}") +var Throw404 = /** @class */ (function () { + function Throw404(init) { + Object.assign(this, init); + } + return Throw404; +}()); +exports.Throw404 = Throw404; +// @Route("/return404") +var Return404 = /** @class */ (function () { + function Return404(init) { + Object.assign(this, init); + } + return Return404; +}()); +exports.Return404 = Return404; +// @Route("/return404result") +var Return404Result = /** @class */ (function () { + function Return404Result(init) { + Object.assign(this, init); + } + return Return404Result; +}()); +exports.Return404Result = Return404Result; +// @Route("/throw/{Type}") +var ThrowType = /** @class */ (function () { + function ThrowType(init) { + Object.assign(this, init); + } + ThrowType.prototype.createResponse = function () { return new ThrowTypeResponse(); }; + ThrowType.prototype.getTypeName = function () { return 'ThrowType'; }; + return ThrowType; +}()); +exports.ThrowType = ThrowType; +// @Route("/throwvalidation") +var ThrowValidation = /** @class */ (function () { + function ThrowValidation(init) { + Object.assign(this, init); + } + ThrowValidation.prototype.createResponse = function () { return new ThrowValidationResponse(); }; + ThrowValidation.prototype.getTypeName = function () { return 'ThrowValidation'; }; + return ThrowValidation; +}()); +exports.ThrowValidation = ThrowValidation; +// @Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE") +// @Route("/api/acsprofiles/{profileId}") +var ACSProfile = /** @class */ (function () { + function ACSProfile(init) { + Object.assign(this, init); + } + ACSProfile.prototype.createResponse = function () { return new acsprofileResponse(); }; + ACSProfile.prototype.getTypeName = function () { return 'ACSProfile'; }; + return ACSProfile; +}()); +exports.ACSProfile = ACSProfile; +// @Route("/return/string") +var ReturnString = /** @class */ (function () { + function ReturnString(init) { + Object.assign(this, init); + } + ReturnString.prototype.createResponse = function () { return ''; }; + ReturnString.prototype.getTypeName = function () { return 'ReturnString'; }; + return ReturnString; +}()); +exports.ReturnString = ReturnString; +// @Route("/return/bytes") +var ReturnBytes = /** @class */ (function () { + function ReturnBytes(init) { + Object.assign(this, init); + } + ReturnBytes.prototype.createResponse = function () { return new Uint8Array(0); }; + ReturnBytes.prototype.getTypeName = function () { return 'ReturnBytes'; }; + return ReturnBytes; +}()); +exports.ReturnBytes = ReturnBytes; +// @Route("/return/stream") +var ReturnStream = /** @class */ (function () { + function ReturnStream(init) { + Object.assign(this, init); + } + ReturnStream.prototype.createResponse = function () { return new Blob(); }; + ReturnStream.prototype.getTypeName = function () { return 'ReturnStream'; }; + return ReturnStream; +}()); +exports.ReturnStream = ReturnStream; +// @Route("/Request1/", "GET") +var GetRequest1 = /** @class */ (function () { + function GetRequest1(init) { + Object.assign(this, init); + } + GetRequest1.prototype.createResponse = function () { return new Array(); }; + GetRequest1.prototype.getTypeName = function () { return 'GetRequest1'; }; + return GetRequest1; +}()); +exports.GetRequest1 = GetRequest1; +// @Route("/Request3", "GET") +var GetRequest2 = /** @class */ (function () { + function GetRequest2(init) { + Object.assign(this, init); + } + GetRequest2.prototype.createResponse = function () { return new ReturnedDto(); }; + GetRequest2.prototype.getTypeName = function () { return 'GetRequest2'; }; + return GetRequest2; +}()); +exports.GetRequest2 = GetRequest2; +// @Route("/matchlast/{Id}") +var MatchesLastInt = /** @class */ (function () { + function MatchesLastInt(init) { + Object.assign(this, init); + } + return MatchesLastInt; +}()); +exports.MatchesLastInt = MatchesLastInt; +// @Route("/matchlast/{Slug}") +var MatchesNotLastInt = /** @class */ (function () { + function MatchesNotLastInt(init) { + Object.assign(this, init); + } + return MatchesNotLastInt; +}()); +exports.MatchesNotLastInt = MatchesNotLastInt; +// @Route("/matchregex/{Id}") +var MatchesId = /** @class */ (function () { + function MatchesId(init) { + Object.assign(this, init); + } + return MatchesId; +}()); +exports.MatchesId = MatchesId; +// @Route("/matchregex/{Slug}") +var MatchesSlug = /** @class */ (function () { + function MatchesSlug(init) { + Object.assign(this, init); + } + return MatchesSlug; +}()); +exports.MatchesSlug = MatchesSlug; +// @Route("/{Version}/userdata", "GET") +var SwaggerVersionTest = /** @class */ (function () { + function SwaggerVersionTest(init) { + Object.assign(this, init); + } + return SwaggerVersionTest; +}()); +exports.SwaggerVersionTest = SwaggerVersionTest; +// @Route("/swagger/range") +var SwaggerRangeTest = /** @class */ (function () { + function SwaggerRangeTest(init) { + Object.assign(this, init); + } + return SwaggerRangeTest; +}()); +exports.SwaggerRangeTest = SwaggerRangeTest; +// @Route("/test/errorview") +var TestErrorView = /** @class */ (function () { + function TestErrorView(init) { + Object.assign(this, init); + } + return TestErrorView; +}()); +exports.TestErrorView = TestErrorView; +// @Route("/timestamp", "GET") +var GetTimestamp = /** @class */ (function () { + function GetTimestamp(init) { + Object.assign(this, init); + } + GetTimestamp.prototype.createResponse = function () { return new TimestampData(); }; + GetTimestamp.prototype.getTypeName = function () { return 'GetTimestamp'; }; + return GetTimestamp; +}()); +exports.GetTimestamp = GetTimestamp; +var TestMiniverView = /** @class */ (function () { + function TestMiniverView(init) { + Object.assign(this, init); + } + return TestMiniverView; +}()); +exports.TestMiniverView = TestMiniverView; +// @Route("/testexecproc") +var TestExecProc = /** @class */ (function () { + function TestExecProc(init) { + Object.assign(this, init); + } + return TestExecProc; +}()); +exports.TestExecProc = TestExecProc; +// @Route("/files/{Path*}") +var GetFile = /** @class */ (function () { + function GetFile(init) { + Object.assign(this, init); + } + return GetFile; +}()); +exports.GetFile = GetFile; +// @Route("/test/html2") +var TestHtml2 = /** @class */ (function () { + function TestHtml2(init) { + Object.assign(this, init); + } + return TestHtml2; +}()); +exports.TestHtml2 = TestHtml2; +// @Route("/views/request") +var ViewRequest = /** @class */ (function () { + function ViewRequest(init) { + Object.assign(this, init); + } + ViewRequest.prototype.createResponse = function () { return new ViewResponse(); }; + ViewRequest.prototype.getTypeName = function () { return 'ViewRequest'; }; + return ViewRequest; +}()); +exports.ViewRequest = ViewRequest; +// @Route("/index") +var IndexPage = /** @class */ (function () { + function IndexPage(init) { + Object.assign(this, init); + } + return IndexPage; +}()); +exports.IndexPage = IndexPage; +// @Route("/return/text") +var ReturnText = /** @class */ (function () { + function ReturnText(init) { + Object.assign(this, init); + } + return ReturnText; +}()); +exports.ReturnText = ReturnText; +// @Route("/gzip/{FileName}") +var DownloadGzipFile = /** @class */ (function () { + function DownloadGzipFile(init) { + Object.assign(this, init); + } + DownloadGzipFile.prototype.createResponse = function () { return new Uint8Array(0); }; + DownloadGzipFile.prototype.getTypeName = function () { return 'DownloadGzipFile'; }; + return DownloadGzipFile; +}()); +exports.DownloadGzipFile = DownloadGzipFile; +// @Route("/match/{Language}/{Name*}") +var MatchName = /** @class */ (function () { + function MatchName(init) { + Object.assign(this, init); + } + MatchName.prototype.createResponse = function () { return new HelloResponse(); }; + MatchName.prototype.getTypeName = function () { return 'MatchName'; }; + return MatchName; +}()); +exports.MatchName = MatchName; +// @Route("/match/{Language*}") +var MatchLang = /** @class */ (function () { + function MatchLang(init) { + Object.assign(this, init); + } + MatchLang.prototype.createResponse = function () { return new HelloResponse(); }; + MatchLang.prototype.getTypeName = function () { return 'MatchLang'; }; + return MatchLang; +}()); +exports.MatchLang = MatchLang; +// @Route("/reqlogstest/{Name}") +var RequestLogsTest = /** @class */ (function () { + function RequestLogsTest(init) { + Object.assign(this, init); + } + RequestLogsTest.prototype.createResponse = function () { return ''; }; + RequestLogsTest.prototype.getTypeName = function () { return 'RequestLogsTest'; }; + return RequestLogsTest; +}()); +exports.RequestLogsTest = RequestLogsTest; +var InProcRequest1 = /** @class */ (function () { + function InProcRequest1(init) { + Object.assign(this, init); + } + return InProcRequest1; +}()); +exports.InProcRequest1 = InProcRequest1; +var InProcRequest2 = /** @class */ (function () { + function InProcRequest2(init) { + Object.assign(this, init); + } + return InProcRequest2; +}()); +exports.InProcRequest2 = InProcRequest2; +/** + * SwaggerTest Service Description + */ +// @Route("/swagger", "GET") +// @Route("/swagger/{Name}", "GET") +// @Route("/swagger/{Name}", "POST") +// @Api(Description="SwaggerTest Service Description") +// @ApiResponse(Description="Your request was not understood", StatusCode=400) +// @ApiResponse(Description="Oops, something broke", StatusCode=500) +// @DataContract +var SwaggerTest = /** @class */ (function () { + function SwaggerTest(init) { + Object.assign(this, init); + } + return SwaggerTest; +}()); +exports.SwaggerTest = SwaggerTest; +// @Route("/swaggertest2", "POST") +var SwaggerTest2 = /** @class */ (function () { + function SwaggerTest2(init) { + Object.assign(this, init); + } + return SwaggerTest2; +}()); +exports.SwaggerTest2 = SwaggerTest2; +// @Route("/swagger-complex", "POST") +var SwaggerComplex = /** @class */ (function () { + function SwaggerComplex(init) { + Object.assign(this, init); + } + SwaggerComplex.prototype.createResponse = function () { return new SwaggerComplexResponse(); }; + SwaggerComplex.prototype.getTypeName = function () { return 'SwaggerComplex'; }; + return SwaggerComplex; +}()); +exports.SwaggerComplex = SwaggerComplex; +// @Route("/swaggerpost/{Required1}", "GET") +// @Route("/swaggerpost/{Required1}/{Optional1}", "GET") +// @Route("/swaggerpost", "POST") +var SwaggerPostTest = /** @class */ (function () { + function SwaggerPostTest(init) { + Object.assign(this, init); + } + SwaggerPostTest.prototype.createResponse = function () { return new HelloResponse(); }; + SwaggerPostTest.prototype.getTypeName = function () { return 'SwaggerPostTest'; }; + return SwaggerPostTest; +}()); +exports.SwaggerPostTest = SwaggerPostTest; +// @Route("/swaggerpost2/{Required1}/{Required2}", "GET") +// @Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", "GET") +// @Route("/swaggerpost2", "POST") +var SwaggerPostTest2 = /** @class */ (function () { + function SwaggerPostTest2(init) { + Object.assign(this, init); + } + SwaggerPostTest2.prototype.createResponse = function () { return new HelloResponse(); }; + SwaggerPostTest2.prototype.getTypeName = function () { return 'SwaggerPostTest2'; }; + return SwaggerPostTest2; +}()); +exports.SwaggerPostTest2 = SwaggerPostTest2; +// @Route("/swagger/multiattrtest", "POST") +// @ApiResponse(Description="Code 1", StatusCode=400) +// @ApiResponse(Description="Code 2", StatusCode=402) +// @ApiResponse(Description="Code 3", StatusCode=401) +var SwaggerMultiApiResponseTest = /** @class */ (function () { + function SwaggerMultiApiResponseTest(init) { + Object.assign(this, init); + } + SwaggerMultiApiResponseTest.prototype.createResponse = function () { }; + SwaggerMultiApiResponseTest.prototype.getTypeName = function () { return 'SwaggerMultiApiResponseTest'; }; + return SwaggerMultiApiResponseTest; +}()); +exports.SwaggerMultiApiResponseTest = SwaggerMultiApiResponseTest; +// @Route("/defaultview/class") +var DefaultViewAttr = /** @class */ (function () { + function DefaultViewAttr(init) { + Object.assign(this, init); + } + return DefaultViewAttr; +}()); +exports.DefaultViewAttr = DefaultViewAttr; +// @Route("/defaultview/action") +var DefaultViewActionAttr = /** @class */ (function () { + function DefaultViewActionAttr(init) { + Object.assign(this, init); + } + return DefaultViewActionAttr; +}()); +exports.DefaultViewActionAttr = DefaultViewActionAttr; +// @Route("/dynamically/registered/{Name}") +var DynamicallyRegistered = /** @class */ (function () { + function DynamicallyRegistered(init) { + Object.assign(this, init); + } + return DynamicallyRegistered; +}()); +exports.DynamicallyRegistered = DynamicallyRegistered; +// @Route("/auth") +// @Route("/auth/{provider}") +// @Route("/authenticate") +// @Route("/authenticate/{provider}") +// @DataContract +var Authenticate = /** @class */ (function () { + function Authenticate(init) { + Object.assign(this, init); + } + Authenticate.prototype.createResponse = function () { return new AuthenticateResponse(); }; + Authenticate.prototype.getTypeName = function () { return 'Authenticate'; }; + return Authenticate; +}()); +exports.Authenticate = Authenticate; +// @Route("/assignroles") +// @DataContract +var AssignRoles = /** @class */ (function () { + function AssignRoles(init) { + Object.assign(this, init); + } + AssignRoles.prototype.createResponse = function () { return new AssignRolesResponse(); }; + AssignRoles.prototype.getTypeName = function () { return 'AssignRoles'; }; + return AssignRoles; +}()); +exports.AssignRoles = AssignRoles; +// @Route("/unassignroles") +// @DataContract +var UnAssignRoles = /** @class */ (function () { + function UnAssignRoles(init) { + Object.assign(this, init); + } + UnAssignRoles.prototype.createResponse = function () { return new UnAssignRolesResponse(); }; + UnAssignRoles.prototype.getTypeName = function () { return 'UnAssignRoles'; }; + return UnAssignRoles; +}()); +exports.UnAssignRoles = UnAssignRoles; +// @Route("/session-to-token") +// @DataContract +var ConvertSessionToToken = /** @class */ (function () { + function ConvertSessionToToken(init) { + Object.assign(this, init); + } + ConvertSessionToToken.prototype.createResponse = function () { return new ConvertSessionToTokenResponse(); }; + ConvertSessionToToken.prototype.getTypeName = function () { return 'ConvertSessionToToken'; }; + return ConvertSessionToToken; +}()); +exports.ConvertSessionToToken = ConvertSessionToToken; +// @Route("/access-token") +// @DataContract +var GetAccessToken = /** @class */ (function () { + function GetAccessToken(init) { + Object.assign(this, init); + } + GetAccessToken.prototype.createResponse = function () { return new GetAccessTokenResponse(); }; + GetAccessToken.prototype.getTypeName = function () { return 'GetAccessToken'; }; + return GetAccessToken; +}()); +exports.GetAccessToken = GetAccessToken; +// @Route("/apikeys") +// @Route("/apikeys/{Environment}") +// @DataContract +var GetApiKeys = /** @class */ (function () { + function GetApiKeys(init) { + Object.assign(this, init); + } + GetApiKeys.prototype.createResponse = function () { return new GetApiKeysResponse(); }; + GetApiKeys.prototype.getTypeName = function () { return 'GetApiKeys'; }; + return GetApiKeys; +}()); +exports.GetApiKeys = GetApiKeys; +// @Route("/apikeys/regenerate") +// @Route("/apikeys/regenerate/{Environment}") +// @DataContract +var RegenerateApiKeys = /** @class */ (function () { + function RegenerateApiKeys(init) { + Object.assign(this, init); + } + RegenerateApiKeys.prototype.createResponse = function () { return new RegenerateApiKeysResponse(); }; + RegenerateApiKeys.prototype.getTypeName = function () { return 'RegenerateApiKeys'; }; + return RegenerateApiKeys; +}()); +exports.RegenerateApiKeys = RegenerateApiKeys; +// @Route("/register") +// @DataContract +var Register = /** @class */ (function () { + function Register(init) { + Object.assign(this, init); + } + Register.prototype.createResponse = function () { return new RegisterResponse(); }; + Register.prototype.getTypeName = function () { return 'Register'; }; + return Register; +}()); +exports.Register = Register; +// @Route("/pgsql/rockstars") +var QueryPostgresRockstars = /** @class */ (function (_super) { + __extends(QueryPostgresRockstars, _super); + function QueryPostgresRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryPostgresRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryPostgresRockstars.prototype.getTypeName = function () { return 'QueryPostgresRockstars'; }; + return QueryPostgresRockstars; +}(QueryDb_1)); +exports.QueryPostgresRockstars = QueryPostgresRockstars; +// @Route("/pgsql/pgrockstars") +var QueryPostgresPgRockstars = /** @class */ (function (_super) { + __extends(QueryPostgresPgRockstars, _super); + function QueryPostgresPgRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryPostgresPgRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryPostgresPgRockstars.prototype.getTypeName = function () { return 'QueryPostgresPgRockstars'; }; + return QueryPostgresPgRockstars; +}(QueryDb_1)); +exports.QueryPostgresPgRockstars = QueryPostgresPgRockstars; +var QueryRockstarsConventions = /** @class */ (function (_super) { + __extends(QueryRockstarsConventions, _super); + function QueryRockstarsConventions(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarsConventions.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarsConventions.prototype.getTypeName = function () { return 'QueryRockstarsConventions'; }; + return QueryRockstarsConventions; +}(QueryDb_1)); +exports.QueryRockstarsConventions = QueryRockstarsConventions; +// @AutoQueryViewer(Description="Use this option to search for Rockstars!", Title="Search for Rockstars") +var QueryCustomRockstars = /** @class */ (function (_super) { + __extends(QueryCustomRockstars, _super); + function QueryCustomRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryCustomRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryCustomRockstars.prototype.getTypeName = function () { return 'QueryCustomRockstars'; }; + return QueryCustomRockstars; +}(QueryDb_2)); +exports.QueryCustomRockstars = QueryCustomRockstars; +// @Route("/customrockstars") +var QueryRockstarAlbums = /** @class */ (function (_super) { + __extends(QueryRockstarAlbums, _super); + function QueryRockstarAlbums(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarAlbums.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarAlbums.prototype.getTypeName = function () { return 'QueryRockstarAlbums'; }; + return QueryRockstarAlbums; +}(QueryDb_2)); +exports.QueryRockstarAlbums = QueryRockstarAlbums; +var QueryRockstarAlbumsImplicit = /** @class */ (function (_super) { + __extends(QueryRockstarAlbumsImplicit, _super); + function QueryRockstarAlbumsImplicit(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarAlbumsImplicit.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarAlbumsImplicit.prototype.getTypeName = function () { return 'QueryRockstarAlbumsImplicit'; }; + return QueryRockstarAlbumsImplicit; +}(QueryDb_2)); +exports.QueryRockstarAlbumsImplicit = QueryRockstarAlbumsImplicit; +var QueryRockstarAlbumsLeftJoin = /** @class */ (function (_super) { + __extends(QueryRockstarAlbumsLeftJoin, _super); + function QueryRockstarAlbumsLeftJoin(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarAlbumsLeftJoin.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarAlbumsLeftJoin.prototype.getTypeName = function () { return 'QueryRockstarAlbumsLeftJoin'; }; + return QueryRockstarAlbumsLeftJoin; +}(QueryDb_2)); +exports.QueryRockstarAlbumsLeftJoin = QueryRockstarAlbumsLeftJoin; +var QueryOverridedRockstars = /** @class */ (function (_super) { + __extends(QueryOverridedRockstars, _super); + function QueryOverridedRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryOverridedRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryOverridedRockstars.prototype.getTypeName = function () { return 'QueryOverridedRockstars'; }; + return QueryOverridedRockstars; +}(QueryDb_1)); +exports.QueryOverridedRockstars = QueryOverridedRockstars; +var QueryOverridedCustomRockstars = /** @class */ (function (_super) { + __extends(QueryOverridedCustomRockstars, _super); + function QueryOverridedCustomRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryOverridedCustomRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryOverridedCustomRockstars.prototype.getTypeName = function () { return 'QueryOverridedCustomRockstars'; }; + return QueryOverridedCustomRockstars; +}(QueryDb_2)); +exports.QueryOverridedCustomRockstars = QueryOverridedCustomRockstars; +// @Route("/query-custom/rockstars") +var QueryFieldRockstars = /** @class */ (function (_super) { + __extends(QueryFieldRockstars, _super); + function QueryFieldRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryFieldRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryFieldRockstars.prototype.getTypeName = function () { return 'QueryFieldRockstars'; }; + return QueryFieldRockstars; +}(QueryDb_1)); +exports.QueryFieldRockstars = QueryFieldRockstars; +var QueryFieldRockstarsDynamic = /** @class */ (function (_super) { + __extends(QueryFieldRockstarsDynamic, _super); + function QueryFieldRockstarsDynamic(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryFieldRockstarsDynamic.prototype.createResponse = function () { return new QueryResponse(); }; + QueryFieldRockstarsDynamic.prototype.getTypeName = function () { return 'QueryFieldRockstarsDynamic'; }; + return QueryFieldRockstarsDynamic; +}(QueryDb_1)); +exports.QueryFieldRockstarsDynamic = QueryFieldRockstarsDynamic; +var QueryRockstarsFilter = /** @class */ (function (_super) { + __extends(QueryRockstarsFilter, _super); + function QueryRockstarsFilter(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarsFilter.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarsFilter.prototype.getTypeName = function () { return 'QueryRockstarsFilter'; }; + return QueryRockstarsFilter; +}(QueryDb_1)); +exports.QueryRockstarsFilter = QueryRockstarsFilter; +var QueryCustomRockstarsFilter = /** @class */ (function (_super) { + __extends(QueryCustomRockstarsFilter, _super); + function QueryCustomRockstarsFilter(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryCustomRockstarsFilter.prototype.createResponse = function () { return new QueryResponse(); }; + QueryCustomRockstarsFilter.prototype.getTypeName = function () { return 'QueryCustomRockstarsFilter'; }; + return QueryCustomRockstarsFilter; +}(QueryDb_2)); +exports.QueryCustomRockstarsFilter = QueryCustomRockstarsFilter; +var QueryRockstarsIFilter = /** @class */ (function (_super) { + __extends(QueryRockstarsIFilter, _super); + function QueryRockstarsIFilter(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarsIFilter.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarsIFilter.prototype.getTypeName = function () { return 'QueryRockstarsIFilter'; }; + return QueryRockstarsIFilter; +}(QueryDb_1)); +exports.QueryRockstarsIFilter = QueryRockstarsIFilter; +// @Route("/OrRockstars") +var QueryOrRockstars = /** @class */ (function (_super) { + __extends(QueryOrRockstars, _super); + function QueryOrRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryOrRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryOrRockstars.prototype.getTypeName = function () { return 'QueryOrRockstars'; }; + return QueryOrRockstars; +}(QueryDb_1)); +exports.QueryOrRockstars = QueryOrRockstars; +var QueryGetRockstars = /** @class */ (function (_super) { + __extends(QueryGetRockstars, _super); + function QueryGetRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryGetRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryGetRockstars.prototype.getTypeName = function () { return 'QueryGetRockstars'; }; + return QueryGetRockstars; +}(QueryDb_1)); +exports.QueryGetRockstars = QueryGetRockstars; +var QueryGetRockstarsDynamic = /** @class */ (function (_super) { + __extends(QueryGetRockstarsDynamic, _super); + function QueryGetRockstarsDynamic(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryGetRockstarsDynamic.prototype.createResponse = function () { return new QueryResponse(); }; + QueryGetRockstarsDynamic.prototype.getTypeName = function () { return 'QueryGetRockstarsDynamic'; }; + return QueryGetRockstarsDynamic; +}(QueryDb_1)); +exports.QueryGetRockstarsDynamic = QueryGetRockstarsDynamic; +// @Route("/movies/search") +var SearchMovies = /** @class */ (function (_super) { + __extends(SearchMovies, _super); + function SearchMovies(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + SearchMovies.prototype.createResponse = function () { return new QueryResponse(); }; + SearchMovies.prototype.getTypeName = function () { return 'SearchMovies'; }; + return SearchMovies; +}(QueryDb_1)); +exports.SearchMovies = SearchMovies; +// @Route("/movies") +var QueryMovies = /** @class */ (function (_super) { + __extends(QueryMovies, _super); + function QueryMovies(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryMovies.prototype.createResponse = function () { return new QueryResponse(); }; + QueryMovies.prototype.getTypeName = function () { return 'QueryMovies'; }; + return QueryMovies; +}(QueryDb_1)); +exports.QueryMovies = QueryMovies; +var StreamMovies = /** @class */ (function (_super) { + __extends(StreamMovies, _super); + function StreamMovies(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + StreamMovies.prototype.createResponse = function () { return new QueryResponse(); }; + StreamMovies.prototype.getTypeName = function () { return 'StreamMovies'; }; + return StreamMovies; +}(QueryDb_1)); +exports.StreamMovies = StreamMovies; +var QueryUnknownRockstars = /** @class */ (function (_super) { + __extends(QueryUnknownRockstars, _super); + function QueryUnknownRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryUnknownRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryUnknownRockstars.prototype.getTypeName = function () { return 'QueryUnknownRockstars'; }; + return QueryUnknownRockstars; +}(QueryDb_1)); +exports.QueryUnknownRockstars = QueryUnknownRockstars; +// @Route("/query/rockstar-references") +var QueryRockstarsWithReferences = /** @class */ (function (_super) { + __extends(QueryRockstarsWithReferences, _super); + function QueryRockstarsWithReferences(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryRockstarsWithReferences.prototype.createResponse = function () { return new QueryResponse(); }; + QueryRockstarsWithReferences.prototype.getTypeName = function () { return 'QueryRockstarsWithReferences'; }; + return QueryRockstarsWithReferences; +}(QueryDb_1)); +exports.QueryRockstarsWithReferences = QueryRockstarsWithReferences; +var QueryPocoBase = /** @class */ (function (_super) { + __extends(QueryPocoBase, _super); + function QueryPocoBase(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryPocoBase.prototype.createResponse = function () { return new QueryResponse(); }; + QueryPocoBase.prototype.getTypeName = function () { return 'QueryPocoBase'; }; + return QueryPocoBase; +}(QueryDb_1)); +exports.QueryPocoBase = QueryPocoBase; +var QueryPocoIntoBase = /** @class */ (function (_super) { + __extends(QueryPocoIntoBase, _super); + function QueryPocoIntoBase(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryPocoIntoBase.prototype.createResponse = function () { return new QueryResponse(); }; + QueryPocoIntoBase.prototype.getTypeName = function () { return 'QueryPocoIntoBase'; }; + return QueryPocoIntoBase; +}(QueryDb_2)); +exports.QueryPocoIntoBase = QueryPocoIntoBase; +// @Route("/query/alltypes") +var QueryAllTypes = /** @class */ (function (_super) { + __extends(QueryAllTypes, _super); + function QueryAllTypes(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryAllTypes.prototype.createResponse = function () { return new QueryResponse(); }; + QueryAllTypes.prototype.getTypeName = function () { return 'QueryAllTypes'; }; + return QueryAllTypes; +}(QueryDb_1)); +exports.QueryAllTypes = QueryAllTypes; +// @Route("/querydata/rockstars") +var QueryDataRockstars = /** @class */ (function (_super) { + __extends(QueryDataRockstars, _super); + function QueryDataRockstars(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + QueryDataRockstars.prototype.createResponse = function () { return new QueryResponse(); }; + QueryDataRockstars.prototype.getTypeName = function () { return 'QueryDataRockstars'; }; + return QueryDataRockstars; +}(QueryData)); +exports.QueryDataRockstars = QueryDataRockstars; diff --git a/tests/CheckMvc/TypeScript.dtos.js.map b/tests/CheckMvc/TypeScript.dtos.js.map new file mode 100644 index 00000000000..87aa6f92ca5 --- /dev/null +++ b/tests/CheckMvc/TypeScript.dtos.js.map @@ -0,0 +1 @@ +{"version":3,"file":"TypeScript.dtos.js","sourceRoot":"","sources":["TypeScript.dtos.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;EAeE;;;;;;;;;;;;AAgDF;IAAA;IAsBA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAtBD,IAsBC;AAtBY,8BAAS;AAwBtB;IAAkC,6BAAS;IAA3C;;IAEA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAFD,CAAkC,SAAS,GAE1C;AAFY,8BAAS;AAItB;IAAA;IAyBA,CAAC;IAAD,sBAAC;AAAD,CAAC,AAzBD,IAyBC;AAzBY,0CAAe;AA2B5B,gBAAgB;AAChB;IAAA;IAaA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAbD,IAaC;AAbY,sCAAa;AAe1B,gBAAgB;AAChB;IAAA;IAgBA,CAAC;IAAD,qBAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,wCAAc;AAkB3B;IAAkC,6BAAS;IAA3C;;IAEA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAFD,CAAkC,SAAS,GAE1C;AAFY,8BAAS;AAItB;IAAA;IAkBA,CAAC;IAAD,eAAC;AAAD,CAAC,AAlBD,IAkBC;AAlBY,4BAAQ;AAoBrB;IAAA;IAGA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oCAAY;AAKzB;IAAA;IAGA,CAAC;IAAD,8BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,0DAAuB;AAKpC;IAAA;IAIA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,8CAAiB;AAM9B;IAAA;IAKA,CAAC;IAAD,0BAAC;AAAD,CAAC,AALD,IAKC;AALY,kDAAmB;AAOhC;IAAA;IAOA,CAAC;IAAD,sBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,0CAAe;AAS5B,gBAAgB;AAChB;IAAA;IAKA,CAAC;IAAD,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB;IAAA;IAKA,CAAC;IAAD,uBAAC;AAAD,CAAC,AALD,IAKC;AALY,4CAAgB;AAO7B;IAAA;IAMA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAND,IAMC;AANY,sCAAa;AAQ1B;IAAA;IAIA,CAAC;IAAD,2BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oDAAoB;AAMjC;IAAA;IAMA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAND,IAMC;AANY,gDAAkB;AAQ/B;IAAA;IAKA,CAAC;IAAD,wBAAC;AAAD,CAAC,AALD,IAKC;AALY,8CAAiB;AAO9B;IAAA;IAoBA,CAAC;IAAD,2BAAC;AAAD,CAAC,AApBD,IAoBC;AApBY,oDAAoB;AAsBjC;IAAA;IAwBA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAxBD,IAwBC;AAxBY,oCAAY;AA0BzB;IAAA;IAKA,CAAC;IAAD,0BAAC;AAAD,CAAC,AALD,IAKC;AALY,kDAAmB;AAOhC;IAAA;IAsBA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAtBD,IAsBC;AAtBY,sDAAqB;AAwBlC;IAAA;IAKA,CAAC;IAAD,8BAAC;AAAD,CAAC,AALD,IAKC;AALY,0DAAuB;AAOpC;IAAA;IAMA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAND,IAMC;AANY,gDAAkB;AAQ/B;IAAA;IAEA,CAAC;IAAD,6BAAC;AAAD,CAAC,AAFD,IAEC;AAFY,wDAAsB;AAInC;IAAA;IAGA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,kCAAW;AAKxB;IAAA;IAGA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,gCAAU;AAKvB;IAAA;IAGA,CAAC;IAAD,0BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,kDAAmB;AAKhC;IAAA;IAGA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,kCAAW;AASxB,WAAW;AACX,IAAY,SAKX;AALD,WAAY,SAAS;IAEjB,6CAAU,CAAA;IACV,6CAAU,CAAA;IACV,6CAAU,CAAA;AACd,CAAC,EALW,SAAS,GAAT,iBAAS,KAAT,iBAAS,QAKpB;AAED;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oBAAI;AAKjB;IAAA;IAcA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAdD,IAcC;AAdY,gDAAkB;AAgB/B;IAAA;IAIA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oCAAY;AAMzB;IAAA;IAIA,CAAC;IAAD,cAAC;AAAD,CAAC,AAJD,IAIC;AAJY,0BAAO;AAMpB;IAAA;IAGA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8BAAS;AAKtB;IAAA;IAGA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8CAAiB;AAK9B;IAAA;IAIA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,kCAAW;AAMxB;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oBAAI;AAKjB;IAAA;IAGA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sCAAa;AAK1B;IAAA;IAGA,CAAC;IAAD,8BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,0DAAuB;AAKpC;IAAA;IAGA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8BAAS;AAkBtB,gBAAgB;AAChB;IAAA;IAqIA,CAAC;IAAD,sBAAC;AAAD,CAAC,AArID,IAqIC;AArIY,0CAAe;AAgJ5B;IAAA;IAEA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAFD,IAEC;AAFY,gCAAU;AASvB;IAAA;IAGA,CAAC;IAAD,YAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sBAAK;AAKlB;IAAA;IAGA,CAAC;IAAD,YAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sBAAK;AAKlB;IAAA;IAIA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,8BAAS;AAQtB;IAAA;IAIA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,sCAAa;AAW1B;IAAA;IAIA,CAAC;IAAD,cAAC;AAAD,CAAC,AAJD,IAIC;AAJY,0BAAO;AAMpB;IAAA;IAKA,CAAC;IAAD,cAAC;AAAD,CAAC,AALD,IAKC;AALY,0BAAO;AAcpB;IAAA;IAOA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,gDAAkB;AAS/B;IAAA;IAmBA,CAAC;IAAD,0BAAC;AAAD,CAAC,AAnBD,IAmBC;AAnBY,kDAAmB;AAuBhC,gBAAgB;AAChB;IAAA;IAUA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAVD,IAUC;AAVY,gCAAU;AAYvB;IAAgC,8BAAQ;IAAxC;;IAEA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAFD,CAAgC,QAAQ,GAEvC;AAFY,gCAAU;AAIvB;IAA2C,6BAAS;IAApD;;IAEA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAFD,CAA2C,SAAS,GAEnD;AAFY,8BAAS;AAItB;IAAA;IAcA,CAAC;IAAD,qBAAC;AAAD,CAAC,AAdD,IAcC;AAdY,wCAAc;AAoB3B;IAAA;IAWA,CAAC;IAAD,YAAC;AAAD,CAAC,AAXD,IAWC;AAXY,sBAAK;AAalB;IAAA;IAKA,CAAC;IAAD,oBAAC;AAAD,CAAC,AALD,IAKC;AALY,sCAAa;AAO1B;IAAA;IAOA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,8CAAiB;AAS9B;IAAA;IAIA,CAAC;IAAD,+BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,4DAAwB;AAMrC;IAAA;IAIA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oEAA4B;AAMzC;IAAA;IAIA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oEAA4B;AAMzC;IAAA;IAEA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAFD,IAEC;AAFY,gCAAU;AAIvB,gBAAgB;AAChB;IAAA;IAgBA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,sCAAa;AAkB1B,gBAAgB;AAChB;IAAA;IAIA,CAAC;IAAD,oCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,sEAA6B;AAM1C;IAAA;IAOA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAPD,IAOC;AAPY,sDAAqB;AASlC;IAAA;IAIA,CAAC;IAAD,8BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,0DAAuB;AAMpC,0BAA0B;AAC1B;IAAA;IAIA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC;IAC/C,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oCAAY;AAMzB,yCAAyC;AACzC;IAAA;IAIA,CAAC;IAFG,oDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,2BAA2B,EAAE,CAAC,CAAC,CAAC;IAC9D,iDAAW,GAAX,cAAgB,MAAM,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC3D,kCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,kEAA2B;AAMxC,sCAAsC;AACtC;IAAA;IAIA,CAAC;IAFG,iDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,wBAAwB,EAAE,CAAC,CAAC,CAAC;IAC3D,8CAAW,GAAX,cAAgB,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACxD,+BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,4DAAwB;AAMrC;IAAA;IAIA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oEAA4B;AAMzC;IAAA;IAGA,CAAC;IAAD,uBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,4CAAgB;AAK7B;IAAA;IAIA,CAAC;IAAD,0BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,kDAAmB;AAMhC;IAAA;IAGA,CAAC;IAAD,2BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oDAAoB;AAKjC;IAAA;IAIA,CAAC;IAAD,2BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oDAAoB;AAMjC,gBAAgB;AAChB;IAAA;IAQA,CAAC;IAAD,yBAAC;AAAD,CAAC,AARD,IAQC;AARY,gDAAkB;AAU/B;IAAA;IAQA,CAAC;IAAD,gCAAC;AAAD,CAAC,AARD,IAQC;AARY,8DAAyB;AAUtC,gBAAgB;AAChB;IAAA;IAcA,CAAC;IAAD,gCAAC;AAAD,CAAC,AAdD,IAcC;AAdY,8DAAyB;AAgBtC;IAAA;IAGA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sCAAa;AAK1B;;EAEE;AACF,gBAAgB;AAChB;IAAA;IAIA,CAAC;IAAD,6BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,wDAAsB;AAMnC;IAAA;IAKA,CAAC;IAFG,kCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,KAAK,EAAc,CAAC,CAAC,CAAC;IACpD,+BAAW,GAAX,cAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,gBAAC;AAAD,CAAC,AALD,IAKC;AALY,8BAAS;AAOtB;IAAA;IAKA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,KAAK,EAAe,CAAC,CAAC,CAAC;IACrD,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AALD,IAKC;AALY,gCAAU;AAOvB;IAAA;IAMA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAND,IAMC;AANY,sDAAqB;AAQlC;IAAA;IAiCA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC3C,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AAjCD,IAiCC;AAjCY,4BAAQ;AAmCrB;IAAA;IAKA,CAAC;IAAD,4BAAC;AAAD,CAAC,AALD,IAKC;AALY,sDAAqB;AAOlC,gBAAgB;AAChB;IAAA;IAIA,CAAC;IAAD,oCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,sEAA6B;AAM1C;;EAEE;AACF;IAAA;IAGA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oEAA4B;AAKzC;IAAkD,gDAAiB;IAAnE;;IAGA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAHD,CAAkD,iBAAiB,GAGlE;AAHY,oEAA4B;AAKzC;IAAsD,oDAAuB;IAA7E;;IAGA,CAAC;IAAD,uCAAC;AAAD,CAAC,AAHD,CAAsD,uBAAuB,GAG5E;AAHY,4EAAgC;AAK7C;IAAA;IAGA,CAAC;IAAD,6BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,wDAAsB;AAKnC;IAAA;IAGA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sDAAqB;AAKlC;IAAA;IAMA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9C,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AAND,IAMC;AANY,kCAAW;AAQxB;IAAA;IAGA,CAAC;IAAD,2BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oDAAoB;AAKjC;IAAA;IAKA,CAAC;IAFG,iDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,wBAAwB,EAAE,CAAC,CAAC,CAAC;IAC3D,8CAAW,GAAX,cAAgB,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACxD,+BAAC;AAAD,CAAC,AALD,IAKC;AALY,4DAAwB;AAOrC;IAAA;IAGA,CAAC;IAAD,uBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,4CAAgB;AAK7B;IAAA;IAGA,CAAC;IAAD,uBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,4CAAgB;AAK7B;IAAA;IAKA,CAAC;IAAD,8BAAC;AAAD,CAAC,AALD,IAKC;AALY,0DAAuB;AAOpC;IAAuC,qCAAe;IAAtD;;IAOA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAPD,CAAuC,eAAe,GAOrD;AAPY,8CAAiB;AAS9B,gBAAgB;AAChB;IAAA;IAgBA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,sDAAqB;AAkBlC;IAAA;IAGA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8CAAiB;AAK9B;IAAA;IAGA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oCAAY;AAKzB;IAAA;IAGA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8CAAiB;AAK9B;IAAA;IAKA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AALD,IAKC;AALY,8CAAiB;AAO9B;IAAA;IAKA,CAAC;IAFG,yCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACnD,sCAAW,GAAX,cAAgB,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAChD,uBAAC;AAAD,CAAC,AALD,IAKC;AALY,4CAAgB;AAO7B;IAAA;IAQA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC;IAC7C,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AARD,IAQC;AARY,gCAAU;AAUvB;IAAA;IAQA,CAAC;IAAD,iCAAC;AAAD,CAAC,AARD,IAQC;AARY,gEAA0B;AAUvC;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oBAAI;AAKjB;IAAA;IAEA,CAAC;IAAD,6BAAC;AAAD,CAAC,AAFD,IAEC;AAFY,wDAAsB;AAInC;IAAA;IAGA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8CAAiB;AAK9B;IAAA;IAMA,CAAC;IAAD,8BAAC;AAAD,CAAC,AAND,IAMC;AANY,0DAAuB;AAQpC;IAAA;IAGA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,gDAAkB;AAK/B;IAAA;IAGA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,kCAAW;AAKxB,6BAA6B;AAC7B;IAAA;IAKA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9C,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB,6BAA6B;AAC7B;IAAA;IAKA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9C,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB;IAAA;IAGA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sCAAa;AAK1B,uBAAuB;AACvB;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC3C,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAAA;IAyBA,CAAC;IAAD,6BAAC;AAAD,CAAC,AAzBD,IAyBC;AAzBY,wDAAsB;AA2BnC;;EAEE;AACF,oCAAoC;AACpC,kCAAkC;AAClC;IAAA;IAKA,CAAC;IAFG,2CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACrD,wCAAW,GAAX,cAAgB,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClD,yBAAC;AAAD,CAAC,AALD,IAKC;AALY,gDAAkB;AAO/B;;EAEE;AACF,yCAAyC;AACzC,iCAAiC;AACjC;IAAA;IAMA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AAND,IAMC;AANY,8CAAiB;AAQ9B;;EAEE;AACF,qCAAqC;AACrC,+BAA+B;AAC/B;IAAA;IAKA,CAAC;IAFG,4CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACtD,yCAAW,GAAX,cAAgB,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACnD,0BAAC;AAAD,CAAC,AALD,IAKC;AALY,kDAAmB;AAOhC;;EAEE;AACF,yCAAyC;AACzC,iCAAiC;AACjC;IAAA;IAMA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AAND,IAMC;AANY,8CAAiB;AAQ9B,0BAA0B;AAC1B;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC3C,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB,gBAAgB;AAChB;IAAA;IA4BA,CAAC;IAAD,2BAAC;AAAD,CAAC,AA5BD,IA4BC;AA5BY,oDAAoB;AA8BjC,gBAAgB;AAChB;IAAA;IAUA,CAAC;IAAD,0BAAC;AAAD,CAAC,AAVD,IAUC;AAVY,kDAAmB;AAYhC,gBAAgB;AAChB;IAAA;IAUA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAVD,IAUC;AAVY,sDAAqB;AAYlC,gBAAgB;AAChB;IAAA;IAOA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,gDAAkB;AAS/B,gBAAgB;AAChB;IAAA;IAyBA,CAAC;IAAD,uBAAC;AAAD,CAAC,AAzBD,IAyBC;AAzBY,4CAAgB;AA2B7B,sBAAsB;AACtB;IAAA;IAEA,CAAC;IAAD,eAAC;AAAD,CAAC,AAFD,IAEC;AAFY,4BAAQ;AAIrB,+BAA+B;AAC/B,sCAAsC;AACtC;IAAsC,oCAA0B;IAAhE;;IAMA,CAAC;IAFG,yCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAmB,CAAC,CAAC,CAAC;IACjE,sCAAW,GAAX,cAAgB,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAChD,uBAAC;AAAD,CAAC,AAND,CAAsC,SAAS,GAM9C;AANY,4CAAgB;AAQ7B;IAA+B,6BAA0B;IAAzD;;IAIA,CAAC;IAFG,kCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAmB,CAAC,CAAC,CAAC;IACjE,+BAAW,GAAX,cAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,gBAAC;AAAD,CAAC,AAJD,CAA+B,SAAS,GAIvC;AAJY,8BAAS;AAMtB;IAAoC,kCAA0B;IAA9D;;IAIA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAmB,CAAC,CAAC,CAAC;IACjE,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AAJD,CAAoC,SAAS,GAI5C;AAJY,wCAAc;AAM3B;IAAmC,iCAA0B;IAA7D;;IAIA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAmB,CAAC,CAAC,CAAC;IACjE,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AAJD,CAAmC,SAAS,GAI3C;AAJY,sCAAa;AAM1B;IAAwC,sCAA0B;IAAlE;;IAIA,CAAC;IAFG,2CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAmB,CAAC,CAAC,CAAC;IACjE,wCAAW,GAAX,cAAgB,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClD,yBAAC;AAAD,CAAC,AAJD,CAAwC,SAAS,GAIhD;AAJY,gDAAkB;AAM/B,6BAA6B;AAC7B;IAAoC,kCAAmB;IAAvD;;IAKA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AALD,CAAoC,SAAS,GAK5C;AALY,wCAAc;AAO3B;IAAA;IAKA,CAAC;IAFG,4CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;IACzC,yCAAW,GAAX,cAAgB,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACnD,0BAAC;AAAD,CAAC,AALD,IAKC;AALY,kDAAmB;AAOhC,4CAA4C;AAC5C,gBAAgB;AAChB;IAAA;IAYA,CAAC;IAFG,8CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAChE,2CAAW,GAAX,cAAgB,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;IACrD,4BAAC;AAAD,CAAC,AAZD,IAYC;AAZY,sDAAqB;AAclC,gCAAgC;AAChC;IAAA;IAKA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AALD,IAKC;AALY,sCAAa;AAO1B,8BAA8B;AAC9B;IAAA;IAGA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oCAAY;AAKzB,mCAAmC;AACnC;IAAA;IAIA,CAAC;IAAD,qBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,wCAAc;AAM3B,uBAAuB;AACvB;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oBAAI;AAKjB;IAAA;IAMA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,uBAAuB,EAAE,CAAC,CAAC,CAAC;IAC1D,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AAND,IAMC;AANY,0CAAe;AAQ5B;IAAA;IAIA,CAAC;IAFG,6CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,4BAA4B,EAAE,CAAC,CAAC,CAAC;IAC/D,0CAAW,GAAX,cAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpD,2BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oDAAoB;AAMjC;IAAA;IAGA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sCAAa;AAK1B;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACnD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAAA;IAMA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACtD,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AAND,IAMC;AANY,kCAAW;AAQxB;IAAA;IAMA,CAAC;IAFG,yCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACtD,sCAAW,GAAX,cAAgB,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAChD,uBAAC;AAAD,CAAC,AAND,IAMC;AANY,4CAAgB;AAQ7B,gCAAgC;AAChC;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC,CAAC;IACvD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAAA;IAKA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC,CAAC;IACvD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AALD,IAKC;AALY,oCAAY;AAOzB,4BAA4B;AAC5B,gBAAgB;AAChB;IAAA;IAIA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACrD,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,gCAAU;AAMvB;IAAA;IAKA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,yBAAyB,EAAE,CAAC,CAAC,CAAC;IAC5D,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AALD,IAKC;AALY,0CAAe;AAO5B;IAAA;IAGA,CAAC;IAAD,8BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,0DAAuB;AAKpC,6BAA6B;AAC7B;IAAA;IAGA,CAAC;IAAD,sBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,0CAAe;AAK5B;;EAEE;AACF;IAAA;IASA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,yBAAyB,EAAE,CAAC,CAAC,CAAC;IAC5D,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AATD,IASC;AATY,8CAAiB;AAW9B;IAAA;IAKA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,oCAAW,GAAX,cAAgB,MAAM,CAAC,uCAAuC,CAAC,CAAC,CAAC;IACrE,qBAAC;AAAD,CAAC,AALD,IAKC;AALY,wCAAc;AAO3B,mBAAmB;AACnB,0BAA0B;AAC1B;IAAA;IAQA,CAAC;IAFG,8BAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,2BAAW,GAAX,cAAgB,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,YAAC;AAAD,CAAC,AARD,IAQC;AARY,sBAAK;AAUlB;;EAEE;AACF,gBAAgB;AAChB;IAAA;IAMA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC;IACzD,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AAND,IAMC;AANY,wCAAc;AAQ3B;IAAA;IAMA,CAAC;IAFG,6CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,0CAAW,GAAX,cAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpD,2BAAC;AAAD,CAAC,AAND,IAMC;AANY,oDAAoB;AAQjC;IAAA;IAKA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,KAAK,EAAuB,CAAC,CAAC,CAAC;IAC7D,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AALD,IAKC;AALY,0CAAe;AAO5B;IAAA;IAKA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AALD,IAKC;AALY,sCAAa;AAO1B;IAAA;IAMA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAND,IAMC;AANY,sCAAa;AAQ1B;IAAA;IAKA,CAAC;IAAD,2BAAC;AAAD,CAAC,AALD,IAKC;AALY,oDAAoB;AAOjC;;EAEE;AACF,uCAAuC;AACvC,oDAAoD;AACpD,8EAA8E;AAC9E,gBAAgB;AAChB;IAAA;IAYA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,8CAAiB;AAc9B;;EAEE;AACF,uCAAuC;AACvC;IAAA;IAOA,CAAC;IAAD,qBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,wCAAc;AAS3B;IAAA;IAOA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,sCAAa;AAS1B;IAAA;IAKA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB;IAAA;IAKA,CAAC;IAFG,kCAAc,GAAd,cAAkB,CAAC;IACnB,+BAAW,GAAX,cAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,gBAAC;AAAD,CAAC,AALD,IAKC;AALY,8BAAS;AAOtB,gBAAgB;AAChB;IAAA;IASA,CAAC;IAFG,8CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAChE,2CAAW,GAAX,cAAgB,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;IACrD,4BAAC;AAAD,CAAC,AATD,IASC;AATY,sDAAqB;AAWlC;;EAEE;AACF;IAAA;IAKA,CAAC;IAFG,6CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,4BAA4B,EAAE,CAAC,CAAC,CAAC;IAC/D,0CAAW,GAAX,cAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpD,2BAAC;AAAD,CAAC,AALD,IAKC;AALY,oDAAoB;AAOjC;IAA0C,wCAAS;IAAnD;;IAKA,CAAC;IAFG,6CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,4BAA4B,EAAE,CAAC,CAAC,CAAC;IAC/D,0CAAW,GAAX,cAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpD,2BAAC;AAAD,CAAC,AALD,CAA0C,SAAS,GAKlD;AALY,oDAAoB;AAOjC;IAAiD,+CAAiB;IAAlE;;IAGA,CAAC;IAAD,kCAAC;AAAD,CAAC,AAHD,CAAiD,WAAW,GAG3D;AAHY,kEAA2B;AAKxC;IAAkD,gDAAkB;IAApE;;IAGA,CAAC;IAAD,mCAAC;AAAD,CAAC,AAHD,CAAkD,WAAW,GAG5D;AAHY,oEAA4B;AAKzC;IAAgD,8CAAiB;IAAjE;;IAEA,CAAC;IAAD,iCAAC;AAAD,CAAC,AAFD,CAAgD,WAAW,GAE1D;AAFY,gEAA0B;AAIvC;IAA8C,4CAAoB;IAAlE;;IAEA,CAAC;IAAD,+BAAC;AAAD,CAAC,AAFD,CAA8C,KAAK,GAElD;AAFY,4DAAwB;AAIrC;IAAA;IAKA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,gCAAgC,EAAE,CAAC,CAAC,CAAC;IACnE,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AALD,IAKC;AALY,0CAAe;AAO5B,wBAAwB;AACxB;IAAA;IAKA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC;IACzD,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AALD,IAKC;AALY,wCAAc;AAO3B;IAAA;IAKA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AALD,IAKC;AALY,sCAAa;AAO1B;IAAA;IAIA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC,CAAC;IACvD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oCAAY;AAMzB;IAAA;IAMA,CAAC;IAAD,qBAAC;AAAD,CAAC,AAND,IAMC;AANY,wCAAc;AAQ3B;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACnD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACnD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAAA;IAIA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,uBAAuB,EAAE,CAAC,CAAC,CAAC;IAC1D,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,0CAAe;AAM5B;IAAA;IAIA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,wCAAc;AAM3B;IAAA;IAIA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,qBAAqB,EAAQ,CAAC,CAAC,CAAC;IAC9D,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,sCAAa;AAM1B;IAAA;IAKA,CAAC;IAAD,oBAAC;AAAD,CAAC,AALD,IAKC;AALY,sCAAa;AAO1B;IAAA;IAMA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;IACzC,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AAND,IAMC;AANY,0CAAe;AAQ5B;IAAA;IAGA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,oCAAY;AAKzB;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAA+B,6BAAS;IAAxC;;IAIA,CAAC;IAFG,kCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,+BAAW,GAAX,cAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,gBAAC;AAAD,CAAC,AAJD,CAA+B,SAAS,GAIvC;AAJY,8BAAS;AAMtB;IAAA;IAKA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB;IAAA;IAKA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB;IAAA;IAKA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AALD,IAKC;AALY,gCAAU;AAOvB;IAAA;IAKA,CAAC;IAFG,wCAAc,GAAd,cAAkB,CAAC;IACnB,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AALD,IAKC;AALY,0CAAe;AAO5B;IAAA;IAKA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC;IAC/C,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB;IAAA;IAIA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oCAAY;AAMzB;IAAA;IAKA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AALD,IAKC;AALY,oCAAY;AAOzB;IAAA;IAMA,CAAC;IAFG,2CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,0BAA0B,EAAE,CAAC,CAAC,CAAC;IAC7D,wCAAW,GAAX,cAAgB,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClD,yBAAC;AAAD,CAAC,AAND,IAMC;AANY,gDAAkB;AAQ/B;;EAEE;AACF,4BAA4B;AAC5B,wCAAwC;AACxC;IAAA;IASA,CAAC;IAFG,+BAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,4BAAW,GAAX,cAAgB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtC,aAAC;AAAD,CAAC,AATD,IASC;AATY,wBAAM;AAWnB;IAAA;IAMA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AAND,IAMC;AANY,gCAAU;AAQvB;IAAA;IAIA,CAAC;IAFG,kCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,+BAAW,GAAX,cAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,gBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,8BAAS;AAMtB,qCAAqC;AACrC;IAAA;IAMA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC;IACzD,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AAND,IAMC;AANY,wCAAc;AAQ3B,sBAAsB;AACtB,gCAAgC;AAChC;IAAA;IAGA,CAAC;IAAD,eAAC;AAAD,CAAC,AAHD,IAGC;AAHY,4BAAQ;AAKrB,uBAAuB;AACvB;IAAA;IAEA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAFD,IAEC;AAFY,8BAAS;AAItB,6BAA6B;AAC7B;IAAA;IAEA,CAAC;IAAD,sBAAC;AAAD,CAAC,AAFD,IAEC;AAFY,0CAAe;AAI5B,0BAA0B;AAC1B;IAAA;IAMA,CAAC;IAFG,kCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACpD,+BAAW,GAAX,cAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,gBAAC;AAAD,CAAC,AAND,IAMC;AANY,8BAAS;AAQtB,6BAA6B;AAC7B;IAAA;IAOA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,uBAAuB,EAAE,CAAC,CAAC,CAAC;IAC1D,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,0CAAe;AAS5B,sDAAsD;AACtD,yCAAyC;AACzC;IAAA;IAyBA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACrD,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AAzBD,IAyBC;AAzBY,gCAAU;AA2BvB,2BAA2B;AAC3B;IAAA;IAKA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AALD,IAKC;AALY,oCAAY;AAOzB,0BAA0B;AAC1B;IAAA;IAKA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB,2BAA2B;AAC3B;IAAA;IAKA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AALD,IAKC;AALY,oCAAY;AAOzB,8BAA8B;AAC9B;IAAA;IAIA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,KAAK,EAAe,CAAC,CAAC,CAAC;IACrD,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,kCAAW;AAMxB,6BAA6B;AAC7B;IAAA;IAIA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9C,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,kCAAW;AAMxB,4BAA4B;AAC5B;IAAA;IAGA,CAAC;IAAD,qBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,wCAAc;AAK3B,8BAA8B;AAC9B;IAAA;IAGA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8CAAiB;AAK9B,6BAA6B;AAC7B;IAAA;IAGA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8BAAS;AAKtB,+BAA+B;AAC/B;IAAA;IAGA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,kCAAW;AAKxB,uCAAuC;AACvC;IAAA;IAGA,CAAC;IAAD,yBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,gDAAkB;AAK/B,4BAA4B;AAC5B;IAAA;IAGA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sCAAa;AAK1B,8BAA8B;AAC9B;IAAA;IAIA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,oCAAY;AAMzB;IAAA;IAEA,CAAC;IAAD,sBAAC;AAAD,CAAC,AAFD,IAEC;AAFY,0CAAe;AAI5B,0BAA0B;AAC1B;IAAA;IAEA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAFD,IAEC;AAFY,oCAAY;AAIzB,2BAA2B;AAC3B;IAAA;IAGA,CAAC;IAAD,cAAC;AAAD,CAAC,AAHD,IAGC;AAHY,0BAAO;AAKpB,wBAAwB;AACxB;IAAA;IAGA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8BAAS;AAKtB,2BAA2B;AAC3B;IAAA;IAGA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,kCAAW;AAKxB,mBAAmB;AACnB;IAAA;IAGA,CAAC;IAAD,gBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,8BAAS;AAKtB,yBAAyB;AACzB;IAAA;IAGA,CAAC;IAAD,iBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,gCAAU;AAKvB;;EAEE;AACF,4BAA4B;AAC5B,mCAAmC;AACnC,oCAAoC;AACpC,sDAAsD;AACtD,8EAA8E;AAC9E,oEAAoE;AACpE,gBAAgB;AAChB;IAAA;IAmDA,CAAC;IAAD,kBAAC;AAAD,CAAC,AAnDD,IAmDC;AAnDY,kCAAW;AAqDxB,kCAAkC;AAClC;IAAA;IAOA,CAAC;IAAD,mBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,oCAAY;AASzB,qCAAqC;AACrC;IAAA;IA2BA,CAAC;IAFG,uCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC;IACzD,oCAAW,GAAX,cAAgB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC9C,qBAAC;AAAD,CAAC,AA3BD,IA2BC;AA3BY,wCAAc;AA6B3B,4CAA4C;AAC5C,wDAAwD;AACxD,iCAAiC;AACjC;IAAA;IAYA,CAAC;IAFG,wCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,qCAAW,GAAX,cAAgB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC/C,sBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,0CAAe;AAc5B,yDAAyD;AACzD,qEAAqE;AACrE,kCAAkC;AAClC;IAAA;IAcA,CAAC;IAFG,yCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,sCAAW,GAAX,cAAgB,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAChD,uBAAC;AAAD,CAAC,AAdD,IAcC;AAdY,4CAAgB;AAgB7B,2CAA2C;AAC3C,qDAAqD;AACrD,qDAAqD;AACrD,qDAAqD;AACrD;IAAA;IAIA,CAAC;IAFG,oDAAc,GAAd,cAAkB,CAAC;IACnB,iDAAW,GAAX,cAAgB,MAAM,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC3D,kCAAC;AAAD,CAAC,AAJD,IAIC;AAJY,kEAA2B;AAMxC,2CAA2C;AAC3C;IAAA;IAGA,CAAC;IAAD,4BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,sDAAqB;AAKlC,kBAAkB;AAClB,6BAA6B;AAC7B,0BAA0B;AAC1B,qCAAqC;AACrC,gBAAgB;AAChB;IAAA;IAyDA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC,CAAC;IACvD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AAzDD,IAyDC;AAzDY,oCAAY;AA2DzB,yBAAyB;AACzB,gBAAgB;AAChB;IAAA;IAYA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACtD,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,kCAAW;AAcxB,2BAA2B;AAC3B,gBAAgB;AAChB;IAAA;IAYA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,sCAAa;AAc1B,qBAAqB;AACrB,mCAAmC;AACnC,gBAAgB;AAChB;IAAA;IAMA,CAAC;IAFG,mCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACrD,gCAAW,GAAX,cAAgB,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC1C,iBAAC;AAAD,CAAC,AAND,IAMC;AANY,gCAAU;AAQvB,gCAAgC;AAChC,8CAA8C;AAC9C,gBAAgB;AAChB;IAAA;IAMA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACrD,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AAND,IAMC;AANY,8CAAiB;AAQ9B,sBAAsB;AACtB,gBAAgB;AAChB;IAAA;IA2BA,CAAC;IAFG,iCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACnD,8BAAW,GAAX,cAAgB,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACxC,eAAC;AAAD,CAAC,AA3BD,IA2BC;AA3BY,4BAAQ;AA6BrB,6BAA6B;AAC7B;IAA4C,0CAAmB;IAA/D;;IAKA,CAAC;IAFG,+CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,4CAAW,GAAX,cAAgB,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACtD,6BAAC;AAAD,CAAC,AALD,CAA4C,SAAS,GAKpD;AALY,wDAAsB;AAOnC,+BAA+B;AAC/B;IAA8C,4CAAqB;IAAnE;;IAKA,CAAC;IAFG,iDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAc,CAAC,CAAC,CAAC;IAC5D,8CAAW,GAAX,cAAgB,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACxD,+BAAC;AAAD,CAAC,AALD,CAA8C,SAAS,GAKtD;AALY,4DAAwB;AAOrC;IAA+C,6CAAmB;IAAlE;;IAeA,CAAC;IAFG,kDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,+CAAW,GAAX,cAAgB,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACzD,gCAAC;AAAD,CAAC,AAfD,CAA+C,SAAS,GAevD;AAfY,8DAAyB;AAiBtC,yGAAyG;AACzG;IAA0C,wCAAmC;IAA7E;;IAKA,CAAC;IAFG,6CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAkB,CAAC,CAAC,CAAC;IAChE,0CAAW,GAAX,cAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpD,2BAAC;AAAD,CAAC,AALD,CAA0C,SAAS,GAKlD;AALY,oDAAoB;AAOjC,6BAA6B;AAC7B;IAAyC,uCAAmC;IAA5E;;IAMA,CAAC;IAFG,4CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAkB,CAAC,CAAC,CAAC;IAChE,yCAAW,GAAX,cAAgB,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACnD,0BAAC;AAAD,CAAC,AAND,CAAyC,SAAS,GAMjD;AANY,kDAAmB;AAQhC;IAAiD,+CAAmC;IAApF;;IAIA,CAAC;IAFG,oDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAkB,CAAC,CAAC,CAAC;IAChE,iDAAW,GAAX,cAAgB,MAAM,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC3D,kCAAC;AAAD,CAAC,AAJD,CAAiD,SAAS,GAIzD;AAJY,kEAA2B;AAMxC;IAAiD,+CAAmC;IAApF;;IAMA,CAAC;IAFG,oDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAkB,CAAC,CAAC,CAAC;IAChE,iDAAW,GAAX,cAAgB,MAAM,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC3D,kCAAC;AAAD,CAAC,AAND,CAAiD,SAAS,GAMzD;AANY,kEAA2B;AAQxC;IAA6C,2CAAmB;IAAhE;;IAKA,CAAC;IAFG,gDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,6CAAW,GAAX,cAAgB,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACvD,8BAAC;AAAD,CAAC,AALD,CAA6C,SAAS,GAKrD;AALY,0DAAuB;AAOpC;IAAmD,iDAAmC;IAAtF;;IAKA,CAAC;IAFG,sDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAkB,CAAC,CAAC,CAAC;IAChE,mDAAW,GAAX,cAAgB,MAAM,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAC7D,oCAAC;AAAD,CAAC,AALD,CAAmD,SAAS,GAK3D;AALY,sEAA6B;AAO1C,oCAAoC;AACpC;IAAyC,uCAAmB;IAA5D;;IAaA,CAAC;IAFG,4CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,yCAAW,GAAX,cAAgB,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACnD,0BAAC;AAAD,CAAC,AAbD,CAAyC,SAAS,GAajD;AAbY,kDAAmB;AAehC;IAAgD,8CAAmB;IAAnE;;IAKA,CAAC;IAFG,mDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,gDAAW,GAAX,cAAgB,MAAM,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAC1D,iCAAC;AAAD,CAAC,AALD,CAAgD,SAAS,GAKxD;AALY,gEAA0B;AAOvC;IAA0C,wCAAmB;IAA7D;;IAKA,CAAC;IAFG,6CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,0CAAW,GAAX,cAAgB,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACpD,2BAAC;AAAD,CAAC,AALD,CAA0C,SAAS,GAKlD;AALY,oDAAoB;AAOjC;IAAgD,8CAAmC;IAAnF;;IAKA,CAAC;IAFG,mDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAkB,CAAC,CAAC,CAAC;IAChE,gDAAW,GAAX,cAAgB,MAAM,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAC1D,iCAAC;AAAD,CAAC,AALD,CAAgD,SAAS,GAKxD;AALY,gEAA0B;AAOvC;IAA2C,yCAAmB;IAA9D;;IAKA,CAAC;IAFG,8CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,2CAAW,GAAX,cAAgB,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;IACrD,4BAAC;AAAD,CAAC,AALD,CAA2C,SAAS,GAKnD;AALY,sDAAqB;AAOlC,yBAAyB;AACzB;IAAsC,oCAAmB;IAAzD;;IAMA,CAAC;IAFG,yCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,sCAAW,GAAX,cAAgB,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAChD,uBAAC;AAAD,CAAC,AAND,CAAsC,SAAS,GAM9C;AANY,4CAAgB;AAQ7B;IAAuC,qCAAmB;IAA1D;;IAQA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AARD,CAAuC,SAAS,GAQ/C;AARY,8CAAiB;AAU9B;IAA8C,4CAAmB;IAAjE;;IAIA,CAAC;IAFG,iDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,8CAAW,GAAX,cAAgB,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACxD,+BAAC;AAAD,CAAC,AAJD,CAA8C,SAAS,GAItD;AAJY,4DAAwB;AAMrC,2BAA2B;AAC3B;IAAkC,gCAAgB;IAAlD;;IAIA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAS,CAAC,CAAC,CAAC;IACvD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AAJD,CAAkC,SAAS,GAI1C;AAJY,oCAAY;AAMzB,oBAAoB;AACpB;IAAiC,+BAAgB;IAAjD;;IAOA,CAAC;IAFG,oCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAS,CAAC,CAAC,CAAC;IACvD,iCAAW,GAAX,cAAgB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,kBAAC;AAAD,CAAC,AAPD,CAAiC,SAAS,GAOzC;AAPY,kCAAW;AASxB;IAAkC,gCAAgB;IAAlD;;IAKA,CAAC;IAFG,qCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAS,CAAC,CAAC,CAAC;IACvD,kCAAW,GAAX,cAAgB,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,mBAAC;AAAD,CAAC,AALD,CAAkC,SAAS,GAK1C;AALY,oCAAY;AAOzB;IAA2C,yCAAmB;IAA9D;;IAMA,CAAC;IAFG,8CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,2CAAW,GAAX,cAAgB,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;IACrD,4BAAC;AAAD,CAAC,AAND,CAA2C,SAAS,GAMnD;AANY,sDAAqB;AAQlC,uCAAuC;AACvC;IAAkD,gDAA4B;IAA9E;;IAKA,CAAC;IAFG,qDAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAqB,CAAC,CAAC,CAAC;IACnE,kDAAW,GAAX,cAAgB,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC;IAC5D,mCAAC;AAAD,CAAC,AALD,CAAkD,SAAS,GAK1D;AALY,oEAA4B;AAOzC;IAAmC,iCAAmC;IAAtE;;IAKA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAA4B,CAAC,CAAC,CAAC;IAC1E,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AALD,CAAmC,SAAS,GAK3C;AALY,sCAAa;AAO1B;IAAuC,qCAAqE;IAA5G;;IAKA,CAAC;IAFG,0CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAgC,CAAC,CAAC,CAAC;IAC9E,uCAAW,GAAX,cAAgB,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACjD,wBAAC;AAAD,CAAC,AALD,CAAuC,SAAS,GAK/C;AALY,8CAAiB;AAO9B,4BAA4B;AAC5B;IAAmC,iCAAmB;IAAtD;;IAIA,CAAC;IAFG,sCAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,mCAAW,GAAX,cAAgB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7C,oBAAC;AAAD,CAAC,AAJD,CAAmC,SAAS,GAI3C;AAJY,sCAAa;AAM1B,iCAAiC;AACjC;IAAwC,sCAAmB;IAA3D;;IAKA,CAAC;IAFG,2CAAc,GAAd,cAAmB,MAAM,CAAC,IAAI,aAAa,EAAY,CAAC,CAAC,CAAC;IAC1D,wCAAW,GAAX,cAAgB,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClD,yBAAC;AAAD,CAAC,AALD,CAAwC,SAAS,GAKhD;AALY,gDAAkB"} \ No newline at end of file diff --git a/tests/CheckMvc/TypeScript.dtos.ts b/tests/CheckMvc/TypeScript.dtos.ts new file mode 100644 index 00000000000..45d2825456b --- /dev/null +++ b/tests/CheckMvc/TypeScript.dtos.ts @@ -0,0 +1,3281 @@ +/* Options: +Date: 2019-02-11 10:08:04 +Version: 5.41 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:55799 + +//GlobalNamespace: +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ + + +export interface IReturn +{ + createResponse(): T; +} + +export interface IReturnVoid +{ + createResponse(): void; +} + +export interface IHasSessionId +{ + sessionId: string; +} + +export interface IHasBearerToken +{ + bearerToken: string; +} + +export interface IGet +{ +} + +export interface IPost +{ +} + +export interface IPut +{ +} + +export interface IDelete +{ +} + +export interface IPatch +{ +} + +export interface IHasVersion +{ + version: number; +} + +export class QueryBase +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public skip: number; + + // @DataMember(Order=2) + public take: number; + + // @DataMember(Order=3) + public orderBy: string; + + // @DataMember(Order=4) + public orderByDesc: string; + + // @DataMember(Order=5) + public include: string; + + // @DataMember(Order=6) + public fields: string; + + // @DataMember(Order=7) + public meta: { [index:string]: string; }; +} + +export class QueryData extends QueryBase +{ + public constructor(init?:Partial>) { super(init); Object.assign(this, init); } +} + +export class RequestLogEntry +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public dateTime: string; + public statusCode: number; + public statusDescription: string; + public httpMethod: string; + public absoluteUri: string; + public pathInfo: string; + // @StringLength(2147483647) + public requestBody: string; + + public requestDto: Object; + public userAuthId: string; + public sessionId: string; + public ipAddress: string; + public forwardedFor: string; + public referer: string; + public headers: { [index:string]: string; }; + public formData: { [index:string]: string; }; + public items: { [index:string]: string; }; + public session: Object; + public responseDto: Object; + public errorResponse: Object; + public exceptionSource: string; + public exceptionData: any; + public requestDuration: string; + public meta: { [index:string]: string; }; +} + +// @DataContract +export class ResponseError +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1, EmitDefaultValue=false) + public errorCode: string; + + // @DataMember(Order=2, EmitDefaultValue=false) + public fieldName: string; + + // @DataMember(Order=3, EmitDefaultValue=false) + public message: string; + + // @DataMember(Order=4, EmitDefaultValue=false) + public meta: { [index:string]: string; }; +} + +// @DataContract +export class ResponseStatus +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public message: string; + + // @DataMember(Order=3) + public stackTrace: string; + + // @DataMember(Order=4) + public errors: ResponseError[]; + + // @DataMember(Order=5) + public meta: { [index:string]: string; }; +} + +export class QueryDb_1 extends QueryBase +{ + public constructor(init?:Partial>) { super(init); Object.assign(this, init); } +} + +export class Rockstar +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * Идентификатор + */ + public id: number; + /** + * Фамилия + */ + public firstName: string; + /** + * Имя + */ + public lastName: string; + /** + * Возраст + */ + public age: number; +} + +export class ArrayElementInDictionary +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +export class ObjectDesign +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +export interface IAuthTokens +{ + provider: string; + userId: string; + accessToken: string; + accessTokenSecret: string; + refreshToken: string; + refreshTokenExpiry?: string; + requestToken: string; + requestTokenSecret: string; + items: { [index:string]: string; }; +} + +// @DataContract +export class AuthUserSession +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public referrerUrl: string; + + // @DataMember(Order=2) + public id: string; + + // @DataMember(Order=3) + public userAuthId: string; + + // @DataMember(Order=4) + public userAuthName: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public twitterUserId: string; + + // @DataMember(Order=7) + public twitterScreenName: string; + + // @DataMember(Order=8) + public facebookUserId: string; + + // @DataMember(Order=9) + public facebookUserName: string; + + // @DataMember(Order=10) + public firstName: string; + + // @DataMember(Order=11) + public lastName: string; + + // @DataMember(Order=12) + public displayName: string; + + // @DataMember(Order=13) + public company: string; + + // @DataMember(Order=14) + public email: string; + + // @DataMember(Order=15) + public primaryEmail: string; + + // @DataMember(Order=16) + public phoneNumber: string; + + // @DataMember(Order=17) + public birthDate: string; + + // @DataMember(Order=18) + public birthDateRaw: string; + + // @DataMember(Order=19) + public address: string; + + // @DataMember(Order=20) + public address2: string; + + // @DataMember(Order=21) + public city: string; + + // @DataMember(Order=22) + public state: string; + + // @DataMember(Order=23) + public country: string; + + // @DataMember(Order=24) + public culture: string; + + // @DataMember(Order=25) + public fullName: string; + + // @DataMember(Order=26) + public gender: string; + + // @DataMember(Order=27) + public language: string; + + // @DataMember(Order=28) + public mailAddress: string; + + // @DataMember(Order=29) + public nickname: string; + + // @DataMember(Order=30) + public postalCode: string; + + // @DataMember(Order=31) + public timeZone: string; + + // @DataMember(Order=32) + public requestTokenSecret: string; + + // @DataMember(Order=33) + public createdAt: string; + + // @DataMember(Order=34) + public lastModified: string; + + // @DataMember(Order=35) + public roles: string[]; + + // @DataMember(Order=36) + public permissions: string[]; + + // @DataMember(Order=37) + public isAuthenticated: boolean; + + // @DataMember(Order=38) + public fromToken: boolean; + + // @DataMember(Order=39) + public profileUrl: string; + + // @DataMember(Order=40) + public sequence: string; + + // @DataMember(Order=41) + public tag: number; + + // @DataMember(Order=42) + public authProvider: string; + + // @DataMember(Order=43) + public providerOAuthAccess: IAuthTokens[]; + + // @DataMember(Order=44) + public meta: { [index:string]: string; }; + + // @DataMember(Order=45) + public audiences: string[]; + + // @DataMember(Order=46) + public scopes: string[]; + + // @DataMember(Order=47) + public dns: string; + + // @DataMember(Order=48) + public rsa: string; + + // @DataMember(Order=49) + public sid: string; + + // @DataMember(Order=50) + public hash: string; + + // @DataMember(Order=51) + public homePhone: string; + + // @DataMember(Order=52) + public mobilePhone: string; + + // @DataMember(Order=53) + public webpage: string; + + // @DataMember(Order=54) + public emailConfirmed: boolean; + + // @DataMember(Order=55) + public phoneNumberConfirmed: boolean; + + // @DataMember(Order=56) + public twoFactorEnabled: boolean; + + // @DataMember(Order=57) + public securityStamp: string; + + // @DataMember(Order=58) + public type: string; +} + +export class MetadataTestNestedChild +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; +} + +export class MetadataTestChild +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public results: MetadataTestNestedChild[]; +} + +export class MenuItemExampleItem +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + // @ApiMember() + public name1: string; +} + +export class MenuItemExample +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + // @ApiMember() + public name1: string; + + public menuItemExampleItem: MenuItemExampleItem; +} + +// @DataContract +export class MenuExample +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + // @ApiMember() + public menuItemExample1: MenuItemExample; +} + +export class MetadataTypeName +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public namespace: string; + public genericArgs: string[]; +} + +export class MetadataRoute +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public path: string; + public verbs: string; + public notes: string; + public summary: string; +} + +export class MetadataDataContract +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public namespace: string; +} + +export class MetadataDataMember +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public order: number; + public isRequired: boolean; + public emitDefaultValue: boolean; +} + +export class MetadataAttribute +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public constructorArgs: MetadataPropertyType[]; + public args: MetadataPropertyType[]; +} + +export class MetadataPropertyType +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public type: string; + public isValueType: boolean; + public isSystemType: boolean; + public isEnum: boolean; + public typeNamespace: string; + public genericArgs: string[]; + public value: string; + public description: string; + public dataMember: MetadataDataMember; + public readOnly: boolean; + public paramType: string; + public displayType: string; + public isRequired: boolean; + public allowableValues: string[]; + public allowableMin: number; + public allowableMax: number; + public attributes: MetadataAttribute[]; +} + +export class MetadataType +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public namespace: string; + public genericArgs: string[]; + public inherits: MetadataTypeName; + public implements: MetadataTypeName[]; + public displayType: string; + public description: string; + public returnVoidMarker: boolean; + public isNested: boolean; + public isEnum: boolean; + public isEnumInt: boolean; + public isInterface: boolean; + public isAbstract: boolean; + public returnMarkerTypeName: MetadataTypeName; + public routes: MetadataRoute[]; + public dataContract: MetadataDataContract; + public properties: MetadataPropertyType[]; + public attributes: MetadataAttribute[]; + public innerTypes: MetadataTypeName[]; + public enumNames: string[]; + public enumValues: string[]; + public meta: { [index:string]: string; }; +} + +export class AutoQueryConvention +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public value: string; + public types: string; +} + +export class AutoQueryViewerConfig +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public serviceBaseUrl: string; + public serviceName: string; + public serviceDescription: string; + public serviceIconUrl: string; + public formats: string[]; + public maxLimit: number; + public isPublic: boolean; + public onlyShowAnnotatedServices: boolean; + public implicitConventions: AutoQueryConvention[]; + public defaultSearchField: string; + public defaultSearchType: string; + public defaultSearchText: string; + public brandUrl: string; + public brandImageUrl: string; + public textColor: string; + public linkColor: string; + public backgroundColor: string; + public backgroundImageUrl: string; + public iconUrl: string; + public meta: { [index:string]: string; }; +} + +export class AutoQueryViewerUserInfo +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public isAuthenticated: boolean; + public queryCount: number; + public meta: { [index:string]: string; }; +} + +export class AutoQueryOperation +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public request: string; + public from: string; + public to: string; + public meta: { [index:string]: string; }; +} + +export class RecursiveNode implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public text: string; + public children: RecursiveNode[]; + public createResponse() { return new RecursiveNode(); } + public getTypeName() { return 'RecursiveNode'; } +} + +export class NativeTypesTestService +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +export class NestedClass +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public value: string; +} + +export class ListResult +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export class OnlyInReturnListArg +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export class ArrayResult +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export enum EnumType +{ + Value1 = 'Value1', + Value2 = 'Value2', +} + +export enum EnumWithValues +{ + Value1 = '1', + Value2 = '2', +} + +// @Flags() +export enum EnumFlags +{ + Value0 = 0, + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value123 = 3, +} + +export enum EnumStyle +{ + lower = 'lower', + UPPER = 'UPPER', + PascalCase = 'PascalCase', + camelCase = 'camelCase', + camelUPPER = 'camelUPPER', + PascalUPPER = 'PascalUPPER', +} + +export class Poco +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; +} + +export class AllCollectionTypes +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public intArray: number[]; + public intList: number[]; + public stringArray: string[]; + public stringList: string[]; + public pocoArray: Poco[]; + public pocoList: Poco[]; + public nullableByteArray: Uint8Array; + public nullableByteList: number[]; + public nullableDateTimeArray: string[]; + public nullableDateTimeList: string[]; + public pocoLookup: { [index:string]: Poco[]; }; + public pocoLookupMap: { [index:string]: { [index:string]: Poco; }[]; }; +} + +export class KeyValuePair +{ + public constructor(init?:Partial>) { Object.assign(this, init); } + public key: TKey; + public value: TValue; +} + +export class SubType +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; +} + +export class HelloBase +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +export class HelloResponseBase +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public refId: number; +} + +export class HelloBase_1 +{ + public constructor(init?:Partial>) { Object.assign(this, init); } + public items: T[]; + public counts: number[]; +} + +export class Item +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public value: string; +} + +export class InheritedItem +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; +} + +export class HelloWithReturnResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export class HelloType +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export interface IPoco +{ + name: string; +} + +export interface IEmptyInterface +{ +} + +export class EmptyClass +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +export interface ImplementsPoco +{ + name: string; +} + +export class TypeB +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public foo: string; +} + +export class TypeA +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public bar: TypeB[]; +} + +export class InnerType +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; +} + +export enum InnerEnum +{ + Foo = 'Foo', + Bar = 'Bar', + Baz = 'Baz', +} + +export class InnerTypeItem +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; +} + +export enum DayOfWeek +{ + Sunday = 'Sunday', + Monday = 'Monday', + Tuesday = 'Tuesday', + Wednesday = 'Wednesday', + Thursday = 'Thursday', + Friday = 'Friday', + Saturday = 'Saturday', +} + +// @DataContract +export enum ShortDays +{ + Monday = 'MON', + Tuesday = 'TUE', + Wednesday = 'WED', + Thursday = 'THU', + Friday = 'FRI', + Saturday = 'SAT', + Sunday = 'SUN', +} + +// @DataContract +export enum ScopeType +{ + Global = '1', + Sale = '2', +} + +export class Tuple_2 +{ + public constructor(init?:Partial>) { Object.assign(this, init); } + public item1: T1; + public item2: T2; +} + +export class Tuple_3 +{ + public constructor(init?:Partial>) { Object.assign(this, init); } + public item1: T1; + public item2: T2; + public item3: T3; +} + +export interface IEcho +{ + sentence: string; +} + +// @Flags() +export enum CacheControl +{ + None = 0, + Public = 1, + Private = 2, + MustRevalidate = 4, + NoCache = 8, + NoStore = 16, + NoTransform = 32, + ProxyRevalidate = 64, +} + +export enum MyColor +{ + Red = 'Red', + Green = 'Green', + Blue = 'Blue', +} + +export class SwaggerNestedModel +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * NestedProperty description + */ + // @ApiMember(Description="NestedProperty description") + public nestedProperty: boolean; +} + +export class SwaggerNestedModel2 +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * NestedProperty2 description + */ + // @ApiMember(Description="NestedProperty2 description") + public nestedProperty2: boolean; + + /** + * MultipleValues description + */ + // @ApiMember(Description="MultipleValues description") + public multipleValues: string; + + /** + * TestRange description + */ + // @ApiMember(Description="TestRange description") + public testRange: number; +} + +export enum MyEnum +{ + A = 'A', + B = 'B', + C = 'C', +} + +// @DataContract +export class UserApiKey +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public key: string; + + // @DataMember(Order=2) + public keyType: string; + + // @DataMember(Order=3) + public expiryDate: string; +} + +export class PgRockstar extends Rockstar +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } +} + +export class QueryDb_2 extends QueryBase +{ + public constructor(init?:Partial>) { super(init); Object.assign(this, init); } +} + +export class CustomRockstar +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @AutoQueryViewerField(Title="Name") + public firstName: string; + + // @AutoQueryViewerField(HideInSummary=true) + public lastName: string; + + public age: number; + // @AutoQueryViewerField(Title="Album") + public rockstarAlbumName: string; + + // @AutoQueryViewerField(Title="Genre") + public rockstarGenreName: string; +} + +export interface IFilterRockstars +{ +} + +export class Movie +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public imdbId: string; + public title: string; + public rating: string; + public score: number; + public director: string; + public releaseDate: string; + public tagLine: string; + public genres: string[]; +} + +export class RockstarAlbum +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public rockstarId: number; + public name: string; +} + +export class RockstarReference +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public firstName: string; + public lastName: string; + public age: number; + public albums: RockstarAlbum[]; +} + +export class OnlyDefinedInGenericType +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; +} + +export class OnlyDefinedInGenericTypeFrom +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; +} + +export class OnlyDefinedInGenericTypeInto +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; +} + +export class TypesGroup +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @DataContract +export class QueryResponse +{ + public constructor(init?:Partial>) { Object.assign(this, init); } + // @DataMember(Order=1) + public offset: number; + + // @DataMember(Order=2) + public total: number; + + // @DataMember(Order=3) + public results: T[]; + + // @DataMember(Order=4) + public meta: { [index:string]: string; }; + + // @DataMember(Order=5) + public responseStatus: ResponseStatus; +} + +export class ChangeRequestResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public contentType: string; + public header: string; + public queryString: string; + public form: string; + public responseStatus: ResponseStatus; +} + +export class DiscoverTypes implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public elementInDictionary: { [index:string]: ArrayElementInDictionary[]; }; + public createResponse() { return new DiscoverTypes(); } + public getTypeName() { return 'DiscoverTypes'; } +} + +export class CustomHttpErrorResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public custom: string; + public responseStatus: ResponseStatus; +} + +// @Route("/alwaysthrows") +export class AlwaysThrows implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new AlwaysThrows(); } + public getTypeName() { return 'AlwaysThrows'; } +} + +// @Route("/alwaysthrowsfilterattribute") +export class AlwaysThrowsFilterAttribute implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new AlwaysThrowsFilterAttribute(); } + public getTypeName() { return 'AlwaysThrowsFilterAttribute'; } +} + +// @Route("/alwaysthrowsglobalfilter") +export class AlwaysThrowsGlobalFilter implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new AlwaysThrowsGlobalFilter(); } + public getTypeName() { return 'AlwaysThrowsGlobalFilter'; } +} + +export class CustomFieldHttpErrorResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public custom: string; + public responseStatus: ResponseStatus; +} + +export class NoRepeatResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: string; +} + +export class BatchThrowsResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; + public responseStatus: ResponseStatus; +} + +export class ObjectDesignResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public data: ObjectDesign; +} + +export class CreateJwtResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public token: string; + public responseStatus: ResponseStatus; +} + +export class CreateRefreshJwtResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public token: string; + public responseStatus: ResponseStatus; +} + +export class MetadataTestResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public results: MetadataTestChild[]; +} + +// @DataContract +export class GetExampleResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public responseStatus: ResponseStatus; + + // @DataMember(Order=2) + // @ApiMember() + public menuExample1: MenuExample; +} + +export class AutoQueryMetadataResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public config: AutoQueryViewerConfig; + public userInfo: AutoQueryViewerUserInfo; + public operations: AutoQueryOperation[]; + public types: MetadataType[]; + public responseStatus: ResponseStatus; + public meta: { [index:string]: string; }; +} + +export class TestAttributeExport implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @Display(AutoGenerateField=true, AutoGenerateFilter=true, ShortName="UnitMeasKey") + public unitMeasKey: number; + public createResponse() { return new TestAttributeExport(); } + public getTypeName() { return 'TestAttributeExport'; } +} + +// @DataContract +export class HelloACodeGenTestResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * Description for FirstResult + */ + // @DataMember + public firstResult: number; + + /** + * Description for SecondResult + */ + // @DataMember + // @ApiMember(Description="Description for SecondResult") + public secondResult: number; +} + +export class HelloResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +/** + * Description on HelloAllResponse type + */ +// @DataContract +export class HelloAnnotatedResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember + public result: string; +} + +export class HelloList implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public names: string[]; + public createResponse() { return new Array(); } + public getTypeName() { return 'HelloList'; } +} + +export class HelloArray implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public names: string[]; + public createResponse() { return new Array(); } + public getTypeName() { return 'HelloArray'; } +} + +export class HelloExistingResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public helloList: HelloList; + public helloArray: HelloArray; + public arrayResults: ArrayResult[]; + public listResults: ListResult[]; +} + +export class AllTypes implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public nullableId: number; + public byte: number; + public short: number; + public int: number; + public long: number; + public uShort: number; + public uInt: number; + public uLong: number; + public float: number; + public double: number; + public decimal: number; + public string: string; + public dateTime: string; + public timeSpan: string; + public dateTimeOffset: string; + public guid: string; + public char: string; + public keyValuePair: KeyValuePair; + public nullableDateTime: string; + public nullableTimeSpan: string; + public stringList: string[]; + public stringArray: string[]; + public stringMap: { [index:string]: string; }; + public intStringMap: { [index:number]: string; }; + public subType: SubType; + public point: string; + // @DataMember(Name="aliasedName") + public originalName: string; + public createResponse() { return new AllTypes(); } + public getTypeName() { return 'AllTypes'; } +} + +export class HelloAllTypesResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; + public allTypes: AllTypes; + public allCollectionTypes: AllCollectionTypes; +} + +// @DataContract +export class HelloWithDataContractResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false) + public result: string; +} + +/** + * Description on HelloWithDescriptionResponse type + */ +export class HelloWithDescriptionResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export class HelloWithInheritanceResponse extends HelloResponseBase +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public result: string; +} + +export class HelloWithAlternateReturnResponse extends HelloWithReturnResponse +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public altResult: string; +} + +export class HelloWithRouteResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export class HelloWithTypeResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: HelloType; +} + +export class HelloStruct implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public point: string; + public nullablePoint: string; + public createResponse() { return new HelloStruct(); } + public getTypeName() { return 'HelloStruct'; } +} + +export class HelloSessionResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: AuthUserSession; +} + +export class HelloImplementsInterface implements IReturn, ImplementsPoco +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloImplementsInterface(); } + public getTypeName() { return 'HelloImplementsInterface'; } +} + +export class Request1Response +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public test: TypeA; +} + +export class Request2Response +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public test: TypeA; +} + +export class HelloInnerTypesResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public innerType: InnerType; + public innerEnum: InnerEnum; + public innerList: InnerTypeItem[]; +} + +export class CustomUserSession extends AuthUserSession +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + // @DataMember + public customName: string; + + // @DataMember + public customInfo: string; +} + +// @DataContract +export class QueryResponseTemplate +{ + public constructor(init?:Partial>) { Object.assign(this, init); } + // @DataMember(Order=1) + public offset: number; + + // @DataMember(Order=2) + public total: number; + + // @DataMember(Order=3) + public results: T[]; + + // @DataMember(Order=4) + public meta: { [index:string]: string; }; + + // @DataMember(Order=5) + public responseStatus: ResponseStatus; +} + +export class HelloVerbResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +export class EnumResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public operator: ScopeType; +} + +export class ExcludeTestNested +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +export class RestrictLocalhost implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new RestrictLocalhost(); } + public getTypeName() { return 'RestrictLocalhost'; } +} + +export class RestrictInternal implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new RestrictInternal(); } + public getTypeName() { return 'RestrictInternal'; } +} + +export class HelloTuple implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public tuple2: Tuple_2; + public tuple3: Tuple_3; + public tuples2: Tuple_2[]; + public tuples3: Tuple_3[]; + public createResponse() { return new HelloTuple(); } + public getTypeName() { return 'HelloTuple'; } +} + +export class HelloAuthenticatedResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public version: number; + public sessionId: string; + public userName: string; + public email: string; + public isAuthenticated: boolean; + public responseStatus: ResponseStatus; +} + +export class Echo implements IEcho +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public sentence: string; +} + +export class ThrowHttpErrorResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +export class ThrowTypeResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public responseStatus: ResponseStatus; +} + +export class ThrowValidationResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public age: number; + public required: string; + public email: string; + public responseStatus: ResponseStatus; +} + +export class acsprofileResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public profileId: string; +} + +export class ReturnedDto +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +// @Route("/matchroute/html") +export class MatchesHtml implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new MatchesHtml(); } + public getTypeName() { return 'MatchesHtml'; } +} + +// @Route("/matchroute/json") +export class MatchesJson implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new MatchesJson(); } + public getTypeName() { return 'MatchesJson'; } +} + +export class TimestampData +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public timestamp: number; +} + +// @Route("/test/html") +export class TestHtml implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new TestHtml(); } + public getTypeName() { return 'TestHtml'; } +} + +export class ViewResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public result: string; +} + +// @Route("/swagger/model") +export class SwaggerModel implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public int: number; + public string: string; + public dateTime: string; + public dateTimeOffset: string; + public timeSpan: string; + public createResponse() { return new SwaggerModel(); } + public getTypeName() { return 'SwaggerModel'; } +} + +// @Route("/plain-dto") +export class PlainDto implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new PlainDto(); } + public getTypeName() { return 'PlainDto'; } +} + +// @Route("/httpresult-dto") +export class HttpResultDto implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HttpResultDto(); } + public getTypeName() { return 'HttpResultDto'; } +} + +// @Route("/restrict/mq") +export class TestMqRestriction implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new TestMqRestriction(); } + public getTypeName() { return 'TestMqRestriction'; } +} + +// @Route("/set-cache") +export class SetCache implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public eTag: string; + public age: string; + public maxAge: string; + public expires: string; + public lastModified: string; + public cacheControl: CacheControl; + public createResponse() { return new SetCache(); } + public getTypeName() { return 'SetCache'; } +} + +export class SwaggerComplexResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember + // @ApiMember() + public isRequired: boolean; + + // @DataMember + // @ApiMember(IsRequired=true) + public arrayString: string[]; + + // @DataMember + // @ApiMember() + public arrayInt: number[]; + + // @DataMember + // @ApiMember() + public listString: string[]; + + // @DataMember + // @ApiMember() + public listInt: number[]; + + // @DataMember + // @ApiMember() + public dictionaryString: { [index:string]: string; }; +} + +/** + * Api GET All + */ +// @Route("/swaggerexamples", "GET") +// @Api(Description="Api GET All") +export class GetSwaggerExamples implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public get: string; + public createResponse() { return new GetSwaggerExamples(); } + public getTypeName() { return 'GetSwaggerExamples'; } +} + +/** + * Api GET Id + */ +// @Route("/swaggerexamples/{Id}", "GET") +// @Api(Description="Api GET Id") +export class GetSwaggerExample implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public get: string; + public createResponse() { return new GetSwaggerExample(); } + public getTypeName() { return 'GetSwaggerExample'; } +} + +/** + * Api POST + */ +// @Route("/swaggerexamples", "POST") +// @Api(Description="Api POST") +export class PostSwaggerExamples implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public post: string; + public createResponse() { return new PostSwaggerExamples(); } + public getTypeName() { return 'PostSwaggerExamples'; } +} + +/** + * Api PUT Id + */ +// @Route("/swaggerexamples/{Id}", "PUT") +// @Api(Description="Api PUT Id") +export class PutSwaggerExample implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public get: string; + public createResponse() { return new PutSwaggerExample(); } + public getTypeName() { return 'PutSwaggerExample'; } +} + +// @Route("/lists", "GET") +export class GetLists implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: string; + public createResponse() { return new GetLists(); } + public getTypeName() { return 'GetLists'; } +} + +// @DataContract +export class AuthenticateResponse implements IHasSessionId, IHasBearerToken +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public referrerUrl: string; + + // @DataMember(Order=6) + public bearerToken: string; + + // @DataMember(Order=7) + public refreshToken: string; + + // @DataMember(Order=8) + public responseStatus: ResponseStatus; + + // @DataMember(Order=9) + public meta: { [index:string]: string; }; +} + +// @DataContract +export class AssignRolesResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class UnAssignRolesResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class ConvertSessionToTokenResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public meta: { [index:string]: string; }; + + // @DataMember(Order=2) + public accessToken: string; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class GetAccessTokenResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public accessToken: string; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class GetApiKeysResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public results: UserApiKey[]; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class RegenerateApiKeysResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public results: UserApiKey[]; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class RegisterResponse +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public referrerUrl: string; + + // @DataMember(Order=5) + public bearerToken: string; + + // @DataMember(Order=6) + public refreshToken: string; + + // @DataMember(Order=7) + public responseStatus: ResponseStatus; + + // @DataMember(Order=8) + public meta: { [index:string]: string; }; +} + +// @Route("/anontype") +export class AnonType +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/query/requestlogs") +// @Route("/query/requestlogs/{Date}") +export class QueryRequestLogs extends QueryData implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public date: string; + public viewErrors: boolean; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRequestLogs'; } +} + +// @AutoQueryViewer(Name="Today\'s Logs", Title="Logs from Today") +export class TodayLogs extends QueryData implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'TodayLogs'; } +} + +export class TodayErrorLogs extends QueryData implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'TodayErrorLogs'; } +} + +export class YesterdayLogs extends QueryData implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'YesterdayLogs'; } +} + +export class YesterdayErrorLogs extends QueryData implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'YesterdayErrorLogs'; } +} + +// @Route("/query/rockstars") +export class QueryRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstars'; } +} + +// @Route("/query/rockstars/cached") +export class QueryRockstarsCached extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarsCached'; } +} + +// @Route("/changerequest/{Id}") +export class ChangeRequest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: string; + public createResponse() { return new ChangeRequestResponse(); } + public getTypeName() { return 'ChangeRequest'; } +} + +// @Route("/compress/{Path*}") +export class CompressFile +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public path: string; +} + +// @Route("/Routing/LeadPost.aspx") +export class LegacyLeadPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public leadType: string; + public myId: number; +} + +// @Route("/info/{Id}") +export class Info +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: string; +} + +export class CustomHttpError implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public statusCode: number; + public statusDescription: string; + public createResponse() { return new CustomHttpErrorResponse(); } + public getTypeName() { return 'CustomHttpError'; } +} + +export class CustomFieldHttpError implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new CustomFieldHttpErrorResponse(); } + public getTypeName() { return 'CustomFieldHttpError'; } +} + +export class FallbackRoute +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public pathInfo: string; +} + +export class NoRepeat implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: string; + public createResponse() { return new NoRepeatResponse(); } + public getTypeName() { return 'NoRepeat'; } +} + +export class BatchThrows implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; + public createResponse() { return new BatchThrowsResponse(); } + public getTypeName() { return 'BatchThrows'; } +} + +export class BatchThrowsAsync implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; + public createResponse() { return new BatchThrowsResponse(); } + public getTypeName() { return 'BatchThrowsAsync'; } +} + +// @Route("/code/object", "GET") +export class ObjectId implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public objectName: string; + public createResponse() { return new ObjectDesignResponse(); } + public getTypeName() { return 'ObjectId'; } +} + +// @Route("/jwt") +export class CreateJwt extends AuthUserSession implements IReturn +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public jwtExpiry: string; + public createResponse() { return new CreateJwtResponse(); } + public getTypeName() { return 'CreateJwt'; } +} + +// @Route("/jwt-refresh") +export class CreateRefreshJwt implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public userAuthId: string; + public jwtExpiry: string; + public createResponse() { return new CreateRefreshJwtResponse(); } + public getTypeName() { return 'CreateRefreshJwt'; } +} + +export class MetadataTest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new MetadataTestResponse(); } + public getTypeName() { return 'MetadataTest'; } +} + +// @Route("/example", "GET") +// @DataContract +export class GetExample implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new GetExampleResponse(); } + public getTypeName() { return 'GetExample'; } +} + +export class MetadataRequest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public metadataType: MetadataType; + public createResponse() { return new AutoQueryMetadataResponse(); } + public getTypeName() { return 'MetadataRequest'; } +} + +export class ExcludeMetadataProperty +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +// @Route("/namedconnection") +export class NamedConnection +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public emailAddresses: string; +} + +/** + * Description for HelloACodeGenTest + */ +export class HelloACodeGenTest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * Description for FirstField + */ + public firstField: number; + public secondFields: string[]; + public createResponse() { return new HelloACodeGenTestResponse(); } + public getTypeName() { return 'HelloACodeGenTest'; } +} + +export class HelloInService implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'NativeTypesTestService.HelloInService'; } +} + +// @Route("/hello") +// @Route("/hello/{Name}") +export class Hello implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @Required() + public name: string; + + public title: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'Hello'; } +} + +/** + * Description on HelloAll type + */ +// @DataContract +export class HelloAnnotated implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember + public name: string; + public createResponse() { return new HelloAnnotatedResponse(); } + public getTypeName() { return 'HelloAnnotated'; } +} + +export class HelloWithNestedClass implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public nestedClassProp: NestedClass; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'HelloWithNestedClass'; } +} + +export class HelloReturnList implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public names: string[]; + public createResponse() { return new Array(); } + public getTypeName() { return 'HelloReturnList'; } +} + +export class HelloExisting implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public names: string[]; + public createResponse() { return new HelloExistingResponse(); } + public getTypeName() { return 'HelloExisting'; } +} + +export class HelloWithEnum +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public enumProp: EnumType; + public enumWithValues: EnumWithValues; + public nullableEnumProp: EnumType; + public enumFlags: EnumFlags; + public enumStyle: EnumStyle; +} + +export class RestrictedAttributes +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public name: string; + public hello: Hello; +} + +/** + * AllowedAttributes Description + */ +// @Route("/allowed-attributes", "GET") +// @Api(Description="AllowedAttributes Description") +// @ApiResponse(Description="Your request was not understood", StatusCode=400) +// @DataContract +export class AllowedAttributes +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember + // @Required() + public id: number; + + /** + * Range Description + */ + // @DataMember(Name="Aliased") + // @ApiMember(DataType="double", Description="Range Description", IsRequired=true, ParameterType="path") + public range: number; +} + +/** + * Multi Line Class + */ +// @Api(Description="Multi \r\nLine \r\nClass") +export class HelloAttributeStringTest +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * Multi Line Property + */ + // @ApiMember(Description="Multi \r\nLine \r\nProperty") + public overflow: string; + + /** + * Some \ escaped chars + */ + // @ApiMember(Description="Some \\ escaped \t \n chars") + public escapedChars: string; +} + +export class HelloAllTypes implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public allTypes: AllTypes; + public allCollectionTypes: AllCollectionTypes; + public createResponse() { return new HelloAllTypesResponse(); } + public getTypeName() { return 'HelloAllTypes'; } +} + +export class HelloString implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return ''; } + public getTypeName() { return 'HelloString'; } +} + +export class HelloVoid implements IReturnVoid +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() {} + public getTypeName() { return 'HelloVoid'; } +} + +// @DataContract +export class HelloWithDataContract implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false) + public name: string; + + // @DataMember(Name="id", Order=2, EmitDefaultValue=false) + public id: number; + public createResponse() { return new HelloWithDataContractResponse(); } + public getTypeName() { return 'HelloWithDataContract'; } +} + +/** + * Description on HelloWithDescription type + */ +export class HelloWithDescription implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloWithDescriptionResponse(); } + public getTypeName() { return 'HelloWithDescription'; } +} + +export class HelloWithInheritance extends HelloBase implements IReturn +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloWithInheritanceResponse(); } + public getTypeName() { return 'HelloWithInheritance'; } +} + +export class HelloWithGenericInheritance extends HelloBase_1 +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public result: string; +} + +export class HelloWithGenericInheritance2 extends HelloBase_1 +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public result: string; +} + +export class HelloWithNestedInheritance extends HelloBase_1 +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } +} + +export class HelloWithListInheritance extends Array +{ + public constructor(init?:Partial) { super(); Object.assign(this, init); } +} + +export class HelloWithReturn implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloWithAlternateReturnResponse(); } + public getTypeName() { return 'HelloWithReturn'; } +} + +// @Route("/helloroute") +export class HelloWithRoute implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloWithRouteResponse(); } + public getTypeName() { return 'HelloWithRoute'; } +} + +export class HelloWithType implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new HelloWithTypeResponse(); } + public getTypeName() { return 'HelloWithType'; } +} + +export class HelloSession implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new HelloSessionResponse(); } + public getTypeName() { return 'HelloSession'; } +} + +export class HelloInterface +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public poco: IPoco; + public emptyInterface: IEmptyInterface; + public emptyClass: EmptyClass; + public value: string; +} + +export class Request1 implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public test: TypeA; + public createResponse() { return new Request1Response(); } + public getTypeName() { return 'Request1'; } +} + +export class Request2 implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public test: TypeA; + public createResponse() { return new Request2Response(); } + public getTypeName() { return 'Request2'; } +} + +export class HelloInnerTypes implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new HelloInnerTypesResponse(); } + public getTypeName() { return 'HelloInnerTypes'; } +} + +export class GetUserSession implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new CustomUserSession(); } + public getTypeName() { return 'GetUserSession'; } +} + +export class QueryTemplate implements IReturn> +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new QueryResponseTemplate(); } + public getTypeName() { return 'QueryTemplate'; } +} + +export class HelloReserved +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public class: string; + public type: string; + public extension: string; +} + +export class HelloDictionary implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public key: string; + public value: string; + public createResponse() { return {}; } + public getTypeName() { return 'HelloDictionary'; } +} + +export class HelloBuiltin +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public dayOfWeek: DayOfWeek; + public shortDays: ShortDays; +} + +export class HelloGet implements IReturn, IGet +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new HelloVerbResponse(); } + public getTypeName() { return 'HelloGet'; } +} + +export class HelloPost extends HelloBase implements IReturn, IPost +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new HelloVerbResponse(); } + public getTypeName() { return 'HelloPost'; } +} + +export class HelloPut implements IReturn, IPut +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new HelloVerbResponse(); } + public getTypeName() { return 'HelloPut'; } +} + +export class HelloDelete implements IReturn, IDelete +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new HelloVerbResponse(); } + public getTypeName() { return 'HelloDelete'; } +} + +export class HelloPatch implements IReturn, IPatch +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() { return new HelloVerbResponse(); } + public getTypeName() { return 'HelloPatch'; } +} + +export class HelloReturnVoid implements IReturnVoid +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; + public createResponse() {} + public getTypeName() { return 'HelloReturnVoid'; } +} + +export class EnumRequest implements IReturn, IPut +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public operator: ScopeType; + public createResponse() { return new EnumResponse(); } + public getTypeName() { return 'EnumRequest'; } +} + +export class ExcludeTest1 implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new ExcludeTestNested(); } + public getTypeName() { return 'ExcludeTest1'; } +} + +export class ExcludeTest2 implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public excludeTestNested: ExcludeTestNested; + public createResponse() { return ''; } + public getTypeName() { return 'ExcludeTest2'; } +} + +export class HelloAuthenticated implements IReturn, IHasSessionId +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public sessionId: string; + public version: number; + public createResponse() { return new HelloAuthenticatedResponse(); } + public getTypeName() { return 'HelloAuthenticated'; } +} + +/** + * Echoes a sentence + */ +// @Route("/echoes", "POST") +// @Api(Description="Echoes a sentence") +export class Echoes implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * The sentence to echo. + */ + // @ApiMember(DataType="string", Description="The sentence to echo.", IsRequired=true, Name="Sentence", ParameterType="form") + public sentence: string; + public createResponse() { return new Echo(); } + public getTypeName() { return 'Echoes'; } +} + +export class CachedEcho implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public reload: boolean; + public sentence: string; + public createResponse() { return new Echo(); } + public getTypeName() { return 'CachedEcho'; } +} + +export class AsyncTest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new Echo(); } + public getTypeName() { return 'AsyncTest'; } +} + +// @Route("/throwhttperror/{Status}") +export class ThrowHttpError implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public status: number; + public message: string; + public createResponse() { return new ThrowHttpErrorResponse(); } + public getTypeName() { return 'ThrowHttpError'; } +} + +// @Route("/throw404") +// @Route("/throw404/{Message}") +export class Throw404 +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public message: string; +} + +// @Route("/return404") +export class Return404 +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/return404result") +export class Return404Result +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/throw/{Type}") +export class ThrowType implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public type: string; + public message: string; + public createResponse() { return new ThrowTypeResponse(); } + public getTypeName() { return 'ThrowType'; } +} + +// @Route("/throwvalidation") +export class ThrowValidation implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public age: number; + public required: string; + public email: string; + public createResponse() { return new ThrowValidationResponse(); } + public getTypeName() { return 'ThrowValidation'; } +} + +// @Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE") +// @Route("/api/acsprofiles/{profileId}") +export class ACSProfile implements IReturn, IHasVersion, IHasSessionId +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public profileId: string; + // @Required() + // @StringLength(20) + public shortName: string; + + // @StringLength(60) + public longName: string; + + // @StringLength(20) + public regionId: string; + + // @StringLength(20) + public groupId: string; + + // @StringLength(12) + public deviceID: string; + + public lastUpdated: string; + public enabled: boolean; + public version: number; + public sessionId: string; + public createResponse() { return new acsprofileResponse(); } + public getTypeName() { return 'ACSProfile'; } +} + +// @Route("/return/string") +export class ReturnString implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public data: string; + public createResponse() { return ''; } + public getTypeName() { return 'ReturnString'; } +} + +// @Route("/return/bytes") +export class ReturnBytes implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public data: Uint8Array; + public createResponse() { return new Uint8Array(0); } + public getTypeName() { return 'ReturnBytes'; } +} + +// @Route("/return/stream") +export class ReturnStream implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public data: Uint8Array; + public createResponse() { return new Blob(); } + public getTypeName() { return 'ReturnStream'; } +} + +// @Route("/Request1/", "GET") +export class GetRequest1 implements IReturn, IGet +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new Array(); } + public getTypeName() { return 'GetRequest1'; } +} + +// @Route("/Request3", "GET") +export class GetRequest2 implements IReturn, IGet +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new ReturnedDto(); } + public getTypeName() { return 'GetRequest2'; } +} + +// @Route("/matchlast/{Id}") +export class MatchesLastInt +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +// @Route("/matchlast/{Slug}") +export class MatchesNotLastInt +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public slug: string; +} + +// @Route("/matchregex/{Id}") +export class MatchesId +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: number; +} + +// @Route("/matchregex/{Slug}") +export class MatchesSlug +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public slug: string; +} + +// @Route("/{Version}/userdata", "GET") +export class SwaggerVersionTest +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public version: string; +} + +// @Route("/swagger/range") +export class SwaggerRangeTest +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public intRange: string; + public doubleRange: string; +} + +// @Route("/test/errorview") +export class TestErrorView +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public id: string; +} + +// @Route("/timestamp", "GET") +export class GetTimestamp implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() { return new TimestampData(); } + public getTypeName() { return 'GetTimestamp'; } +} + +export class TestMiniverView +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/testexecproc") +export class TestExecProc +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/files/{Path*}") +export class GetFile +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public path: string; +} + +// @Route("/test/html2") +export class TestHtml2 +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; +} + +// @Route("/views/request") +export class ViewRequest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return new ViewResponse(); } + public getTypeName() { return 'ViewRequest'; } +} + +// @Route("/index") +export class IndexPage +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public pathInfo: string; +} + +// @Route("/return/text") +export class ReturnText +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public text: string; +} + +// @Route("/gzip/{FileName}") +export class DownloadGzipFile implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public fileName: string; + public createResponse() { return new Uint8Array(0); } + public getTypeName() { return 'DownloadGzipFile'; } +} + +// @Route("/match/{Language}/{Name*}") +export class MatchName implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public language: string; + public name: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'MatchName'; } +} + +// @Route("/match/{Language*}") +export class MatchLang implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public language: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'MatchLang'; } +} + +// @Route("/reqlogstest/{Name}") +export class RequestLogsTest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; + public createResponse() { return ''; } + public getTypeName() { return 'RequestLogsTest'; } +} + +export class InProcRequest1 +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +export class InProcRequest2 +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +/** + * SwaggerTest Service Description + */ +// @Route("/swagger", "GET") +// @Route("/swagger/{Name}", "GET") +// @Route("/swagger/{Name}", "POST") +// @Api(Description="SwaggerTest Service Description") +// @ApiResponse(Description="Your request was not understood", StatusCode=400) +// @ApiResponse(Description="Oops, something broke", StatusCode=500) +// @DataContract +export class SwaggerTest +{ + public constructor(init?:Partial) { Object.assign(this, init); } + /** + * Color Description + */ + // @DataMember + // @ApiMember(DataType="string", Description="Color Description", IsRequired=true, ParameterType="path") + public name: string; + + // @DataMember + // @ApiMember() + public color: MyColor; + + /** + * Aliased Description + */ + // @DataMember(Name="Aliased") + // @ApiMember(DataType="string", Description="Aliased Description", IsRequired=true) + public original: string; + + /** + * Not Aliased Description + */ + // @DataMember + // @ApiMember(DataType="string", Description="Not Aliased Description", IsRequired=true) + public notAliased: string; + + /** + * Format as password + */ + // @DataMember + // @ApiMember(DataType="password", Description="Format as password") + public password: string; + + // @DataMember + // @ApiMember(AllowMultiple=true) + public myDateBetween: string[]; + + /** + * Nested model 1 + */ + // @DataMember + // @ApiMember(DataType="SwaggerNestedModel", Description="Nested model 1") + public nestedModel1: SwaggerNestedModel; + + /** + * Nested model 2 + */ + // @DataMember + // @ApiMember(DataType="SwaggerNestedModel2", Description="Nested model 2") + public nestedModel2: SwaggerNestedModel2; +} + +// @Route("/swaggertest2", "POST") +export class SwaggerTest2 +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @ApiMember() + public myEnumProperty: MyEnum; + + // @ApiMember(DataType="string", IsRequired=true, Name="Token", ParameterType="header") + public token: string; +} + +// @Route("/swagger-complex", "POST") +export class SwaggerComplex implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember + // @ApiMember() + public isRequired: boolean; + + // @DataMember + // @ApiMember(IsRequired=true) + public arrayString: string[]; + + // @DataMember + // @ApiMember() + public arrayInt: number[]; + + // @DataMember + // @ApiMember() + public listString: string[]; + + // @DataMember + // @ApiMember() + public listInt: number[]; + + // @DataMember + // @ApiMember() + public dictionaryString: { [index:string]: string; }; + public createResponse() { return new SwaggerComplexResponse(); } + public getTypeName() { return 'SwaggerComplex'; } +} + +// @Route("/swaggerpost/{Required1}", "GET") +// @Route("/swaggerpost/{Required1}/{Optional1}", "GET") +// @Route("/swaggerpost", "POST") +export class SwaggerPostTest implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @ApiMember(Verb="POST") + // @ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}", Verb="GET") + // @ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET") + public required1: string; + + // @ApiMember(Verb="POST") + // @ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET") + public optional1: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'SwaggerPostTest'; } +} + +// @Route("/swaggerpost2/{Required1}/{Required2}", "GET") +// @Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", "GET") +// @Route("/swaggerpost2", "POST") +export class SwaggerPostTest2 implements IReturn +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET") + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET") + public required1: string; + + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET") + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET") + public required2: string; + + // @ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET") + public optional1: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'SwaggerPostTest2'; } +} + +// @Route("/swagger/multiattrtest", "POST") +// @ApiResponse(Description="Code 1", StatusCode=400) +// @ApiResponse(Description="Code 2", StatusCode=402) +// @ApiResponse(Description="Code 3", StatusCode=401) +export class SwaggerMultiApiResponseTest implements IReturnVoid +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public createResponse() {} + public getTypeName() { return 'SwaggerMultiApiResponseTest'; } +} + +// @Route("/defaultview/class") +export class DefaultViewAttr +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/defaultview/action") +export class DefaultViewActionAttr +{ + public constructor(init?:Partial) { Object.assign(this, init); } +} + +// @Route("/dynamically/registered/{Name}") +export class DynamicallyRegistered +{ + public constructor(init?:Partial) { Object.assign(this, init); } + public name: string; +} + +// @Route("/auth") +// @Route("/auth/{provider}") +// @Route("/authenticate") +// @Route("/authenticate/{provider}") +// @DataContract +export class Authenticate implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public provider: string; + + // @DataMember(Order=2) + public state: string; + + // @DataMember(Order=3) + public oauth_token: string; + + // @DataMember(Order=4) + public oauth_verifier: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public rememberMe: boolean; + + // @DataMember(Order=8) + public continue: string; + + // @DataMember(Order=9) + public errorView: string; + + // @DataMember(Order=10) + public nonce: string; + + // @DataMember(Order=11) + public uri: string; + + // @DataMember(Order=12) + public response: string; + + // @DataMember(Order=13) + public qop: string; + + // @DataMember(Order=14) + public nc: string; + + // @DataMember(Order=15) + public cnonce: string; + + // @DataMember(Order=16) + public useTokenCookie: boolean; + + // @DataMember(Order=17) + public accessToken: string; + + // @DataMember(Order=18) + public accessTokenSecret: string; + + // @DataMember(Order=19) + public meta: { [index:string]: string; }; + public createResponse() { return new AuthenticateResponse(); } + public getTypeName() { return 'Authenticate'; } +} + +// @Route("/assignroles") +// @DataContract +export class AssignRoles implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + public createResponse() { return new AssignRolesResponse(); } + public getTypeName() { return 'AssignRoles'; } +} + +// @Route("/unassignroles") +// @DataContract +export class UnAssignRoles implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + public createResponse() { return new UnAssignRolesResponse(); } + public getTypeName() { return 'UnAssignRoles'; } +} + +// @Route("/session-to-token") +// @DataContract +export class ConvertSessionToToken implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public preserveSession: boolean; + public createResponse() { return new ConvertSessionToTokenResponse(); } + public getTypeName() { return 'ConvertSessionToToken'; } +} + +// @Route("/access-token") +// @DataContract +export class GetAccessToken implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public refreshToken: string; + public createResponse() { return new GetAccessTokenResponse(); } + public getTypeName() { return 'GetAccessToken'; } +} + +// @Route("/apikeys") +// @Route("/apikeys/{Environment}") +// @DataContract +export class GetApiKeys implements IReturn, IGet +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public environment: string; + public createResponse() { return new GetApiKeysResponse(); } + public getTypeName() { return 'GetApiKeys'; } +} + +// @Route("/apikeys/regenerate") +// @Route("/apikeys/regenerate/{Environment}") +// @DataContract +export class RegenerateApiKeys implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public environment: string; + public createResponse() { return new RegenerateApiKeysResponse(); } + public getTypeName() { return 'RegenerateApiKeys'; } +} + +// @Route("/register") +// @DataContract +export class Register implements IReturn, IPost +{ + public constructor(init?:Partial) { Object.assign(this, init); } + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public firstName: string; + + // @DataMember(Order=3) + public lastName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public email: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public confirmPassword: string; + + // @DataMember(Order=8) + public autoLogin: boolean; + + // @DataMember(Order=9) + public continue: string; + + // @DataMember(Order=10) + public errorView: string; + public createResponse() { return new RegisterResponse(); } + public getTypeName() { return 'Register'; } +} + +// @Route("/pgsql/rockstars") +export class QueryPostgresRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryPostgresRockstars'; } +} + +// @Route("/pgsql/pgrockstars") +export class QueryPostgresPgRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryPostgresPgRockstars'; } +} + +export class QueryRockstarsConventions extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public ids: number[]; + public ageOlderThan: number; + public ageGreaterThanOrEqualTo: number; + public ageGreaterThan: number; + public greaterThanAge: number; + public firstNameStartsWith: string; + public lastNameEndsWith: string; + public lastNameContains: string; + public rockstarAlbumNameContains: string; + public rockstarIdAfter: number; + public rockstarIdOnOrAfter: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarsConventions'; } +} + +// @AutoQueryViewer(Description="Use this option to search for Rockstars!", Title="Search for Rockstars") +export class QueryCustomRockstars extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryCustomRockstars'; } +} + +// @Route("/customrockstars") +export class QueryRockstarAlbums extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public rockstarAlbumName: string; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarAlbums'; } +} + +export class QueryRockstarAlbumsImplicit extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarAlbumsImplicit'; } +} + +export class QueryRockstarAlbumsLeftJoin extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public albumName: string; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarAlbumsLeftJoin'; } +} + +export class QueryOverridedRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryOverridedRockstars'; } +} + +export class QueryOverridedCustomRockstars extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryOverridedCustomRockstars'; } +} + +// @Route("/query-custom/rockstars") +export class QueryFieldRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public firstName: string; + public firstNames: string[]; + public age: number; + public firstNameCaseInsensitive: string; + public firstNameStartsWith: string; + public lastNameEndsWith: string; + public firstNameBetween: string[]; + public orLastName: string; + public firstNameContainsMulti: string[]; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryFieldRockstars'; } +} + +export class QueryFieldRockstarsDynamic extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryFieldRockstarsDynamic'; } +} + +export class QueryRockstarsFilter extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarsFilter'; } +} + +export class QueryCustomRockstarsFilter extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryCustomRockstarsFilter'; } +} + +export class QueryRockstarsIFilter extends QueryDb_1 implements IReturn>, IFilterRockstars +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarsIFilter'; } +} + +// @Route("/OrRockstars") +export class QueryOrRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public firstName: string; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryOrRockstars'; } +} + +export class QueryGetRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public ids: number[]; + public ages: number[]; + public firstNames: string[]; + public idsBetween: number[]; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryGetRockstars'; } +} + +export class QueryGetRockstarsDynamic extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryGetRockstarsDynamic'; } +} + +// @Route("/movies/search") +export class SearchMovies extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'SearchMovies'; } +} + +// @Route("/movies") +export class QueryMovies extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public ids: number[]; + public imdbIds: string[]; + public ratings: string[]; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryMovies'; } +} + +export class StreamMovies extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public ratings: string[]; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'StreamMovies'; } +} + +export class QueryUnknownRockstars extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public unknownInt: number; + public unknownProperty: string; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryUnknownRockstars'; } +} + +// @Route("/query/rockstar-references") +export class QueryRockstarsWithReferences extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryRockstarsWithReferences'; } +} + +export class QueryPocoBase extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public id: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryPocoBase'; } +} + +export class QueryPocoIntoBase extends QueryDb_2 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public id: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryPocoIntoBase'; } +} + +// @Route("/query/alltypes") +export class QueryAllTypes extends QueryDb_1 implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryAllTypes'; } +} + +// @Route("/querydata/rockstars") +export class QueryDataRockstars extends QueryData implements IReturn> +{ + public constructor(init?:Partial) { super(init); Object.assign(this, init); } + public age: number; + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryDataRockstars'; } +} diff --git a/tests/CheckMvc/Views/Home/About.cshtml b/tests/CheckMvc/Views/Home/About.cshtml new file mode 100644 index 00000000000..942bfe669b9 --- /dev/null +++ b/tests/CheckMvc/Views/Home/About.cshtml @@ -0,0 +1,16 @@ +@model CheckMvc.Controllers.HomeViewModel + + + + + + MVC Home Index + + +
+

@Model.Name Page

+ +

@Model.Name Counter: @Model.Counter

+
+ + \ No newline at end of file diff --git a/tests/CheckMvc/Views/Home/Contact.cshtml b/tests/CheckMvc/Views/Home/Contact.cshtml new file mode 100644 index 00000000000..6bd67d61d21 --- /dev/null +++ b/tests/CheckMvc/Views/Home/Contact.cshtml @@ -0,0 +1,10 @@ +@using ServiceStack.Html +@model CheckMvc.Controllers.HomeViewModel + +
+

@Model.Name Page

+ +

@Model.Name Counter: @Model.Counter

+
+ +@ServiceStack.MiniProfiler.Profiler.RenderIncludes().AsRaw() diff --git a/tests/CheckMvc/Views/Home/Hello.cshtml b/tests/CheckMvc/Views/Home/Hello.cshtml new file mode 100644 index 00000000000..7e9ec4c2196 --- /dev/null +++ b/tests/CheckMvc/Views/Home/Hello.cshtml @@ -0,0 +1,3 @@ +

Absolute URI

+ +

@ViewBag.Message

diff --git a/tests/CheckMvc/Views/Home/Index.cshtml b/tests/CheckMvc/Views/Home/Index.cshtml new file mode 100644 index 00000000000..bb244fc7020 --- /dev/null +++ b/tests/CheckMvc/Views/Home/Index.cshtml @@ -0,0 +1,26 @@ +@model CheckMvc.Controllers.HomeViewModel + + + + + + MVC Home Index + + +
+

@Model.Name Page

+ +

@Model.Name Counter: @Model.Counter

+ +

JSON

+

@Model.Json

+ +

To: /api/addsmrimportrequest/2017/8/30/9/2017/0/0/xxxxuser/192.168.23.64

+ +
+ + +
+
+ + \ No newline at end of file diff --git a/tests/CheckMvc/Views/Shared/_Layout.cshtml b/tests/CheckMvc/Views/Shared/_Layout.cshtml new file mode 100644 index 00000000000..bcb770fac0d --- /dev/null +++ b/tests/CheckMvc/Views/Shared/_Layout.cshtml @@ -0,0 +1,43 @@ +@using ServiceStack.Html + + + + + + @ViewBag.Title - My ASP.NET Application + + + +
+ @RenderBody() +
+ + @RenderSection("footer", required: false) + +
+
+

© @DateTime.Now.Year - ASP.NET MVC with ServiceStack

+
+ + @RenderSection("scripts", required: false) + + + \ No newline at end of file diff --git a/tests/CheckMvc/Views/Web.config b/tests/CheckMvc/Views/Web.config new file mode 100644 index 00000000000..826ce19e84c --- /dev/null +++ b/tests/CheckMvc/Views/Web.config @@ -0,0 +1,58 @@ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/CheckMvc/Web.Debug.config b/tests/CheckMvc/Web.Debug.config new file mode 100644 index 00000000000..3e2a97c957c --- /dev/null +++ b/tests/CheckMvc/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckMvc/Web.Release.config b/tests/CheckMvc/Web.Release.config new file mode 100644 index 00000000000..9fd481fdfeb --- /dev/null +++ b/tests/CheckMvc/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckMvc/Web.config b/tests/CheckMvc/Web.config new file mode 100644 index 00000000000..c3249c28e04 --- /dev/null +++ b/tests/CheckMvc/Web.config @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckMvc/dir/index.html b/tests/CheckMvc/dir/index.html new file mode 100644 index 00000000000..31063146576 --- /dev/null +++ b/tests/CheckMvc/dir/index.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

dir/index.html

+ + + \ No newline at end of file diff --git a/tests/CheckMvc/dir/sub/index.html b/tests/CheckMvc/dir/sub/index.html new file mode 100644 index 00000000000..e9fa3e179b7 --- /dev/null +++ b/tests/CheckMvc/dir/sub/index.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

dir/sub/index.html

+ + + \ No newline at end of file diff --git a/tests/CheckMvc/tsconfig.json b/tests/CheckMvc/tsconfig.json new file mode 100644 index 00000000000..54cfd3877c9 --- /dev/null +++ b/tests/CheckMvc/tsconfig.json @@ -0,0 +1,58 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "lib": [ "dom", "es2015" ], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} diff --git a/tests/CheckRazorCore/CheckRazorCore.csproj b/tests/CheckRazorCore/CheckRazorCore.csproj new file mode 100644 index 00000000000..2a003cdd132 --- /dev/null +++ b/tests/CheckRazorCore/CheckRazorCore.csproj @@ -0,0 +1,21 @@ + + + + false + net6.0 + + + + + + + + + + + + + + + + diff --git a/tests/CheckRazorCore/Configure.Auth.cs b/tests/CheckRazorCore/Configure.Auth.cs new file mode 100644 index 00000000000..fa4dfba91ff --- /dev/null +++ b/tests/CheckRazorCore/Configure.Auth.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.FluentValidation; + +namespace CheckWebCore +{ + /// + /// Run before AppHost.Configure() + /// + public class ConfigureAuth : IConfigureAppHost, IConfigureServices + { + private IConfiguration configuration; + public ConfigureAuth(IConfiguration configuration) => this.configuration = configuration; + + public void Configure(IServiceCollection services) + { + services.AddSingleton(new InMemoryAuthRepository()); + } + + public void Configure(IAppHost appHost) + { + var AppSettings = appHost.AppSettings; + appHost.Plugins.Add(new AuthFeature(() => new CustomUserSession(), + new IAuthProvider[] { + //new BasicAuthProvider(), //Sign-in with HTTP Basic Auth + new JwtAuthProvider(AppSettings) + { + AuthKey = AesUtils.CreateKey(), + RequireSecureConnection = false, + }, + new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials + new AppleAuthProvider(AppSettings), + new TwitterAuthProvider(AppSettings), + new GithubAuthProvider(AppSettings), + new GoogleAuthProvider(AppSettings), + new FacebookAuthProvider(AppSettings), + new MicrosoftGraphAuthProvider(AppSettings), +// new LinkedInAuthProvider(AppSettings), + })); + + appHost.Plugins.Add(new RegistrationFeature()); + + //override the default registration validation with your own custom implementation + appHost.RegisterAs>(); + + var authRepo = appHost.TryResolve(); + + var newAdmin = new UserAuth {Email = "admin@email.com", DisplayName = "Admin User"}; + var user = authRepo.CreateUserAuth(newAdmin, "p@55wOrd"); + authRepo.AssignRoles(user, new List {"Admin"}); + } + } + + public class CustomUserSession : AuthUserSession {} + + public class CustomRegistrationValidator : RegistrationValidator + { + public CustomRegistrationValidator() + { + RuleSet(ApplyTo.Post, () => + { + RuleFor(x => x.DisplayName).NotEmpty(); + RuleFor(x => x.ConfirmPassword).NotEmpty(); + }); + } + } + +} \ No newline at end of file diff --git a/tests/CheckRazorCore/Program.cs b/tests/CheckRazorCore/Program.cs new file mode 100644 index 00000000000..fd579c5a452 --- /dev/null +++ b/tests/CheckRazorCore/Program.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using ServiceStack; + +namespace CheckRazorCore +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) +// .UseModularStartup(); + .UseStartup(); + } + +} \ No newline at end of file diff --git a/tests/CheckRazorCore/Properties/launchSettings.json b/tests/CheckRazorCore/Properties/launchSettings.json new file mode 100644 index 00000000000..1e84bc81767 --- /dev/null +++ b/tests/CheckRazorCore/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:27286", + "sslPort": 44340 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "CheckRazorCore": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/tests/CheckRazorCore/Startup.cs b/tests/CheckRazorCore/Startup.cs new file mode 100644 index 00000000000..34cf159c123 --- /dev/null +++ b/tests/CheckRazorCore/Startup.cs @@ -0,0 +1,177 @@ +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using ServiceStack; +using ServiceStack.Mvc; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace CheckRazorCore +{ + public class Startup : ModularStartup + { + public Startup(IConfiguration configuration) : base(configuration) {} + + public new void ConfigureServices(IServiceCollection services) + { +#if DEBUG + services.AddMvc().AddRazorRuntimeCompilation(); +#else + services.AddMvc(); +#endif + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseServiceStack(new AppHost { + AppSettings = new NetCoreAppSettings(Configuration) + }); + } + } + + [Route("/hello")] + [Route("/hello/{Name}")] + public class Hello : IReturn + { + public string Name { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/testauth")] + public class TestAuth : IReturn {} + + [Route("/razor/view/{Path}")] + public class RazorView : IReturn + { + public string Path { get; set; } + public string Layout { get; set; } + } + + [Route("/razor/hello/{Path}")] + public class RazorViewHello : IReturn + { + public string Path { get; set; } + public string Layout { get; set; } + } + + [Route("/razor/bytes/{Path}")] + public class RazorViewBytes : IReturn + { + public string Path { get; set; } + public string Layout { get; set; } + } + + [Route("/razor/content")] + [Route("/razor/content/{Path}")] + public class RazorContent : IReturn + { + public string Path { get; set; } + public string Layout { get; set; } + } + + public class RazorViewResponse + { + public string Html { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class MyServices : Service + { + public object Any(Hello request) + { + return new HelloResponse {Result = $"Hello, {request.Name}!"}; + } + + [Authenticate] + public object Any(TestAuth request) => request; + + public async Task Any(RazorView request) + { + var razor = GetPlugin(); + var view = razor.GetViewPage(request.Path); + if (view == null) + throw HttpError.NotFound("Razor view not found: " + request.Path); + + var ret = await razor.RenderToHtmlAsync(view, new { Name = "World" }, + layout:request.Layout); + return ret; + } + + public async Task Any(RazorViewHello request) + { + var razor = GetPlugin(); + var view = razor.GetViewPage(request.Path); + if (view == null) + throw HttpError.NotFound("Razor view not found: " + request.Path); + + var ret = await razor.RenderToHtmlAsync(view, new Hello { Name = "World" }, + layout:request.Layout); + return ret; + } + + public async Task Any(RazorViewBytes request) + { + var razor = GetPlugin(); + var view = razor.GetViewPage(request.Path); + if (view == null) + throw HttpError.NotFound("Razor view not found: " + request.Path); + + await razor.WriteHtmlAsync(Response.OutputStream, view, new Hello { Name = "World" }, + layout:request.Layout); + } + + public async Task Any(RazorContent request) + { + var razor = GetPlugin(); + var view = razor.GetContentPage(request.Path); + if (view == null) + throw HttpError.NotFound("Razor view not found: " + request.Path); + + var ret = await razor.RenderToHtmlAsync(view, new Hello { Name = "World" }, + layout:request.Layout); + return ret; + } + } + + public class AppHost : AppHostBase + { + public AppHost() + : base(nameof(CheckRazorCore), typeof(MyServices).Assembly) { } + + public override void Configure(IServiceCollection services) + { + //Register dependencies shared by ServiceStack and ASP.NET Core + } + + public override void Configure(Container container) + { + if (Config.DebugMode) + { + Plugins.Add(new HotReloadFeature { + DefaultPattern = "*.js;*.css;*.html;*.cshtml" + }); + } + + Plugins.Add(new RazorFormat()); + + Plugins.Add(new ValidationFeature()); + + this.CustomErrorHttpHandlers[HttpStatusCode.Forbidden] = new RazorHandler("/forbidden"); + } + } +} \ No newline at end of file diff --git a/tests/CheckRazorCore/Views/Hello.cshtml b/tests/CheckRazorCore/Views/Hello.cshtml new file mode 100644 index 00000000000..6810cbb861e --- /dev/null +++ b/tests/CheckRazorCore/Views/Hello.cshtml @@ -0,0 +1,12 @@ +@model HelloResponse + +

View Page for /hello API

+ +

@Model.Result

+ + diff --git a/tests/CheckRazorCore/Views/Shared/_BasicLayout.cshtml b/tests/CheckRazorCore/Views/Shared/_BasicLayout.cshtml new file mode 100644 index 00000000000..2093f2f8f6b --- /dev/null +++ b/tests/CheckRazorCore/Views/Shared/_BasicLayout.cshtml @@ -0,0 +1,9 @@ + + + + Empty :: @ViewBag.Title + + + @RenderBody() + + \ No newline at end of file diff --git a/tests/CheckRazorCore/Views/Shared/_Layout.cshtml b/tests/CheckRazorCore/Views/Shared/_Layout.cshtml new file mode 100644 index 00000000000..3bbf9923a1c --- /dev/null +++ b/tests/CheckRazorCore/Views/Shared/_Layout.cshtml @@ -0,0 +1,82 @@ + + + + @ViewBag.Title + + + + + + @Html.CssIncludes("bootstrap","default") + + + @if (DebugMode) { + + } + + + + + +
+
+
+

@ViewBag.Title

+ @RenderBody() +
+
+
+ +

+ Learn about ServiceStack Razor +

+ + + + @{ + var min = DebugMode ? "" : "[hash].min"; + } + + @Html.BundleJs(new BundleOptions { + Sources = { + "content:/src/source.js", + "content:/src/components/", + "/assets/js/jquery.min.js", + "/assets/js/popper.min.js", + "/assets/js/", + "/js/ss-utils.js", + "/lib/@servicestack/client/index.js", + "/dtos.js" + }, + Minify = !DebugMode, + Cache = !DebugMode, + SaveToDisk = !DebugMode, + OutputTo = $"/js/bundle{min}.js", + }) + + @RenderSection("scripts", required: false) + + + \ No newline at end of file diff --git a/tests/CheckRazorCore/Views/Shared/_RequiresAuth.cshtml b/tests/CheckRazorCore/Views/Shared/_RequiresAuth.cshtml new file mode 100644 index 00000000000..fa9749f1ca2 --- /dev/null +++ b/tests/CheckRazorCore/Views/Shared/_RequiresAuth.cshtml @@ -0,0 +1,8 @@ +@{ RedirectIfNotAuthenticated($"/validation/client-razor/login?continue={Request.PathInfo}"); } + +
+ + @UserSession.DisplayName + | Sign Out + +
diff --git a/tests/CheckRazorCore/Views/Shared/_RequiresAuthServer.cshtml b/tests/CheckRazorCore/Views/Shared/_RequiresAuthServer.cshtml new file mode 100644 index 00000000000..88d0eaf621c --- /dev/null +++ b/tests/CheckRazorCore/Views/Shared/_RequiresAuthServer.cshtml @@ -0,0 +1,8 @@ +@{ RedirectIfNotAuthenticated($"/validation/server-razor/login?continue={Request.PathInfo}"); } + +
+ + @UserSession.DisplayName + | Sign Out + +
diff --git a/tests/CheckRazorCore/Views/TestAuth.cshtml b/tests/CheckRazorCore/Views/TestAuth.cshtml new file mode 100644 index 00000000000..8185ece8ebe --- /dev/null +++ b/tests/CheckRazorCore/Views/TestAuth.cshtml @@ -0,0 +1,5 @@ +@model TestAuth + +@{ RedirectIfNotAuthenticated(); } + +

View Page for /testauth API

diff --git a/tests/CheckRazorCore/Views/Throw.cshtml b/tests/CheckRazorCore/Views/Throw.cshtml new file mode 100644 index 00000000000..7262aa7d268 --- /dev/null +++ b/tests/CheckRazorCore/Views/Throw.cshtml @@ -0,0 +1,11 @@ +@model HelloResponse + +

View Page for /throw API

+ +

@Model

+ +

IsError: @IsError

+ +

GetErrorStatus(): @GetErrorStatus()

+ +@if (RenderErrorIfAny()) { return; } diff --git a/tests/CheckRazorCore/Views/_ViewImports.cshtml b/tests/CheckRazorCore/Views/_ViewImports.cshtml new file mode 100644 index 00000000000..825cace4ab5 --- /dev/null +++ b/tests/CheckRazorCore/Views/_ViewImports.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage + +@using ServiceStack +@using ServiceStack.Mvc +@using ServiceStack.Text +@using CheckRazorCore + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/tests/CheckRazorCore/Views/services.cshtml b/tests/CheckRazorCore/Views/services.cshtml new file mode 100644 index 00000000000..4884b2f17d4 --- /dev/null +++ b/tests/CheckRazorCore/Views/services.cshtml @@ -0,0 +1,7 @@ +@{ + ViewBag.Title = "Services we provide"; +} + +

+ Services page. +

diff --git a/tests/CheckRazorCore/Views/simple-hello.cshtml b/tests/CheckRazorCore/Views/simple-hello.cshtml new file mode 100644 index 00000000000..5244f985fdb --- /dev/null +++ b/tests/CheckRazorCore/Views/simple-hello.cshtml @@ -0,0 +1,10 @@ +@model Hello + +@if (Model != null) +{ +

This is my sample view, Hello @Model.Name!

+} +else +{ +

Model == null

+} diff --git a/tests/CheckRazorCore/Views/simple.cshtml b/tests/CheckRazorCore/Views/simple.cshtml new file mode 100644 index 00000000000..5a35dc99e56 --- /dev/null +++ b/tests/CheckRazorCore/Views/simple.cshtml @@ -0,0 +1,10 @@ +@model dynamic + +@if (Model != null) +{ +

This is my sample view, Hello @Model.Name!

+} +else +{ +

Model == null

+} diff --git a/tests/CheckRazorCore/appsettings.Development.json b/tests/CheckRazorCore/appsettings.Development.json new file mode 100644 index 00000000000..e203e9407e7 --- /dev/null +++ b/tests/CheckRazorCore/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/tests/CheckRazorCore/appsettings.json b/tests/CheckRazorCore/appsettings.json new file mode 100644 index 00000000000..ba97529c7bb --- /dev/null +++ b/tests/CheckRazorCore/appsettings.json @@ -0,0 +1,63 @@ +{ + "DebugMode": true, + "oauth.RedirectUrl": "https://localhost:5001/", + "oauth.CallbackUrl": "https://localhost:5001/auth/{0}", + "oauth.facebook.Permissions": [ "email", "user_location" ], + "oauth.facebook.Permissions2": "email,user_location", + "oauth.facebook.AppId": "531608123577340", + "oauth.facebook.AppSecret": "9e1e6591a7f15cbc1b305729f4b14c0b", + "oauth.twitter.ConsumerKey": "JvWZokH73rdghDdCFCFkJtCEU", + "oauth.twitter.ConsumerSecret": "WNeOT6YalxXDR4iWZjc4jVjFaydoDcY8jgRrGc5FVLjsVlY2Y8", + "oauth.github.Scopes": [ "user" ], + "oauth.github.ClientId": "04cc321f8fdac2260fa7", + "oauth.github.ClientSecret": "868d2b4c7b1632d1b774d6209b1c6ae522fe1954", + "oauth.microsoftgraph.AppId": "8208d98e-400d-4ce9-89ba-d92610c67e13", + "oauth.microsoftgraph.AppSecret": "hsrMP46|_kfkcYCWSW516?%", + "oauth.microsoftgraph.SavePhoto": "true", + "oauth.microsoftgraph.SavePhotoSize": "32x32", + "oauth.apple.RedirectUrl": "https://localtest.me:5001/", + "oauth.apple.CallbackUrl": "https://localtest.me:5001/auth/apple", + "oauth.apple.TeamId": "DK4VJ3YB24", + "oauth.apple.ClientId": "net.servicestack.myappid", + "oauth.apple.KeyId": "L8N2DSVU8J", + "oauth.apple.KeyPath": "AuthKey_L8N2DSVU8J.p8", + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*", + "NavItems": [ + { "href":"/", "label": "Home", "exact":true }, + { "href":"/about", "label": "About" }, + { "href":"/services", "label": "Services" }, + { "href":"/contact", "label": "Contact", + "children": [ + { "href": "/contact/me", "label":"Me" }, + { "href": "/contact/email", "label":"Email" }, + { "label":"-" }, + { "href": "/contact/phone", "label":"Phone" } + ] + }, + { "href":"/login", "label": "Sign In", "hide": "auth" }, + { "href":"/profile", "label": "Profile", "show":"auth" }, + { "href":"/admin", "label": "Admin", "show":"role:Admin" } + ], + "NavItemsMap": { + "aside": [ + { "href":"/aside", "label":"Aside" } + ], + "footer": [ + { "href":"/terms", "label":"About" }, + { "href":"/navitems", "label":"Services" }, + { "href":"/contacts", "label": "Contacts", + "children": [ + { "href": "/contact/me", "label":"Me" }, + { "href": "/contact/email", "label":"Email" }, + { "label":"-" }, + { "href": "/contact/phone", "label":"Phone" } + ] + } + ] + } +} diff --git a/tests/CheckRazorCore/src/components/home.js b/tests/CheckRazorCore/src/components/home.js new file mode 100644 index 00000000000..1b46f5a195c --- /dev/null +++ b/tests/CheckRazorCore/src/components/home.js @@ -0,0 +1,8 @@ +"use strict"; +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +new A().template = "TypeScript " + Date(); +//# sourceMappingURL=home.js.map \ No newline at end of file diff --git a/tests/CheckRazorCore/src/components/home.js.map b/tests/CheckRazorCore/src/components/home.js.map new file mode 100644 index 00000000000..be2b3132025 --- /dev/null +++ b/tests/CheckRazorCore/src/components/home.js.map @@ -0,0 +1 @@ +{"version":3,"file":"home.js","sourceRoot":"","sources":["home.ts"],"names":[],"mappings":";AAAA;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC;AAED,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG,gBAAc,IAAI,EAAI,CAAC"} \ No newline at end of file diff --git a/tests/CheckRazorCore/src/components/home.ts b/tests/CheckRazorCore/src/components/home.ts new file mode 100644 index 00000000000..515d5e6ad9c --- /dev/null +++ b/tests/CheckRazorCore/src/components/home.ts @@ -0,0 +1,6 @@ +class A +{ + template: string; +} + +new A().template = `TypeScript ${Date()}`; diff --git a/tests/CheckRazorCore/src/components/sub/SubB.js b/tests/CheckRazorCore/src/components/sub/SubB.js new file mode 100644 index 00000000000..27880081a5e --- /dev/null +++ b/tests/CheckRazorCore/src/components/sub/SubB.js @@ -0,0 +1,8 @@ +"use strict"; +var SubB = /** @class */ (function () { + function SubB() { + } + return SubB; +}()); +new SubB().template = "/src/components/sub/SubB.ts " + Date(); +//# sourceMappingURL=SubB.js.map \ No newline at end of file diff --git a/tests/CheckRazorCore/src/components/sub/SubB.js.map b/tests/CheckRazorCore/src/components/sub/SubB.js.map new file mode 100644 index 00000000000..fe9be5c4c92 --- /dev/null +++ b/tests/CheckRazorCore/src/components/sub/SubB.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SubB.js","sourceRoot":"","sources":["SubB.ts"],"names":[],"mappings":";AAAA;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAED,IAAI,IAAI,EAAE,CAAC,QAAQ,GAAG,iCAA+B,IAAI,EAAI,CAAC"} \ No newline at end of file diff --git a/tests/CheckRazorCore/src/components/sub/SubB.ts b/tests/CheckRazorCore/src/components/sub/SubB.ts new file mode 100644 index 00000000000..eeac0d0f52e --- /dev/null +++ b/tests/CheckRazorCore/src/components/sub/SubB.ts @@ -0,0 +1,6 @@ +class SubB +{ + template: string; +} + +new SubB().template = `/src/components/sub/SubB.ts ${Date()}`; diff --git a/tests/CheckRazorCore/src/components/sub/sub2/SubC.js b/tests/CheckRazorCore/src/components/sub/sub2/SubC.js new file mode 100644 index 00000000000..2cbc69f8d39 --- /dev/null +++ b/tests/CheckRazorCore/src/components/sub/sub2/SubC.js @@ -0,0 +1,8 @@ +"use strict"; +var SubC = /** @class */ (function () { + function SubC() { + } + return SubC; +}()); +new SubC().template = "/src/components/sub/sub2/SubC.ts " + Date(); +//# sourceMappingURL=SubC.js.map \ No newline at end of file diff --git a/tests/CheckRazorCore/src/components/sub/sub2/SubC.js.map b/tests/CheckRazorCore/src/components/sub/sub2/SubC.js.map new file mode 100644 index 00000000000..533a9fd3ad4 --- /dev/null +++ b/tests/CheckRazorCore/src/components/sub/sub2/SubC.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SubC.js","sourceRoot":"","sources":["SubC.ts"],"names":[],"mappings":";AAAA;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAED,IAAI,IAAI,EAAE,CAAC,QAAQ,GAAG,sCAAoC,IAAI,EAAI,CAAC"} \ No newline at end of file diff --git a/tests/CheckRazorCore/src/components/sub/sub2/SubC.ts b/tests/CheckRazorCore/src/components/sub/sub2/SubC.ts new file mode 100644 index 00000000000..6a58e4ea199 --- /dev/null +++ b/tests/CheckRazorCore/src/components/sub/sub2/SubC.ts @@ -0,0 +1,6 @@ +class SubC +{ + template: string; +} + +new SubC().template = `/src/components/sub/sub2/SubC.ts ${Date()}`; diff --git a/tests/CheckRazorCore/src/source.js b/tests/CheckRazorCore/src/source.js new file mode 100644 index 00000000000..0762d0fab7c --- /dev/null +++ b/tests/CheckRazorCore/src/source.js @@ -0,0 +1 @@ +function source() { return "source.js"; } \ No newline at end of file diff --git a/tests/CheckRazorCore/svg/my-icons/spirals.html b/tests/CheckRazorCore/svg/my-icons/spirals.html new file mode 100644 index 00000000000..a97caab29ab --- /dev/null +++ b/tests/CheckRazorCore/svg/my-icons/spirals.html @@ -0,0 +1,7 @@ + +{{#each range(180) }} + {{ 120 + 100 * cos((5) * it * 0.02827) | assignTo: x }} + {{ 320 + 300 * sin((1) * it * 0.02827) | assignTo: y }} + +{{/each}} + diff --git a/tests/CheckRazorCore/svg/my-icons/vue.svg b/tests/CheckRazorCore/svg/my-icons/vue.svg new file mode 100644 index 00000000000..18972867ab5 --- /dev/null +++ b/tests/CheckRazorCore/svg/my-icons/vue.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/CheckRazorCore/svg/svg-icons/vscode.svg b/tests/CheckRazorCore/svg/svg-icons/vscode.svg new file mode 100644 index 00000000000..c00bbfbeca4 --- /dev/null +++ b/tests/CheckRazorCore/svg/svg-icons/vscode.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/tests/CheckRazorCore/wwwroot/_ViewImports.cshtml b/tests/CheckRazorCore/wwwroot/_ViewImports.cshtml new file mode 100644 index 00000000000..825cace4ab5 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/_ViewImports.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage + +@using ServiceStack +@using ServiceStack.Mvc +@using ServiceStack.Text +@using CheckRazorCore + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/tests/CheckRazorCore/wwwroot/about.cshtml b/tests/CheckRazorCore/wwwroot/about.cshtml new file mode 100644 index 00000000000..c2b9fc1e0ec --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/about.cshtml @@ -0,0 +1,7 @@ +@{ + ViewBag.Title = "About Us"; +} + +

+ About Us page. +

diff --git a/tests/CheckRazorCore/wwwroot/admin.cshtml b/tests/CheckRazorCore/wwwroot/admin.cshtml new file mode 100644 index 00000000000..ef8a9f5cbb1 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/admin.cshtml @@ -0,0 +1,5 @@ + +@AssertRole("Admin") + +

Admin Page

+ diff --git a/tests/CheckRazorCore/wwwroot/assets/css/bootstrap.css b/tests/CheckRazorCore/wwwroot/assets/css/bootstrap.css new file mode 100644 index 00000000000..9746051d909 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/assets/css/bootstrap.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.1.2 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-label::after{border-color:#80bdff}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:2.25rem;padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:not(:disabled):not(.disabled){cursor:pointer}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease}@media screen and (prefers-reduced-motion:reduce){.carousel-item-next,.carousel-item-prev,.carousel-item.active{transition:none}}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/tests/CheckRazorCore/wwwroot/assets/css/default.css b/tests/CheckRazorCore/wwwroot/assets/css/default.css new file mode 100644 index 00000000000..a761b5b565d --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/assets/css/default.css @@ -0,0 +1,38 @@ +body { + padding-top: 54px; +} +@media (min-width: 992px) { + body { + padding-top: 56px; + } +} +span[data-click] { + color: #007bff; + cursor: pointer; +} +span[data-click]:hover { + text-decoration: underline; +} +.quicklist span { + display: block; + margin-left: 1em; +} + +form { + padding: 10px; +} +table form { + padding: 0; +} +table#results button { + margin: 5px; +} +table#results td:first-child { + padding: 2px 10px; +} + +.form-check.form-control { + padding-left: 1.75rem; +} + + diff --git a/tests/CheckRazorCore/wwwroot/assets/img/logo.png b/tests/CheckRazorCore/wwwroot/assets/img/logo.png new file mode 100644 index 00000000000..6dbd73bc0eb Binary files /dev/null and b/tests/CheckRazorCore/wwwroot/assets/img/logo.png differ diff --git a/tests/CheckRazorCore/wwwroot/assets/js/bootstrap.min.js b/tests/CheckRazorCore/wwwroot/assets/js/bootstrap.min.js new file mode 100644 index 00000000000..c4c0d1f95cd --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/assets/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.3.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t=t||self).bootstrap={},t.jQuery,t.Popper)}(this,function(t,g,u){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)g(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Ee},je="show",He="out",Re={HIDE:"hide"+De,HIDDEN:"hidden"+De,SHOW:"show"+De,SHOWN:"shown"+De,INSERTED:"inserted"+De,CLICK:"click"+De,FOCUSIN:"focusin"+De,FOCUSOUT:"focusout"+De,MOUSEENTER:"mouseenter"+De,MOUSELEAVE:"mouseleave"+De},xe="fade",Fe="show",Ue=".tooltip-inner",We=".arrow",qe="hover",Me="focus",Ke="click",Qe="manual",Be=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(xe);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:We},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===He&&e._leave(null,e)};if(g(this.tip).hasClass(xe)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==je&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ke]=!1,this._activeTrigger[Me]=!1,this._activeTrigger[qe]=!1,g(this.tip).hasClass(xe)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Ae+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Ue)),this.getTitle()),g(t).removeClass(xe+" "+Fe)},t.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Se(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text())},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return Pe[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Qe){var e=t===qe?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===qe?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Me:qe]=!0),g(e.getTipElement()).hasClass(Fe)||e._hoverState===je?e._hoverState=je:(clearTimeout(e._timeout),e._hoverState=je,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===je&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Me:qe]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===He&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){var e=g(this.element).data();return Object.keys(e).forEach(function(t){-1!==Oe.indexOf(t)&&delete e[t]}),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(be,t,this.constructor.DefaultType),t.sanitize&&(t.template=Se(t.template,t.whiteList,t.sanitizeFn)),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ne);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(xe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ie),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ie,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Le}},{key:"NAME",get:function(){return be}},{key:"DATA_KEY",get:function(){return Ie}},{key:"Event",get:function(){return Re}},{key:"EVENT_KEY",get:function(){return De}},{key:"DefaultType",get:function(){return ke}}]),i}();g.fn[be]=Be._jQueryInterface,g.fn[be].Constructor=Be,g.fn[be].noConflict=function(){return g.fn[be]=we,Be._jQueryInterface};var Ve="popover",Ye="bs.popover",ze="."+Ye,Xe=g.fn[Ve],$e="bs-popover",Ge=new RegExp("(^|\\s)"+$e+"\\S+","g"),Je=l({},Be.Default,{placement:"right",trigger:"click",content:"",template:''}),Ze=l({},Be.DefaultType,{content:"(string|element|function)"}),tn="fade",en="show",nn=".popover-header",on=".popover-body",rn={HIDE:"hide"+ze,HIDDEN:"hidden"+ze,SHOW:"show"+ze,SHOWN:"shown"+ze,INSERTED:"inserted"+ze,CLICK:"click"+ze,FOCUSIN:"focusin"+ze,FOCUSOUT:"focusout"+ze,MOUSEENTER:"mouseenter"+ze,MOUSELEAVE:"mouseleave"+ze},sn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass($e+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(nn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(on),e),t.removeClass(tn+" "+en)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ge);null!==e&&0=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),le({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=fe({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},le(n,m,$(v)),le(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ge.FLIP:p=[n,i];break;case ge.CLOCKWISE:p=G(n);break;case ge.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u);(m||b||y)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),y&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=fe({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!me),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=H('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=fe({},E,e.attributes),e.styles=fe({},m,e.styles),e.arrowStyles=fe({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return j(e.instance.popper,e.styles),V(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&j(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),j(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ue}); +//# sourceMappingURL=popper.min.js.map \ No newline at end of file diff --git a/tests/CheckRazorCore/wwwroot/content-hello.cshtml b/tests/CheckRazorCore/wwwroot/content-hello.cshtml new file mode 100644 index 00000000000..d9c502474e3 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/content-hello.cshtml @@ -0,0 +1,10 @@ +@model Hello + +@if (Model != null) +{ +

This is my content page, Hello @Model.Name!

+} +else +{ +

(content) Model == null

+} diff --git a/tests/CheckRazorCore/wwwroot/default.cshtml b/tests/CheckRazorCore/wwwroot/default.cshtml new file mode 100644 index 00000000000..161e9478921 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/default.cshtml @@ -0,0 +1,31 @@ +@using ServiceStack.Mvc +@{ + ViewBag.Title = "Home Page"; +} + +

Links

+ + + +@Html.SvgImage("male-color") + + + + + + + +
diff --git a/tests/CheckRazorCore/wwwroot/dir/content-hello.cshtml b/tests/CheckRazorCore/wwwroot/dir/content-hello.cshtml new file mode 100644 index 00000000000..e232c014a39 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/dir/content-hello.cshtml @@ -0,0 +1,10 @@ +@model Hello + +@if (Model != null) +{ +

This is my dir/content page, Hello @Model.Name!

+} +else +{ +

(dir/content) Model == null

+} diff --git a/tests/CheckRazorCore/wwwroot/dtos.js b/tests/CheckRazorCore/wwwroot/dtos.js new file mode 100644 index 00000000000..7f11b2c2381 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/dtos.js @@ -0,0 +1,297 @@ +"use strict"; +/* Options: +Date: 2019-02-14 23:07:52 +Version: 5.41 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:5000 + +//GlobalNamespace: +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ +Object.defineProperty(exports, "__esModule", { value: true }); +var Title; +(function (Title) { + Title["Unspecified"] = "Unspecified"; + Title["Mr"] = "Mr"; + Title["Mrs"] = "Mrs"; + Title["Miss"] = "Miss"; +})(Title = exports.Title || (exports.Title = {})); +var Contact = /** @class */ (function () { + function Contact(init) { + Object.assign(this, init); + } + return Contact; +}()); +exports.Contact = Contact; +// @DataContract +var ResponseError = /** @class */ (function () { + function ResponseError(init) { + Object.assign(this, init); + } + return ResponseError; +}()); +exports.ResponseError = ResponseError; +// @DataContract +var ResponseStatus = /** @class */ (function () { + function ResponseStatus(init) { + Object.assign(this, init); + } + return ResponseStatus; +}()); +exports.ResponseStatus = ResponseStatus; +var FilmGenres; +(function (FilmGenres) { + FilmGenres["Action"] = "Action"; + FilmGenres["Adventure"] = "Adventure"; + FilmGenres["Comedy"] = "Comedy"; + FilmGenres["Drama"] = "Drama"; +})(FilmGenres = exports.FilmGenres || (exports.FilmGenres = {})); +var HelloResponse = /** @class */ (function () { + function HelloResponse(init) { + Object.assign(this, init); + } + return HelloResponse; +}()); +exports.HelloResponse = HelloResponse; +// @Route("/testauth") +var TestAuth = /** @class */ (function () { + function TestAuth(init) { + Object.assign(this, init); + } + TestAuth.prototype.createResponse = function () { return new TestAuth(); }; + TestAuth.prototype.getTypeName = function () { return 'TestAuth'; }; + return TestAuth; +}()); +exports.TestAuth = TestAuth; +// @DataContract +var AuthUserSession = /** @class */ (function () { + function AuthUserSession(init) { + Object.assign(this, init); + } + return AuthUserSession; +}()); +exports.AuthUserSession = AuthUserSession; +var GetContactsResponse = /** @class */ (function () { + function GetContactsResponse(init) { + Object.assign(this, init); + } + return GetContactsResponse; +}()); +exports.GetContactsResponse = GetContactsResponse; +var GetContactResponse = /** @class */ (function () { + function GetContactResponse(init) { + Object.assign(this, init); + } + return GetContactResponse; +}()); +exports.GetContactResponse = GetContactResponse; +var CreateContactResponse = /** @class */ (function () { + function CreateContactResponse(init) { + Object.assign(this, init); + } + return CreateContactResponse; +}()); +exports.CreateContactResponse = CreateContactResponse; +var UpdateContactResponse = /** @class */ (function () { + function UpdateContactResponse(init) { + Object.assign(this, init); + } + return UpdateContactResponse; +}()); +exports.UpdateContactResponse = UpdateContactResponse; +// @DataContract +var AuthenticateResponse = /** @class */ (function () { + function AuthenticateResponse(init) { + Object.assign(this, init); + } + return AuthenticateResponse; +}()); +exports.AuthenticateResponse = AuthenticateResponse; +// @DataContract +var AssignRolesResponse = /** @class */ (function () { + function AssignRolesResponse(init) { + Object.assign(this, init); + } + return AssignRolesResponse; +}()); +exports.AssignRolesResponse = AssignRolesResponse; +// @DataContract +var UnAssignRolesResponse = /** @class */ (function () { + function UnAssignRolesResponse(init) { + Object.assign(this, init); + } + return UnAssignRolesResponse; +}()); +exports.UnAssignRolesResponse = UnAssignRolesResponse; +// @DataContract +var ConvertSessionToTokenResponse = /** @class */ (function () { + function ConvertSessionToTokenResponse(init) { + Object.assign(this, init); + } + return ConvertSessionToTokenResponse; +}()); +exports.ConvertSessionToTokenResponse = ConvertSessionToTokenResponse; +// @DataContract +var GetAccessTokenResponse = /** @class */ (function () { + function GetAccessTokenResponse(init) { + Object.assign(this, init); + } + return GetAccessTokenResponse; +}()); +exports.GetAccessTokenResponse = GetAccessTokenResponse; +// @DataContract +var RegisterResponse = /** @class */ (function () { + function RegisterResponse(init) { + Object.assign(this, init); + } + return RegisterResponse; +}()); +exports.RegisterResponse = RegisterResponse; +// @Route("/hello") +// @Route("/hello/{Name}") +var Hello = /** @class */ (function () { + function Hello(init) { + Object.assign(this, init); + } + Hello.prototype.createResponse = function () { return new HelloResponse(); }; + Hello.prototype.getTypeName = function () { return 'Hello'; }; + return Hello; +}()); +exports.Hello = Hello; +// @Route("/session") +var Session = /** @class */ (function () { + function Session(init) { + Object.assign(this, init); + } + Session.prototype.createResponse = function () { return new AuthUserSession(); }; + Session.prototype.getTypeName = function () { return 'Session'; }; + return Session; +}()); +exports.Session = Session; +// @Route("/contacts", "GET") +var GetContacts = /** @class */ (function () { + function GetContacts(init) { + Object.assign(this, init); + } + GetContacts.prototype.createResponse = function () { return new GetContactsResponse(); }; + GetContacts.prototype.getTypeName = function () { return 'GetContacts'; }; + return GetContacts; +}()); +exports.GetContacts = GetContacts; +// @Route("/contacts/{Id}", "GET") +var GetContact = /** @class */ (function () { + function GetContact(init) { + Object.assign(this, init); + } + GetContact.prototype.createResponse = function () { return new GetContactResponse(); }; + GetContact.prototype.getTypeName = function () { return 'GetContact'; }; + return GetContact; +}()); +exports.GetContact = GetContact; +// @Route("/contacts", "POST") +var CreateContact = /** @class */ (function () { + function CreateContact(init) { + Object.assign(this, init); + } + CreateContact.prototype.createResponse = function () { return new CreateContactResponse(); }; + CreateContact.prototype.getTypeName = function () { return 'CreateContact'; }; + return CreateContact; +}()); +exports.CreateContact = CreateContact; +// @Route("/contacts/{Id}", "DELETE") +// @Route("/contacts/{Id}/delete", "POST") +var DeleteContact = /** @class */ (function () { + function DeleteContact(init) { + Object.assign(this, init); + } + DeleteContact.prototype.createResponse = function () { }; + DeleteContact.prototype.getTypeName = function () { return 'DeleteContact'; }; + return DeleteContact; +}()); +exports.DeleteContact = DeleteContact; +// @Route("/contacts/{Id}", "POST PUT") +var UpdateContact = /** @class */ (function () { + function UpdateContact(init) { + Object.assign(this, init); + } + UpdateContact.prototype.createResponse = function () { return new UpdateContactResponse(); }; + UpdateContact.prototype.getTypeName = function () { return 'UpdateContact'; }; + return UpdateContact; +}()); +exports.UpdateContact = UpdateContact; +// @Route("/auth") +// @Route("/auth/{provider}") +// @Route("/authenticate") +// @Route("/authenticate/{provider}") +// @DataContract +var Authenticate = /** @class */ (function () { + function Authenticate(init) { + Object.assign(this, init); + } + Authenticate.prototype.createResponse = function () { return new AuthenticateResponse(); }; + Authenticate.prototype.getTypeName = function () { return 'Authenticate'; }; + return Authenticate; +}()); +exports.Authenticate = Authenticate; +// @Route("/assignroles") +// @DataContract +var AssignRoles = /** @class */ (function () { + function AssignRoles(init) { + Object.assign(this, init); + } + AssignRoles.prototype.createResponse = function () { return new AssignRolesResponse(); }; + AssignRoles.prototype.getTypeName = function () { return 'AssignRoles'; }; + return AssignRoles; +}()); +exports.AssignRoles = AssignRoles; +// @Route("/unassignroles") +// @DataContract +var UnAssignRoles = /** @class */ (function () { + function UnAssignRoles(init) { + Object.assign(this, init); + } + UnAssignRoles.prototype.createResponse = function () { return new UnAssignRolesResponse(); }; + UnAssignRoles.prototype.getTypeName = function () { return 'UnAssignRoles'; }; + return UnAssignRoles; +}()); +exports.UnAssignRoles = UnAssignRoles; +// @Route("/session-to-token") +// @DataContract +var ConvertSessionToToken = /** @class */ (function () { + function ConvertSessionToToken(init) { + Object.assign(this, init); + } + ConvertSessionToToken.prototype.createResponse = function () { return new ConvertSessionToTokenResponse(); }; + ConvertSessionToToken.prototype.getTypeName = function () { return 'ConvertSessionToToken'; }; + return ConvertSessionToToken; +}()); +exports.ConvertSessionToToken = ConvertSessionToToken; +// @Route("/access-token") +// @DataContract +var GetAccessToken = /** @class */ (function () { + function GetAccessToken(init) { + Object.assign(this, init); + } + GetAccessToken.prototype.createResponse = function () { return new GetAccessTokenResponse(); }; + GetAccessToken.prototype.getTypeName = function () { return 'GetAccessToken'; }; + return GetAccessToken; +}()); +exports.GetAccessToken = GetAccessToken; +// @Route("/register") +// @DataContract +var Register = /** @class */ (function () { + function Register(init) { + Object.assign(this, init); + } + Register.prototype.createResponse = function () { return new RegisterResponse(); }; + Register.prototype.getTypeName = function () { return 'Register'; }; + return Register; +}()); +exports.Register = Register; +//# sourceMappingURL=dtos.js.map \ No newline at end of file diff --git a/tests/CheckRazorCore/wwwroot/dtos.js.map b/tests/CheckRazorCore/wwwroot/dtos.js.map new file mode 100644 index 00000000000..cfbe8d7e70c --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/dtos.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dtos.js","sourceRoot":"","sources":["dtos.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;EAcE;;AAwCF,IAAY,KAMX;AAND,WAAY,KAAK;IAEb,oCAA2B,CAAA;IAC3B,kBAAS,CAAA;IACT,oBAAW,CAAA;IACX,sBAAa,CAAA;AACjB,CAAC,EANW,KAAK,GAAL,aAAK,KAAL,aAAK,QAMhB;AAED;IAEI,iBAAmB,IAAsB;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAQpF,cAAC;AAAD,CAAC,AAVD,IAUC;AAVY,0BAAO;AAYpB,gBAAgB;AAChB;IAEI,uBAAmB,IAA4B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAY1F,oBAAC;AAAD,CAAC,AAdD,IAcC;AAdY,sCAAa;AAgB1B,gBAAgB;AAChB;IAEI,wBAAmB,IAA6B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAe3F,qBAAC;AAAD,CAAC,AAjBD,IAiBC;AAjBY,wCAAc;AAmB3B,IAAY,UAMX;AAND,WAAY,UAAU;IAElB,+BAAiB,CAAA;IACjB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;IACjB,6BAAe,CAAA;AACnB,CAAC,EANW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAMrB;AAED;IAEI,uBAAmB,IAA4B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAE1F,oBAAC;AAAD,CAAC,AAJD,IAIC;AAJY,sCAAa;AAM1B,sBAAsB;AACtB;IAEI,kBAAmB,IAAuB;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAC1E,iCAAc,GAArB,cAA0B,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC3C,8BAAW,GAAlB,cAAuB,OAAO,UAAU,CAAC,CAAC,CAAC;IAC/C,eAAC;AAAD,CAAC,AALD,IAKC;AALY,4BAAQ;AAOrB,gBAAgB;AAChB;IAEI,yBAAmB,IAA8B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IA8K5F,sBAAC;AAAD,CAAC,AAhLD,IAgLC;AAhLY,0CAAe;AAkL5B;IAEI,6BAAmB,IAAkC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAGhG,0BAAC;AAAD,CAAC,AALD,IAKC;AALY,kDAAmB;AAOhC;IAEI,4BAAmB,IAAiC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAG/F,yBAAC;AAAD,CAAC,AALD,IAKC;AALY,gDAAkB;AAO/B;IAEI,+BAAmB,IAAoC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAGlG,4BAAC;AAAD,CAAC,AALD,IAKC;AALY,sDAAqB;AAOlC;IAEI,+BAAmB,IAAoC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAElG,4BAAC;AAAD,CAAC,AAJD,IAIC;AAJY,sDAAqB;AAMlC,gBAAgB;AAChB;IAEI,8BAAmB,IAAmC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IA2BjG,2BAAC;AAAD,CAAC,AA7BD,IA6BC;AA7BY,oDAAoB;AA+BjC,gBAAgB;AAChB;IAEI,6BAAmB,IAAkC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAShG,0BAAC;AAAD,CAAC,AAXD,IAWC;AAXY,kDAAmB;AAahC,gBAAgB;AAChB;IAEI,+BAAmB,IAAoC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IASlG,4BAAC;AAAD,CAAC,AAXD,IAWC;AAXY,sDAAqB;AAalC,gBAAgB;AAChB;IAEI,uCAAmB,IAA4C;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAS1G,oCAAC;AAAD,CAAC,AAXD,IAWC;AAXY,sEAA6B;AAa1C,gBAAgB;AAChB;IAEI,gCAAmB,IAAqC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAMnG,6BAAC;AAAD,CAAC,AARD,IAQC;AARY,wDAAsB;AAUnC,gBAAgB;AAChB;IAEI,0BAAmB,IAA+B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAwB7F,uBAAC;AAAD,CAAC,AA1BD,IA0BC;AA1BY,4CAAgB;AA4B7B,mBAAmB;AACnB,0BAA0B;AAC1B;IAEI,eAAmB,IAAoB;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAEvE,8BAAc,GAArB,cAA0B,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;IAChD,2BAAW,GAAlB,cAAuB,OAAO,OAAO,CAAC,CAAC,CAAC;IAC5C,YAAC;AAAD,CAAC,AAND,IAMC;AANY,sBAAK;AAQlB,qBAAqB;AACrB;IAEI,iBAAmB,IAAsB;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IACzE,gCAAc,GAArB,cAA0B,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC;IAClD,6BAAW,GAAlB,cAAuB,OAAO,SAAS,CAAC,CAAC,CAAC;IAC9C,cAAC;AAAD,CAAC,AALD,IAKC;AALY,0BAAO;AAOpB,6BAA6B;AAC7B;IAEI,qBAAmB,IAA0B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAC7E,oCAAc,GAArB,cAA0B,OAAO,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACtD,iCAAW,GAAlB,cAAuB,OAAO,aAAa,CAAC,CAAC,CAAC;IAClD,kBAAC;AAAD,CAAC,AALD,IAKC;AALY,kCAAW;AAOxB,kCAAkC;AAClC;IAEI,oBAAmB,IAAyB;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAE5E,mCAAc,GAArB,cAA0B,OAAO,IAAI,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACrD,gCAAW,GAAlB,cAAuB,OAAO,YAAY,CAAC,CAAC,CAAC;IACjD,iBAAC;AAAD,CAAC,AAND,IAMC;AANY,gCAAU;AAQvB,8BAA8B;AAC9B;IAEI,uBAAmB,IAA4B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAS/E,sCAAc,GAArB,cAA0B,OAAO,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAlB,cAAuB,OAAO,eAAe,CAAC,CAAC,CAAC;IACpD,oBAAC;AAAD,CAAC,AAbD,IAaC;AAbY,sCAAa;AAe1B,qCAAqC;AACrC,0CAA0C;AAC1C;IAEI,uBAAmB,IAA4B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAE/E,sCAAc,GAArB,cAAyB,CAAC;IACnB,mCAAW,GAAlB,cAAuB,OAAO,eAAe,CAAC,CAAC,CAAC;IACpD,oBAAC;AAAD,CAAC,AAND,IAMC;AANY,sCAAa;AAQ1B,uCAAuC;AACvC;IAEI,uBAAmB,IAA4B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAS/E,sCAAc,GAArB,cAA0B,OAAO,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAlB,cAAuB,OAAO,eAAe,CAAC,CAAC,CAAC;IACpD,oBAAC;AAAD,CAAC,AAbD,IAaC;AAbY,sCAAa;AAe1B,kBAAkB;AAClB,6BAA6B;AAC7B,0BAA0B;AAC1B,qCAAqC;AACrC,gBAAgB;AAChB;IAEI,sBAAmB,IAA2B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAyD9E,qCAAc,GAArB,cAA0B,OAAO,IAAI,oBAAoB,EAAE,CAAC,CAAC,CAAC;IACvD,kCAAW,GAAlB,cAAuB,OAAO,cAAc,CAAC,CAAC,CAAC;IACnD,mBAAC;AAAD,CAAC,AA7DD,IA6DC;AA7DY,oCAAY;AA+DzB,yBAAyB;AACzB,gBAAgB;AAChB;IAEI,qBAAmB,IAA0B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAS7E,oCAAc,GAArB,cAA0B,OAAO,IAAI,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACtD,iCAAW,GAAlB,cAAuB,OAAO,aAAa,CAAC,CAAC,CAAC;IAClD,kBAAC;AAAD,CAAC,AAbD,IAaC;AAbY,kCAAW;AAexB,2BAA2B;AAC3B,gBAAgB;AAChB;IAEI,uBAAmB,IAA4B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAS/E,sCAAc,GAArB,cAA0B,OAAO,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC;IACxD,mCAAW,GAAlB,cAAuB,OAAO,eAAe,CAAC,CAAC,CAAC;IACpD,oBAAC;AAAD,CAAC,AAbD,IAaC;AAbY,sCAAa;AAe1B,8BAA8B;AAC9B,gBAAgB;AAChB;IAEI,+BAAmB,IAAoC;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAGvF,8CAAc,GAArB,cAA0B,OAAO,IAAI,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAChE,2CAAW,GAAlB,cAAuB,OAAO,uBAAuB,CAAC,CAAC,CAAC;IAC5D,4BAAC;AAAD,CAAC,AAPD,IAOC;AAPY,sDAAqB;AASlC,0BAA0B;AAC1B,gBAAgB;AAChB;IAEI,wBAAmB,IAA6B;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IAGhF,uCAAc,GAArB,cAA0B,OAAO,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC;IACzD,oCAAW,GAAlB,cAAuB,OAAO,gBAAgB,CAAC,CAAC,CAAC;IACrD,qBAAC;AAAD,CAAC,AAPD,IAOC;AAPY,wCAAc;AAS3B,sBAAsB;AACtB,gBAAgB;AAChB;IAEI,kBAAmB,IAAuB;QAAU,MAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;IA8B1E,iCAAc,GAArB,cAA0B,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACnD,8BAAW,GAAlB,cAAuB,OAAO,UAAU,CAAC,CAAC,CAAC;IAC/C,eAAC;AAAD,CAAC,AAlCD,IAkCC;AAlCY,4BAAQ"} \ No newline at end of file diff --git a/tests/CheckRazorCore/wwwroot/dtos.ts b/tests/CheckRazorCore/wwwroot/dtos.ts new file mode 100644 index 00000000000..1e9e29a561c --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/dtos.ts @@ -0,0 +1,692 @@ +/* Options: +Date: 2019-02-14 23:07:52 +Version: 5.41 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:5000 + +//GlobalNamespace: +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ + + +export interface IReturn +{ + createResponse(): T; +} + +export interface IReturnVoid +{ + createResponse(): void; +} + +export interface IHasSessionId +{ + sessionId: string; +} + +export interface IHasBearerToken +{ + bearerToken: string; +} + +export interface IPost +{ +} + +export interface IAuthTokens +{ + provider: string; + userId: string; + accessToken: string; + accessTokenSecret: string; + refreshToken: string; + refreshTokenExpiry?: string; + requestToken: string; + requestTokenSecret: string; + items: { [index:string]: string; }; +} + +export enum Title +{ + Unspecified = 'Unspecified', + Mr = 'Mr', + Mrs = 'Mrs', + Miss = 'Miss', +} + +export class Contact +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public id: number; + public userAuthId: number; + public title: Title; + public name: string; + public color: string; + public filmGenres: FilmGenres[]; + public age: number; +} + +// @DataContract +export class ResponseError +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1, EmitDefaultValue=false) + public errorCode: string; + + // @DataMember(Order=2, EmitDefaultValue=false) + public fieldName: string; + + // @DataMember(Order=3, EmitDefaultValue=false) + public message: string; + + // @DataMember(Order=4, EmitDefaultValue=false) + public meta: { [index:string]: string; }; +} + +// @DataContract +export class ResponseStatus +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public message: string; + + // @DataMember(Order=3) + public stackTrace: string; + + // @DataMember(Order=4) + public errors: ResponseError[]; + + // @DataMember(Order=5) + public meta: { [index:string]: string; }; +} + +export enum FilmGenres +{ + Action = 'Action', + Adventure = 'Adventure', + Comedy = 'Comedy', + Drama = 'Drama', +} + +export class HelloResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public result: string; +} + +// @Route("/testauth") +export class TestAuth implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public createResponse() { return new TestAuth(); } + public getTypeName() { return 'TestAuth'; } +} + +// @DataContract +export class AuthUserSession +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public referrerUrl: string; + + // @DataMember(Order=2) + public id: string; + + // @DataMember(Order=3) + public userAuthId: string; + + // @DataMember(Order=4) + public userAuthName: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public twitterUserId: string; + + // @DataMember(Order=7) + public twitterScreenName: string; + + // @DataMember(Order=8) + public facebookUserId: string; + + // @DataMember(Order=9) + public facebookUserName: string; + + // @DataMember(Order=10) + public firstName: string; + + // @DataMember(Order=11) + public lastName: string; + + // @DataMember(Order=12) + public displayName: string; + + // @DataMember(Order=13) + public company: string; + + // @DataMember(Order=14) + public email: string; + + // @DataMember(Order=15) + public primaryEmail: string; + + // @DataMember(Order=16) + public phoneNumber: string; + + // @DataMember(Order=17) + public birthDate: string; + + // @DataMember(Order=18) + public birthDateRaw: string; + + // @DataMember(Order=19) + public address: string; + + // @DataMember(Order=20) + public address2: string; + + // @DataMember(Order=21) + public city: string; + + // @DataMember(Order=22) + public state: string; + + // @DataMember(Order=23) + public country: string; + + // @DataMember(Order=24) + public culture: string; + + // @DataMember(Order=25) + public fullName: string; + + // @DataMember(Order=26) + public gender: string; + + // @DataMember(Order=27) + public language: string; + + // @DataMember(Order=28) + public mailAddress: string; + + // @DataMember(Order=29) + public nickname: string; + + // @DataMember(Order=30) + public postalCode: string; + + // @DataMember(Order=31) + public timeZone: string; + + // @DataMember(Order=32) + public requestTokenSecret: string; + + // @DataMember(Order=33) + public createdAt: string; + + // @DataMember(Order=34) + public lastModified: string; + + // @DataMember(Order=35) + public roles: string[]; + + // @DataMember(Order=36) + public permissions: string[]; + + // @DataMember(Order=37) + public isAuthenticated: boolean; + + // @DataMember(Order=38) + public fromToken: boolean; + + // @DataMember(Order=39) + public profileUrl: string; + + // @DataMember(Order=40) + public sequence: string; + + // @DataMember(Order=41) + public tag: number; + + // @DataMember(Order=42) + public authProvider: string; + + // @DataMember(Order=43) + public providerOAuthAccess: IAuthTokens[]; + + // @DataMember(Order=44) + public meta: { [index:string]: string; }; + + // @DataMember(Order=45) + public audiences: string[]; + + // @DataMember(Order=46) + public scopes: string[]; + + // @DataMember(Order=47) + public dns: string; + + // @DataMember(Order=48) + public rsa: string; + + // @DataMember(Order=49) + public sid: string; + + // @DataMember(Order=50) + public hash: string; + + // @DataMember(Order=51) + public homePhone: string; + + // @DataMember(Order=52) + public mobilePhone: string; + + // @DataMember(Order=53) + public webpage: string; + + // @DataMember(Order=54) + public emailConfirmed: boolean; + + // @DataMember(Order=55) + public phoneNumberConfirmed: boolean; + + // @DataMember(Order=56) + public twoFactorEnabled: boolean; + + // @DataMember(Order=57) + public securityStamp: string; + + // @DataMember(Order=58) + public type: string; +} + +export class GetContactsResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public results: Contact[]; + public responseStatus: ResponseStatus; +} + +export class GetContactResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public result: Contact; + public responseStatus: ResponseStatus; +} + +export class CreateContactResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public result: Contact; + public responseStatus: ResponseStatus; +} + +export class UpdateContactResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public responseStatus: ResponseStatus; +} + +// @DataContract +export class AuthenticateResponse implements IHasSessionId, IHasBearerToken +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public referrerUrl: string; + + // @DataMember(Order=6) + public bearerToken: string; + + // @DataMember(Order=7) + public refreshToken: string; + + // @DataMember(Order=8) + public responseStatus: ResponseStatus; + + // @DataMember(Order=9) + public meta: { [index:string]: string; }; +} + +// @DataContract +export class AssignRolesResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class UnAssignRolesResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class ConvertSessionToTokenResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public meta: { [index:string]: string; }; + + // @DataMember(Order=2) + public accessToken: string; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class GetAccessTokenResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public accessToken: string; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; +} + +// @DataContract +export class RegisterResponse +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public referrerUrl: string; + + // @DataMember(Order=5) + public bearerToken: string; + + // @DataMember(Order=6) + public refreshToken: string; + + // @DataMember(Order=7) + public responseStatus: ResponseStatus; + + // @DataMember(Order=8) + public meta: { [index:string]: string; }; +} + +// @Route("/hello") +// @Route("/hello/{Name}") +export class Hello implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public name: string; + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'Hello'; } +} + +// @Route("/session") +export class Session implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public createResponse() { return new AuthUserSession(); } + public getTypeName() { return 'Session'; } +} + +// @Route("/contacts", "GET") +export class GetContacts implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public createResponse() { return new GetContactsResponse(); } + public getTypeName() { return 'GetContacts'; } +} + +// @Route("/contacts/{Id}", "GET") +export class GetContact implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public id: number; + public createResponse() { return new GetContactResponse(); } + public getTypeName() { return 'GetContact'; } +} + +// @Route("/contacts", "POST") +export class CreateContact implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public title: Title; + public name: string; + public color: string; + public filmGenres: FilmGenres[]; + public age: number; + public agree: boolean; + public continue: string; + public errorView: string; + public createResponse() { return new CreateContactResponse(); } + public getTypeName() { return 'CreateContact'; } +} + +// @Route("/contacts/{Id}", "DELETE") +// @Route("/contacts/{Id}/delete", "POST") +export class DeleteContact implements IReturnVoid +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public id: number; + public createResponse() {} + public getTypeName() { return 'DeleteContact'; } +} + +// @Route("/contacts/{Id}", "POST PUT") +export class UpdateContact implements IReturn +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + public id: number; + public title: Title; + public name: string; + public color: string; + public filmGenres: FilmGenres[]; + public age: number; + public continue: string; + public errorView: string; + public createResponse() { return new UpdateContactResponse(); } + public getTypeName() { return 'UpdateContact'; } +} + +// @Route("/auth") +// @Route("/auth/{provider}") +// @Route("/authenticate") +// @Route("/authenticate/{provider}") +// @DataContract +export class Authenticate implements IReturn, IPost +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public provider: string; + + // @DataMember(Order=2) + public state: string; + + // @DataMember(Order=3) + public oauth_token: string; + + // @DataMember(Order=4) + public oauth_verifier: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public rememberMe: boolean; + + // @DataMember(Order=8) + public continue: string; + + // @DataMember(Order=9) + public errorView: string; + + // @DataMember(Order=10) + public nonce: string; + + // @DataMember(Order=11) + public uri: string; + + // @DataMember(Order=12) + public response: string; + + // @DataMember(Order=13) + public qop: string; + + // @DataMember(Order=14) + public nc: string; + + // @DataMember(Order=15) + public cnonce: string; + + // @DataMember(Order=16) + public useTokenCookie: boolean; + + // @DataMember(Order=17) + public accessToken: string; + + // @DataMember(Order=18) + public accessTokenSecret: string; + + // @DataMember(Order=19) + public meta: { [index:string]: string; }; + public createResponse() { return new AuthenticateResponse(); } + public getTypeName() { return 'Authenticate'; } +} + +// @Route("/assignroles") +// @DataContract +export class AssignRoles implements IReturn, IPost +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + public createResponse() { return new AssignRolesResponse(); } + public getTypeName() { return 'AssignRoles'; } +} + +// @Route("/unassignroles") +// @DataContract +export class UnAssignRoles implements IReturn, IPost +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + public createResponse() { return new UnAssignRolesResponse(); } + public getTypeName() { return 'UnAssignRoles'; } +} + +// @Route("/session-to-token") +// @DataContract +export class ConvertSessionToToken implements IReturn, IPost +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public preserveSession: boolean; + public createResponse() { return new ConvertSessionToTokenResponse(); } + public getTypeName() { return 'ConvertSessionToToken'; } +} + +// @Route("/access-token") +// @DataContract +export class GetAccessToken implements IReturn, IPost +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public refreshToken: string; + public createResponse() { return new GetAccessTokenResponse(); } + public getTypeName() { return 'GetAccessToken'; } +} + +// @Route("/register") +// @DataContract +export class Register implements IReturn, IPost +{ + public constructor(init?:Partial) { (Object).assign(this, init); } + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public firstName: string; + + // @DataMember(Order=3) + public lastName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public email: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public confirmPassword: string; + + // @DataMember(Order=8) + public autoLogin: boolean; + + // @DataMember(Order=9) + public continue: string; + + // @DataMember(Order=10) + public errorView: string; + public createResponse() { return new RegisterResponse(); } + public getTypeName() { return 'Register'; } +} + diff --git a/tests/CheckRazorCore/wwwroot/forbidden.cshtml b/tests/CheckRazorCore/wwwroot/forbidden.cshtml new file mode 100644 index 00000000000..529b34e7289 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/forbidden.cshtml @@ -0,0 +1,6 @@ +

You are not authorized to access this page

+ +@if (!string.IsNullOrEmpty(Request.QueryString["role"])) +{ +

Missing role Request.QueryString["role"]

+} diff --git a/tests/CheckRazorCore/wwwroot/login2.cshtml b/tests/CheckRazorCore/wwwroot/login2.cshtml new file mode 100644 index 00000000000..4d39476fdb9 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/login2.cshtml @@ -0,0 +1,63 @@ +@{ +} + +

Sign In using credentials

+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@@email.com + new@@user.com +
+
+ +@section scripts { + + + +} diff --git a/tests/CheckRazorCore/wwwroot/profile.cshtml b/tests/CheckRazorCore/wwwroot/profile.cshtml new file mode 100644 index 00000000000..caba0202ce2 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/profile.cshtml @@ -0,0 +1,8 @@ + +@{ RedirectIfNotAuthenticated(); } + +

Profile Page

+ +

+ /auth/logout?continue=/login +

diff --git a/tests/CheckRazorCore/wwwroot/signup.cshtml b/tests/CheckRazorCore/wwwroot/signup.cshtml new file mode 100644 index 00000000000..f88b44dee88 --- /dev/null +++ b/tests/CheckRazorCore/wwwroot/signup.cshtml @@ -0,0 +1,51 @@ +

Register New User

+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ Quick Populate: +
+ new@@user.com +
+
+
+ +@section scripts +{ + +} diff --git a/tests/CheckTemplatesCore/CheckTemplatesCore.csproj b/tests/CheckTemplatesCore/CheckTemplatesCore.csproj new file mode 100644 index 00000000000..966da840052 --- /dev/null +++ b/tests/CheckTemplatesCore/CheckTemplatesCore.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + + diff --git a/tests/CheckTemplatesCore/Program.cs b/tests/CheckTemplatesCore/Program.cs new file mode 100644 index 00000000000..9e195243284 --- /dev/null +++ b/tests/CheckTemplatesCore/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace CheckTemplatesCore +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} \ No newline at end of file diff --git a/tests/CheckTemplatesCore/Properties/launchSettings.json b/tests/CheckTemplatesCore/Properties/launchSettings.json new file mode 100644 index 00000000000..4d38a4d5e30 --- /dev/null +++ b/tests/CheckTemplatesCore/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:33868", + "sslPort": 44350 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "CheckTemplatesCore": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/tests/CheckTemplatesCore/Startup.cs b/tests/CheckTemplatesCore/Startup.cs new file mode 100644 index 00000000000..096d24b069e --- /dev/null +++ b/tests/CheckTemplatesCore/Startup.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using ServiceStack; +using ServiceStack.Validation; + +namespace CheckTemplatesCore +{ + public class Startup + { + public IConfiguration Configuration { get; } + public Startup(IConfiguration configuration) => Configuration = configuration; + + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseServiceStack(new AppHost + { + AppSettings = new NetCoreAppSettings(Configuration) + }); + } + } + + public class AppHost : AppHostBase + { + public AppHost() : base("MyApp", typeof(MyServices).Assembly) { } + + // Configure your AppHost with the necessary configuration and dependencies your App needs + public override void Configure(Container container) + { + base.SetConfig(new HostConfig + { + DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), true) + }); + + Plugins.Add(new ValidationFeature()); + Plugins.Add(new SharpPagesFeature()); + + this.CustomErrorHttpHandlers[HttpStatusCode.NotFound] = + new SharpPageHandler("/notfound"); + + this.GlobalHtmlErrorHttpHandler = new SharpPageHandler("/error"); + } + } + + [Route("/hello")] + [Route("/hello/{Name}")] + public class Hello + { + public string Name { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throw404")] + [Route("/throw404/{Message}")] + public class Throw404 + { + public string Message { get; set; } + } + + [Route("/throw")] + [Route("/throw/{Message}")] + public class Throw + { + public string Message { get; set; } + } + + public class MyServices : Service + { + public object Any(Hello request) => new HelloResponse { + Result = $"Hi, {request.Name}!" + }; + + public object Any(Throw404 request) => throw HttpError.NotFound(request.Message ?? "Not Found"); + + public object Any(Throw request) => throw new Exception(request.Message ?? "Exception in 'Throw' Service"); + + public object Any(ViewIndex request) + { + return Request.GetPageResult("/index"); + //equivalent to: return new PageResult(Request.GetPage("/index")).BindRequest(Request); + } + + public object Any(ValidationTest request) => request; + } + + [Route("/validation/test")] + public class ValidationTest : IReturn + { + [ValidateNotNull] + public string Name { get; set; } + } + + [FallbackRoute("/{PathInfo*}", Matches="AcceptsHtml")] + public class ViewIndex + { + public string PathInfo { get; set; } + } +} \ No newline at end of file diff --git a/tests/CheckTemplatesCore/wwwroot/_layout.html b/tests/CheckTemplatesCore/wwwroot/_layout.html new file mode 100644 index 00000000000..ffe5e47f353 --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/_layout.html @@ -0,0 +1,53 @@ + + + + {{ title }} + + + + + + + + + + + + + + + + +
+
+
+

{{ title }}

+ {{ page }} +
+
+
+ +

+ Learn about #Script +

+ + + + + + {{ scripts | raw }} + + + \ No newline at end of file diff --git a/tests/CheckTemplatesCore/wwwroot/about.html b/tests/CheckTemplatesCore/wwwroot/about.html new file mode 100644 index 00000000000..1060d0938fb --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/about.html @@ -0,0 +1,7 @@ + + +

+ About Us page. +

\ No newline at end of file diff --git a/tests/CheckTemplatesCore/wwwroot/assets/css/bootstrap.css b/tests/CheckTemplatesCore/wwwroot/assets/css/bootstrap.css new file mode 100644 index 00000000000..882691283ab --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/assets/css/bootstrap.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.1.3 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(2.25rem + 2px);padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.8125rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(2.875rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::after,.was-validated .custom-file-input:valid~.custom-file-label::after{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::after,.was-validated .custom-file-input:invalid~.custom-file-label::after{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{height:calc(2.875rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{height:calc(1.8125rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-label::after{border-color:#80bdff}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:2.25rem;padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:not(:disabled):not(.disabled){cursor:pointer}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-dialog-centered::before{display:block;height:calc(100vh - (.5rem * 2));content:""}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-dialog-centered::before{height:calc(100vh - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease}@media screen and (prefers-reduced-motion:reduce){.carousel-item-next,.carousel-item-prev,.carousel-item.active{transition:none}}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/tests/CheckTemplatesCore/wwwroot/assets/css/default.css b/tests/CheckTemplatesCore/wwwroot/assets/css/default.css new file mode 100644 index 00000000000..26bc2fcd255 --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/assets/css/default.css @@ -0,0 +1,8 @@ +body { + padding-top: 54px; +} +@media (min-width: 992px) { + body { + padding-top: 56px; + } +} diff --git a/tests/CheckTemplatesCore/wwwroot/assets/img/favicon.ico b/tests/CheckTemplatesCore/wwwroot/assets/img/favicon.ico new file mode 100644 index 00000000000..5bd24b95537 Binary files /dev/null and b/tests/CheckTemplatesCore/wwwroot/assets/img/favicon.ico differ diff --git a/tests/CheckTemplatesCore/wwwroot/assets/img/logo.png b/tests/CheckTemplatesCore/wwwroot/assets/img/logo.png new file mode 100644 index 00000000000..6dbd73bc0eb Binary files /dev/null and b/tests/CheckTemplatesCore/wwwroot/assets/img/logo.png differ diff --git a/tests/CheckTemplatesCore/wwwroot/assets/js/bootstrap.min.js b/tests/CheckTemplatesCore/wwwroot/assets/js/bootstrap.min.js new file mode 100644 index 00000000000..00c895f0f3f --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/assets/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.1.3 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e(t.bootstrap={},t.jQuery,t.Popper)}(this,function(t,e,h){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)P(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right
',trigger:"hover focus",title:"",delay:0,html:!(Ie={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"}),selector:!(Se={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)"}),placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},we="out",Ne={HIDE:"hide"+Ee,HIDDEN:"hidden"+Ee,SHOW:(De="show")+Ee,SHOWN:"shown"+Ee,INSERTED:"inserted"+Ee,CLICK:"click"+Ee,FOCUSIN:"focusin"+Ee,FOCUSOUT:"focusout"+Ee,MOUSEENTER:"mouseenter"+Ee,MOUSELEAVE:"mouseleave"+Ee},Oe="fade",ke="show",Pe=".tooltip-inner",je=".arrow",He="hover",Le="focus",Re="click",xe="manual",We=function(){function i(t,e){if("undefined"==typeof h)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=pe(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),pe(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(pe(this.getTipElement()).hasClass(ke))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),pe.removeData(this.element,this.constructor.DATA_KEY),pe(this.element).off(this.constructor.EVENT_KEY),pe(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&pe(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===pe(this.element).css("display"))throw new Error("Please use show on visible elements");var t=pe.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){pe(this.element).trigger(t);var n=pe.contains(this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!n)return;var i=this.getTipElement(),r=Fn.getUID(this.constructor.NAME);i.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&pe(i).addClass(Oe);var o="function"==typeof this.config.placement?this.config.placement.call(this,i,this.element):this.config.placement,s=this._getAttachment(o);this.addAttachmentClass(s);var a=!1===this.config.container?document.body:pe(document).find(this.config.container);pe(i).data(this.constructor.DATA_KEY,this),pe.contains(this.element.ownerDocument.documentElement,this.tip)||pe(i).appendTo(a),pe(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new h(this.element,i,{placement:s,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:je},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),pe(i).addClass(ke),"ontouchstart"in document.documentElement&&pe(document.body).children().on("mouseover",null,pe.noop);var l=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,pe(e.element).trigger(e.constructor.Event.SHOWN),t===we&&e._leave(null,e)};if(pe(this.tip).hasClass(Oe)){var c=Fn.getTransitionDurationFromElement(this.tip);pe(this.tip).one(Fn.TRANSITION_END,l).emulateTransitionEnd(c)}else l()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=pe.Event(this.constructor.Event.HIDE),r=function(){e._hoverState!==De&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),pe(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(pe(this.element).trigger(i),!i.isDefaultPrevented()){if(pe(n).removeClass(ke),"ontouchstart"in document.documentElement&&pe(document.body).children().off("mouseover",null,pe.noop),this._activeTrigger[Re]=!1,this._activeTrigger[Le]=!1,this._activeTrigger[He]=!1,pe(this.tip).hasClass(Oe)){var o=Fn.getTransitionDurationFromElement(n);pe(n).one(Fn.TRANSITION_END,r).emulateTransitionEnd(o)}else r();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){pe(this.getTipElement()).addClass(Te+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||pe(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(pe(t.querySelectorAll(Pe)),this.getTitle()),pe(t).removeClass(Oe+" "+ke)},t.setElementContent=function(t,e){var n=this.config.html;"object"==typeof e&&(e.nodeType||e.jquery)?n?pe(e).parent().is(t)||t.empty().append(e):t.text(pe(e).text()):t[n?"html":"text"](e)},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getAttachment=function(t){return Ie[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)pe(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==xe){var e=t===He?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===He?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;pe(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}pe(i.element).closest(".modal").on("hide.bs.modal",function(){return i.hide()})}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||pe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),pe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Le:He]=!0),pe(e.getTipElement()).hasClass(ke)||e._hoverState===De?e._hoverState=De:(clearTimeout(e._timeout),e._hoverState=De,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===De&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||pe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),pe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Le:He]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=we,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===we&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){return"number"==typeof(t=l({},this.constructor.Default,pe(this.element).data(),"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),Fn.typeCheckConfig(ve,t,this.constructor.DefaultType),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=pe(this.getTipElement()),e=t.attr("class").match(be);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(pe(t).removeClass(Oe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=pe(this).data(ye),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),pe(this).data(ye,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.1.3"}},{key:"Default",get:function(){return Ae}},{key:"NAME",get:function(){return ve}},{key:"DATA_KEY",get:function(){return ye}},{key:"Event",get:function(){return Ne}},{key:"EVENT_KEY",get:function(){return Ee}},{key:"DefaultType",get:function(){return Se}}]),i}(),pe.fn[ve]=We._jQueryInterface,pe.fn[ve].Constructor=We,pe.fn[ve].noConflict=function(){return pe.fn[ve]=Ce,We._jQueryInterface},We),Jn=(qe="popover",Ke="."+(Fe="bs.popover"),Me=(Ue=e).fn[qe],Qe="bs-popover",Be=new RegExp("(^|\\s)"+Qe+"\\S+","g"),Ve=l({},zn.Default,{placement:"right",trigger:"click",content:"",template:''}),Ye=l({},zn.DefaultType,{content:"(string|element|function)"}),ze="fade",Ze=".popover-header",Ge=".popover-body",$e={HIDE:"hide"+Ke,HIDDEN:"hidden"+Ke,SHOW:(Je="show")+Ke,SHOWN:"shown"+Ke,INSERTED:"inserted"+Ke,CLICK:"click"+Ke,FOCUSIN:"focusin"+Ke,FOCUSOUT:"focusout"+Ke,MOUSEENTER:"mouseenter"+Ke,MOUSELEAVE:"mouseleave"+Ke},Xe=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){Ue(this.getTipElement()).addClass(Qe+"-"+t)},r.getTipElement=function(){return this.tip=this.tip||Ue(this.config.template)[0],this.tip},r.setContent=function(){var t=Ue(this.getTipElement());this.setElementContent(t.find(Ze),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(Ge),e),t.removeClass(ze+" "+Je)},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=Ue(this.getTipElement()),e=t.attr("class").match(Be);null!==e&&0=this._offsets[r]&&("undefined"==typeof this._offsets[r+1]||t=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),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("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" +{{/raw}} \ No newline at end of file diff --git a/tests/CheckTemplatesCore/wwwroot/menu.html b/tests/CheckTemplatesCore/wwwroot/menu.html new file mode 100644 index 00000000000..a7788d07211 --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/menu.html @@ -0,0 +1,15 @@ +{{ { '/': 'Home', + '/about': 'About', + '/services': 'Services', + '/contact': 'Contact', + } | toList | assignTo: links }} + + diff --git a/tests/CheckTemplatesCore/wwwroot/notfound.html b/tests/CheckTemplatesCore/wwwroot/notfound.html new file mode 100644 index 00000000000..184815a603a --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/notfound.html @@ -0,0 +1,19 @@ + + +

+ Resource does not exist. +

+ +

Error Vars

+ +{{#raw}}

{{errorStatus | htmldump}}

{{/raw}} + +{{errorStatus | htmldump}} + +{{#raw}}

{{error | htmlErrorMessage}}

{{/raw}} +{{error | htmlErrorMessage}} + +{{#raw}}

{{error | htmlError}}

{{/raw}} +{{error | htmlError}} diff --git a/tests/CheckTemplatesCore/wwwroot/services.html b/tests/CheckTemplatesCore/wwwroot/services.html new file mode 100644 index 00000000000..6813961ef76 --- /dev/null +++ b/tests/CheckTemplatesCore/wwwroot/services.html @@ -0,0 +1,7 @@ + + +

+ Services page. +

\ No newline at end of file diff --git a/tests/CheckWeb/.well-known/acme-challenge/XzF9VXFuw4UMBVdiX2jDj2vykjrvEsQR8AZ8kJiaBdk b/tests/CheckWeb/.well-known/acme-challenge/XzF9VXFuw4UMBVdiX2jDj2vykjrvEsQR8AZ8kJiaBdk new file mode 100644 index 00000000000..2c3f576c481 --- /dev/null +++ b/tests/CheckWeb/.well-known/acme-challenge/XzF9VXFuw4UMBVdiX2jDj2vykjrvEsQR8AZ8kJiaBdk @@ -0,0 +1 @@ +XzF9VXFuw4UMBVdiX2jDj2vykjrvEsQR8AZ8kJiaBdk.gGc1b09BEhvS3F73Kd4CKe_cAEErTgszBKsdgHvkODc \ No newline at end of file diff --git a/tests/CheckWeb/AutoQueryCrudModels.cs b/tests/CheckWeb/AutoQueryCrudModels.cs new file mode 100644 index 00000000000..68f413078d9 --- /dev/null +++ b/tests/CheckWeb/AutoQueryCrudModels.cs @@ -0,0 +1,470 @@ +using System; +using System.Threading.Tasks; +using Check.ServiceModel; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace CheckWeb +{ + public abstract class RockstarBase + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + [Alias(nameof(Rockstar))] + public class RockstarAuto : RockstarBase + { + [AutoIncrement] + public int Id { get; set; } + } + + public class RockstarAutoGuid : RockstarBase + { + [AutoId] + public Guid Id { get; set; } + } + + public class RockstarAudit : RockstarBase + { + [AutoIncrement] + public int Id { get; set; } + public DateTime CreatedDate { get; set; } + public string CreatedBy { get; set; } + public string CreatedInfo { get; set; } + public DateTime ModifiedDate { get; set; } + public string ModifiedBy { get; set; } + public string ModifiedInfo { get; set; } + } + + public interface IAudit + { + DateTime CreatedDate { get; set; } + string CreatedBy { get; set; } + string CreatedInfo { get; set; } + DateTime ModifiedDate { get; set; } + string ModifiedBy { get; set; } + string ModifiedInfo { get; set; } + DateTime? SoftDeletedDate { get; set; } + string SoftDeletedBy { get; set; } + string SoftDeletedInfo { get; set; } + } + + public interface IAuditTenant : IAudit + { + int TenantId { get; set; } + } + + public abstract class AuditBase : IAudit + { + public DateTime CreatedDate { get; set; } + [Required] + public string CreatedBy { get; set; } + [Required] + public string CreatedInfo { get; set; } + + public DateTime ModifiedDate { get; set; } + [Required] + public string ModifiedBy { get; set; } + [Required] + public string ModifiedInfo { get; set; } + + [Index] //Check if Deleted + public DateTime? SoftDeletedDate { get; set; } + public string SoftDeletedBy { get; set; } + public string SoftDeletedInfo { get; set; } + } + + public class RockstarAuditTenant : AuditBase + { + [Index] + public int TenantId { get; set; } + [AutoIncrement] + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class RockstarVersion : RockstarBase + { + [AutoIncrement] + public int Id { get; set; } + public ulong RowVersion { get; set; } + } + + public class CreateRockstar : RockstarBase, ICreateDb, IReturn + { + } + + public class CreateRockstarResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateRockstarWithReturn : RockstarBase, ICreateDb, IReturn + { + } + public class CreateRockstarWithVoidReturn : RockstarBase, ICreateDb, IReturnVoid + { + } + + public class CreateRockstarWithAutoGuid : RockstarBase, ICreateDb, IReturn + { + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public class CreateRockstarAudit : RockstarBase, ICreateDb, IReturn + { + } + + [Authenticate] + [AutoPopulate(nameof(IAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class CreateAuditBase : ICreateDb, IReturn {} + + [AutoPopulate(nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class CreateAuditTenantBase : CreateAuditBase {} + + [Authenticate] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class UpdateAuditBase : IUpdateDb
, IReturn {} + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class UpdateAuditTenantBase : UpdateAuditBase {} + + [Authenticate] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class PatchAuditBase : IPatchDb
, IReturn {} + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class PatchAuditTenantBase : PatchAuditBase {} + + [Authenticate] + [AutoPopulate(nameof(IAudit.SoftDeletedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.SoftDeletedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.SoftDeletedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class SoftDeleteAuditBase : IUpdateDb
, IReturn {} + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class SoftDeleteAuditTenantBase : SoftDeleteAuditBase {} + + [Authenticate] + [AutoFilter(QueryTerm.Ensure, nameof(IAudit.SoftDeletedDate), Template = SqlTemplate.IsNull)] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class QueryDbTenant : QueryDb {} + + public class CreateRockstarAuditTenant : CreateAuditTenantBase, IHasSessionId + { + public string SessionId { get; set; } //Authenticate MQ Requests + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class UpdateRockstarAuditTenant : UpdateAuditTenantBase, IHasSessionId + { + public string SessionId { get; set; } //Authenticate MQ Requests + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class PatchRockstarAuditTenant : PatchAuditTenantBase, IHasSessionId + { + public string SessionId { get; set; } //Authenticate MQ Requests + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class CreateRockstarAuditTenantGateway : IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class UpdateRockstarAuditTenantGateway : IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class PatchRockstarAuditTenantGateway : IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class RealDeleteAuditTenantGateway : IReturn + { + public int Id { get; set; } + } + + public class SoftDeleteAuditTenant : SoftDeleteAuditTenantBase + { + public int Id { get; set; } + } + + [Authenticate] + public class CreateRockstarAuditTenantMq : IReturnVoid + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + [Authenticate] + public class UpdateRockstarAuditTenantMq : IReturnVoid + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class PatchRockstarAuditTenantMq : IReturnVoid + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class RealDeleteAuditTenantMq : IReturnVoid + { + public int Id { get; set; } + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public class CreateRockstarAuditMqToken : RockstarBase, ICreateDb, IReturn, IHasBearerToken + { + public string BearerToken { get; set; } + } + + + [Authenticate] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public class RealDeleteAuditTenant : IDeleteDb, IReturn, IHasSessionId + { + public string SessionId { get; set; } //Authenticate MQ Requests + public int Id { get; set; } + public int? Age { get; set; } + } + + public class QueryRockstarAudit : QueryDbTenant + { + public int? Id { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [AutoFilter(QueryTerm.Ensure, nameof(AuditBase.SoftDeletedDate), SqlTemplate.IsNull)] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public class QueryRockstarAuditSubOr : QueryDb + { + public string FirstNameStartsWith { get; set; } + public int? AgeOlderThan { get; set; } + } + + public class CreateRockstarVersion : RockstarBase, ICreateDb, IReturn + { + } + + public class RockstarWithIdResponse + { + public int Id { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + public class RockstarWithIdAndCountResponse + { + public int Id { get; set; } + public int Count { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class RockstarWithIdAndRowVersionResponse + { + public int Id { get; set; } + public uint RowVersion { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class RockstarWithIdAndResultResponse + { + public int Id { get; set; } + public RockstarAuto Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateRockstarWithReturnGuidResponse + { + public Guid Id { get; set; } + public RockstarAutoGuid Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateRockstarAdhocNonDefaults : ICreateDb, IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + [AutoDefault(Value = 21)] + public int? Age { get; set; } + [AutoDefault(Expression = "date(2001,1,1)")] + public DateTime DateOfBirth { get; set; } + [AutoDefault(Eval = "utcNow")] + public DateTime? DateDied { get; set; } + [AutoDefault(Value = global::Check.ServiceModel.LivingStatus.Dead)] + public LivingStatus? LivingStatus { get; set; } + } + + public class CreateRockstarAutoMap : ICreateDb, IReturn + { + [AutoMap(nameof(RockstarAuto.FirstName))] + public string MapFirstName { get; set; } + + [AutoMap(nameof(RockstarAuto.LastName))] + public string MapLastName { get; set; } + + [AutoMap(nameof(RockstarAuto.Age))] + [AutoDefault(Value = 21)] + public int? MapAge { get; set; } + + [AutoMap(nameof(RockstarAuto.DateOfBirth))] + [AutoDefault(Expression = "date(2001,1,1)")] + public DateTime MapDateOfBirth { get; set; } + + [AutoMap(nameof(RockstarAuto.DateDied))] + [AutoDefault(Eval = "utcNow")] + public DateTime? MapDateDied { get; set; } + + [AutoMap(nameof(RockstarAuto.LivingStatus))] + [AutoDefault(Value = LivingStatus.Dead)] + public LivingStatus? MapLivingStatus { get; set; } + } + + public class UpdateRockstar : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public class UpdateRockstarAudit : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + [Authenticate] + public class DeleteRockstarAudit : IDeleteDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateRockstarVersion : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + public ulong RowVersion { get; set; } + } + + public class PatchRockstar : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateRockstarAdhocNonDefaults : IUpdateDb, IReturn + { + public int Id { get; set; } + [AutoUpdate(AutoUpdateStyle.NonDefaults)] + public string FirstName { get; set; } + public string LastName { get; set; } + [AutoDefault(Value = 21)] + public int? Age { get; set; } + [AutoDefault(Expression = "date(2001,1,1)")] + public DateTime DateOfBirth { get; set; } + [AutoDefault(Eval = "utcNow")] + public DateTime? DateDied { get; set; } + [AutoUpdate(AutoUpdateStyle.NonDefaults), AutoDefault(Value = LivingStatus.Dead)] + public LivingStatus LivingStatus { get; set; } + } + + public class DeleteRockstar : IDeleteDb, IReturn + { + public int Id { get; set; } + } + + public class DeleteRockstarFilters : IDeleteDb, IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + } + + public class DeleteRockstarCountResponse + { + public int Count { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateNamedRockstar : RockstarBase, ICreateDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateNamedRockstar : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + } + + //[ConnectionInfo] on AutoCrudConnectionInfoServices + public class CreateConnectionInfoRockstar : RockstarBase, ICreateDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateConnectionInfoRockstar : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + } + + } \ No newline at end of file diff --git a/tests/CheckWeb/AutoQueryCrudTests.ValidateModels.cs b/tests/CheckWeb/AutoQueryCrudTests.ValidateModels.cs new file mode 100644 index 00000000000..ca80f931a09 --- /dev/null +++ b/tests/CheckWeb/AutoQueryCrudTests.ValidateModels.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using Check.ServiceModel; +using ServiceStack; +using ServiceStack.FluentValidation; +using ServiceStack.Model; + +namespace CheckWeb +{ + public static class ValidationConditions + { + public const string IsOdd = "it.isOdd()"; + public const string IsOver2Digits = "it.log10() > 2"; + } + + public class ValidateCreateRockstar + : ICreateDb, IReturn + { + [Validate(nameof(ValidateScripts.NotNull))] + // [Validate("NotNull")] + public string FirstName { get; set; } + + //Added by Fluent Validator + public string LastName { get; set; } + + // [Validate("[" + nameof(ValidateScripts.NotNull) + "," + nameof(ValidateScripts.Length) + "(13,100)]")] e.g. Typed + // [Validate("[NotNull,Length(13,100)]")] + [Validate("NotNull")] + [Validate("InclusiveBetween(13,100)")] + public int? Age { get; set; } + + [Validate("NotEmpty(default('DateTime'))")] + //[Validate("NotEmpty")] equivalent to above thanks to: Validators.AppendDefaultValueOnEmptyValidators + public DateTime DateOfBirth { get; set; } + + public DateTime? DateDied { get; set; } + + public LivingStatus LivingStatus { get; set; } + } + + public class ValidateCreateRockstarValidator : AbstractValidator + { + public ValidateCreateRockstarValidator() + { + RuleFor(x => x.LastName).NotNull(); + } + } + + [AutoPopulate(nameof(LivingStatus), Value = LivingStatus.Alive)] + public class NoAbstractValidator + : ICreateDb, IReturn + { + [Validate("NotNull")] + public string FirstName { get; set; } + + [Validate("NotNull")] + public string LastName { get; set; } + + [Validate("[NotNull,InclusiveBetween(13,100)]")] + public int? Age { get; set; } + + [Validate("NotEmpty")] + public DateTime DateOfBirth { get; set; } + + public LivingStatus LivingStatus { get; set; } + } + + public class EmptyValidators + : ICreateDb, IReturn + { + // [Validate("NotEmpty(0)")] + [Validate("NotEmpty")] + public int Int { get; set; } + [Validate("NotEmpty")] + public int? NInt { get; set; } + [Validate("NotEmpty")] + // [Validate("NotEmpty(default('System.TimeSpan'))")] + public TimeSpan TimeSpan { get; set; } + [Validate("NotEmpty")] + public TimeSpan? NTimeSpan { get; set; } + [Validate("NotEmpty")] + public string String { get; set; } + [Validate("NotEmpty")] + public int[] IntArray { get; set; } + [Validate("NotEmpty")] + public List StringList { get; set; } + } + + public class TriggerAllValidators + : ICreateDb, IReturn + { + [Validate("CreditCard")] + public string CreditCard { get; set; } + [Validate("Email")] + public string Email { get; set; } + [Validate("Empty")] + public string Empty { get; set; } + [Validate("Equal('Equal')")] + public string Equal { get; set; } + [Validate("ExclusiveBetween(10, 20)")] + public int ExclusiveBetween { get; set; } + [Validate("GreaterThanOrEqual(10)")] + public int GreaterThanOrEqual { get; set; } + [Validate("GreaterThan(10)")] + public int GreaterThan { get; set; } + [Validate("InclusiveBetween(10, 20)")] + public int InclusiveBetween { get; set; } + [Validate("ExactLength(10)")] + public string Length { get; set; } + [Validate("LessThanOrEqual(10)")] + public int LessThanOrEqual { get; set; } + [Validate("LessThan(10)")] + public int LessThan { get; set; } + [Validate("NotEmpty")] + public string NotEmpty { get; set; } + [Validate("NotEqual('NotEqual')")] + public string NotEqual { get; set; } + [Validate("Null")] + public string Null { get; set; } + [Validate("RegularExpression('^[a-z]*$')")] + public string RegularExpression { get; set; } + [Validate("ScalePrecision(1,1)")] + public decimal ScalePrecision { get; set; } + } + + public class DynamicValidationRules + : ICreateDb, IReturn + { + [Validate("NotNull")] + public string FirstName { get; set; } + + //[Validate("NotNull")] added in IValidationSource + public string LastName { get; set; } + + // [Validate("[NotNull,InclusiveBetween(13,100)]")] + [Validate("NotNull")] + //[Validate("InclusiveBetween(13,100)")] added in IValidationSource + public int? Age { get; set; } + + [Validate("NotEmpty")] + public DateTime DateOfBirth { get; set; } + + public LivingStatus LivingStatus { get; set; } + } + + public class CustomValidationErrors + : ICreateDb, IReturn + { + // Just overrides ErrorCode + [Validate("NotNull", ErrorCode = "ZERROR")] + public string CustomErrorCode { get; set; } + + // Overrides both ErrorCode & Message + [Validate("InclusiveBetween(1,2)", ErrorCode = "ZERROR", + Message = "{PropertyName} has to be between {From} and {To}, you: {PropertyValue}")] + public int CustomErrorCodeAndMessage { get; set; } + + // Overrides ErrorCode & uses Message from Validators + [Validate("NotNull", ErrorCode = "RuleMessage")] + public string ErrorCodeRule { get; set; } + + // Overrides ErrorCode & uses Message from Validators + [Validate(Condition = ValidationConditions.IsOdd)] + public int IsOddCondition { get; set; } + + // Combined typed conditions + Error code + [Validate(AllConditions = new[]{ ValidationConditions.IsOdd, ValidationConditions.IsOver2Digits }, ErrorCode = "RuleMessage")] + public int IsOddAndOverTwoDigitsCondition { get; set; } + + // Combined typed conditions + unknown error code + [Validate(AnyConditions = new[]{ ValidationConditions.IsOdd, ValidationConditions.IsOver2Digits })] + public int IsOddOrOverTwoDigitsCondition { get; set; } + } + + [ValidateRequest("HasRole('Manager')")] + public class TestAuthValidators + : ICreateDb, IReturn + { + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest("[IsAuthenticated,HasRole('Manager')]")] + public class TestMultiAuthValidators + : ICreateDb, IReturn + { + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest("IsAdmin")] + public class TestIsAdmin + : ICreateDb, IReturn + { + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest(Condition = "!dbExistsSync('SELECT * FROM RockstarAlbum WHERE RockstarId = @Id', { dto.Id })", + ErrorCode = "HasForeignKeyReferences")] + public class TestDbCondition + : ICreateDb, IReturn + { + public int Id { get; set; } + + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + // [ValidateRequest("NoRockstarAlbumReferences")] + public class TestDbValidator + : ICreateDb, IReturn, IHasId + { + public int Id { get; set; } + + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + // [ValidateRequest(Conditions = new[]{ "it.Test.isOdd()", "it.Test.log10() > 2" }, ErrorCode = "RuleMessage")] + [ValidateRequest(Condition = "it.Test.log10() > 3", ErrorCode = "AssertFailed2", Message = "2nd Assert Failed", StatusCode = 401)] + public class OnlyValidatesRequest + : ICreateDb, IReturn + { + // Combined typed conditions + Error code + public int Test { get; set; } + + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + + public class DaoBase + { + public virtual Guid Id { get; set; } + public virtual DateTimeOffset CreateDate { get; set; } + public virtual string CreatedBy { get; set; } + public virtual DateTimeOffset ModifiedDate { get; set; } + public virtual string ModifiedBy { get; set; } + } + + public class Bookmark : DaoBase + { + public string Slug { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Url { get; set; } + } + + public class QueryBookmarks : QueryDb { } + + // custom script methods + [AutoPopulate(nameof(Bookmark.Id), Eval = "F('Guid.NewGuid')()")] + [AutoPopulate(nameof(Bookmark.CreatedBy), Eval = "userAuthId")] + [AutoPopulate(nameof(Bookmark.CreateDate), Eval = "utcNowOffset")] + [AutoPopulate(nameof(Bookmark.ModifiedBy), Eval = "userAuthId")] + [AutoPopulate(nameof(Bookmark.ModifiedDate), Eval = "utcNowOffset")] + public class CreateBookmark : ICreateDb, IReturn + { + public string Slug { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Url { get; set; } + } + + public class CreateBookmarkResponse + { + public Guid Id { get; set; } + public Bookmark Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } +} \ No newline at end of file diff --git a/tests/CheckWeb/CheckWeb.csproj b/tests/CheckWeb/CheckWeb.csproj new file mode 100644 index 00000000000..a6ad070cc67 --- /dev/null +++ b/tests/CheckWeb/CheckWeb.csproj @@ -0,0 +1,236 @@ + + + + + Debug + AnyCPU + + + 2.0 + {45DAECA2-659E-40D7-AA70-8EB4A56B2331} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + CheckWeb + CheckWeb + v4.7.2 + true + + + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + + + + + + + PreserveNewest + + + Designer + + + + + + + HttpBenchmarks.tt + True + True + + + Global.asax + + + + + + + + + + TextTemplatingFileGenerator + HttpBenchmarks.cs + + + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + Web.config + + + Web.config + + + + + {9982317F-831C-478B-9CC3-57F888BCD97A} + Check.ServiceInterface + + + {213EF4BA-786A-432F-B147-5702B18DE3CC} + Check.ServiceModel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 59295 + / + http://localhost:55799/ + False + False + + + False + + + + + + \ No newline at end of file diff --git a/tests/CheckWeb/Global.asax b/tests/CheckWeb/Global.asax new file mode 100644 index 00000000000..92228f2187c --- /dev/null +++ b/tests/CheckWeb/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CheckWeb.Global" Language="C#" %> diff --git a/tests/CheckWeb/Global.asax.cs b/tests/CheckWeb/Global.asax.cs new file mode 100644 index 00000000000..2c876f9eadb --- /dev/null +++ b/tests/CheckWeb/Global.asax.cs @@ -0,0 +1,745 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Check.ServiceInterface; +using Check.ServiceModel; +using Check.ServiceModel.Operations; +using Check.ServiceModel.Types; +using Funq; +using ServiceStack; +using ServiceStack.Api.OpenApi; +using ServiceStack.Api.OpenApi.Specification; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Html; +using ServiceStack.IO; +using ServiceStack.MiniProfiler; +using ServiceStack.ProtoBuf; +using ServiceStack.Razor; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.DataAnnotations; +using ServiceStack.Redis; + +namespace CheckWeb +{ + public class AppHost : AppHostBase + { + /// + /// Initializes a new instance of the class. + /// + public AppHost() + : base("CheckWeb", typeof(ErrorsService).Assembly, typeof(HtmlServices).Assembly) { } + + // public override void HttpCookieFilter(HttpCookie cookie) + // { + // cookie.SameSite = SameSiteMode.None; + // } + + /// + /// Configure the Web Application host. + /// + /// The container. + public override void Configure(Container container) + { +// EnableBuffering(); + + this.CustomErrorHttpHandlers[HttpStatusCode.NotFound] = new RazorHandler("/Views/TestErrorNotFound"); + + // Change ServiceStack configuration + SetConfig(new HostConfig + { + DebugMode = true, + //UseHttpsLinks = true, + AppendUtf8CharsetOnContentTypes = { MimeTypes.Html }, + CompressFilesWithExtensions = { "js", "css" }, + UseCamelCase = true, + AdminAuthSecret = "secretz", + //HandlerFactoryPath = "CheckWeb", //when hosted on IIS + //AllowJsConfig = false, + + // Set to return JSON if no request content type is defined + // e.g. text/html or application/json + //DefaultContentType = MimeTypes.Json, + // Disable SOAP endpoints + //EnableFeatures = Feature.All.Remove(Feature.Soap) + //EnableFeatures = Feature.All.Remove(Feature.Metadata) + }); + + container.Register(c => + new JsonServiceClient("http://localhost:55799/")); + + Plugins.Add(new SharpPagesFeature + { + MetadataDebugAdminRole = RoleNames.AllowAnyUser, + ScriptAdminRole = RoleNames.AllowAnon, + }); + + //ProxyFeatureTests + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/proxy/test"), + resolveUrl: req => "http://test.servicestack.net".CombineWith(req.RawUrl.Replace("/test", "/")))); + + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/techstacks"), + resolveUrl: req => "http://techstacks.io".CombineWith(req.RawUrl.Replace("/techstacks", "/")))); + + Plugins.Add(new AutoQueryFeature { MaxLimit = 100 }); + + Plugins.Add(new AutoQueryDataFeature() + .AddDataSource(ctx => ctx.MemorySource(GetRockstars()))); + + //Plugins.Add(new AdminFeature()); + + Plugins.Add(new PostmanFeature()); + Plugins.Add(new CorsFeature( + allowOriginWhitelist: new[] { "http://localhost", "http://localhost:8080", "http://localhost:56500", "http://test.servicestack.net", "http://null.jsbin.com" }, + allowCredentials: true, + allowedHeaders: "Content-Type, Allow, Authorization, X-Args")); + + Plugins.Add(new ServerEventsFeature + { + LimitToAuthenticatedUsers = true + }); + + GlobalRequestFilters.Add((req, res, dto) => + { + if (dto is AlwaysThrowsGlobalFilter) + throw new Exception(dto.GetType().Name); + }); + + Plugins.Add(new RequestLogsFeature + { + RequestLogger = new CsvRequestLogger(), + EnableResponseTracking = true + }); + + Plugins.Add(new DynamicallyRegisteredPlugin()); + + var nativeTypes = GetPlugin(); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DisplayAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DisplayColumnAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DisplayFormatAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(DataTypeAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(EditableAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(ServiceStack.DataAnnotations.PrimaryKeyAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(ServiceStack.DataAnnotations.AutoIncrementAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(ServiceStack.DataAnnotations.AutoIdAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(System.ComponentModel.BindableAttribute)); + nativeTypes.MetadataTypesConfig.ExportAttributes.Add(typeof(AssociationAttribute)); + + nativeTypes.ExportAttribute(x => + { + var metadata = nativeTypes.GetGenerator().ToMetadataAttribute(x); + try + { + var attr = (DisplayAttribute)x; + if (attr.GetAutoGenerateField() == null || (attr.GetAutoGenerateField().HasValue && !attr.GetAutoGenerateField().Value)) + metadata.Args.Add(new MetadataPropertyType { + Name = nameof(DisplayAttribute.AutoGenerateField), + TypeNamespace = "System", + Type = nameof(Boolean), + Value = "false" + }); + return metadata; + } + catch (Exception ex) + { + throw; + } + }); + + +// container.Register( +// new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); +// //container.Register( +// // new OrmLiteConnectionFactory("Server=localhost;Database=test;User Id=test;Password=test;", SqlServerDialect.Provider)); +// +// using (var db = container.Resolve().Open()) +// { +// db.DropAndCreateTable(); +// db.InsertAll(GetRockstars()); +// +// db.DropAndCreateTable(); +// db.Insert(new AllTypes +// { +// Id = 1, +// Int = 2, +// Long = 3, +// Float = 1.1f, +// Double = 2.2, +// Decimal = 3.3m, +// DateTime = DateTime.Now, +// Guid = Guid.NewGuid(), +// TimeSpan = TimeSpan.FromMilliseconds(1), +// String = "String" +// }); +// } +// +// Plugins.Add(new MiniProfilerFeature()); +// +// var dbFactory = (OrmLiteConnectionFactory)container.Resolve(); +// dbFactory.RegisterConnection("SqlServer", +// new OrmLiteConnectionFactory( +// "Server=localhost;Database=test;User Id=test;Password=test;", +// SqlServerDialect.Provider) +// { +// ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current) +// }); +// +// dbFactory.RegisterConnection("pgsql", +// new OrmLiteConnectionFactory( +// Environment.GetEnvironmentVariable("PGSQL_CONNECTION") ?? +// "Server=localhost;Port=5432;User Id=test;Password=test;Database=test;Pooling=true;MinPoolSize=0;MaxPoolSize=200", +// PostgreSqlDialect.Provider)); +// +// using (var db = dbFactory.OpenDbConnection("pgsql")) +// { +// db.DropAndCreateTable(); +// db.DropAndCreateTable(); +// +// db.Insert(new Rockstar { Id = 1, FirstName = "PostgreSQL", LastName = "Connection", Age = 1 }); +// db.Insert(new PgRockstar { Id = 1, FirstName = "PostgreSQL", LastName = "Named Connection", Age = 1 }); +// } + + //this.GlobalHtmlErrorHttpHandler = new RazorHandler("GlobalErrorHandler.cshtml"); + + // Configure JSON serialization properties. + this.ConfigureSerialization(container); + + // Configure ServiceStack database connections. + this.ConfigureDataConnection(container); + + // Configure ServiceStack Authentication plugin. + this.ConfigureAuth(container); + + // Configure ServiceStack Fluent Validation plugin. + this.ConfigureValidation(container); + + // Configure ServiceStack Razor views. + this.ConfigureView(container); + + this.StartUpErrors.Add(new ResponseStatus("Mock", "Startup Error")); + + //PreRequestFilters.Add((req, res) => + //{ + // if (req.PathInfo.StartsWith("/metadata") || req.PathInfo.StartsWith("/swagger-ui")) + // { + // var session = req.GetSession(); + // if (!session.IsAuthenticated) + // { + // res.StatusCode = (int)HttpStatusCode.Unauthorized; + // res.EndRequest(); + // } + // } + //}); + + Plugins.Add(new ProtoBufFormat()); + } + + public static Rockstar[] GetRockstars() + { + return new[] + { + new Rockstar {Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27}, + new Rockstar {Id = 2, FirstName = "Jim", LastName = "Morrison", Age = 27}, + new Rockstar {Id = 3, FirstName = "Kurt", LastName = "Cobain", Age = 27}, + new Rockstar {Id = 4, FirstName = "Elvis", LastName = "Presley", Age = 42}, + new Rockstar {Id = 5, FirstName = "David", LastName = "Grohl", Age = 44}, + new Rockstar {Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48}, + new Rockstar {Id = 7, FirstName = "Michael", LastName = "Jackson", Age = 50}, + }; + } + + /// + /// Configure JSON serialization properties. + /// + /// The container. + private void ConfigureSerialization(Container container) + { + // Set JSON web services to return ISO8601 date format + // Exclude type info during serialization as an effect of IoC + JsConfig.Init(new ServiceStack.Text.Config { + DateHandler = DateHandler.ISO8601, + ExcludeTypeInfo = true, + }); + } + + /// + /// // Configure ServiceStack database connections. + /// + /// The container. + private void ConfigureDataConnection(Container container) + { + // ... + } + + /// + /// Configure ServiceStack Authentication plugin. + /// + /// The container. + private void ConfigureAuth(Container container) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new CredentialsAuthProvider(AppSettings), + new JwtAuthProvider(AppSettings) + { + AuthKey = Convert.FromBase64String("3n/aJNQHPx0cLu/2dN3jWf0GSYL35QlMqgz+LH3hUyA="), + RequireSecureConnection = false, + }, +// new ApiKeyAuthProvider(AppSettings), + new BasicAuthProvider(AppSettings), + })); + + Plugins.Add(new RegistrationFeature()); + +// var authRepo = new OrmLiteAuthRepository(container.Resolve()); +// container.Register(c => authRepo); +// authRepo.InitSchema(); +// +// authRepo.CreateUserAuth(new UserAuth +// { +// UserName = "test", +// DisplayName = "Credentials", +// FirstName = "First", +// LastName = "Last", +// FullName = "First Last", +// }, "test"); + } + + /// + /// Configure ServiceStack Fluent Validation plugin. + /// + /// The container. + private void ConfigureValidation(Container container) + { + // Provide fluent validation functionality for web services + Plugins.Add(new ValidationFeature()); + + container.RegisterValidators(typeof(AppHost).Assembly); + container.RegisterValidators(typeof(ThrowValidationValidator).Assembly); + } + + /// + /// Configure ServiceStack Razor views. + /// + /// The container. + private void ConfigureView(Container container) + { + // Enable ServiceStack Razor + var razor = new RazorFormat(); + razor.Deny.RemoveAt(0); + Plugins.Add(razor); + + container.Register(c => new RedisManagerPool()); + + Plugins.Add(new OpenApiFeature + { + ApiDeclarationFilter = api => + { + foreach (var path in new[] { api.Paths["/auth"], api.Paths["/auth/{provider}"] }) + { + path.Get = path.Put = path.Delete = null; + } + }, + OperationFilter = (verb, op) => { + if (op.RequestType == nameof(SwaggerRangeTest)) + { + var intRange = op.Parameters.FirstOrDefault(p => p.Name == nameof(SwaggerRangeTest.IntRange)); + intRange.Minimum = 1; + intRange.Maximum = 2; + + var dobleRange = op.Parameters.FirstOrDefault(p => p.Name == nameof(SwaggerRangeTest.DoubleRange)); + dobleRange.Minimum = 1.1; + dobleRange.Maximum = 2.2; + } + }, + Tags = + { + new OpenApiTag + { + Name = "TheTag", + Description = "TheTag Description", + ExternalDocs = new OpenApiExternalDocumentation + { + Description = "Link to External Docs Desc", + Url = "http://example.org/docs/path", + } + } + } + }); + + // Enable support for Swagger API browser + //Plugins.Add(new SwaggerFeature + //{ + // UseBootstrapTheme = true, + // LogoUrl = "//lh6.googleusercontent.com/-lh7Gk4ZoVAM/AAAAAAAAAAI/AAAAAAAAAAA/_0CgCb4s1e0/s32-c/photo.jpg" + //}); + //Plugins.Add(new CorsFeature()); // Uncomment if the services to be available from external sites + } + + public void EnableBuffering() + { + PreRequestFilters.Add((req, res) => + { + req.UseBufferedStream = true; + res.UseBufferedStream = true; + }); + } + + public override List GetVirtualFileSources() + { + var existingProviders = base.GetVirtualFileSources(); + //return existingProviders; + + var memFs = new MemoryVirtualFiles(); + + //Get FileSystem Provider + var fs = existingProviders.First(x => x is FileSystemVirtualFiles); + + //Process all .html files: + foreach (var file in fs.GetAllMatchingFiles("*.html")) + { + var contents = Minifiers.HtmlAdvanced.Compress(file.ReadAllText()); + memFs.WriteFile(file.VirtualPath, contents); + } + + //Process all .css files: + foreach (var file in fs.GetAllMatchingFiles("*.css") + .Where(file => !file.VirtualPath.EndsWith(".min.css"))) + { + var contents = Minifiers.Css.Compress(file.ReadAllText()); + memFs.WriteFile(file.VirtualPath, contents); + } + + //Process all .js files + foreach (var file in fs.GetAllMatchingFiles("*.js") + .Where(file => !file.VirtualPath.EndsWith(".min.js"))) + { + try + { + var js = file.ReadAllText(); + var contents = Minifiers.JavaScript.Compress(js); + memFs.WriteFile(file.VirtualPath, contents); + } + catch (Exception ex) + { + //Report any errors in StartUpErrors collection on ?debug=requestinfo + base.OnStartupException(new Exception("JSMin Error in {0}: {1}".Fmt(file.VirtualPath, ex.Message))); + } + } + + //Give new Memory FS highest priority + existingProviders.Insert(0, memFs); + return existingProviders; + } + } + + [Route("/query/alltypes")] + public class QueryAllTypes : QueryDb { } + + [Route("/test/html")] + public class TestHtml : IReturn + { + public string Name { get; set; } + } + + [Route("/test/html2")] + public class TestHtml2 + { + public string Name { get; set; } + } + + [HtmlOnly] + [CacheResponse(Duration = 3600)] + public class HtmlServices : Service + { + public object Any(TestHtml request) => request; + + public object Any(TestHtml2 request) => new HttpResult(new TestHtml { Name = request.Name }) + { + View = nameof(TestHtml) + }; + } + + [Route("/views/request")] + public class ViewRequest : IReturn + { + public string Name { get; set; } + } + + public class ViewResponse + { + public string Result { get; set; } + } + + public class ViewServices : Service + { + public object Get(ViewRequest request) + { + var result = Gateway.Send(new TestHtml()); + return new ViewResponse { Result = request.Name }; + } + + public object Get(ViewRequest[] requests) + { + return requests.Map(x => new ViewResponse {Result = x.Name}).ToArray(); + } + } + + [Route("/index")] + public class IndexPage + { + public string PathInfo { get; set; } + } + + [Route("/return/text")] + public class ReturnText + { + public string Text { get; set; } + } + + [Route("/swagger/model")] + public class SwaggerModel : IReturn + { + public int Int { get; set; } + public string String { get; set; } + public DateTime DateTime { get; set; } + public DateTimeOffset DateTimeOffset { get; set; } + public TimeSpan TimeSpan { get; set; } + } + + [Route("/async/redis")] + [Route("/async/redis/{Incr}")] + public class AsyncRedis : IReturn + { + public uint Incr { get; set; } + } + + public class MyServices : Service + { + //Return default.html for unmatched requests so routing is handled on client + public object Any(IndexPage request) => + new HttpResult(VirtualFileSources.GetFile("default.html")); + + [AddHeader(ContentType = MimeTypes.PlainText)] + public object Any(ReturnText request) => request.Text; + + public object Any(SwaggerModel request) => request; + + public async Task Any(AsyncRedis request) + { + var redis = await GetRedisAsync(); + await redis.IncrementAsync(nameof(AsyncRedis), request.Incr); + + var response = new IdResponse { + Id = (await redis.GetAsync(nameof(AsyncRedis))).ToString() + }; + return response; + } + } + + [Route("/plain-dto")] + public class PlainDto : IReturn + { + public string Name { get; set; } + } + + [Route("/httpresult-dto")] + public class HttpResultDto : IReturn + { + public string Name { get; set; } + } + + public class HttpResultServices : Service + { + public object Any(PlainDto request) => request; + + public object Any(HttpResultDto request) => new HttpResult(request, HttpStatusCode.Created); + } + + [Route("/restrict/mq")] + [Restrict(RequestAttributes.MessageQueue)] + public class TestMqRestriction : IReturn + { + public string Name { get; set; } + } + + public class TestRestrictionsService : Service + { + public object Any(TestMqRestriction request) => request; + } + + [Route("/set-cache")] + public class SetCache : IReturn + { + public string ETag { get; set; } + public TimeSpan? Age { get; set; } + public TimeSpan? MaxAge { get; set; } + public DateTime? Expires { get; set; } + public DateTime? LastModified { get; set; } + public CacheControl? CacheControl { get; set; } + } + + public class CacheEtagServices : Service + { + public object Any(SetCache request) + { + return new HttpResult(request) + { + Age = request.Age, + ETag = request.ETag, + MaxAge = request.MaxAge, + Expires = request.Expires, + LastModified = request.LastModified, + CacheControl = request.CacheControl.GetValueOrDefault(CacheControl.None), + }; + } + } + + + [Route("/gzip/{FileName}")] + public class DownloadGzipFile : IReturn + { + public string FileName { get; set; } + } + + public class FileServices : Service + { + public object Get(DownloadGzipFile request) + { + var filePath = HostContext.AppHost.MapProjectPath($"~/img/{request.FileName}"); + if (Request.RequestPreferences.AcceptsGzip) + { + var targetPath = string.Concat(filePath, ".gz"); + Compress(filePath, targetPath); + + //var bs = new BufferedStream(File.OpenRead(targetPath), 8192); + //Response.AddHeader("Content-Type", "application/pdf"); + //Response.AddHeader("Content-Disposition", "attachment; filename=test.pdf"); + //return new GZipStream(bs, CompressionMode.Decompress); + + return new HttpResult(new FileInfo(targetPath)) + { + Headers = { + { HttpHeaders.ContentDisposition, "attachment; filename=" + request.FileName }, + { HttpHeaders.ContentEncoding, CompressionTypes.GZip } + } + }; + } + + return new HttpResult(filePath) + { + Headers = { + { HttpHeaders.ContentDisposition, "attachment; filename=" + request.FileName }, + } + }; + } + + private void Compress(string readFrom, string writeTo) + { + byte[] b; + using (var f = new FileStream(readFrom, FileMode.Open)) + { + b = new byte[f.Length]; + f.Read(b, 0, (int)f.Length); + } + + using (var fs = new FileStream(writeTo, FileMode.OpenOrCreate)) + using (var gz = new GZipStream(fs, CompressionMode.Compress, false)) + { + gz.Write(b, 0, b.Length); + } + } + } + + [Route("/match/{Language}/{Name*}", Matches = @"PathInfo =~ \/match\/[a-z]{2}\/[A-Za-z]+$")] + public class MatchName : IReturn + { + public string Language { get; set; } + public string Name { get; set; } + } + + [Route("/match/{Language*}", Matches = @"PathInfo =~ \/match\/[a-z]{2}$")] + public class MatchLang : IReturn + { + public string Language { get; set; } + } + + public class RouteMatchServices : Service + { + public HelloResponse Any(MatchName request) => new HelloResponse { Result = request.GetType().Name }; + public HelloResponse Any(MatchLang request) => new HelloResponse { Result = request.GetType().Name }; + } + + [Route("/reqlogstest/{Name}")] + public class RequestLogsTest : IReturn + { + public string Name { get; set; } + } + + public class InProcRequest1 {} + public class InProcRequest2 {} + + public class RequestLogsServices : Service + { + public object Any(RequestLogsTest request) + { + Gateway.Publish(new InProcRequest1()); + Gateway.Publish(new InProcRequest2()); + + return "hello"; + } + + public object Any(InProcRequest1 request) => "InProcRequest1 response"; + public object Any(InProcRequest2 request) => "InProcRequest2 response"; + } + + [Alias("Rockstar")] + [NamedConnection("SqlServer")] + public class NamedRockstar : Rockstar { } + + public class Global : System.Web.HttpApplication + { + protected void Application_Start(object sender, EventArgs e) + { + try + { + new AppHost().Init(); + } + catch (Exception exception) + { + Console.WriteLine(exception); + throw exception; + } + } + + protected void Application_BeginRequest(object src, EventArgs e) + { + if (Request.IsLocal) + Profiler.Start(); + } + + protected void Application_EndRequest(object src, EventArgs e) + { + Profiler.Stop(); + } + } + + public static class HtmlHelpers + { + public static MvcHtmlString DisplayPrice(this HtmlHelper html, decimal price) + { + return MvcHtmlString.Create(price == 0 + ? "FREE!" + : $"{price:C2}"); + } + } +} \ No newline at end of file diff --git a/tests/CheckWeb/GlobalErrorHandler.cshtml b/tests/CheckWeb/GlobalErrorHandler.cshtml new file mode 100644 index 00000000000..d4c1b3ee7e0 --- /dev/null +++ b/tests/CheckWeb/GlobalErrorHandler.cshtml @@ -0,0 +1,7 @@ +@{ + ViewBag.Title = "Global Error Handler"; +} + +

Global Error Handler

+ +@Html.Raw(base.GetErrorHtml()) \ No newline at end of file diff --git a/tests/CheckWeb/HttpBenchmarks.cs b/tests/CheckWeb/HttpBenchmarks.cs new file mode 100644 index 00000000000..1b7818dcd23 --- /dev/null +++ b/tests/CheckWeb/HttpBenchmarks.cs @@ -0,0 +1,289 @@ +/* Options: +Date: 2017-11-09 21:58:38 +Version: 4.50 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: https://httpbenchmarks.servicestack.net + +//GlobalNamespace: +//MakePartial: True +//MakeVirtual: True +//MakeInternal: False +//MakeDataContractsExtensible: False +//AddReturnMarker: True +//AddDescriptionAsComments: True +//AddDataContractAttributes: False +//AddIndexesToDataMembers: False +//AddGeneratedCodeAttributes: False +//AddResponseStatus: False +//AddImplicitVersion: +//InitializeCollections: True +//IncludeTypes: +//ExcludeTypes: +//AddNamespaces: +//AddDefaultXmlNamespace: http://schemas.servicestack.net/types +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; +using BenchmarksAnalyzer.ServiceModel.Types; +using BenchmarksAnalyzer.ServiceModel; + + +namespace BenchmarksAnalyzer.ServiceModel +{ + + [Route("/testplans/{TestPlanId}/testresults", "POST")] + [Route("/testplans/{TestPlanId}/testruns/{TestRunId}/testresults", "POST")] + public partial class AddTestResults + : IReturn> + { + public virtual int TestPlanId { get; set; } + public virtual int? TestRunId { get; set; } + public virtual string Contents { get; set; } + } + + [Route("/testplans", "POST")] + public partial class CreateTestPlan + : IReturn + { + public virtual string Name { get; set; } + public virtual string Slug { get; set; } + } + + [Route("/testplans/{TestPlanId}/testruns", "POST")] + public partial class CreateTestRun + : IReturn + { + public virtual int TestPlanId { get; set; } + public virtual string SeriesId { get; set; } + } + + [Route("/testplans/{Id}/delete", "POST DELETE")] + public partial class DeleteTestPlan + { + public virtual int Id { get; set; } + } + + [Route("/testruns/{Id}/delete", "POST DELETE")] + public partial class DeleteTestRun + { + public virtual int Id { get; set; } + } + + [Route("/testplans/{Id}/edit")] + [Route("/testplans/{Id}/testruns/{TestRunId}/edit")] + public partial class EditTestPlan + : IReturn + { + public virtual int Id { get; set; } + public virtual int? TestRunId { get; set; } + } + + [Route("/testplans", "GET")] + public partial class FindTestPlans + : IReturn> + { + } + + [Route("/testplans/{TestPlanId}/testruns", "GET")] + public partial class FindTestRuns + : IReturn> + { + public virtual int TestPlanId { get; set; } + } + + [Route("/testplans/{Id}")] + public partial class GetTestPlan + : IReturn + { + public virtual int Id { get; set; } + } + + [Route("/myinfo")] + public partial class MyInfo + : IReturn + { + } + + [Route("/ping")] + public partial class Ping + : IReturn + { + } + + public partial class PingResponse + { + public virtual string Result { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/reset")] + public partial class Reset + { + } + + [Route("/testplans/{TestPlanId}/results", "GET")] + [Route("/testplans/{TestPlanId}/testruns/{TestRunId}/results", "GET")] + public partial class SearchTestResults + : IReturn + { + public virtual int TestPlanId { get; set; } + public virtual int? TestRunId { get; set; } + public virtual int? Skip { get; set; } + public virtual int? Take { get; set; } + public virtual string Host { get; set; } + public virtual int? Port { get; set; } + public virtual string RequestPath { get; set; } + } + + public partial class SearchTestResultsResponse + { + public SearchTestResultsResponse() + { + Results = new List{}; + } + + public virtual int TestPlanId { get; set; } + public virtual int? TestRunId { get; set; } + public virtual int? Skip { get; set; } + public virtual int? Take { get; set; } + public virtual string Host { get; set; } + public virtual int? Port { get; set; } + public virtual string RequestPath { get; set; } + public virtual int Total { get; set; } + public virtual List Results { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/testplans/{Id}/labels", "POST")] + public partial class UpdateTestPlanLabels + : IReturn + { + public virtual int Id { get; set; } + public virtual string ServerLabels { get; set; } + public virtual string TestLabels { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/testplans/{TestPlanId}/upload", "POST")] + [Route("/testplans/{TestPlanId}/testruns/{TestRunId}/upload", "POST")] + public partial class UploadTestResults + : IReturn> + { + public virtual int TestPlanId { get; set; } + public virtual int? TestRunId { get; set; } + public virtual bool CreateNewTestRuns { get; set; } + } + + [Route("/{Slug}")] + public partial class ViewTestPlan + : IReturn + { + public virtual string Slug { get; set; } + public virtual int? Id { get; set; } + } + + public partial class ViewTestPlanResponse + { + public ViewTestPlanResponse() + { + Results = new List{}; + } + + public virtual TestPlan TestPlan { get; set; } + public virtual TestRun TestRun { get; set; } + public virtual List Results { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } +} + +namespace BenchmarksAnalyzer.ServiceModel.Types +{ + + public partial class DisplayResult + { + public virtual int Id { get; set; } + public virtual string Software { get; set; } + public virtual string Host { get; set; } + public virtual int Port { get; set; } + public virtual string RequestPath { get; set; } + public virtual int RequestLength { get; set; } + public virtual int Concurrency { get; set; } + public virtual double TimeTaken { get; set; } + public virtual int TotalRequests { get; set; } + public virtual int FailedRequests { get; set; } + public virtual int TotalTransferred { get; set; } + public virtual int HtmlTransferred { get; set; } + public virtual double RequestsPerSec { get; set; } + public virtual double TimePerRequest { get; set; } + public virtual double TransferRate { get; set; } + } + + public partial class TestPlan + { + public TestPlan() + { + ServerLabels = new Dictionary{}; + TestLabels = new Dictionary{}; + } + + public virtual int Id { get; set; } + public virtual int UserAuthId { get; set; } + public virtual string Name { get; set; } + public virtual string Slug { get; set; } + public virtual Dictionary ServerLabels { get; set; } + public virtual Dictionary TestLabels { get; set; } + public virtual DateTime CreatedDate { get; set; } + } + + public partial class TestResult + { + public virtual int Id { get; set; } + public virtual int UserAuthId { get; set; } + public virtual int TestPlanId { get; set; } + public virtual int TestRunId { get; set; } + public virtual string Software { get; set; } + public virtual string Hostname { get; set; } + public virtual int Port { get; set; } + public virtual string RequestPath { get; set; } + public virtual int RequestLength { get; set; } + public virtual int Concurrency { get; set; } + public virtual double TimeTaken { get; set; } + public virtual int TotalRequests { get; set; } + public virtual int FailedRequests { get; set; } + public virtual string FailedReasons { get; set; } + public virtual int TotalTransferred { get; set; } + public virtual int HtmlTransferred { get; set; } + public virtual double RequestsPerSec { get; set; } + public virtual double TimePerRequest { get; set; } + public virtual double TransferRate { get; set; } + public virtual string RawData { get; set; } + } + + public partial class TestRun + { + public virtual int Id { get; set; } + public virtual int UserAuthId { get; set; } + public virtual int TestPlanId { get; set; } + public virtual string SeriesId { get; set; } + public virtual DateTime CreatedDate { get; set; } + [Ignore] + public virtual int TestResultsCount { get; set; } + } + + public partial class UserInfo + { + public virtual int Id { get; set; } + public virtual int UserAuthId { get; set; } + public virtual string DisplayName { get; set; } + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual string ProfileUrl64 { get; set; } + } +} + + diff --git a/tests/CheckWeb/HttpBenchmarks.tt b/tests/CheckWeb/HttpBenchmarks.tt new file mode 100644 index 00000000000..de618593a06 --- /dev/null +++ b/tests/CheckWeb/HttpBenchmarks.tt @@ -0,0 +1,37 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ output extension=".cs" #> +<#= DownloadCSharpDtos("https://httpbenchmarks.servicestack.net/types/csharp") #> +<#+ +public class CodegenOptions +{ + bool? MakePartial; + bool? MakeVirtual; + bool? MakeDataContractsExtensible; + bool? InitializeCollections; + bool? AddReturnMarker; + bool? AddDescriptionAsComments; + bool? AddDataContractAttributes; + bool? AddIndexesToDataMembers; + bool? AddResponseStatus; + int? AddImplicitVersion; + string AddDefaultXmlNamespace; +} +#> + +<#+ +public static string DownloadCSharpDtos(string baseUrl) { + var sb = new System.Text.StringBuilder(); + var fields = typeof(CodegenOptions).GetFields( + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var config = new CodegenOptions(); + foreach (var f in fields) { + var value = f.GetValue(config); + if (value == null) continue; + if (sb.Length > 0) sb.Append("&"); + sb.AppendFormat("{0}={1}", f.Name, value); + } + var qs = sb.ToString(); + if (qs.Length > 0) baseUrl += "?" + qs; + return new System.Net.WebClient().DownloadString(baseUrl); +} +#> \ No newline at end of file diff --git a/tests/CheckWeb/Properties/AssemblyInfo.cs b/tests/CheckWeb/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..e24213ead75 --- /dev/null +++ b/tests/CheckWeb/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CheckWeb")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CheckWeb")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c498a512-5e13-4fcd-98c2-e2685211bdd0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/CheckWeb/RequestInfoTests.cs b/tests/CheckWeb/RequestInfoTests.cs new file mode 100644 index 00000000000..813e482bd51 --- /dev/null +++ b/tests/CheckWeb/RequestInfoTests.cs @@ -0,0 +1,96 @@ +using System.Net; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Host.Handlers; + +namespace CheckWeb +{ + public class RequestInfoServices : Service + { + } + + public partial class RequestInfoTests + { + public string BaseUrl = "http://localhost:55799/"; + + private RequestInfoResponse GetRequestInfoForPath(string path) + { + var url = BaseUrl.CombineWith(path).AddQueryParam("debug", "requestinfo"); + var json = url.GetJsonFromUrl(); + var info = json.FromJson(); + return info; + } + + private void AssertHasContent(string pathInfo, string accept, string containsContent) + { + var url = BaseUrl.CombineWith(pathInfo); + var content = url.GetStringFromUrl(accept: accept); + Assert.That(content, Does.Contain(containsContent)); + } + + [Test] + public void Does_return_expected_content() + { + AssertHasContent("metadata", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("metadata/", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("dir", MimeTypes.Html, "

dir/index.html

"); + AssertHasContent("dir/", MimeTypes.Html, "

dir/index.html

"); + AssertHasContent("dir/sub", MimeTypes.Html, "

dir/sub/index.html

"); + AssertHasContent("dir/sub/", MimeTypes.Html, "

dir/sub/index.html

"); + AssertHasContent("swagger-ui", MimeTypes.Html, "Swagger UI"); + AssertHasContent("swagger-ui/", MimeTypes.Html, "Swagger UI"); + } + + [Test] + public void Does_have_correct_path_info() + { + Assert.That(GetRequestInfoForPath("dir/").PathInfo, Is.EqualTo("/dir/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("swagger-ui/").PathInfo, Is.EqualTo("/swagger-ui/")); + } + } + + public partial class RequestInfoTests + { + private void DoesRedirectToRemoveTrailingSlash(string dirWIthoutSlash) + { + BaseUrl.CombineWith(dirWIthoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWIthoutSlash + "/"))); + }); + } + + private void DoesRedirectToAddTrailingSlash(string dirWithoutSlash) + { + BaseUrl.CombineWith(dirWithoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWithoutSlash.TrimEnd('/')))); + }); + } + + [Test] + public void Does_redirect_dirs_without_trailing_slash() + { + DoesRedirectToRemoveTrailingSlash("dir"); + DoesRedirectToRemoveTrailingSlash("dir/sub"); + DoesRedirectToRemoveTrailingSlash("swagger-ui"); + } + + [Test] + public void Does_redirect_metadata_page_to_without_slash() + { + DoesRedirectToAddTrailingSlash("metadata/"); + } + } +} \ No newline at end of file diff --git a/tests/CheckWeb/ServiceModels.cs b/tests/CheckWeb/ServiceModels.cs new file mode 100644 index 00000000000..ec6a36301bc --- /dev/null +++ b/tests/CheckWeb/ServiceModels.cs @@ -0,0 +1,701 @@ +/* Options: +Version: 1 +BaseUrl: http://localhost:55799 + +ServerVersion: 1 +MakePartial: True +MakeVirtual: True +MakeDataContractsExtensible: False +AddReturnMarker: True +AddDescriptionAsComments: True +AddDataContractAttributes: False +AddIndexesToDataMembers: False +AddResponseStatus: False +AddImplicitVersion: +InitializeCollections: True +AddDefaultXmlNamespace: http://schemas.servicestack.net/types +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; +using Check.ServiceModel; +using Check.ServiceModel.Operations; +using Check.ServiceModel.Types; +using Check.ServiceInterface; + + +namespace Check.ServiceInterface +{ + + [Route("/api/acsprofiles/{profileId}")] + [Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE")] + public partial class ACSProfile + : IReturn + { + public virtual string profileId { get; set; } + [StringLength(20)] + [Required] + public virtual string shortName { get; set; } + + [StringLength(60)] + public virtual string longName { get; set; } + + [StringLength(20)] + public virtual string regionId { get; set; } + + [StringLength(20)] + public virtual string groupId { get; set; } + + [StringLength(12)] + public virtual string deviceID { get; set; } + + public virtual DateTime lastUpdated { get; set; } + public virtual bool enabled { get; set; } + } + + public partial class acsprofileResponse + { + public virtual string profileId { get; set; } + } + + [Route("/anontype")] + public partial class AnonType + { + } + + [Route("/changerequest/{Id}")] + public partial class ChangeRequest + : IReturn + { + public virtual string Id { get; set; } + } + + public partial class ChangeRequestResponse + { + public virtual string ContentType { get; set; } + public virtual string Header { get; set; } + public virtual string QueryString { get; set; } + public virtual string Form { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class CustomRockstar + { + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual int? Age { get; set; } + public virtual string RockstarAlbumName { get; set; } + } + + public partial class Movie + { + public Movie() + { + Genres = new List{}; + } + + public virtual int Id { get; set; } + public virtual string ImdbId { get; set; } + public virtual string Title { get; set; } + public virtual string Rating { get; set; } + public virtual decimal Score { get; set; } + public virtual string Director { get; set; } + public virtual DateTime ReleaseDate { get; set; } + public virtual string TagLine { get; set; } + public virtual List Genres { get; set; } + } + + public partial class QueryCustomRockstars + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryCustomRockstarsFilter + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryFieldRockstars + : QueryBase, IReturn> + { + public QueryFieldRockstars() + { + FirstNames = new string[]{}; + FirstNameBetween = new string[]{}; + } + + public virtual string FirstName { get; set; } + public virtual string[] FirstNames { get; set; } + public virtual int? Age { get; set; } + public virtual string FirstNameCaseInsensitive { get; set; } + public virtual string FirstNameStartsWith { get; set; } + public virtual string LastNameEndsWith { get; set; } + public virtual string[] FirstNameBetween { get; set; } + public virtual string OrLastName { get; set; } + } + + public partial class QueryFieldRockstarsDynamic + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryGetRockstars + : QueryBase, IReturn> + { + public QueryGetRockstars() + { + Ids = new int[]{}; + Ages = new List{}; + FirstNames = new List{}; + IdsBetween = new int[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual List Ages { get; set; } + public virtual List FirstNames { get; set; } + public virtual int[] IdsBetween { get; set; } + } + + public partial class QueryGetRockstarsDynamic + : QueryBase, IReturn> + { + } + + [Route("/movies")] + public partial class QueryMovies + : QueryBase, IReturn> + { + public QueryMovies() + { + Ids = new int[]{}; + ImdbIds = new string[]{}; + Ratings = new string[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual string[] ImdbIds { get; set; } + public virtual string[] Ratings { get; set; } + } + + [Route("/OrRockstars")] + public partial class QueryOrRockstars + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + public virtual string FirstName { get; set; } + } + + public partial class QueryOverridedCustomRockstars + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryOverridedRockstars + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/customrockstars")] + public partial class QueryRockstarAlbums + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + public virtual string RockstarAlbumName { get; set; } + } + + public partial class QueryRockstarAlbumsImplicit + : QueryBase, IReturn> + { + } + + public partial class QueryRockstarAlbumsLeftJoin + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + public virtual string AlbumName { get; set; } + } + + [Route("/query/rockstars")] + public partial class QueryRockstars + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryRockstarsConventions + : QueryBase, IReturn> + { + public QueryRockstarsConventions() + { + Ids = new int[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual int? AgeOlderThan { get; set; } + public virtual int? AgeGreaterThanOrEqualTo { get; set; } + public virtual int? AgeGreaterThan { get; set; } + public virtual int? GreaterThanAge { get; set; } + public virtual string FirstNameStartsWith { get; set; } + public virtual string LastNameEndsWith { get; set; } + public virtual string LastNameContains { get; set; } + public virtual string RockstarAlbumNameContains { get; set; } + public virtual int? RockstarIdAfter { get; set; } + public virtual int? RockstarIdOnOrAfter { get; set; } + } + + public partial class QueryRockstarsFilter + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryRockstarsIFilter + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/query/rockstar-references")] + public partial class QueryRockstarsWithReferences + : QueryBase, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryUnknownRockstars + : QueryBase, IReturn> + { + public virtual int UnknownInt { get; set; } + public virtual string UnknownProperty { get; set; } + } + + public partial class RockstarAlbum + { + public virtual int Id { get; set; } + public virtual int RockstarId { get; set; } + public virtual string Name { get; set; } + } + + public partial class RockstarReference + { + public RockstarReference() + { + Albums = new List{}; + } + + public virtual int Id { get; set; } + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual int? Age { get; set; } + public virtual List Albums { get; set; } + } + + [Route("/movies/search")] + public partial class SearchMovies + : QueryBase, IReturn> + { + } + + public partial class StreamMovies + : QueryBase, IReturn> + { + public StreamMovies() + { + Ratings = new string[]{}; + } + + public virtual string[] Ratings { get; set; } + } +} + +namespace Check.ServiceModel +{ + + public partial class AsyncTest + : IReturn + { + } + + public partial class Echo + { + public virtual string Sentence { get; set; } + } + + /// + ///Echoes a sentence + /// + [Route("/echoes", "POST")] + [Api("Echoes a sentence")] + public partial class Echoes + : IReturn + { + [ApiMember(Description="The sentence to echo.", ParameterType="form", DataType="string", IsRequired=true, Name="Sentence")] + public virtual string Sentence { get; set; } + } + + public partial class Rockstar + { + public virtual int Id { get; set; } + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual int? Age { get; set; } + } + + [Route("/throwhttperror/{Status}")] + public partial class ThrowHttpError + { + public virtual int Status { get; set; } + public virtual string Message { get; set; } + } +} + +namespace Check.ServiceModel.Operations +{ + + /// + ///AllowedAttributes Description + /// + [Route("/allowed-attributes", "GET")] + [Api("AllowedAttributes Description")] + [ApiResponse(400, "Your request was not understood")] + [DataContract] + public partial class AllowedAttributes + { + [Required] + [Default(5)] + public virtual int Id { get; set; } + + [DataMember(Name="Aliased")] + [ApiMember(Description="Range Description", ParameterType="path", DataType="double", IsRequired=true)] + public virtual double Range { get; set; } + + [StringLength(20)] + [Meta("Foo", "Bar")] + [References(typeof(Check.ServiceModel.Operations.Hello))] + public virtual string Name { get; set; } + } + + [Flags] + public enum EnumFlags + { + Value1 = 1, + Value2 = 2, + Value3 = 4, + } + + public enum EnumType + { + Value1, + Value2, + } + + [Route("/hello/{Name}")] + public partial class Hello + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloAllTypes + : IReturn + { + public virtual string Name { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + public partial class HelloAllTypesResponse + { + public virtual string Result { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + /// + ///Description on HelloAll type + /// + [DataContract] + public partial class HelloAnnotated + : IReturn + { + [DataMember] + public virtual string Name { get; set; } + } + + /// + ///Description on HelloAllResponse type + /// + [DataContract] + public partial class HelloAnnotatedResponse + { + [DataMember] + public virtual string Result { get; set; } + } + + public partial class HelloBase + { + public HelloBase() + { + Items = new List{}; + Counts = new List{}; + } + + public virtual List Items { get; set; } + public virtual List Counts { get; set; } + } + + public partial class HelloResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloString + { + public virtual string Name { get; set; } + } + + public partial class HelloVoid + { + public virtual string Name { get; set; } + } + + public partial class HelloWithAlternateReturnResponse + : HelloWithReturnResponse + { + public virtual string AltResult { get; set; } + } + + [DataContract] + public partial class HelloWithDataContract + : IReturn + { + [DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Name { get; set; } + + [DataMember(Name="id", Order=2, EmitDefaultValue=false)] + public virtual int Id { get; set; } + } + + [DataContract] + public partial class HelloWithDataContractResponse + { + [DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Result { get; set; } + } + + /// + ///Description on HelloWithDescription type + /// + public partial class HelloWithDescription + : IReturn + { + public virtual string Name { get; set; } + } + + /// + ///Description on HelloWithDescriptionResponse type + /// + public partial class HelloWithDescriptionResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithEnum + { + public virtual EnumType EnumProp { get; set; } + public virtual EnumType? NullableEnumProp { get; set; } + public virtual EnumFlags EnumFlags { get; set; } + } + + public partial class HelloWithGenericInheritance + : HelloBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithGenericInheritance2 + : HelloBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithInheritance + : HelloBase, IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithInheritanceResponse + : HelloResponseBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithListInheritance + : List + { + } + + public partial class HelloWithNestedClass + : IReturn + { + public virtual string Name { get; set; } + public virtual NestedClass NestedClassProp { get; set; } + + public partial class NestedClass + { + public virtual string Value { get; set; } + } + } + + public partial class HelloWithNestedInheritance + : HelloBase + { + + public partial class Item + { + public virtual string Value { get; set; } + } + } + + public partial class HelloWithReturn + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/helloroute")] + public partial class HelloWithRoute + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithRouteResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithType + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithTypeResponse + { + public virtual HelloType Result { get; set; } + } + + public partial class InheritedItem + { + public virtual string Name { get; set; } + } + + public partial class RestrictedAttributes + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual Hello Hello { get; set; } + } +} + +namespace Check.ServiceModel.Types +{ + + public partial class AllCollectionTypes + { + public AllCollectionTypes() + { + IntArray = new int[]{}; + IntList = new List{}; + StringArray = new string[]{}; + StringList = new List{}; + PocoArray = new Poco[]{}; + PocoList = new List{}; + } + + public virtual int[] IntArray { get; set; } + public virtual List IntList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual List StringList { get; set; } + public virtual Poco[] PocoArray { get; set; } + public virtual List PocoList { get; set; } + } + + public partial class AllTypes + { + public AllTypes() + { + StringList = new List{}; + StringArray = new string[]{}; + StringMap = new Dictionary{}; + IntStringMap = new Dictionary{}; + } + + public virtual int Id { get; set; } + public virtual int? NullableId { get; set; } + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTime? NullableDateTime { get; set; } + public virtual TimeSpan? NullableTimeSpan { get; set; } + public virtual List StringList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual Dictionary StringMap { get; set; } + public virtual Dictionary IntStringMap { get; set; } + public virtual SubType SubType { get; set; } + } + + public partial class HelloBase + { + public virtual int Id { get; set; } + } + + public partial class HelloResponseBase + { + public virtual int RefId { get; set; } + } + + public partial class HelloType + { + public virtual string Result { get; set; } + } + + public partial class HelloWithReturnResponse + { + public virtual string Result { get; set; } + } + + public partial class Poco + { + public virtual string Name { get; set; } + } + + public partial class SubType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } +} + + diff --git a/tests/CheckWeb/ServiceModels.tt b/tests/CheckWeb/ServiceModels.tt new file mode 100644 index 00000000000..0e21ae2c436 --- /dev/null +++ b/tests/CheckWeb/ServiceModels.tt @@ -0,0 +1,37 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ output extension=".cs" #> +<#= DownloadCSharpDtos("http://localhost:55799/types/csharp") #> +<#+ +public class CodegenOptions +{ + bool? MakePartial; + bool? MakeVirtual; + bool? MakeDataContractsExtensible; + bool? InitializeCollections; + bool? AddReturnMarker; + bool? AddDescriptionAsComments; + bool? AddDataContractAttributes; + bool? AddIndexesToDataMembers; + bool? AddResponseStatus; + int? AddImplicitVersion; + string AddDefaultXmlNamespace; +} +#> + +<#+ +public static string DownloadCSharpDtos(string baseUrl) { + var sb = new System.Text.StringBuilder(); + var fields = typeof(CodegenOptions).GetFields( + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var config = new CodegenOptions(); + foreach (var f in fields) { + var value = f.GetValue(config); + if (value == null) continue; + if (sb.Length > 0) sb.Append("&"); + sb.AppendFormat("{0}={1}", f.Name, value); + } + var qs = sb.ToString(); + if (qs.Length > 0) baseUrl += "?" + qs; + return new System.Net.WebClient().DownloadString(baseUrl); +} +#> \ No newline at end of file diff --git a/tests/CheckWeb/SwaggerTestService.cs b/tests/CheckWeb/SwaggerTestService.cs new file mode 100644 index 00000000000..cb9576e09c4 --- /dev/null +++ b/tests/CheckWeb/SwaggerTestService.cs @@ -0,0 +1,362 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.Serialization; +using Check.ServiceModel.Operations; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace CheckWeb +{ + public enum MyColor + { + Red, + Green, + Blue + } + + [Tag("TheTag")] + [Api("SwaggerTest Service Description")] + [ApiResponse(HttpStatusCode.BadRequest, "Your request was not understood")] + [ApiResponse(HttpStatusCode.InternalServerError, "Oops, something broke")] + [Route("/swagger", "GET", Summary = @"GET / Summary", Notes = "GET / Notes")] + [Route("/swagger/{Name}", "GET", Summary = @"GET Summary", Notes = "GET /Name Notes")] + [Route("/swagger/{Name}", "POST", Summary = @"POST Summary", Notes = "POST /Name Notes")] + [DataContract] + public class SwaggerTest + { + [ApiMember(Description = "Color Description", + ParameterType = "path", DataType = "string", IsRequired = true)] + [ApiAllowableValues("Name", typeof(MyColor))] //Enum + [DataMember] + public string Name { get; set; } + + [ApiMember] + [ApiAllowableValues("Color", typeof(MyColor))] //Enum + [DataMember] + public MyColor Color { get; set; } + + [ApiMember(Description = "Aliased Description", + DataType = "string", IsRequired = true)] + [DataMember(Name = "Aliased")] + public string Original { get; set; } + + [ApiMember(Description = "Not Aliased Description", + DataType = "string", IsRequired = true)] + [DataMember] + public string NotAliased { get; set; } + + [ApiMember(Description = "Format as password", DataType = "password")] + [DataMember] + public string Password { get; set; } + + [DataMember] + [ApiMember(IsRequired = false, AllowMultiple = true)] + public DateTime[] MyDateBetween { get; set; } + + [ApiMember(Description = "Nested model 1", DataType = "SwaggerNestedModel")] + [DataMember] + public SwaggerNestedModel NestedModel1 { get; set; } + + [ApiMember(Description = "Nested model 2", DataType = "SwaggerNestedModel2")] + [DataMember] + public SwaggerNestedModel2 NestedModel2 { get; set; } + } + + public class SwaggerNestedModel + { + [ApiMember(Description = "NestedProperty description")] + public bool NestedProperty { get; set; } + } + + public class SwaggerNestedModel2 + { + [ApiMember(Description = "NestedProperty2 description")] + public bool NestedProperty2 { get; set; } + + [ApiMember(Description = "MultipleValues description")] + [ApiAllowableValues("MultipleValues", new[] { "val1", "val2" })] + public string MultipleValues { get; set; } + + [ApiMember(Description = "TestRange description")] + [ApiAllowableValues("TestRange", 1, 10)] + public int TestRange { get; set; } + } + + public enum MyEnum { A, B, C } + + [Route("/swaggertest2", "POST")] + public class SwaggerTest2 + { + [ApiMember] + [ApiAllowableValues("MyEnumProperty", typeof(MyEnum))] + public MyEnum MyEnumProperty { get; set; } + + [IgnoreDataMember] + public string Ignored { get; set; } + + [ApiMember( + Name = "Token", + ParameterType = "header", + DataType = "string", + IsRequired = true)] + public string Token { get; set; } + } + + [Route("/swagger-complex", "POST")] + public class SwaggerComplex : IReturn + { + [ApiMember] + [DataMember] + [Description("IsRequired Description")] + public bool IsRequired { get; set; } + + [ApiMember(IsRequired = true)] + [DataMember] + public string[] ArrayString { get; set; } + + [ApiMember] + [DataMember] + public int[] ArrayInt { get; set; } + + [ApiMember] + [DataMember] + public List ListString { get; set; } + + [ApiMember] + [DataMember] + public List ListInt { get; set; } + + [ApiMember] + [DataMember] + public Dictionary DictionaryString { get; set; } + } + + public class SwaggerComplexResponse + { + [ApiMember] + [DataMember] + public bool IsRequired { get; set; } + + [ApiMember(IsRequired = true)] + [DataMember] + public string[] ArrayString { get; set; } + + [ApiMember] + [DataMember] + public int[] ArrayInt { get; set; } + + [ApiMember] + [DataMember] + public List ListString { get; set; } + + [ApiMember] + [DataMember] + public List ListInt { get; set; } + + [ApiMember] + [DataMember] + public Dictionary DictionaryString { get; set; } + } + + [Route("/swaggerpost/{Required1}", Verbs = "GET")] + [Route("/swaggerpost/{Required1}/{Optional1}", Verbs = "GET")] + [Route("/swaggerpost", Verbs = "POST")] + public class SwaggerPostTest : IReturn + { + [ApiMember(Verb = "POST")] + [ApiMember(Route = "/swaggerpost/{Required1}", Verb = "GET", ParameterType = "path")] + [ApiMember(Route = "/swaggerpost/{Required1}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Required1 { get; set; } + + [ApiMember(Verb = "POST")] + [ApiMember(Route = "/swaggerpost/{Required1}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Optional1 { get; set; } + } + + [Route("/swaggerpost2/{Required1}/{Required2}", Verbs = "GET")] + [Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verbs = "GET")] + [Route("/swaggerpost2", Verbs = "POST")] + public class SwaggerPostTest2 : IReturn + { + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}", Verb = "GET", ParameterType = "path")] + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Required1 { get; set; } + + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}", Verb = "GET", ParameterType = "path")] + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Required2 { get; set; } + + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Optional1 { get; set; } + } + + [Api("Api GET All")] + [Route("/swaggerexamples", "GET")] + public class GetSwaggerExamples : IReturn + { + public string Get { get; set; } + } + + [Api("Api POST")] + [Route("/swaggerexamples", "POST")] + public class PostSwaggerExamples : IReturn + { + public string Post { get; set; } + } + + [Api("Api GET Id")] + [Route("/swaggerexamples/{Id}", "GET")] + public class GetSwaggerExample : IReturn + { + public int Id { get; set; } + public string Get { get; set; } + } + + [Api("Api PUT Id")] + [Route("/swaggerexamples/{Id}", "PUT")] + public class PutSwaggerExample : IReturn + { + public int Id { get; set; } + public string Get { get; set; } + } + + [Route("/lists", "GET")] + public class GetLists : IReturn + { + public string Id { get; set; } + } + + [Route("/lists", "POST")] + [Exclude(Feature.Metadata)] + public class CreateList : IReturn + { + public string Id { get; set; } + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public sealed class CustomApiResponseAttribute : ApiResponseAttribute + { + private static int errCode = 402; + + public CustomApiResponseAttribute() + : base(++errCode, Guid.NewGuid().ToString()) {} + } + + [ApiResponse(400, "Code 1")] + [CustomApiResponse()] + [ApiResponse(402, "Code 2")] + [CustomApiResponse()] + [CustomApiResponse()] + [ApiResponse(401, "Code 3")] + [Route("/swagger/multiattrtest", Verbs = "POST", Summary = "Sample request")] + public sealed class SwaggerMultiApiResponseTest : IReturnVoid {} + + [Route("/stream-request")] + public class StreamRequest : IReturn + { + } + + public class StreamResponse + { + public Stream Stream { get; set; } + } + + public class Stream + { + public int Streamid { get; set; } + public string Description { get; set; } + public string Name { get; set; } + public string ProjectId { get; set; } + } + + [Route( + "/surveys/{surveyId}/sendouts/{sendoutId}/respondents", + HttpMethods.Post, + Summary = "Adding Respondents", + Notes = "Add a new Respondent with optional background data to a Sendout." + )] + //[Exclude(Feature.Metadata)] // hide from OpenAPI + //[RateLimitedPerUser] + public class AddRespondentRequest : IReturn + { + [ApiMember(Name = "surveyId", + Description = "Remarks: SurveyId of requested Survey.", + ParameterType = "path", + DataType = "integer", Format = "int32", + IsRequired = true + )] + public int surveyId { get; set; } + + [ApiMember(Name = "sendoutId", + Description = "Remarks: SendoutId of Sendout to which a respondent is added.", + ParameterType = "path", + DataType = "integer", + Format = "int32", + IsRequired = true + )] + public int sendoutId { get; set; } + + [ApiMember(Name = "contactDetails", + Description = "Remarks: Valid email address, SMS recipient or login identifier.", + ParameterType = "query", + DataType = "string", + IsRequired = false + )] + public string contactDetails { get; set; } + + [ApiMember(Name = "sendMail", + Description = "Remarks: Indicates whether Netigate should send the survey link to the respondent, or if you distribute it yourself.", + DataType = "boolean", + ParameterType = "query", + IsRequired = false + )] + public bool sendMail { get; set; } + + [ApiMember(Name = "backgroundData", + Description = "Remarks: Key = BGDataLabelId, Value = respondent's background data (not empty or null)", + ParameterType = "query", + //DataType = "object", + IsRequired = false + )] + public Dictionary backgroundData { get; set; } + } + + public class AddRespondentResponse + { + public int RespondentId { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public string SurveyURL { get; set; } + } + + public class SwaggerTestService : Service + { + public object Any(AddRespondentRequest request) => new AddRespondentResponse(); + public object Any(SwaggerTest request) => request; + + public object Post(SwaggerTest2 request) => request; + + public object Post(SwaggerComplex request) => request.ConvertTo(); + + public object Any(SwaggerPostTest request) => new HelloResponse { Result = request.Required1 }; + + public object Any(SwaggerPostTest2 request) => new HelloResponse { Result = request.Required1 }; + + public object Any(GetSwaggerExamples request) => request; + + public object Any(GetSwaggerExample request) => request; + + public object Any(PostSwaggerExamples request) => request; + + public object Any(PutSwaggerExample request) => request; + + public object Any(GetLists request) => request; + + public object Any(CreateList request) => request; + + public object Any(SwaggerMultiApiResponseTest request) => request; + +// public object Any(StreamRequest request) => new StreamResponse(); + } +} \ No newline at end of file diff --git a/tests/CheckWeb/Test.dtos.cs b/tests/CheckWeb/Test.dtos.cs new file mode 100644 index 00000000000..3be6417b8ac --- /dev/null +++ b/tests/CheckWeb/Test.dtos.cs @@ -0,0 +1,1930 @@ +/* Options: +Date: 2017-06-23 03:04:21 +Version: 4.512 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:55799 + +GlobalNamespace: dtos +//MakePartial: True +//MakeVirtual: True +//MakeInternal: False +//MakeDataContractsExtensible: False +//AddReturnMarker: True +//AddDescriptionAsComments: True +//AddDataContractAttributes: False +//AddIndexesToDataMembers: False +//AddGeneratedCodeAttributes: False +//AddResponseStatus: False +//AddImplicitVersion: +//InitializeCollections: True +//ExportValueTypes: False +//IncludeTypes: +//ExcludeTypes: +AddNamespaces: System.Net,Item=dtos.HelloWithNestedInheritance.Item +//AddDefaultXmlNamespace: http://schemas.servicestack.net/types +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.DataAnnotations; +using System.Net; +using Item=dtos.HelloWithNestedInheritance.Item; +using System.IO; +using dtos; + + +namespace dtos +{ + + [Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE")] + [Route("/api/acsprofiles/{profileId}")] + public partial class ACSProfile + : IReturn + { + public virtual string profileId { get; set; } + [Required] + [StringLength(20)] + public virtual string shortName { get; set; } + + [StringLength(60)] + public virtual string longName { get; set; } + + [StringLength(20)] + public virtual string regionId { get; set; } + + [StringLength(20)] + public virtual string groupId { get; set; } + + [StringLength(12)] + public virtual string deviceID { get; set; } + + public virtual DateTime lastUpdated { get; set; } + public virtual bool enabled { get; set; } + public virtual int Version { get; set; } + public virtual string SessionId { get; set; } + } + + public partial class acsprofileResponse + { + public virtual string profileId { get; set; } + } + + [Route("/anontype")] + public partial class AnonType + { + } + + public partial class BatchThrows + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class BatchThrowsAsync + : IReturn + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class BatchThrowsResponse + { + public virtual string Result { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/changerequest/{Id}")] + public partial class ChangeRequest + : IReturn + { + public virtual string Id { get; set; } + } + + public partial class ChangeRequestResponse + { + public virtual string ContentType { get; set; } + public virtual string Header { get; set; } + public virtual string QueryString { get; set; } + public virtual string Form { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/compress/{Path*}")] + public partial class CompressFile + { + public virtual string Path { get; set; } + } + + public partial class CustomRockstar + { + [AutoQueryViewerField(Title="Name")] + public virtual string FirstName { get; set; } + + [AutoQueryViewerField(HideInSummary=true)] + public virtual string LastName { get; set; } + + public virtual int? Age { get; set; } + [AutoQueryViewerField(Title="Album")] + public virtual string RockstarAlbumName { get; set; } + + [AutoQueryViewerField(Title="Genre")] + public virtual string RockstarGenreName { get; set; } + } + + public partial class CustomUserSession + : AuthUserSession + { + [DataMember] + public virtual string CustomName { get; set; } + + [DataMember] + public virtual string CustomInfo { get; set; } + } + + [Route("{PathInfo*}")] + public partial class FallbackRoute + { + public virtual string PathInfo { get; set; } + } + + [Route("/files/{Path*}")] + public partial class GetFile + { + public virtual string Path { get; set; } + } + + [Route("/Request1/", "GET")] + public partial class GetRequest1 + : IReturn>, IGet + { + } + + [Route("/Request3", "GET")] + public partial class GetRequest2 + : IReturn, IGet + { + } + + [Route("/timestamp", "GET")] + public partial class GetTimestamp + : IReturn + { + } + + public partial class GetUserSession + : IReturn + { + } + + [Route("/info/{Id}")] + public partial class Info + { + public virtual string Id { get; set; } + } + + [Route("/Routing/LeadPost.aspx")] + public partial class LegacyLeadPost + { + public virtual string LeadType { get; set; } + public virtual int MyId { get; set; } + } + + public partial class MetadataRequest + : IReturn + { + public virtual MetadataType MetadataType { get; set; } + } + + public partial class Movie + { + public Movie() + { + Genres = new List{}; + } + + public virtual int Id { get; set; } + public virtual string ImdbId { get; set; } + public virtual string Title { get; set; } + public virtual string Rating { get; set; } + public virtual decimal Score { get; set; } + public virtual string Director { get; set; } + public virtual DateTime ReleaseDate { get; set; } + public virtual string TagLine { get; set; } + public virtual List Genres { get; set; } + } + + [Route("/namedconnection")] + public partial class NamedConnection + { + public virtual string EmailAddresses { get; set; } + } + + public partial class NativeTypesTestService + { + + public partial class HelloInService + { + public virtual string Name { get; set; } + } + } + + public partial class NoRepeat + : IReturn + { + public virtual Guid Id { get; set; } + } + + public partial class NoRepeatResponse + { + public virtual Guid Id { get; set; } + } + + public partial class ObjectDesign + { + public virtual int Id { get; set; } + } + + public partial class ObjectDesignResponse + { + public virtual ObjectDesign data { get; set; } + } + + [Route("/code/object", "GET")] + public partial class ObjectId + : IReturn + { + public virtual string objectName { get; set; } + } + + public partial class PgRockstar + : Rockstar + { + } + + [AutoQueryViewer(Description="Use this option to search for Rockstars!", Title="Search for Rockstars")] + public partial class QueryCustomRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryCustomRockstarsFilter + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/querydata/rockstars")] + public partial class QueryDataRockstars + : QueryData, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/query-custom/rockstars")] + public partial class QueryFieldRockstars + : QueryDb, IReturn> + { + public QueryFieldRockstars() + { + FirstNames = new string[]{}; + FirstNameBetween = new string[]{}; + FirstNameContainsMulti = new string[]{}; + } + + public virtual string FirstName { get; set; } + public virtual string[] FirstNames { get; set; } + public virtual int? Age { get; set; } + public virtual string FirstNameCaseInsensitive { get; set; } + public virtual string FirstNameStartsWith { get; set; } + public virtual string LastNameEndsWith { get; set; } + public virtual string[] FirstNameBetween { get; set; } + public virtual string OrLastName { get; set; } + public virtual string[] FirstNameContainsMulti { get; set; } + } + + public partial class QueryFieldRockstarsDynamic + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryGetRockstars + : QueryDb, IReturn> + { + public QueryGetRockstars() + { + Ids = new int[]{}; + Ages = new List{}; + FirstNames = new List{}; + IdsBetween = new int[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual List Ages { get; set; } + public virtual List FirstNames { get; set; } + public virtual int[] IdsBetween { get; set; } + } + + public partial class QueryGetRockstarsDynamic + : QueryDb, IReturn> + { + } + + [Route("/movies")] + public partial class QueryMovies + : QueryDb, IReturn> + { + public QueryMovies() + { + Ids = new int[]{}; + ImdbIds = new string[]{}; + Ratings = new string[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual string[] ImdbIds { get; set; } + public virtual string[] Ratings { get; set; } + } + + [Route("/OrRockstars")] + public partial class QueryOrRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + public virtual string FirstName { get; set; } + } + + public partial class QueryOverridedCustomRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryOverridedRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/pgsql/pgrockstars")] + public partial class QueryPostgresPgRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/pgsql/rockstars")] + public partial class QueryPostgresRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/query/requestlogs")] + [Route("/query/requestlogs/{Date}")] + public partial class QueryRequestLogs + : QueryData, IReturn> + { + public virtual DateTime? Date { get; set; } + public virtual bool ViewErrors { get; set; } + } + + [Route("/customrockstars")] + public partial class QueryRockstarAlbums + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + public virtual string RockstarAlbumName { get; set; } + } + + public partial class QueryRockstarAlbumsImplicit + : QueryDb, IReturn> + { + } + + public partial class QueryRockstarAlbumsLeftJoin + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + public virtual string AlbumName { get; set; } + } + + [Route("/query/rockstars")] + public partial class QueryRockstars + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryRockstarsConventions + : QueryDb, IReturn> + { + public QueryRockstarsConventions() + { + Ids = new int[]{}; + } + + public virtual int[] Ids { get; set; } + public virtual int? AgeOlderThan { get; set; } + public virtual int? AgeGreaterThanOrEqualTo { get; set; } + public virtual int? AgeGreaterThan { get; set; } + public virtual int? GreaterThanAge { get; set; } + public virtual string FirstNameStartsWith { get; set; } + public virtual string LastNameEndsWith { get; set; } + public virtual string LastNameContains { get; set; } + public virtual string RockstarAlbumNameContains { get; set; } + public virtual int? RockstarIdAfter { get; set; } + public virtual int? RockstarIdOnOrAfter { get; set; } + } + + public partial class QueryRockstarsFilter + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryRockstarsIFilter + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + [Route("/query/rockstar-references")] + public partial class QueryRockstarsWithReferences + : QueryDb, IReturn> + { + public virtual int? Age { get; set; } + } + + public partial class QueryUnknownRockstars + : QueryDb, IReturn> + { + public virtual int UnknownInt { get; set; } + public virtual string UnknownProperty { get; set; } + } + + public partial class ReturnedDto + { + public virtual int Id { get; set; } + } + + public partial class RockstarAlbum + { + public virtual int Id { get; set; } + public virtual int RockstarId { get; set; } + public virtual string Name { get; set; } + } + + public partial class RockstarReference + { + public RockstarReference() + { + Albums = new List{}; + } + + public virtual int Id { get; set; } + public virtual string FirstName { get; set; } + public virtual string LastName { get; set; } + public virtual int? Age { get; set; } + public virtual List Albums { get; set; } + } + + [Route("/movies/search")] + public partial class SearchMovies + : QueryDb, IReturn> + { + } + + public partial class StreamMovies + : QueryDb, IReturn> + { + public StreamMovies() + { + Ratings = new string[]{}; + } + + public virtual string[] Ratings { get; set; } + } + + [Route("/test/errorview")] + public partial class TestErrorView + { + public virtual string Id { get; set; } + } + + [Route("/testexecproc")] + public partial class TestExecProc + { + } + + public partial class TestMiniverView + { + } + + public partial class TimestampData + { + public virtual long Timestamp { get; set; } + } + + public partial class TodayErrorLogs + : QueryData, IReturn> + { + } + + public partial class TodayLogs + : QueryData, IReturn> + { + } + + public partial class YesterdayErrorLogs + : QueryData, IReturn> + { + } + + public partial class YesterdayLogs + : QueryData, IReturn> + { + } + + [Route("/alwaysthrows")] + public partial class AlwaysThrows + : IReturn + { + } + + [Route("/alwaysthrowsfilterattribute")] + public partial class AlwaysThrowsFilterAttribute + : IReturn + { + } + + [Route("/alwaysthrowsglobalfilter")] + public partial class AlwaysThrowsGlobalFilter + : IReturn + { + } + + public partial class AsyncTest + : IReturn + { + } + + public partial class CachedEcho + : IReturn + { + public virtual bool Reload { get; set; } + public virtual string Sentence { get; set; } + } + + public partial class CustomFieldHttpError + : IReturn + { + } + + public partial class CustomFieldHttpErrorResponse + { + public virtual string Custom { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class CustomHttpError + : IReturn + { + public virtual int StatusCode { get; set; } + public virtual string StatusDescription { get; set; } + } + + public partial class CustomHttpErrorResponse + { + public virtual string Custom { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/dynamically/registered/{Name}")] + public partial class DynamicallyRegistered + { + public virtual string Name { get; set; } + } + + public partial class Echo + { + public virtual string Sentence { get; set; } + } + + /// + ///Echoes a sentence + /// + [Route("/echoes", "POST")] + [Api(Description="Echoes a sentence")] + public partial class Echoes + : IReturn + { + /// + ///The sentence to echo. + /// + [ApiMember(DataType="string", Description="The sentence to echo.", IsRequired=true, Name="Sentence", ParameterType="form")] + public virtual string Sentence { get; set; } + } + + [Route("/example", "GET")] + [DataContract] + public partial class GetExample + : IReturn + { + } + + [DataContract] + public partial class GetExampleResponse + { + [DataMember(Order=1)] + public virtual ResponseStatus ResponseStatus { get; set; } + + [DataMember(Order=2)] + [ApiMember] + public virtual MenuExample MenuExample1 { get; set; } + } + + public partial class Issue221Base + { + public virtual T Id { get; set; } + } + + public partial class Issue221Long + : Issue221Base + { + } + + [DataContract] + public partial class MenuExample + { + [DataMember(Order=1)] + [ApiMember] + public virtual MenuItemExample MenuItemExample1 { get; set; } + } + + public partial class MenuItemExample + { + [DataMember(Order=1)] + [ApiMember] + public virtual string Name1 { get; set; } + + public virtual MenuItemExampleItem MenuItemExampleItem { get; set; } + } + + public partial class MenuItemExampleItem + { + [DataMember(Order=1)] + [ApiMember] + public virtual string Name1 { get; set; } + } + + public partial class MetadataTest + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class MetadataTestChild + { + public MetadataTestChild() + { + Results = new List{}; + } + + public virtual string Name { get; set; } + public virtual List Results { get; set; } + } + + public partial class MetadataTestNestedChild + { + public virtual string Name { get; set; } + } + + public partial class MetadataTestResponse + { + public MetadataTestResponse() + { + Results = new List{}; + } + + public virtual int Id { get; set; } + public virtual List Results { get; set; } + } + + public partial class OnlyDefinedInGenericType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class OnlyDefinedInGenericTypeFrom + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class OnlyDefinedInGenericTypeInto + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class QueryPocoBase + : QueryDb, IReturn> + { + public virtual int Id { get; set; } + } + + public partial class QueryPocoIntoBase + : QueryDb, IReturn> + { + public virtual int Id { get; set; } + } + + [Route("/return404")] + public partial class Return404 + { + } + + [Route("/return404result")] + public partial class Return404Result + { + } + + [Route("/return/bytes")] + public partial class ReturnBytes + : IReturn + { + public ReturnBytes() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/httpwebresponse")] + public partial class ReturnHttpWebResponse + : IReturn + { + public ReturnHttpWebResponse() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/stream")] + public partial class ReturnStream + : IReturn + { + public ReturnStream() + { + Data = new byte[]{}; + } + + public virtual byte[] Data { get; set; } + } + + [Route("/return/string")] + public partial class ReturnString + : IReturn + { + public virtual string Data { get; set; } + } + + public partial class Rockstar + { + /// + ///Идентификатор + /// + public virtual int Id { get; set; } + /// + ///Фамилия + /// + public virtual string FirstName { get; set; } + /// + ///Имя + /// + public virtual string LastName { get; set; } + /// + ///Возраст + /// + public virtual int? Age { get; set; } + } + + [Route("/{Version}/userdata", "GET")] + public partial class SwaggerVersionTest + { + public virtual string Version { get; set; } + } + + [Route("/throw404")] + [Route("/throw404/{Message}")] + public partial class Throw404 + { + public virtual string Message { get; set; } + } + + [Route("/throwhttperror/{Status}")] + public partial class ThrowHttpError + : IReturn + { + public virtual int Status { get; set; } + public virtual string Message { get; set; } + } + + public partial class ThrowHttpErrorResponse + { + } + + [Route("/throw/{Type}")] + public partial class ThrowType + : IReturn + { + public virtual string Type { get; set; } + public virtual string Message { get; set; } + } + + public partial class ThrowTypeResponse + { + public virtual ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throwvalidation")] + public partial class ThrowValidation + : IReturn + { + public virtual int Age { get; set; } + public virtual string Required { get; set; } + public virtual string Email { get; set; } + } + + public partial class ThrowValidationResponse + { + public virtual int Age { get; set; } + public virtual string Required { get; set; } + public virtual string Email { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + + /// + ///AllowedAttributes Description + /// + [Route("/allowed-attributes", "GET")] + [Api(Description="AllowedAttributes Description")] + [ApiResponse(400, "Your request was not understood")] + [DataContract] + public partial class AllowedAttributes + { + [DataMember] + [Required] + public virtual int Id { get; set; } + + /// + ///Range Description + /// + [DataMember(Name="Aliased")] + [ApiMember(DataType="double", Description="Range Description", IsRequired=true, ParameterType="path")] + public virtual double Range { get; set; } + } + + public partial class ArrayResult + { + public virtual string Result { get; set; } + } + + [Flags] + public enum EnumFlags + { + Value1 = 1, + Value2 = 2, + Value3 = 4, + } + + public enum EnumType + { + Value1, + Value2, + } + + public enum EnumWithValues + { + Value1 = 1, + Value2 = 2, + } + + [Route("/hello")] + [Route("/hello/{Name}")] + public partial class Hello + : IReturn + { + [Required] + public virtual string Name { get; set; } + + public virtual string Title { get; set; } + } + + /// + ///Description for HelloACodeGenTest + /// + public partial class HelloACodeGenTest + : IReturn + { + public HelloACodeGenTest() + { + SecondFields = new List{}; + } + + /// + ///Description for FirstField + /// + public virtual int FirstField { get; set; } + public virtual List SecondFields { get; set; } + } + + [DataContract] + public partial class HelloACodeGenTestResponse + { + /// + ///Description for FirstResult + /// + [DataMember] + public virtual int FirstResult { get; set; } + + /// + ///Description for SecondResult + /// + [DataMember] + [ApiMember(Description="Description for SecondResult")] + public virtual int SecondResult { get; set; } + } + + public partial class HelloAllTypes + : IReturn + { + public virtual string Name { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + public partial class HelloAllTypesResponse + { + public virtual string Result { get; set; } + public virtual AllTypes AllTypes { get; set; } + public virtual AllCollectionTypes AllCollectionTypes { get; set; } + } + + /// + ///Description on HelloAll type + /// + [DataContract] + public partial class HelloAnnotated + : IReturn + { + [DataMember] + public virtual string Name { get; set; } + } + + /// + ///Description on HelloAllResponse type + /// + [DataContract] + public partial class HelloAnnotatedResponse + { + [DataMember] + public virtual string Result { get; set; } + } + + public partial class HelloArray + : IReturn + { + public HelloArray() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + public partial class HelloBase + { + public HelloBase() + { + Items = new List{}; + Counts = new List{}; + } + + public virtual List Items { get; set; } + public virtual List Counts { get; set; } + } + + public partial class HelloExisting + : IReturn + { + public HelloExisting() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + public partial class HelloExistingResponse + { + public HelloExistingResponse() + { + ArrayResults = new ArrayResult[]{}; + ListResults = new List{}; + } + + public virtual HelloList HelloList { get; set; } + public virtual HelloArray HelloArray { get; set; } + public virtual ArrayResult[] ArrayResults { get; set; } + public virtual List ListResults { get; set; } + } + + public partial class HelloList + : IReturn> + { + public HelloList() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + /// + ///Multi Line Class + /// + [Api(Description="Multi Line Class")] + public partial class HelloMultiline + { + /// + ///Multi Line Property + /// + [ApiMember(Description="Multi Line Property")] + public virtual string Overflow { get; set; } + } + + public partial class HelloResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloReturnList + : IReturn> + { + public HelloReturnList() + { + Names = new List{}; + } + + public virtual List Names { get; set; } + } + + public partial class HelloString + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloVoid + : IReturnVoid + { + public virtual string Name { get; set; } + } + + public partial class HelloWithAlternateReturnResponse + : HelloWithReturnResponse + { + public virtual string AltResult { get; set; } + } + + [DataContract] + public partial class HelloWithDataContract + : IReturn + { + [DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Name { get; set; } + + [DataMember(Name="id", Order=2, EmitDefaultValue=false)] + public virtual int Id { get; set; } + } + + [DataContract] + public partial class HelloWithDataContractResponse + { + [DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false)] + public virtual string Result { get; set; } + } + + /// + ///Description on HelloWithDescription type + /// + public partial class HelloWithDescription + : IReturn + { + public virtual string Name { get; set; } + } + + /// + ///Description on HelloWithDescriptionResponse type + /// + public partial class HelloWithDescriptionResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithEnum + { + public virtual EnumType EnumProp { get; set; } + public virtual EnumWithValues EnumWithValues { get; set; } + public virtual EnumType? NullableEnumProp { get; set; } + public virtual EnumFlags EnumFlags { get; set; } + } + + public partial class HelloWithGenericInheritance + : HelloBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithGenericInheritance2 + : HelloBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithInheritance + : HelloBase, IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithInheritanceResponse + : HelloResponseBase + { + public virtual string Result { get; set; } + } + + public partial class HelloWithListInheritance + : List + { + } + + public partial class HelloWithNestedClass + : IReturn + { + public virtual string Name { get; set; } + public virtual HelloWithNestedClass.NestedClass NestedClassProp { get; set; } + + public partial class NestedClass + { + public virtual string Value { get; set; } + } + } + + public partial class HelloWithNestedInheritance + : HelloBase + { + + public partial class Item + { + public virtual string Value { get; set; } + } + } + + public partial class HelloWithReturn + : IReturn + { + public virtual string Name { get; set; } + } + + [Route("/helloroute")] + public partial class HelloWithRoute + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithRouteResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithType + : IReturn + { + public virtual string Name { get; set; } + } + + public partial class HelloWithTypeResponse + { + public virtual HelloType Result { get; set; } + } + + public partial class InheritedItem + { + public virtual string Name { get; set; } + } + + public partial class ListResult + { + public virtual string Result { get; set; } + } + + public partial class OnlyInReturnListArg + { + public virtual string Result { get; set; } + } + + public partial class RestrictedAttributes + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual Hello Hello { get; set; } + } + + public partial class AllCollectionTypes + { + public AllCollectionTypes() + { + IntArray = new int[]{}; + IntList = new List{}; + StringArray = new string[]{}; + StringList = new List{}; + PocoArray = new Poco[]{}; + PocoList = new List{}; + NullableByteArray = new Nullable[]{}; + NullableByteList = new List>{}; + NullableDateTimeArray = new Nullable[]{}; + NullableDateTimeList = new List>{}; + PocoLookup = new Dictionary>{}; + PocoLookupMap = new Dictionary>>{}; + } + + public virtual int[] IntArray { get; set; } + public virtual List IntList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual List StringList { get; set; } + public virtual Poco[] PocoArray { get; set; } + public virtual List PocoList { get; set; } + public virtual Nullable[] NullableByteArray { get; set; } + public virtual List> NullableByteList { get; set; } + public virtual Nullable[] NullableDateTimeArray { get; set; } + public virtual List> NullableDateTimeList { get; set; } + public virtual Dictionary> PocoLookup { get; set; } + public virtual Dictionary>> PocoLookupMap { get; set; } + } + + public partial class AllTypes + : IReturn + { + public AllTypes() + { + StringList = new List{}; + StringArray = new string[]{}; + StringMap = new Dictionary{}; + IntStringMap = new Dictionary{}; + } + + public virtual int Id { get; set; } + public virtual int? NullableId { get; set; } + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual Guid Guid { get; set; } + public virtual Char Char { get; set; } + public virtual KeyValuePair KeyValuePair { get; set; } + public virtual DateTime? NullableDateTime { get; set; } + public virtual TimeSpan? NullableTimeSpan { get; set; } + public virtual List StringList { get; set; } + public virtual string[] StringArray { get; set; } + public virtual Dictionary StringMap { get; set; } + public virtual Dictionary IntStringMap { get; set; } + public virtual SubType SubType { get; set; } + public virtual string Point { get; set; } + [DataMember(Name="aliasedName")] + public virtual string OriginalName { get; set; } + } + + public partial class EmptyClass + { + } + + public partial class EnumRequest + : IReturn, IPut + { + public virtual ScopeType Operator { get; set; } + } + + public partial class EnumResponse + { + public virtual ScopeType Operator { get; set; } + } + + public partial class ExcludeTest1 + : IReturn + { + } + + public partial class ExcludeTest2 + : IReturn + { + public virtual ExcludeTestNested ExcludeTestNested { get; set; } + } + + public partial class ExcludeTestNested + { + public virtual int Id { get; set; } + } + + public partial class HelloBase + { + public virtual int Id { get; set; } + } + + public partial class HelloBuiltin + { + public virtual DayOfWeek DayOfWeek { get; set; } + } + + public partial class HelloDelete + : IReturn, IDelete + { + public virtual int Id { get; set; } + } + + public partial class HelloDictionary + : IReturn> + { + public virtual string Key { get; set; } + public virtual string Value { get; set; } + } + + public partial class HelloGet + : IReturn, IGet + { + public virtual int Id { get; set; } + } + + public partial class HelloInnerTypes + : IReturn + { + } + + public partial class HelloInnerTypesResponse + { + public HelloInnerTypesResponse() + { + InnerList = new List{}; + } + + public virtual TypesGroup.InnerType InnerType { get; set; } + public virtual TypesGroup.InnerEnum InnerEnum { get; set; } + public virtual List InnerList { get; set; } + } + + public partial class HelloInterface + { + public virtual IPoco Poco { get; set; } + public virtual IEmptyInterface EmptyInterface { get; set; } + public virtual EmptyClass EmptyClass { get; set; } + public virtual string Value { get; set; } + } + + public partial class HelloPatch + : IReturn, IPatch + { + public virtual int Id { get; set; } + } + + public partial class HelloPost + : HelloBase, IReturn, IPost + { + } + + public partial class HelloPut + : IReturn, IPut + { + public virtual int Id { get; set; } + } + + public partial class HelloReserved + { + public virtual string Class { get; set; } + public virtual string Type { get; set; } + public virtual string extension { get; set; } + } + + public partial class HelloResponseBase + { + public virtual int RefId { get; set; } + } + + public partial class HelloReturnVoid + : IReturnVoid + { + public virtual int Id { get; set; } + } + + public partial class HelloSession + : IReturn + { + } + + public partial class HelloSessionResponse + { + public virtual AuthUserSession Result { get; set; } + } + + public partial class HelloStruct + : IReturn + { + public virtual string Point { get; set; } + public virtual string NullablePoint { get; set; } + } + + public partial class HelloTuple + : IReturn + { + public HelloTuple() + { + Tuples2 = new List>{}; + Tuples3 = new List>{}; + } + + public virtual Tuple Tuple2 { get; set; } + public virtual Tuple Tuple3 { get; set; } + public virtual List> Tuples2 { get; set; } + public virtual List> Tuples3 { get; set; } + } + + public partial class HelloType + { + public virtual string Result { get; set; } + } + + public partial class HelloVerbResponse + { + public virtual string Result { get; set; } + } + + public partial class HelloWithReturnResponse + { + public virtual string Result { get; set; } + } + + public partial interface IEmptyInterface + { + } + + public partial interface IPoco + { + string Name { get; set; } + } + + public partial class Poco + { + public virtual string Name { get; set; } + } + + [DataContract] + public partial class QueryResponseTemplate + { + public QueryResponseTemplate() + { + Results = new List{}; + Meta = new Dictionary{}; + } + + [DataMember(Order=1)] + public virtual int Offset { get; set; } + + [DataMember(Order=2)] + public virtual int Total { get; set; } + + [DataMember(Order=3)] + public virtual List Results { get; set; } + + [DataMember(Order=4)] + public virtual Dictionary Meta { get; set; } + + [DataMember(Order=5)] + public virtual ResponseStatus ResponseStatus { get; set; } + } + + public partial class QueryTemplate + : IReturn> + { + } + + public partial class Request1 + : IReturn + { + public virtual TypeA Test { get; set; } + } + + public partial class Request1Response + { + public virtual TypeA Test { get; set; } + } + + public partial class Request2 + : IReturn + { + public virtual TypeA Test { get; set; } + } + + public partial class Request2Response + { + public virtual TypeA Test { get; set; } + } + + public partial class RestrictInternal + : IReturn + { + public virtual int Id { get; set; } + } + + public partial class RestrictLocalhost + : IReturn + { + public virtual int Id { get; set; } + } + + [DataContract] + public enum ScopeType + { + Global = 1, + Sale = 2, + } + + public partial class SubType + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class TypeA + { + public TypeA() + { + Bar = new List{}; + } + + public virtual List Bar { get; set; } + } + + public partial class TypeB + { + public virtual string Foo { get; set; } + } + + public partial class TypesGroup + { + + public partial class InnerType + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } + + public partial class InnerTypeItem + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } + + public enum InnerEnum + { + Foo, + Bar, + Baz, + } + } + + [Route("/lists", "GET")] + public partial class GetLists + : IReturn + { + public virtual string Id { get; set; } + } + + /// + ///Api GET Id + /// + [Route("/swaggerexamples/{Id}", "GET")] + [Api(Description="Api GET Id")] + public partial class GetSwaggerExample + : IReturn + { + public virtual int Id { get; set; } + public virtual string Get { get; set; } + } + + /// + ///Api GET All + /// + [Route("/swaggerexamples", "GET")] + [Api(Description="Api GET All")] + public partial class GetSwaggerExamples + : IReturn + { + public virtual string Get { get; set; } + } + + [Route("/index")] + public partial class IndexPage + { + public virtual string PathInfo { get; set; } + } + + public enum MyColor + { + Red, + Green, + Blue, + } + + public enum MyEnum + { + A, + B, + C, + } + + /// + ///Api POST + /// + [Route("/swaggerexamples", "POST")] + [Api(Description="Api POST")] + public partial class PostSwaggerExamples + : IReturn + { + public virtual string Post { get; set; } + } + + /// + ///Api PUT Id + /// + [Route("/swaggerexamples/{Id}", "PUT")] + [Api(Description="Api PUT Id")] + public partial class PutSwaggerExample + : IReturn + { + public virtual int Id { get; set; } + public virtual string Get { get; set; } + } + + [Route("/swagger-complex", "POST")] + public partial class SwaggerComplex + : IReturn + { + public SwaggerComplex() + { + ArrayString = new string[]{}; + ArrayInt = new int[]{}; + ListString = new List{}; + ListInt = new List{}; + DictionaryString = new Dictionary{}; + } + + [DataMember] + [ApiMember] + public virtual bool IsRequired { get; set; } + + [DataMember] + [ApiMember(IsRequired=true)] + public virtual string[] ArrayString { get; set; } + + [DataMember] + [ApiMember] + public virtual int[] ArrayInt { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListString { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListInt { get; set; } + + [DataMember] + [ApiMember] + public virtual Dictionary DictionaryString { get; set; } + } + + public partial class SwaggerComplexResponse + { + public SwaggerComplexResponse() + { + ArrayString = new string[]{}; + ArrayInt = new int[]{}; + ListString = new List{}; + ListInt = new List{}; + DictionaryString = new Dictionary{}; + } + + [DataMember] + [ApiMember] + public virtual bool IsRequired { get; set; } + + [DataMember] + [ApiMember(IsRequired=true)] + public virtual string[] ArrayString { get; set; } + + [DataMember] + [ApiMember] + public virtual int[] ArrayInt { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListString { get; set; } + + [DataMember] + [ApiMember] + public virtual List ListInt { get; set; } + + [DataMember] + [ApiMember] + public virtual Dictionary DictionaryString { get; set; } + } + + [Route("/swagger/multiattrtest", "POST")] + [ApiResponse(400, "Code 1")] + [ApiResponse(402, "Code 2")] + [ApiResponse(401, "Code 3")] + public partial class SwaggerMultiApiResponseTest + : IReturnVoid + { + } + + public partial class SwaggerNestedModel + { + /// + ///NestedProperty description + /// + [ApiMember(Description="NestedProperty description")] + public virtual bool NestedProperty { get; set; } + } + + public partial class SwaggerNestedModel2 + { + /// + ///NestedProperty2 description + /// + [ApiMember(Description="NestedProperty2 description")] + public virtual bool NestedProperty2 { get; set; } + + /// + ///MultipleValues description + /// + [ApiMember(Description="MultipleValues description")] + public virtual string MultipleValues { get; set; } + + /// + ///TestRange description + /// + [ApiMember(Description="TestRange description")] + public virtual int TestRange { get; set; } + } + + [Route("/swaggerpost/{Required1}", "GET")] + [Route("/swaggerpost/{Required1}/{Optional1}", "GET")] + [Route("/swaggerpost", "POST")] + public partial class SwaggerPostTest + : IReturn + { + [ApiMember(Verb="POST")] + [ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}", Verb="GET")] + [ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET")] + public virtual string Required1 { get; set; } + + [ApiMember(Verb="POST")] + [ApiMember(ParameterType="path", Route="/swaggerpost/{Required1}/{Optional1}", Verb="GET")] + public virtual string Optional1 { get; set; } + } + + [Route("/swaggerpost2/{Required1}/{Required2}", "GET")] + [Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", "GET")] + [Route("/swaggerpost2", "POST")] + public partial class SwaggerPostTest2 + : IReturn + { + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET")] + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET")] + public virtual string Required1 { get; set; } + + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}", Verb="GET")] + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET")] + public virtual string Required2 { get; set; } + + [ApiMember(ParameterType="path", Route="/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb="GET")] + public virtual string Optional1 { get; set; } + } + + /// + ///SwaggerTest Service Description + /// + [Route("/swagger", "GET")] + [Route("/swagger/{Name}", "GET")] + [Route("/swagger/{Name}", "POST")] + [Api(Description="SwaggerTest Service Description")] + [ApiResponse(400, "Your request was not understood")] + [ApiResponse(500, "Oops, something broke")] + [DataContract] + public partial class SwaggerTest + { + public SwaggerTest() + { + MyDateBetween = new DateTime[]{}; + } + + /// + ///Color Description + /// + [DataMember] + [ApiMember(DataType="string", Description="Color Description", IsRequired=true, ParameterType="path")] + public virtual string Name { get; set; } + + [DataMember] + [ApiMember] + public virtual MyColor Color { get; set; } + + /// + ///Aliased Description + /// + [DataMember(Name="Aliased")] + [ApiMember(DataType="string", Description="Aliased Description", IsRequired=true)] + public virtual string Original { get; set; } + + /// + ///Not Aliased Description + /// + [DataMember] + [ApiMember(DataType="string", Description="Not Aliased Description", IsRequired=true)] + public virtual string NotAliased { get; set; } + + /// + ///Format as password + /// + [DataMember] + [ApiMember(DataType="password", Description="Format as password")] + public virtual string Password { get; set; } + + [DataMember] + [ApiMember(AllowMultiple=true)] + public virtual DateTime[] MyDateBetween { get; set; } + + /// + ///Nested model 1 + /// + [DataMember] + [ApiMember(DataType="SwaggerNestedModel", Description="Nested model 1")] + public virtual SwaggerNestedModel NestedModel1 { get; set; } + + /// + ///Nested model 2 + /// + [DataMember] + [ApiMember(DataType="SwaggerNestedModel2", Description="Nested model 2")] + public virtual SwaggerNestedModel2 NestedModel2 { get; set; } + } + + [Route("/swaggertest2", "POST")] + public partial class SwaggerTest2 + { + [ApiMember] + public virtual MyEnum MyEnumProperty { get; set; } + + [ApiMember(DataType="string", IsRequired=true, Name="Token", ParameterType="header")] + public virtual string Token { get; set; } + } + + [Route("/test/html")] + public partial class TestHtml + { + public virtual string Name { get; set; } + } +} + diff --git a/tests/CheckWeb/Test.dtos.d.ts b/tests/CheckWeb/Test.dtos.d.ts new file mode 100644 index 00000000000..e83efc3a11e --- /dev/null +++ b/tests/CheckWeb/Test.dtos.d.ts @@ -0,0 +1,915 @@ +/* Options: +Date: 2014-12-08 15:41:51 +Version: 1 +BaseUrl: http://localhost:55799 + +//GlobalNamespace: +//MakePropertiesOptional: True +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +*/ + +declare module Check.ServiceModel +{ + + interface IReturnVoid + { + } + + interface IReturn + { + } + + interface QueryBase_1 extends QueryBase + { + } + + interface Rockstar + { + id?:number; + firstName?:string; + lastName?:string; + age?:number; + } + + // @DataContract + interface ResponseStatus + { + // @DataMember(Order=1) + errorCode?:string; + + // @DataMember(Order=2) + message?:string; + + // @DataMember(Order=3) + stackTrace?:string; + + // @DataMember(Order=4) + errors?:ResponseError[]; + } + + interface MetadataTestChild + { + name?:string; + results?:MetadataTestNestedChild[]; + } + + interface NestedClass + { + value?:string; + } + + enum EnumType + { + value1, + value2, + } + + // @Flags() + enum EnumFlags + { + value1 = 1, + value2 = 2, + value3 = 4, + } + + interface AllTypes + { + id?:number; + nullableId?:number; + byte?:number; + short?:number; + int?:number; + long?:number; + uShort?:number; + uInt?:number; + uLong?:number; + float?:number; + double?:number; + decimal?:number; + string?:string; + dateTime?:string; + timeSpan?:string; + nullableDateTime?:string; + nullableTimeSpan?:string; + stringList?:string[]; + stringArray?:string[]; + stringMap?:{ [index:string]: string; }; + intStringMap?:{ [index:number]: string; }; + subType?:SubType; + } + + interface AllCollectionTypes + { + intArray?:number[]; + intList?:number[]; + stringArray?:string[]; + stringList?:string[]; + pocoArray?:Poco[]; + pocoList?:Poco[]; + } + + interface HelloBase + { + id?:number; + } + + interface HelloResponseBase + { + refId?:number; + } + + interface Poco + { + name?:string; + } + + interface HelloBase_1 + { + items?:T[]; + counts?:number[]; + } + + interface Item + { + value?:string; + } + + interface InheritedItem + { + name?:string; + } + + interface HelloWithReturnResponse + { + result?:string; + } + + interface HelloType + { + result?:string; + } + + // @DataContract + interface AuthUserSession + { + // @DataMember(Order=1) + referrerUrl?:string; + + // @DataMember(Order=2) + id?:string; + + // @DataMember(Order=3) + userAuthId?:string; + + // @DataMember(Order=4) + userAuthName?:string; + + // @DataMember(Order=5) + userName?:string; + + // @DataMember(Order=6) + twitterUserId?:string; + + // @DataMember(Order=7) + twitterScreenName?:string; + + // @DataMember(Order=8) + facebookUserId?:string; + + // @DataMember(Order=9) + facebookUserName?:string; + + // @DataMember(Order=10) + firstName?:string; + + // @DataMember(Order=11) + lastName?:string; + + // @DataMember(Order=12) + displayName?:string; + + // @DataMember(Order=13) + company?:string; + + // @DataMember(Order=14) + email?:string; + + // @DataMember(Order=15) + primaryEmail?:string; + + // @DataMember(Order=16) + phoneNumber?:string; + + // @DataMember(Order=17) + birthDate?:string; + + // @DataMember(Order=18) + birthDateRaw?:string; + + // @DataMember(Order=19) + address?:string; + + // @DataMember(Order=20) + address2?:string; + + // @DataMember(Order=21) + city?:string; + + // @DataMember(Order=22) + state?:string; + + // @DataMember(Order=23) + country?:string; + + // @DataMember(Order=24) + culture?:string; + + // @DataMember(Order=25) + fullName?:string; + + // @DataMember(Order=26) + gender?:string; + + // @DataMember(Order=27) + language?:string; + + // @DataMember(Order=28) + mailAddress?:string; + + // @DataMember(Order=29) + nickname?:string; + + // @DataMember(Order=30) + postalCode?:string; + + // @DataMember(Order=31) + timeZone?:string; + + // @DataMember(Order=32) + requestTokenSecret?:string; + + // @DataMember(Order=33) + createdAt?:string; + + // @DataMember(Order=34) + lastModified?:string; + + // @DataMember(Order=35) + providerOAuthAccess?:IAuthTokens[]; + + // @DataMember(Order=36) + roles?:string[]; + + // @DataMember(Order=37) + permissions?:string[]; + + // @DataMember(Order=38) + isAuthenticated?:boolean; + + // @DataMember(Order=39) + sequence?:string; + + // @DataMember(Order=40) + tag?:number; + } + + interface IPoco + { + name?:string; + } + + interface IEmptyInterface + { + } + + interface EmptyClass + { + } + + // @DataContract + interface RestService + { + // @DataMember(Name="path") + path?:string; + + // @DataMember(Name="description") + description?:string; + } + + interface QueryBase_2 extends QueryBase + { + } + + interface CustomRockstar + { + firstName?:string; + lastName?:string; + age?:number; + rockstarAlbumName?:string; + } + + interface Movie + { + id?:number; + imdbId?:string; + title?:string; + rating?:string; + score?:number; + director?:string; + releaseDate?:string; + tagLine?:string; + genres?:string[]; + } + + interface RockstarReference + { + id?:number; + firstName?:string; + lastName?:string; + age?:number; + albums?:RockstarAlbum[]; + } + + interface QueryBase + { + // @DataMember(Order=1) + skip?:number; + + // @DataMember(Order=2) + take?:number; + + // @DataMember(Order=3) + orderBy?:string; + + // @DataMember(Order=4) + orderByDesc?:string; + } + + // @DataContract + interface ResponseError + { + // @DataMember(Order=1, EmitDefaultValue=false) + errorCode?:string; + + // @DataMember(Order=2, EmitDefaultValue=false) + fieldName?:string; + + // @DataMember(Order=3, EmitDefaultValue=false) + message?:string; + } + + interface MetadataTestNestedChild + { + name?:string; + } + + interface SubType + { + id?:number; + name?:string; + } + + interface IAuthTokens + { + provider?:string; + userId?:string; + accessToken?:string; + accessTokenSecret?:string; + refreshToken?:string; + refreshTokenExpiry?:string; + requestToken?:string; + requestTokenSecret?:string; + items?:{ [index:string]: string; }; + } + + interface RockstarAlbum + { + id?:number; + rockstarId?:number; + name?:string; + } + + // @DataContract + interface QueryResponse + { + // @DataMember(Order=1) + offset?:number; + + // @DataMember(Order=2) + total?:number; + + // @DataMember(Order=3) + results?:Rockstar[]; + + // @DataMember(Order=4) + meta?:{ [index:string]: string; }; + + // @DataMember(Order=5) + responseStatus?:ResponseStatus; + } + + interface ChangeRequestResponse + { + contentType?:string; + header?:string; + queryString?:string; + form?:string; + responseStatus?:ResponseStatus; + } + + interface CustomHttpErrorResponse + { + custom?:string; + responseStatus?:ResponseStatus; + } + + interface CustomFieldHttpErrorResponse + { + custom?:string; + responseStatus?:ResponseStatus; + } + + interface MetadataTestResponse + { + id?:number; + results?:MetadataTestChild[]; + } + + interface HelloResponse + { + result?:string; + } + + /** + * Description on HelloAllResponse type + */ + // @DataContract + interface HelloAnnotatedResponse + { + // @DataMember + result?:string; + } + + interface HelloAllTypesResponse + { + result?:string; + allTypes?:AllTypes; + allCollectionTypes?:AllCollectionTypes; + } + + // @DataContract + interface HelloWithDataContractResponse + { + // @DataMember(Name="result", Order=1, IsRequired=true, EmitDefaultValue=false) + result?:string; + } + + /** + * Description on HelloWithDescriptionResponse type + */ + interface HelloWithDescriptionResponse + { + result?:string; + } + + interface HelloWithInheritanceResponse extends HelloResponseBase + { + result?:string; + } + + interface HelloWithAlternateReturnResponse extends HelloWithReturnResponse + { + altResult?:string; + } + + interface HelloWithRouteResponse + { + result?:string; + } + + interface HelloWithTypeResponse + { + result?:HelloType; + } + + interface HelloSessionResponse + { + result?:AuthUserSession; + } + + interface Echo + { + sentence?:string; + } + + interface acsprofileResponse + { + profileId?:string; + } + + // @DataContract + interface ResourcesResponse + { + // @DataMember(Name="swaggerVersion") + swaggerVersion?:string; + + // @DataMember(Name="apiVersion") + apiVersion?:string; + + // @DataMember(Name="basePath") + basePath?:string; + + // @DataMember(Name="apis") + apis?:RestService[]; + } + + // @Route("/anontype") + interface AnonType + { + } + + // @Route("/query/rockstars") + interface QueryRockstars extends QueryBase_1, IReturn> + { + age?:number; + } + + // @Route("/changerequest/{Id}") + interface ChangeRequest extends IReturn + { + id?:string; + } + + // @Route("/Routing/LeadPost.aspx") + interface LegacyLeadPost + { + leadType?:string; + myId?:number; + } + + interface CustomHttpError extends IReturn + { + statusCode?:number; + statusDescription?:string; + } + + interface CustomFieldHttpError extends IReturn + { + } + + interface MetadataTest extends IReturn + { + id?:number; + } + + // @Route("/hello/{Name}") + interface Hello extends IReturn + { + name?:string; + } + + /** + * Description on HelloAll type + */ + // @DataContract + interface HelloAnnotated extends IReturn + { + // @DataMember + name?:string; + } + + interface HelloWithNestedClass extends IReturn + { + name?:string; + nestedClassProp?:NestedClass; + } + + interface HelloWithEnum + { + enumProp?:EnumType; + nullableEnumProp?:EnumType; + enumFlags?:EnumFlags; + } + + interface RestrictedAttributes + { + id?:number; + name?:string; + hello?:Hello; + } + + /** + * AllowedAttributes Description + */ + // @Route("/allowed-attributes", "GET") + // @Api("AllowedAttributes Description") + // @ApiResponse(400, "Your request was not understood") + // @DataContract + interface AllowedAttributes + { + // @Default(5) + // @Required() + id:number; + + // @DataMember(Name="Aliased") + // @ApiMember(Description="Range Description", ParameterType="path", DataType="double", IsRequired=true) + range?:number; + + // @Meta("Foo", "Bar") + // @StringLength(20) + // @References(typeof(Hello)) + name?:string; + } + + interface HelloAllTypes extends IReturn + { + name?:string; + allTypes?:AllTypes; + allCollectionTypes?:AllCollectionTypes; + } + + interface HelloString + { + name?:string; + } + + interface HelloVoid + { + name?:string; + } + + // @DataContract + interface HelloWithDataContract extends IReturn + { + // @DataMember(Name="name", Order=1, IsRequired=true, EmitDefaultValue=false) + name?:string; + + // @DataMember(Name="id", Order=2, EmitDefaultValue=false) + id?:number; + } + + /** + * Description on HelloWithDescription type + */ + interface HelloWithDescription extends IReturn + { + name?:string; + } + + interface HelloWithInheritance extends HelloBase, IReturn + { + name?:string; + } + + interface HelloWithGenericInheritance extends HelloBase_1 + { + result?:string; + } + + interface HelloWithGenericInheritance2 extends HelloBase_1 + { + result?:string; + } + + interface HelloWithNestedInheritance extends HelloBase_1 + { + } + + interface HelloWithListInheritance extends Array + { + } + + interface HelloWithReturn extends IReturn + { + name?:string; + } + + // @Route("/helloroute") + interface HelloWithRoute extends IReturn + { + name?:string; + } + + interface HelloWithType extends IReturn + { + name?:string; + } + + interface HelloSession extends IReturn + { + } + + interface HelloInterface + { + poco?:IPoco; + emptyInterface?:IEmptyInterface; + emptyClass?:EmptyClass; + } + + /** + * Echoes a sentence + */ + // @Route("/echoes", "POST") + // @Api("Echoes a sentence") + interface Echoes extends IReturn + { + // @ApiMember(Description="The sentence to echo.", ParameterType="form", DataType="string", IsRequired=true, Name="Sentence") + sentence?:string; + } + + interface AsyncTest extends IReturn + { + } + + // @Route("/throwhttperror/{Status}") + interface ThrowHttpError + { + status?:number; + message?:string; + } + + // @Route("/api/acsprofiles/{profileId}") + // @Route("/api/acsprofiles", "POST,PUT,PATCH,DELETE") + interface ACSProfile extends IReturn + { + profileId?:string; + // @StringLength(20) + // @Required() + shortName:string; + + // @StringLength(60) + longName?:string; + + // @StringLength(20) + regionId?:string; + + // @StringLength(20) + groupId?:string; + + // @StringLength(12) + deviceID?:string; + + lastUpdated?:string; + enabled?:boolean; + } + + // @Route("/resources") + // @DataContract + interface Resources extends IReturn + { + // @DataMember(Name="apiKey") + apiKey?:string; + } + + // @Route("/resource/{Name*}") + // @DataContract + interface ResourceRequest + { + // @DataMember(Name="apiKey") + apiKey?:string; + + // @DataMember(Name="name") + name?:string; + } + + // @Route("/postman") + interface Postman + { + label?:string[]; + exportSession?:boolean; + ssid?:string; + sspid?:string; + ssopt?:string; + } + + interface QueryRockstarsConventions extends QueryBase_1, IReturn> + { + ids?:number[]; + ageOlderThan?:number; + ageGreaterThanOrEqualTo?:number; + ageGreaterThan?:number; + greaterThanAge?:number; + firstNameStartsWith?:string; + lastNameEndsWith?:string; + lastNameContains?:string; + rockstarAlbumNameContains?:string; + rockstarIdAfter?:number; + rockstarIdOnOrAfter?:number; + } + + interface QueryCustomRockstars extends QueryBase_2, IReturn> + { + age?:number; + } + + // @Route("/customrockstars") + interface QueryRockstarAlbums extends QueryBase_2, IReturn> + { + age?:number; + rockstarAlbumName?:string; + } + + interface QueryRockstarAlbumsImplicit extends QueryBase_2, IReturn> + { + } + + interface QueryRockstarAlbumsLeftJoin extends QueryBase_2, IReturn> + { + age?:number; + albumName?:string; + } + + interface QueryOverridedRockstars extends QueryBase_1, IReturn> + { + age?:number; + } + + interface QueryOverridedCustomRockstars extends QueryBase_2, IReturn> + { + age?:number; + } + + interface QueryFieldRockstars extends QueryBase_1, IReturn> + { + firstName?:string; + firstNames?:string[]; + age?:number; + firstNameCaseInsensitive?:string; + firstNameStartsWith?:string; + lastNameEndsWith?:string; + firstNameBetween?:string[]; + orLastName?:string; + } + + interface QueryFieldRockstarsDynamic extends QueryBase_1, IReturn> + { + age?:number; + } + + interface QueryRockstarsFilter extends QueryBase_1, IReturn> + { + age?:number; + } + + interface QueryCustomRockstarsFilter extends QueryBase_2, IReturn> + { + age?:number; + } + + interface QueryRockstarsIFilter extends QueryBase_1, IReturn> + { + age?:number; + } + + // @Route("/OrRockstars") + interface QueryOrRockstars extends QueryBase_1, IReturn> + { + age?:number; + firstName?:string; + } + + interface QueryGetRockstars extends QueryBase_1, IReturn> + { + ids?:number[]; + ages?:number[]; + firstNames?:string[]; + idsBetween?:number[]; + } + + interface QueryGetRockstarsDynamic extends QueryBase_1, IReturn> + { + } + + // @Route("/movies/search") + interface SearchMovies extends QueryBase_1, IReturn> + { + } + + // @Route("/movies") + interface QueryMovies extends QueryBase_1, IReturn> + { + ids?:number[]; + imdbIds?:string[]; + ratings?:string[]; + } + + interface StreamMovies extends QueryBase_1, IReturn> + { + ratings?:string[]; + } + + interface QueryUnknownRockstars extends QueryBase_1, IReturn> + { + unknownInt?:number; + unknownProperty?:string; + } + + // @Route("/query/rockstar-references") + interface QueryRockstarsWithReferences extends QueryBase_1, IReturn> + { + age?:number; + } + +} diff --git a/tests/CheckWeb/TestAuth.cshtml b/tests/CheckWeb/TestAuth.cshtml new file mode 100644 index 00000000000..bc830b062a6 --- /dev/null +++ b/tests/CheckWeb/TestAuth.cshtml @@ -0,0 +1,17 @@ + + + + + Test Auth + + + +
+ + + + + + + + \ No newline at end of file diff --git a/tests/CheckWeb/TestError.cshtml b/tests/CheckWeb/TestError.cshtml new file mode 100644 index 00000000000..6022680f8b9 --- /dev/null +++ b/tests/CheckWeb/TestError.cshtml @@ -0,0 +1,4 @@ +@{ + ViewBag.Title = "Test Error"; + +

Test Error

diff --git a/tests/CheckWeb/TestMinifier.cshtml b/tests/CheckWeb/TestMinifier.cshtml new file mode 100644 index 00000000000..c0928237091 --- /dev/null +++ b/tests/CheckWeb/TestMinifier.cshtml @@ -0,0 +1,65 @@ + + + + Test Minifier Razor Content Page + + + + + + + + + + + + + @ServiceStack.MiniProfiler.Profiler.RenderIncludes().AsRaw() + + +

Test Minifier Razor Content Page

+ +
+

HTML5 Report View

+ +
+ + + + diff --git a/tests/CheckWeb/TestMinifier2.html b/tests/CheckWeb/TestMinifier2.html new file mode 100644 index 00000000000..44ccf4d9b32 --- /dev/null +++ b/tests/CheckWeb/TestMinifier2.html @@ -0,0 +1,63 @@ + + + + Test Minifier Razor Content Page + + + + + + + + + + + + + +

Test Minifier Razor Content Page

+ +
+

HTML5 Report View

+ +
+ + + + diff --git a/tests/CheckWeb/TestMinifierView.cshtml b/tests/CheckWeb/TestMinifierView.cshtml new file mode 100644 index 00000000000..5c313b1d5fb --- /dev/null +++ b/tests/CheckWeb/TestMinifierView.cshtml @@ -0,0 +1,10 @@ +@inherits ViewPage +@{ + Layout = "SimpleLayout"; +} + +

TestView

+ +@Model.Sentence + + \ No newline at end of file diff --git a/tests/CheckWeb/ViewTests.cs b/tests/CheckWeb/ViewTests.cs new file mode 100644 index 00000000000..60549967779 --- /dev/null +++ b/tests/CheckWeb/ViewTests.cs @@ -0,0 +1,23 @@ +using ServiceStack; + +namespace CheckWeb +{ + [Route("/defaultview/class")] + public class DefaultViewAttr {} + + [DefaultView("TheView")] + public class ViewTests : Service + { + public object Get(DefaultViewAttr request) => request; + } + + [Route("/defaultview/action")] + public class DefaultViewActionAttr {} + + public class ActionViewTests : Service + { + [DefaultView("TheView")] + public object Get(DefaultViewActionAttr request) => request; + } + +} \ No newline at end of file diff --git a/tests/CheckWeb/Views/Authenticate.cshtml b/tests/CheckWeb/Views/Authenticate.cshtml new file mode 100644 index 00000000000..a6a95a7bb6e --- /dev/null +++ b/tests/CheckWeb/Views/Authenticate.cshtml @@ -0,0 +1,8 @@ +@using ServiceStack +@{ + ViewBag.Title = "Test Authenticate Error"; +} + +

Test Error View

+ +

@GetErrorMessage()

\ No newline at end of file diff --git a/tests/RazorRockstars.Console/Views/Shared/SimpleLayout.cshtml b/tests/CheckWeb/Views/Shared/SimpleLayout.cshtml similarity index 93% rename from tests/RazorRockstars.Console/Views/Shared/SimpleLayout.cshtml rename to tests/CheckWeb/Views/Shared/SimpleLayout.cshtml index 37cee4d1baf..c1bb71efc9f 100644 --- a/tests/RazorRockstars.Console/Views/Shared/SimpleLayout.cshtml +++ b/tests/CheckWeb/Views/Shared/SimpleLayout.cshtml @@ -1,41 +1,42 @@ - - - - Simple Layout - - - -

@ViewBag.Title

- -
- @RenderBody() -
- - - - +@using ServiceStack.Razor + + + + Simple Layout + + + +

@ViewBag.Title

+ +
+ @RenderBody() +
+ + + + diff --git a/tests/CheckWeb/Views/Shared/TestMinifierLayout.cshtml b/tests/CheckWeb/Views/Shared/TestMinifierLayout.cshtml new file mode 100644 index 00000000000..37e747bcb18 --- /dev/null +++ b/tests/CheckWeb/Views/Shared/TestMinifierLayout.cshtml @@ -0,0 +1,62 @@ +@using ServiceStack.Razor + + + + Simple Layout + + + + + + + + + + + + + @ServiceStack.MiniProfiler.Profiler.RenderIncludes().AsRaw() + + +

@ViewBag.Title

+ +
+ @RenderBody() +
+ + + + diff --git a/tests/CheckWeb/Views/TestErrorNotFound.cshtml b/tests/CheckWeb/Views/TestErrorNotFound.cshtml new file mode 100644 index 00000000000..32539d50e45 --- /dev/null +++ b/tests/CheckWeb/Views/TestErrorNotFound.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage +@{ + ViewBag.Title = "Test Error NotFound"; +} + +

Test Error NotFound

+ +@Html.GetErrorMessage() diff --git a/tests/CheckWeb/Views/TestErrorView.cshtml b/tests/CheckWeb/Views/TestErrorView.cshtml new file mode 100644 index 00000000000..e41ca60f69a --- /dev/null +++ b/tests/CheckWeb/Views/TestErrorView.cshtml @@ -0,0 +1,4 @@ +@{ + ViewBag.Title = "Test Error View"; + +

Test Error View

diff --git a/tests/CheckWeb/Views/TestHtml.cshtml b/tests/CheckWeb/Views/TestHtml.cshtml new file mode 100644 index 00000000000..fd9ac1469ae --- /dev/null +++ b/tests/CheckWeb/Views/TestHtml.cshtml @@ -0,0 +1,9 @@ +@inherits ViewPage + +

TestHtml

+ +

@Model.Name

+ +

@DateTime.Now

+ + \ No newline at end of file diff --git a/tests/CheckWeb/Views/TestHtml2.cshtml b/tests/CheckWeb/Views/TestHtml2.cshtml new file mode 100644 index 00000000000..e026af46346 --- /dev/null +++ b/tests/CheckWeb/Views/TestHtml2.cshtml @@ -0,0 +1,9 @@ +@inherits ViewPage + +

TestHtml2

+ +

@Model.Name

+ +

@DateTime.Now

+ + \ No newline at end of file diff --git a/tests/CheckWeb/Views/TestMinifierView.cshtml b/tests/CheckWeb/Views/TestMinifierView.cshtml new file mode 100644 index 00000000000..5c313b1d5fb --- /dev/null +++ b/tests/CheckWeb/Views/TestMinifierView.cshtml @@ -0,0 +1,10 @@ +@inherits ViewPage +@{ + Layout = "SimpleLayout"; +} + +

TestView

+ +@Model.Sentence + + \ No newline at end of file diff --git a/tests/CheckWeb/Views/TestView.cshtml b/tests/CheckWeb/Views/TestView.cshtml new file mode 100644 index 00000000000..8952f33584e --- /dev/null +++ b/tests/CheckWeb/Views/TestView.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage +@{ + Layout = "TestMinifierLayout"; +} + +

TestMinifierLayout

+ + \ No newline at end of file diff --git a/tests/CheckWeb/Views/TheView.cshtml b/tests/CheckWeb/Views/TheView.cshtml new file mode 100644 index 00000000000..097cdf61625 --- /dev/null +++ b/tests/CheckWeb/Views/TheView.cshtml @@ -0,0 +1,3 @@ +

The View

+ + \ No newline at end of file diff --git a/tests/CheckWeb/Views/ViewRequest.cshtml b/tests/CheckWeb/Views/ViewRequest.cshtml new file mode 100644 index 00000000000..53506619e14 --- /dev/null +++ b/tests/CheckWeb/Views/ViewRequest.cshtml @@ -0,0 +1,9 @@ +@inherits ViewPage + +

ViewRequest

+ +

@Model.Result

+ +

@System.DateTime.Now

+ + \ No newline at end of file diff --git a/tests/ServiceStack.Razor.Tests/Web.Debug.config b/tests/CheckWeb/Web.Debug.config similarity index 100% rename from tests/ServiceStack.Razor.Tests/Web.Debug.config rename to tests/CheckWeb/Web.Debug.config diff --git a/tests/CheckWeb/Web.Release.config b/tests/CheckWeb/Web.Release.config new file mode 100644 index 00000000000..c35844462ba --- /dev/null +++ b/tests/CheckWeb/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckWeb/Web.config b/tests/CheckWeb/Web.config new file mode 100644 index 00000000000..651e9af7f93 --- /dev/null +++ b/tests/CheckWeb/Web.config @@ -0,0 +1,80 @@ + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckWeb/_init.html b/tests/CheckWeb/_init.html new file mode 100644 index 00000000000..860151f4dac --- /dev/null +++ b/tests/CheckWeb/_init.html @@ -0,0 +1 @@ +Hi from _init.html \ No newline at end of file diff --git a/tests/CheckWeb/css/bootstrap.css b/tests/CheckWeb/css/bootstrap.css new file mode 100644 index 00000000000..7fa1f93fd1f --- /dev/null +++ b/tests/CheckWeb/css/bootstrap.css @@ -0,0 +1,2448 @@ +/*! + * Bootstrap @VERSION + * + * Copyright 2014 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + * Date: @DATE + *//* Reset.less + * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc). + * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */html, body { + margin: 0; + padding: 0; +} +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +cite, +code, +del, +dfn, +em, +img, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +dd, +dl, +dt, +li, +ol, +ul, +fieldset, +form, +label, +legend, +button, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td { + margin: 0; + padding: 0; + border: 0; + font-weight: normal; + font-style: normal; + font-size: 100%; + line-height: 1; + font-family: inherit; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +ol, ul { + list-style: none; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +html { + overflow-y: scroll; + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted; +} +a:hover, a:active { + outline: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + font-size: 100%; + margin: 0; + vertical-align: baseline; + *vertical-align: middle; +} +button, input { + line-height: normal; + *overflow: visible; +} +button::-moz-focus-inner, input::-moz-focus-inner { + border: 0; + padding: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +/* Variables.less + * Variables to customize the look and feel of Bootstrap + * ----------------------------------------------------- *//* Mixins.less + * Snippets of reusable CSS to develop faster and keep code readable + * ----------------------------------------------------------------- *//* + * Scaffolding + * Basic and global styles for generating a grid system, structural layout, and page templates + * ------------------------------------------------------------------------------------------- */body { + background-color: white; + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 18px; + color: #404040; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; + zoom: 1; +} +.container:after { + clear: both; +} +.container-fluid { + position: relative; + min-width: 940px; + padding-left: 20px; + padding-right: 20px; + zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; + zoom: 1; +} +.container-fluid:after { + clear: both; +} +.container-fluid > .sidebar { + position: absolute; + top: 0; + left: 20px; + width: 220px; +} +.container-fluid > .content { + margin-left: 240px; +} +a { + color: #0069d6; + text-decoration: none; + line-height: inherit; + font-weight: inherit; +} +a:hover { + color: #00438a; + text-decoration: underline; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.row { + zoom: 1; + margin-left: -20px; +} +.row:before, .row:after { + display: table; + content: ""; + zoom: 1; +} +.row:after { + clear: both; +} +.row > [class*="span"] { + display: inline; + float: left; + margin-left: 20px; +} +.span1 { + width: 40px; +} +.span2 { + width: 100px; +} +.span3 { + width: 160px; +} +.span4 { + width: 220px; +} +.span5 { + width: 280px; +} +.span6 { + width: 340px; +} +.span7 { + width: 400px; +} +.span8 { + width: 460px; +} +.span9 { + width: 520px; +} +.span10 { + width: 580px; +} +.span11 { + width: 640px; +} +.span12 { + width: 700px; +} +.span13 { + width: 760px; +} +.span14 { + width: 820px; +} +.span15 { + width: 880px; +} +.span16 { + width: 940px; +} +.span17 { + width: 1000px; +} +.span18 { + width: 1060px; +} +.span19 { + width: 1120px; +} +.span20 { + width: 1180px; +} +.span21 { + width: 1240px; +} +.span22 { + width: 1300px; +} +.span23 { + width: 1360px; +} +.span24 { + width: 1420px; +} +.row > .offset1 { + margin-left: 80px; +} +.row > .offset2 { + margin-left: 140px; +} +.row > .offset3 { + margin-left: 200px; +} +.row > .offset4 { + margin-left: 260px; +} +.row > .offset5 { + margin-left: 320px; +} +.row > .offset6 { + margin-left: 380px; +} +.row > .offset7 { + margin-left: 440px; +} +.row > .offset8 { + margin-left: 500px; +} +.row > .offset9 { + margin-left: 560px; +} +.row > .offset10 { + margin-left: 620px; +} +.row > .offset11 { + margin-left: 680px; +} +.row > .offset12 { + margin-left: 740px; +} +.span-one-third { + width: 300px; +} +.span-two-thirds { + width: 620px; +} +.row > .offset-one-third { + margin-left: 340px; +} +.row > .offset-two-thirds { + margin-left: 660px; +} +/* Typography.less + * Headings, body text, lists, code, and more for a versatile and durable typography system + * ---------------------------------------------------------------------------------------- */p { + font-size: 13px; + font-weight: normal; + line-height: 18px; + margin-bottom: 9px; +} +p small { + font-size: 11px; + color: #bfbfbf; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: bold; + color: #404040; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + color: #bfbfbf; +} +h1 { + margin-bottom: 18px; + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 14px; +} +h3, +h4, +h5, +h6 { + line-height: 36px; +} +h3 { + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4 { + font-size: 16px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 14px; +} +h6 { + font-size: 13px; + color: #bfbfbf; + text-transform: uppercase; +} +ul, ol { + margin: 0 0 18px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; + color: gray; +} +ul.unstyled { + list-style: none; + margin-left: 0; +} +dl { + margin-bottom: 18px; +} +dl dt, dl dd { + line-height: 18px; +} +dl dt { + font-weight: bold; +} +dl dd { + margin-left: 9px; +} +hr { + margin: 20px 0 19px; + border: 0; + border-bottom: 1px solid #eee; +} +strong { + font-style: inherit; + font-weight: bold; +} +em { + font-style: italic; + font-weight: inherit; + line-height: inherit; +} +.muted { + color: #bfbfbf; +} +blockquote { + margin-bottom: 18px; + border-left: 5px solid #eee; + padding-left: 15px; +} +blockquote p { + font-size: 14px; + font-weight: 300; + line-height: 18px; + margin-bottom: 0; +} +blockquote small { + display: block; + font-size: 12px; + font-weight: 300; + line-height: 18px; + color: #bfbfbf; +} +blockquote small:before { + content: '\2014 \00A0'; +} +address { + display: block; + line-height: 18px; + margin-bottom: 18px; +} +code, pre { + padding: 0 3px 2px; + font-family: Monaco, Andale Mono, Courier New, monospace; + font-size: 12px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + background-color: #fee9cc; + color: rgba(0, 0, 0, 0.75); + padding: 1px 3px; +} +pre { + background-color: #f5f5f5; + display: block; + padding: 8.5px; + margin: 0 0 18px; + line-height: 18px; + font-size: 12px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} +/* Forms.less + * Base styles for various input types, form layouts, and states + * ------------------------------------------------------------- */form { + margin-bottom: 18px; +} +fieldset { + margin-bottom: 18px; + padding-top: 18px; +} +fieldset legend { + display: block; + padding-left: 150px; + font-size: 19.5px; + line-height: 1; + color: #404040; + *padding: 0 0 5px 145px; + /* IE6-7 */ + *line-height: 1.5; + /* IE6-7 */ +} +form .clearfix { + margin-bottom: 18px; + zoom: 1; +} +form .clearfix:before, form .clearfix:after { + display: table; + content: ""; + zoom: 1; +} +form .clearfix:after { + clear: both; +} +label, +input, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: normal; +} +label { + padding-top: 6px; + font-size: 13px; + line-height: 18px; + float: left; + width: 130px; + text-align: right; + color: #404040; +} +form .input { + margin-left: 150px; +} +input[type=checkbox], input[type=radio] { + cursor: pointer; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + font-size: 13px; + line-height: 18px; + color: gray; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +select { + padding: initial; +} +input[type=checkbox], input[type=radio] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE6-7 */ + line-height: normal; + border: none; +} +input[type=file] { + background-color: white; + padding: initial; + border: initial; + line-height: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type=button], input[type=reset], input[type=submit] { + width: auto; + height: auto; +} +select, input[type=file] { + height: 27px; + *height: auto; + line-height: 27px; + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ +} +select[multiple] { + height: inherit; + background-color: white; +} +textarea { + height: auto; +} +.uneditable-input { + background-color: white; + display: block; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #bfbfbf; +} +::-webkit-input-placeholder { + color: #bfbfbf; +} +input, textarea { + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); +} +input:focus, textarea:focus { + outline: 0; + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); +} +input[type=file]:focus, input[type=checkbox]:focus, select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: 1px dotted #666; +} +form .clearfix.error > label, form .clearfix.error .help-block, form .clearfix.error .help-inline { + color: #b94a48; +} +form .clearfix.error input, form .clearfix.error textarea { + color: #b94a48; + border-color: #ee5f5b; +} +form .clearfix.error input:focus, form .clearfix.error textarea:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +form .clearfix.error .input-prepend .add-on, form .clearfix.error .input-append .add-on { + color: #b94a48; + background-color: #fce6e6; + border-color: #b94a48; +} +form .clearfix.warning > label, form .clearfix.warning .help-block, form .clearfix.warning .help-inline { + color: #c09853; +} +form .clearfix.warning input, form .clearfix.warning textarea { + color: #c09853; + border-color: #ccae64; +} +form .clearfix.warning input:focus, form .clearfix.warning textarea:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +form .clearfix.warning .input-prepend .add-on, form .clearfix.warning .input-append .add-on { + color: #c09853; + background-color: #d2b877; + border-color: #c09853; +} +form .clearfix.success > label, form .clearfix.success .help-block, form .clearfix.success .help-inline { + color: #468847; +} +form .clearfix.success input, form .clearfix.success textarea { + color: #468847; + border-color: #57a957; +} +form .clearfix.success input:focus, form .clearfix.success textarea:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +form .clearfix.success .input-prepend .add-on, form .clearfix.success .input-append .add-on { + color: #468847; + background-color: #bcddbc; + border-color: #468847; +} +.input-mini, +input.mini, +textarea.mini, +select.mini { + width: 60px; +} +.input-small, +input.small, +textarea.small, +select.small { + width: 90px; +} +.input-medium, +input.medium, +textarea.medium, +select.medium { + width: 150px; +} +.input-large, +input.large, +textarea.large, +select.large { + width: 210px; +} +.input-xlarge, +input.xlarge, +textarea.xlarge, +select.xlarge { + width: 270px; +} +.input-xxlarge, +input.xxlarge, +textarea.xxlarge, +select.xxlarge { + width: 530px; +} +textarea.xxlarge { + overflow-y: auto; +} +input.span1, textarea.span1 { + display: inline-block; + float: none; + width: 30px; + margin-left: 0; +} +input.span2, textarea.span2 { + display: inline-block; + float: none; + width: 90px; + margin-left: 0; +} +input.span3, textarea.span3 { + display: inline-block; + float: none; + width: 150px; + margin-left: 0; +} +input.span4, textarea.span4 { + display: inline-block; + float: none; + width: 210px; + margin-left: 0; +} +input.span5, textarea.span5 { + display: inline-block; + float: none; + width: 270px; + margin-left: 0; +} +input.span6, textarea.span6 { + display: inline-block; + float: none; + width: 330px; + margin-left: 0; +} +input.span7, textarea.span7 { + display: inline-block; + float: none; + width: 390px; + margin-left: 0; +} +input.span8, textarea.span8 { + display: inline-block; + float: none; + width: 450px; + margin-left: 0; +} +input.span9, textarea.span9 { + display: inline-block; + float: none; + width: 510px; + margin-left: 0; +} +input.span10, textarea.span10 { + display: inline-block; + float: none; + width: 570px; + margin-left: 0; +} +input.span11, textarea.span11 { + display: inline-block; + float: none; + width: 630px; + margin-left: 0; +} +input.span12, textarea.span12 { + display: inline-block; + float: none; + width: 690px; + margin-left: 0; +} +input.span13, textarea.span13 { + display: inline-block; + float: none; + width: 750px; + margin-left: 0; +} +input.span14, textarea.span14 { + display: inline-block; + float: none; + width: 810px; + margin-left: 0; +} +input.span15, textarea.span15 { + display: inline-block; + float: none; + width: 870px; + margin-left: 0; +} +input.span16, textarea.span16 { + display: inline-block; + float: none; + width: 930px; + margin-left: 0; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.actions { + background: #f5f5f5; + margin-top: 18px; + margin-bottom: 18px; + padding: 17px 20px 18px 150px; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; +} +.actions .secondary-action { + float: right; +} +.actions .secondary-action a { + line-height: 30px; +} +.actions .secondary-action a:hover { + text-decoration: underline; +} +.help-inline, .help-block { + font-size: 13px; + line-height: 18px; + color: #bfbfbf; +} +.help-inline { + padding-left: 5px; + *position: relative; + /* IE6-7 */ + *top: -5px; + /* IE6-7 */ +} +.help-block { + display: block; + max-width: 600px; +} +.inline-inputs { + color: gray; +} +.inline-inputs span { + padding: 0 2px 0 1px; +} +.input-prepend input, .input-append input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend .add-on, .input-append .add-on { + position: relative; + background: #f5f5f5; + border: 1px solid #ccc; + z-index: 2; + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + padding: 4px 4px 4px 5px; + margin-right: -1px; + font-weight: normal; + line-height: 18px; + color: #bfbfbf; + text-align: center; + text-shadow: 0 1px 0 white; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ +} +.input-append input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .add-on { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; + margin-right: 0; + margin-left: -1px; +} +.inputs-list { + margin: 0 0 5px; + width: 100%; +} +.inputs-list li { + display: block; + padding: 0; + width: 100%; +} +.inputs-list label { + display: block; + float: none; + width: auto; + padding: 0; + margin-left: 20px; + line-height: 18px; + text-align: left; + white-space: normal; +} +.inputs-list label strong { + color: gray; +} +.inputs-list label small { + font-size: 11px; + font-weight: normal; +} +.inputs-list .inputs-list { + margin-left: 25px; + margin-bottom: 10px; + padding-top: 0; +} +.inputs-list:first-child { + padding-top: 6px; +} +.inputs-list li + li { + padding-top: 2px; +} +.inputs-list input[type=radio], .inputs-list input[type=checkbox] { + margin-bottom: 0; + margin-left: -20px; + float: left; +} +.form-stacked { + padding-left: 20px; +} +.form-stacked fieldset { + padding-top: 9px; +} +.form-stacked legend { + padding-left: 0; +} +.form-stacked label { + display: block; + float: none; + width: auto; + font-weight: bold; + text-align: left; + line-height: 20px; + padding-top: 0; +} +.form-stacked .clearfix { + margin-bottom: 9px; +} +.form-stacked .clearfix div.input { + margin-left: 0; +} +.form-stacked .inputs-list { + margin-bottom: 0; +} +.form-stacked .inputs-list li { + padding-top: 0; +} +.form-stacked .inputs-list li label { + font-weight: normal; + padding-top: 0; +} +.form-stacked div.clearfix.error { + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + margin-top: 0; + margin-left: -10px; +} +.form-stacked .actions { + margin-left: -20px; + padding-left: 20px; +} +/* + * Tables.less + * Tables for, you guessed it, tabular data + * ---------------------------------------- */table { + width: 100%; + margin-bottom: 18px; + padding: 0; + font-size: 13px; + border-collapse: collapse; +} +table th, table td { + padding: 10px 10px 9px; + line-height: 18px; + text-align: left; +} +table th { + padding-top: 9px; + font-weight: bold; + vertical-align: middle; +} +table td { + vertical-align: top; + border-top: 1px solid #ddd; +} +table tbody th { + border-top: 1px solid #ddd; + vertical-align: top; +} +.condensed-table th, .condensed-table td { + padding: 5px 5px 4px; +} +.bordered-table { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapse; + /* IE7, collapse table to remove spacing */ + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.bordered-table th + th, .bordered-table td + td, .bordered-table th + td { + border-left: 1px solid #ddd; +} +.bordered-table thead tr:first-child th:first-child, .bordered-table tbody tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.bordered-table thead tr:first-child th:last-child, .bordered-table tbody tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.bordered-table tbody tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.bordered-table tbody tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +table .span1 { + width: 20px; +} +table .span2 { + width: 60px; +} +table .span3 { + width: 100px; +} +table .span4 { + width: 140px; +} +table .span5 { + width: 180px; +} +table .span6 { + width: 220px; +} +table .span7 { + width: 260px; +} +table .span8 { + width: 300px; +} +table .span9 { + width: 340px; +} +table .span10 { + width: 380px; +} +table .span11 { + width: 420px; +} +table .span12 { + width: 460px; +} +table .span13 { + width: 500px; +} +table .span14 { + width: 540px; +} +table .span15 { + width: 580px; +} +table .span16 { + width: 620px; +} +.zebra-striped tbody tr:nth-child(odd) td, .zebra-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.zebra-striped tbody tr:hover td, .zebra-striped tbody tr:hover th { + background-color: #f5f5f5; +} +table .header { + cursor: pointer; +} +table .header:after { + content: ""; + float: right; + margin-top: 7px; + border-width: 0 4px 4px; + border-style: solid; + border-color: #000 transparent; + visibility: hidden; +} +table .headerSortUp, table .headerSortDown { + background-color: rgba(141, 192, 219, 0.25); + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); +} +table .header:hover:after { + visibility: visible; +} +table .headerSortDown:after, table .headerSortDown:hover:after { + visibility: visible; + filter: alpha(opacity=60); + -khtml-opacity: 0.6; + -moz-opacity: 0.6; + opacity: 0.6; +} +table .headerSortUp:after { + border-bottom: none; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000; + visibility: visible; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + filter: alpha(opacity=60); + -khtml-opacity: 0.6; + -moz-opacity: 0.6; + opacity: 0.6; +} +table .blue { + color: #049cdb; + border-bottom-color: #049cdb; +} +table .headerSortUp.blue, table .headerSortDown.blue { + background-color: #ade6fe; +} +table .green { + color: #46a546; + border-bottom-color: #46a546; +} +table .headerSortUp.green, table .headerSortDown.green { + background-color: #cdeacd; +} +table .red { + color: #9d261d; + border-bottom-color: #9d261d; +} +table .headerSortUp.red, table .headerSortDown.red { + background-color: #f4c8c5; +} +table .yellow { + color: #ffc40d; + border-bottom-color: #ffc40d; +} +table .headerSortUp.yellow, table .headerSortDown.yellow { + background-color: #fff6d9; +} +table .orange { + color: #f89406; + border-bottom-color: #f89406; +} +table .headerSortUp.orange, table .headerSortDown.orange { + background-color: #fee9cc; +} +table .purple { + color: #7a43b6; + border-bottom-color: #7a43b6; +} +table .headerSortUp.purple, table .headerSortDown.purple { + background-color: #e2d5f0; +} +/* Patterns.less + * Repeatable UI elements outside the base styles provided from the scaffolding + * ---------------------------------------------------------------------------- */.topbar { + height: 40px; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 10000; + overflow: visible; +} +.topbar a { + color: #bfbfbf; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.topbar h3 a:hover, .topbar .brand:hover, .topbar ul .active > a { + background-color: #333; + background-color: rgba(255, 255, 255, 0.05); + color: white; + text-decoration: none; +} +.topbar h3 { + position: relative; +} +.topbar h3 a, .topbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + color: white; + font-size: 20px; + font-weight: 200; + line-height: 1; +} +.topbar p { + margin: 0; + line-height: 40px; +} +.topbar p a:hover { + background-color: transparent; + color: white; +} +.topbar form { + float: left; + margin: 5px 0 0 0; + position: relative; + filter: alpha(opacity=100); + -khtml-opacity: 1; + -moz-opacity: 1; + opacity: 1; +} +.topbar form.pull-right { + float: right; +} +.topbar input { + background-color: #444; + background-color: rgba(255, 255, 255, 0.3); + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: normal; + font-weight: 13px; + line-height: 1; + padding: 4px 9px; + color: white; + color: rgba(255, 255, 255, 0.75); + border: 1px solid #111; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.25); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.25); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.25); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.topbar input:-moz-placeholder { + color: #e6e6e6; +} +.topbar input::-webkit-input-placeholder { + color: #e6e6e6; +} +.topbar input:hover { + background-color: #bfbfbf; + background-color: rgba(255, 255, 255, 0.5); + color: white; +} +.topbar input:focus, .topbar input.focused { + outline: 0; + background-color: white; + color: #404040; + text-shadow: 0 1px 0 white; + border: 0; + padding: 5px 10px; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} +.topbar-inner, .topbar .fill { + background-color: #222; + background-color: #222222; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#333333), to(#222222)); + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #333333), color-stop(100%, #222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.topbar div > ul, .nav { + display: block; + float: left; + margin: 0 10px 0 0; + position: relative; + left: 0; +} +.topbar div > ul > li, .nav > li { + display: block; + float: left; +} +.topbar div > ul a, .nav a { + display: block; + float: none; + padding: 10px 10px 11px; + line-height: 19px; + text-decoration: none; +} +.topbar div > ul a:hover, .nav a:hover { + color: white; + text-decoration: none; +} +.topbar div > ul .active > a, .nav .active > a { + background-color: #222; + background-color: rgba(0, 0, 0, 0.5); +} +.topbar div > ul.secondary-nav, .nav.secondary-nav { + float: right; + margin-left: 10px; + margin-right: 0; +} +.topbar div > ul.secondary-nav .menu-dropdown, +.nav.secondary-nav .menu-dropdown, +.topbar div > ul.secondary-nav .dropdown-menu, +.nav.secondary-nav .dropdown-menu { + right: 0; + border: 0; +} +.topbar div > ul a.menu:hover, +.nav a.menu:hover, +.topbar div > ul li.open .menu, +.nav li.open .menu, +.topbar div > ul .dropdown-toggle:hover, +.nav .dropdown-toggle:hover, +.topbar div > ul .dropdown.open .dropdown-toggle, +.nav .dropdown.open .dropdown-toggle { + background: #444; + background: rgba(255, 255, 255, 0.05); +} +.topbar div > ul .menu-dropdown, +.nav .menu-dropdown, +.topbar div > ul .dropdown-menu, +.nav .dropdown-menu { + background-color: #333; +} +.topbar div > ul .menu-dropdown a.menu, +.nav .menu-dropdown a.menu, +.topbar div > ul .dropdown-menu a.menu, +.nav .dropdown-menu a.menu, +.topbar div > ul .menu-dropdown .dropdown-toggle, +.nav .menu-dropdown .dropdown-toggle, +.topbar div > ul .dropdown-menu .dropdown-toggle, +.nav .dropdown-menu .dropdown-toggle { + color: white; +} +.topbar div > ul .menu-dropdown a.menu.open, +.nav .menu-dropdown a.menu.open, +.topbar div > ul .dropdown-menu a.menu.open, +.nav .dropdown-menu a.menu.open, +.topbar div > ul .menu-dropdown .dropdown-toggle.open, +.nav .menu-dropdown .dropdown-toggle.open, +.topbar div > ul .dropdown-menu .dropdown-toggle.open, +.nav .dropdown-menu .dropdown-toggle.open { + background: #444; + background: rgba(255, 255, 255, 0.05); +} +.topbar div > ul .menu-dropdown li a, +.nav .menu-dropdown li a, +.topbar div > ul .dropdown-menu li a, +.nav .dropdown-menu li a { + color: #999; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5); +} +.topbar div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +.topbar div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #191919; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919)); + background-image: -moz-linear-gradient(top, #292929, #191919); + background-image: -ms-linear-gradient(top, #292929, #191919); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919)); + background-image: -webkit-linear-gradient(top, #292929, #191919); + background-image: -o-linear-gradient(top, #292929, #191919); + background-image: linear-gradient(top, #292929, #191919); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0); + color: white; +} +.topbar div > ul .menu-dropdown .active a, +.nav .menu-dropdown .active a, +.topbar div > ul .dropdown-menu .active a, +.nav .dropdown-menu .active a { + color: white; +} +.topbar div > ul .menu-dropdown .divider, +.nav .menu-dropdown .divider, +.topbar div > ul .dropdown-menu .divider, +.nav .dropdown-menu .divider { + background-color: #222; + border-color: #444; +} +.topbar ul .menu-dropdown li a, .topbar ul .dropdown-menu li a { + padding: 4px 15px; +} +li.menu, .dropdown { + position: relative; +} +a.menu:after, .dropdown-toggle:after { + width: 0; + height: 0; + display: inline-block; + content: "↓"; + text-indent: -99999px; + vertical-align: top; + margin-top: 8px; + margin-left: 4px; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid white; + filter: alpha(opacity=50); + -khtml-opacity: 0.5; + -moz-opacity: 0.5; + opacity: 0.5; +} +.menu-dropdown, .dropdown-menu { + background-color: white; + float: left; + display: none; + position: absolute; + top: 40px; + z-index: 900; + min-width: 160px; + max-width: 220px; + _width: 160px; + margin-left: 0; + margin-right: 0; + padding: 6px 0; + zoom: 1; + border-color: #999; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 0 1px 1px; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.menu-dropdown li, .dropdown-menu li { + float: none; + display: block; + background-color: none; +} +.menu-dropdown .divider, .dropdown-menu .divider { + height: 1px; + margin: 5px 0; + overflow: hidden; + background-color: #eee; + border-bottom: 1px solid white; +} +.topbar .dropdown-menu a, .dropdown-menu a { + display: block; + padding: 4px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: gray; + text-shadow: 0 1px 0 white; +} +.topbar .dropdown-menu a:hover, +.dropdown-menu a:hover, +.topbar .dropdown-menu a.hover, +.dropdown-menu a.hover { + background-color: #dddddd; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd)); + background-image: -moz-linear-gradient(top, #eeeeee, #dddddd); + background-image: -ms-linear-gradient(top, #eeeeee, #dddddd); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)); + background-image: -webkit-linear-gradient(top, #eeeeee, #dddddd); + background-image: -o-linear-gradient(top, #eeeeee, #dddddd); + background-image: linear-gradient(top, #eeeeee, #dddddd); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0); + color: #404040; + text-decoration: none; + -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025); +} +.open .menu, +.dropdown.open .menu, +.open .dropdown-toggle, +.dropdown.open .dropdown-toggle { + color: white; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.open .menu-dropdown, +.dropdown.open .menu-dropdown, +.open .dropdown-menu, +.dropdown.open .dropdown-menu { + display: block; +} +.tabs, .pills { + margin: 0 0 18px; + padding: 0; + list-style: none; + zoom: 1; +} +.tabs:before, +.pills:before, +.tabs:after, +.pills:after { + display: table; + content: ""; + zoom: 1; +} +.tabs:after, .pills:after { + clear: both; +} +.tabs > li, .pills > li { + float: left; +} +.tabs > li > a, .pills > li > a { + display: block; +} +.tabs { + border-color: #ddd; + border-style: solid; + border-width: 0 0 1px; +} +.tabs > li { + position: relative; + margin-bottom: -1px; +} +.tabs > li > a { + padding: 0 15px; + margin-right: 2px; + line-height: 34px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.tabs > li > a:hover { + text-decoration: none; + background-color: #eee; + border-color: #eee #eee #ddd; +} +.tabs .active > a, .tabs .active > a:hover { + color: gray; + background-color: white; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.tabs .menu-dropdown, .tabs .dropdown-menu { + top: 35px; + border-width: 1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} +.tabs a.menu:after, .tabs .dropdown-toggle:after { + border-top-color: #999; + margin-top: 15px; + margin-left: 5px; +} +.tabs li.open.menu .menu, .tabs .open.dropdown .dropdown-toggle { + border-color: #999; +} +.tabs li.open a.menu:after, .tabs .dropdown.open .dropdown-toggle:after { + border-top-color: #555; +} +.pills a { + margin: 5px 3px 5px 0; + padding: 0 15px; + line-height: 30px; + text-shadow: 0 1px 1px white; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pills a:hover { + color: white; + text-decoration: none; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); + background-color: #00438a; +} +.pills .active a { + color: white; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25); + background-color: #0069d6; +} +.pills-vertical > li { + float: none; +} +.tab-content > .tab-pane, +.pill-content > .pill-pane, +.tab-content > div, +.pill-content > div { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #f5f5f5; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(white), to(#f5f5f5)); + background-image: -moz-linear-gradient(top, white, #f5f5f5); + background-image: -ms-linear-gradient(top, white, #f5f5f5); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #f5f5f5)); + background-image: -webkit-linear-gradient(top, white, #f5f5f5); + background-image: -o-linear-gradient(top, white, #f5f5f5); + background-image: linear-gradient(top, white, #f5f5f5); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='white', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 white; + -moz-box-shadow: inset 0 1px 0 white; + box-shadow: inset 0 1px 0 white; +} +.breadcrumb li { + display: inline; + text-shadow: 0 1px 0 white; +} +.breadcrumb .divider { + padding: 0 5px; + color: #bfbfbf; +} +.breadcrumb .active a { + color: #404040; +} +.hero-unit { + background-color: #f5f5f5; + margin-bottom: 30px; + padding: 60px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +footer { + margin-top: 17px; + padding-top: 17px; + border-top: 1px solid #eee; +} +.page-header { + margin-bottom: 17px; + border-bottom: 1px solid #ddd; + -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.page-header h1 { + margin-bottom: 8px; +} +.btn.danger, +.alert-message.danger, +.btn.danger:hover, +.alert-message.danger:hover, +.btn.error, +.alert-message.error, +.btn.error:hover, +.alert-message.error:hover, +.btn.success, +.alert-message.success, +.btn.success:hover, +.alert-message.success:hover, +.btn.info, +.alert-message.info, +.btn.info:hover, +.alert-message.info:hover { + color: white; +} +.btn .close, .alert-message .close { + font-family: Arial, sans-serif; + line-height: 18px; +} +.btn.danger, +.alert-message.danger, +.btn.error, +.alert-message.error { + background-color: #c43c35; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35)); + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border-color: #c43c35 #c43c35 #882a25; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} +.btn.success, .alert-message.success { + background-color: #57a957; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957)); + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border-color: #57a957 #57a957 #3d773d; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} +.btn.info, .alert-message.info { + background-color: #339bb9; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9)); + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border-color: #339bb9 #339bb9 #22697d; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} +.btn { + cursor: pointer; + display: inline-block; + background-color: #e6e6e6; + background-repeat: no-repeat; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), color-stop(25%, white), to(#e6e6e6)); + background-image: -webkit-linear-gradient(white, white 25%, #e6e6e6); + background-image: -moz-linear-gradient(top, white, white 25%, #e6e6e6); + background-image: -ms-linear-gradient(white, white 25%, #e6e6e6); + background-image: -o-linear-gradient(white, white 25%, #e6e6e6); + background-image: linear-gradient(white, white 25%, #e6e6e6); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='white', endColorstr='#e6e6e6', GradientType=0); + padding: 5px 14px 6px; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + color: #333; + font-size: 13px; + line-height: normal; + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -webkit-transition: 0.1s linear all; + -moz-transition: 0.1s linear all; + -ms-transition: 0.1s linear all; + -o-transition: 0.1s linear all; + transition: 0.1s linear all; +} +.btn:hover { + background-position: 0 -15px; + color: #333; + text-decoration: none; +} +.btn:focus { + outline: 1px dotted #666; +} +.btn.primary { + color: white; + background-color: #0064cd; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd)); + background-image: -moz-linear-gradient(top, #049cdb, #0064cd); + background-image: -ms-linear-gradient(top, #049cdb, #0064cd); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd)); + background-image: -webkit-linear-gradient(top, #049cdb, #0064cd); + background-image: -o-linear-gradient(top, #049cdb, #0064cd); + background-image: linear-gradient(top, #049cdb, #0064cd); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border-color: #0064cd #0064cd #003f81; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} +.btn.active, .btn:active { + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn.disabled { + cursor: default; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + filter: alpha(opacity=65); + -khtml-opacity: 0.65; + -moz-opacity: 0.65; + opacity: 0.65; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn[disabled] { + cursor: default; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + filter: alpha(opacity=65); + -khtml-opacity: 0.65; + -moz-opacity: 0.65; + opacity: 0.65; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn.large { + font-size: 15px; + line-height: normal; + padding: 9px 14px 9px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.btn.small { + padding: 7px 9px 7px; + font-size: 11px; +} +:root .alert-message, :root .btn { + border-radius: 0 \0; +} +button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +.close { + float: right; + color: black; + font-size: 20px; + font-weight: bold; + line-height: 13.5px; + text-shadow: 0 1px 0 white; + filter: alpha(opacity=25); + -khtml-opacity: 0.25; + -moz-opacity: 0.25; + opacity: 0.25; +} +.close:hover { + color: black; + text-decoration: none; + filter: alpha(opacity=40); + -khtml-opacity: 0.4; + -moz-opacity: 0.4; + opacity: 0.4; +} +.alert-message { + position: relative; + padding: 7px 15px; + margin-bottom: 18px; + color: #404040; + background-color: #eedc94; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94)); + background-image: -moz-linear-gradient(top, #fceec1, #eedc94); + background-image: -ms-linear-gradient(top, #fceec1, #eedc94); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94)); + background-image: -webkit-linear-gradient(top, #fceec1, #eedc94); + background-image: -o-linear-gradient(top, #fceec1, #eedc94); + background-image: linear-gradient(top, #fceec1, #eedc94); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0); + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border-color: #eedc94 #eedc94 #e4c652; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + border-width: 1px; + border-style: solid; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); +} +.alert-message .close { + margin-top: 1px; + *margin-top: 0; +} +.alert-message a { + font-weight: bold; + color: #404040; +} +.alert-message.danger p a, +.alert-message.error p a, +.alert-message.success p a, +.alert-message.info p a { + color: white; +} +.alert-message h5 { + line-height: 18px; +} +.alert-message p { + margin-bottom: 0; +} +.alert-message div { + margin-top: 5px; + margin-bottom: 2px; + line-height: 28px; +} +.alert-message .btn { + -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); + -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); +} +.alert-message.block-message { + background-image: none; + background-color: #fdf5d9; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + padding: 14px; + border-color: #fceec1; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.alert-message.block-message ul, .alert-message.block-message p { + margin-right: 30px; +} +.alert-message.block-message ul { + margin-bottom: 0; +} +.alert-message.block-message li { + color: #404040; +} +.alert-message.block-message .alert-actions { + margin-top: 5px; +} +.alert-message.block-message.error, .alert-message.block-message.success, .alert-message.block-message.info { + color: #404040; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.alert-message.block-message.error { + background-color: #fddfde; + border-color: #fbc7c6; +} +.alert-message.block-message.success { + background-color: #d1eed1; + border-color: #bfe7bf; +} +.alert-message.block-message.info { + background-color: #ddf4fb; + border-color: #c6edf9; +} +.alert-message.block-message.danger p a, +.alert-message.block-message.error p a, +.alert-message.block-message.success p a, +.alert-message.block-message.info p a { + color: #404040; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + float: left; + margin: 0; + border: 1px solid #ddd; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + border-right: 1px solid; + border-right-color: #ddd; + border-right-color: rgba(0, 0, 0, 0.15); + *border-right-color: #ddd; + /* IE6-7 */ + text-decoration: none; +} +.pagination a:hover, .pagination .active a { + background-color: #c7eefe; +} +.pagination .disabled a, .pagination .disabled a:hover { + background-color: transparent; + color: #bfbfbf; +} +.pagination .next a { + border: 0; +} +.well { + background-color: #f5f5f5; + margin-bottom: 20px; + padding: 19px; + min-height: 20px; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.modal-backdrop { + background-color: black; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 10000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + filter: alpha(opacity=80); + -khtml-opacity: 0.8; + -moz-opacity: 0.8; + opacity: 0.8; +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 11000; + width: 560px; + margin: -250px 0 0 -280px; + background-color: white; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal .close { + margin-top: 7px; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + border-bottom: 1px solid #eee; + padding: 5px 15px; +} +.modal-body { + padding: 15px; +} +.modal-body form { + margin-bottom: 0; +} +.modal-footer { + background-color: #f5f5f5; + padding: 14px 15px 15px; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 white; + -moz-box-shadow: inset 0 1px 0 white; + box-shadow: inset 0 1px 0 white; + zoom: 1; + margin-bottom: 0; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; + zoom: 1; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; +} +.modal .popover, .modal .twipsy { + z-index: 12000; +} +.twipsy { + display: block; + position: absolute; + visibility: visible; + padding: 5px; + font-size: 11px; + z-index: 1000; + filter: alpha(opacity=80); + -khtml-opacity: 0.8; + -moz-opacity: 0.8; + opacity: 0.8; +} +.twipsy.fade.in { + filter: alpha(opacity=80); + -khtml-opacity: 0.8; + -moz-opacity: 0.8; + opacity: 0.8; +} +.twipsy.above .twipsy-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid black; +} +.twipsy.left .twipsy-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid black; +} +.twipsy.below .twipsy-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid black; +} +.twipsy.right .twipsy-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid black; +} +.twipsy-inner { + padding: 3px 8px; + background-color: black; + color: white; + text-align: center; + max-width: 200px; + text-decoration: none; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.twipsy-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1000; + padding: 5px; + display: none; +} +.popover.above .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid black; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid black; +} +.popover.below .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid black; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid black; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover .inner { + background: black; + background: rgba(0, 0, 0, 0.8); + padding: 3px; + overflow: hidden; + width: 280px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover .title { + background-color: #f5f5f5; + padding: 9px 15px; + line-height: 1; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + border-bottom: 1px solid #eee; +} +.popover .content { + background-color: white; + padding: 14px; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover .content p, .popover .content ul, .popover .content ol { + margin-bottom: 0; +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.label { + padding: 1px 3px 2px; + font-size: 9.75px; + font-weight: bold; + color: white; + text-transform: uppercase; + white-space: nowrap; + background-color: #bfbfbf; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label.important { + background-color: #c43c35; +} +.label.warning { + background-color: #f89406; +} +.label.success { + background-color: #46a546; +} +.label.notice { + background-color: #62cffc; +} +.media-grid { + margin-left: -20px; + margin-bottom: 0; + zoom: 1; +} +.media-grid:before, .media-grid:after { + display: table; + content: ""; + zoom: 1; +} +.media-grid:after { + clear: both; +} +.media-grid li { + display: inline; +} +.media-grid a { + float: left; + padding: 4px; + margin: 0 0 18px 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +.media-grid a img { + display: block; +} +.media-grid a:hover { + border-color: #0069d6; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} diff --git a/tests/CheckWeb/css/default.css b/tests/CheckWeb/css/default.css new file mode 100644 index 00000000000..ca3d40c7f67 --- /dev/null +++ b/tests/CheckWeb/css/default.css @@ -0,0 +1,30 @@ +.fade-when-loading { + opacity: 1; + -webkit-transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1); + -moz-transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1); + -ms-transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1); + -o-transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1); + transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1); + /* easeOutExpo */ + +} +.loading.fade-when-loading { + filter: alpha(opacity=20); + -khtml-opacity: 0.2; + -moz-opacity: 0.2; + opacity: 0.2; +} + +#title { margin: 20px 0 40px 0; } +#login #register { + display: none; +} +#login .has-errors .error-summary +{ + display: inline; + color: #B94A48; +} + +#facebook-signin { + margin: 50px 0 10px 0; +} \ No newline at end of file diff --git a/tests/CheckWeb/default.cshtml b/tests/CheckWeb/default.cshtml new file mode 100644 index 00000000000..bce08eaa5b5 --- /dev/null +++ b/tests/CheckWeb/default.cshtml @@ -0,0 +1,32 @@ +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "Page with typed 'Rockstars' model and no C# controller"; +} + +Test +@ServiceStack.MiniProfiler.Profiler.RenderIncludes(showControls: true).AsRaw() + +@(new MarkdownSharp.Markdown().Transform("## Heading").AsRaw()) + +@Html.RenderMarkdownToHtml("## Heading 2") + +@Html.DisplayPrice(0) + +@DisplayPrice(1.1m) + +@helper DisplayPrice(Decimal price) { + if (price == 0) { + FREE! + } + else { + @String.Format("{0:C2}", price) + } +} + + diff --git a/tests/CheckWeb/default.html b/tests/CheckWeb/default.html new file mode 100644 index 00000000000..bab92c61dfc --- /dev/null +++ b/tests/CheckWeb/default.html @@ -0,0 +1,11 @@ + + + Title + + +

Heading

+

+ Body! +

+ + diff --git a/tests/CheckWeb/dir/index.html b/tests/CheckWeb/dir/index.html new file mode 100644 index 00000000000..31063146576 --- /dev/null +++ b/tests/CheckWeb/dir/index.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

dir/index.html

+ + + \ No newline at end of file diff --git a/tests/CheckWeb/dir/sub/index.html b/tests/CheckWeb/dir/sub/index.html new file mode 100644 index 00000000000..e9fa3e179b7 --- /dev/null +++ b/tests/CheckWeb/dir/sub/index.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

dir/sub/index.html

+ + + \ No newline at end of file diff --git a/tests/CheckWeb/folder/_new.cshtml b/tests/CheckWeb/folder/_new.cshtml new file mode 100644 index 00000000000..8c37f257a6c --- /dev/null +++ b/tests/CheckWeb/folder/_new.cshtml @@ -0,0 +1,6 @@ +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "_new.chtml page"; +} + +

_new.cshtml

diff --git a/tests/CheckWeb/folder/new.cshtml b/tests/CheckWeb/folder/new.cshtml new file mode 100644 index 00000000000..d79830de139 --- /dev/null +++ b/tests/CheckWeb/folder/new.cshtml @@ -0,0 +1,6 @@ +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "new.chtml page"; +} + +

new.cshtml

diff --git a/tests/CheckWeb/img/favicon.png b/tests/CheckWeb/img/favicon.png new file mode 100644 index 00000000000..08e81b4cf92 Binary files /dev/null and b/tests/CheckWeb/img/favicon.png differ diff --git a/tests/CheckWeb/img/pdf-sample.pdf b/tests/CheckWeb/img/pdf-sample.pdf new file mode 100644 index 00000000000..f698ff53d41 Binary files /dev/null and b/tests/CheckWeb/img/pdf-sample.pdf differ diff --git a/tests/CheckWeb/img/pdf-sample.pdf.gz b/tests/CheckWeb/img/pdf-sample.pdf.gz new file mode 100644 index 00000000000..21e99ac5bec Binary files /dev/null and b/tests/CheckWeb/img/pdf-sample.pdf.gz differ diff --git a/tests/CheckWeb/index-rename.html b/tests/CheckWeb/index-rename.html new file mode 100644 index 00000000000..3691bca9bc6 --- /dev/null +++ b/tests/CheckWeb/index-rename.html @@ -0,0 +1,5 @@ + + +

index.html

+ + \ No newline at end of file diff --git a/tests/CheckWeb/js/backbone.min.js b/tests/CheckWeb/js/backbone.min.js new file mode 100644 index 00000000000..3f0d495dc39 --- /dev/null +++ b/tests/CheckWeb/js/backbone.min.js @@ -0,0 +1,33 @@ +// Backbone.js 0.5.3 +// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://documentcloud.github.com/backbone +(function(){var h=this,p=h.Backbone,e;e=typeof exports!=="undefined"?exports:h.Backbone={};e.VERSION="0.5.3";var f=h._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var g=h.jQuery||h.Zepto;e.noConflict=function(){h.Backbone=p;return this};e.emulateHTTP=!1;e.emulateJSON=!1;e.Events={bind:function(a,b,c){var d=this._callbacks||(this._callbacks={});(d[a]||(d[a]=[])).push([b,c]);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d= +0,e=c.length;d/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")},has:function(a){return this.attributes[a]!=null},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes,d=this._escapedAttributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return!1;if(this.idAttribute in a)this.id=a[this.idAttribute]; +var e=this._changing;this._changing=!0;for(var g in a){var h=a[g];if(!f.isEqual(c[g],h))c[g]=h,delete d[g],this._changed=!0,b.silent||this.trigger("change:"+g,this,h,b)}!e&&!b.silent&&this._changed&&this.change(b);this._changing=!1;return this},unset:function(a,b){if(!(a in this.attributes))return this;b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&!this._performValidation(c,b))return!1;delete this.attributes[a];delete this._escapedAttributes[a];a==this.idAttribute&&delete this.id;this._changed= +!0;b.silent||(this.trigger("change:"+a,this,void 0,b),this.change(b));return this},clear:function(a){a||(a={});var b,c=this.attributes,d={};for(b in c)d[b]=void 0;if(!a.silent&&this.validate&&!this._performValidation(d,a))return!1;this.attributes={};this._escapedAttributes={};this._changed=!0;if(!a.silent){for(b in c)this.trigger("change:"+b,this,void 0,a);this.change(a)}return this},fetch:function(a){a||(a={});var b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&& +c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"read",this,a)},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return!1;var c=this,d=b.success;b.success=function(a,e,f){if(!c.set(c.parse(a,f),b))return!1;d&&d(c,a,f)};b.error=i(b.error,c,b);var f=this.isNew()?"create":"update";return(this.sync||e.sync).call(this,f,this,b)},destroy:function(a){a||(a={});if(this.isNew())return this.trigger("destroy",this,this.collection,a);var b=this,c=a.success;a.success=function(d){b.trigger("destroy", +b,b.collection,a);c&&c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"delete",this,a)},url:function(){var a=k(this.collection)||this.urlRoot||l();if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return this.id==null},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=!1},hasChanged:function(a){if(a)return this._previousAttributes[a]!= +this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=!1,d;for(d in a)f.isEqual(b[d],a[d])||(c=c||{},c[d]=a[d]);return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);if(c)return b.error?b.error(this,c,b):this.trigger("error",this,c,b),!1;return!0}}); +e.Collection=function(a,b){b||(b={});if(b.comparator)this.comparator=b.comparator;f.bindAll(this,"_onModelEvent","_removeReference");this._reset();a&&this.reset(a,{silent:!0});this.initialize.apply(this,arguments)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c').hide().appendTo("body")[0].contentWindow,this.navigate(a); +this._hasPushState?g(window).bind("popstate",this.checkUrl):"onhashchange"in window&&!b?g(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);this.fragment=a;m=!0;a=window.location;b=a.pathname==this.options.root;if(this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;else if(this._wantsPushState&&this._hasPushState&&b&&a.hash)this.fragment=a.hash.replace(j,""),window.history.replaceState({}, +document.title,a.protocol+"//"+a.host+this.options.root+this.fragment);if(!this.options.silent)return this.loadUrl()},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.iframe.location.hash));if(a==this.fragment||a==decodeURIComponent(this.fragment))return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(window.location.hash)},loadUrl:function(a){var b=this.fragment=this.getFragment(a); +return f.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){var c=(a||"").replace(j,"");if(!(this.fragment==c||this.fragment==decodeURIComponent(c))){if(this._hasPushState){var d=window.location;c.indexOf(this.options.root)!=0&&(c=this.options.root+c);this.fragment=c;window.history.pushState({},document.title,d.protocol+"//"+d.host+c)}else if(window.location.hash=this.fragment=c,this.iframe&&c!=this.getFragment(this.iframe.location.hash))this.iframe.document.open().close(), +this.iframe.location.hash=c;b&&this.loadUrl(a)}}});e.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize.apply(this,arguments)};var u=/^(\S+)\s*(.*)$/,n=["model","collection","el","id","attributes","className","tagName"];f.extend(e.View.prototype,e.Events,{tagName:"div",$:function(a){return g(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){g(this.el).remove();return this},make:function(a, +b,c){a=document.createElement(a);b&&g(a).attr(b);c&&g(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events))for(var b in f.isFunction(a)&&(a=a.call(this)),g(this.el).unbind(".delegateEvents"+this.cid),a){var c=this[a[b]];if(!c)throw Error('Event "'+a[b]+'" does not exist');var d=b.match(u),e=d[1];d=d[2];c=f.bind(c,this);e+=".delegateEvents"+this.cid;d===""?g(this.el).bind(e,c):g(this.el).delegate(d,e,c)}},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b= +0,c=n.length;b").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/tests/CheckWeb/js/jsonreport.js b/tests/CheckWeb/js/jsonreport.js new file mode 100644 index 00000000000..60cef2f85e9 --- /dev/null +++ b/tests/CheckWeb/js/jsonreport.js @@ -0,0 +1,150 @@ +/** + * Created by demis.bellot@gmail.com + * Open Source under the New BSD Licence: https://github.com/AjaxStack/AjaxStack/blob/master/LICENSE + */ + +//for non-modern browsers i.e: <=IE8 +!window.JSON && document.write(unescape('%3Cscript src=""http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js""%3E%3C/script%3E')); + +var cssText = + ".jsonreport TABLE { border-collapse:collapse; border: solid 1px #ccc; clear: left; }\r\n" + + ".jsonreport TH { text-align: left; padding: 4px 8px; text-shadow: #fff 1px 1px -1px; background: #f1f1f1; white-space:nowrap; cursor:pointer; font-weight: bold; }\r\n" + + ".jsonreport TH, .jsonreport TD, .jsonreport TD DT, .jsonreport TD DD { font-size: 13px; font-family: Arial; }\r\n" + + ".jsonreport TD { padding: 8px 8px 0 8px; vertical-align: top; }\r\n" + + ".jsonreport DL { clear: left; }\r\n" + + ".jsonreport DT { margin: 10px 0 5px 0; font: bold 18px Helvetica, Verdana, Arial; width: 200px; clear: left; float: left; display:block; white-space:nowrap; }\r\n" + + ".jsonreport DD { margin: 5px 10px; font: 18px Arial; padding: 2px; display: block; float: left; }\r\n" + + ".jsonreport DL DL DT { font: bold 16px Arial; }\r\n" + + ".jsonreport DL DL DD { font: 16px Arial; }\r\n" + + ".jsonreport HR { display:none; }\r\n" + + ".jsonreport TD DL HR { display:block; padding: 0; clear: left; border: none; }\r\n" + + ".jsonreport TD DL { padding: 4px; margin: 0; height:100%; max-width: 700px; }\r\n" + + ".jsonreport DL TD DL DT { padding: 2px; margin: 0 10px 0 0; font-weight: bold; font-size: 13px; width: 120px; overflow: hidden; clear: left; float: left; display:block; }\r\n" + + ".jsonreport DL TD DL DD { margin: 0; padding: 2px; font-size: 13px; display: block; float: left; }\r\n" + + ".jsonreport TBODY>TR:last-child>TD { padding: 8px; }\r\n" + + ".jsonreport THEAD { -webkit-user-select:none; -moz-user-select:none; }\r\n" + + ".jsonreport .desc, .jsonreport .asc { background-color: #FAFAD2; }\r\n" + + ".jsonreport .desc { background-color: #D4EDC9; }\r\n" + + ".jsonreport TH B { display:block; float:right; margin: 0 0 0 5px; width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #ccc; border-bottom: none; }\r\n" + + ".jsonreport .asc B { border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid #333; border-bottom: none; }\r\n" + + ".jsonreport .desc B { border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid #333; border-top: none; }\r\n" + + ".jsonreport H3 { font-size: 18px; margin: 0 0 10px 0; }"; + +document.write('\r\n'); + +if (!_) let _ = {}; +_.jsonreport = (function(){ + let root = this, doc = document, + $ = function(id) { return doc.getElementById(id); }, + $$ = function(sel) { return doc.getElementsByTagName(sel); }, + $each = function(fn) { for (var i=0,len=this.length; i
' + val(m[k]) + '
'; + sb += ''; + return sb; + } + function arr(m) { + if (typeof m[0] == 'string' || typeof m[0] == 'number') return m.join(', '); + let id=tbls.length, h=uniqueKeys(m); + let sb = '
'; + tbls.push(m); + let i=0; + for (let k in h) sb += ''; + sb += '' + makeRows(h,m) + '
' + splitCase(k) + '
'; + return sb; + } + + function makeRows(h,m) { + let sb = ''; + for (let r=0,len=m.length; r'; + sb += ''; + } + return sb; + } + + function setTableBody(tbody, html) { + if (!isIE) { tbody.innerHTML = html; return; } + let temp = tbody.ownerDocument.createElement('div'); + temp.innerHTML = '' + html + '
'; + tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); + } + + function clearSel() { + if (doc.selection && doc.selection.empty) doc.selection.empty(); + else if(root.getSelection) { + let sel=root.getSelection(); + if (sel && sel.removeAllRanges) sel.removeAllRanges(); + } + } + + function cmp(v1, v2){ + let f1=parseFloat(v1), f2=parseFloat(v2) + if (!isNaN(f1) && !isNaN(f2)) { v1=f1; v2=f2 } + if (typeof v1 == 'string' && v1.substr(0,6) === '/Date(') { v1=date(v1); v2=date(v2) } + if (v1 === v2) return 0 + return v1 > v2 ? 1 : -1 + } + + function enc(html) { + if (typeof html != 'string') return html; + return html.replace(//g,'>').replace(/"/g,'"'); + } + + function addEvent(obj, type, fn) { + if (obj.attachEvent) { + obj['e'+type+fn] = fn; + obj[type+fn] = function(){obj['e'+type+fn]( root.event );} + obj.attachEvent( 'on'+type, obj[type+fn] ); + } else + obj.addEventListener( type, fn, false ); + } + + addEvent(doc, 'click', function (e) { + e = e || root.event + let el = e.target || e.srcElement, cls = el.className + if (el.tagName === 'B') el = el.parentNode + if (el.tagName !== 'TH') return + el.className = cls === 'asc' ? 'desc' : (cls === 'desc' ? null : 'asc') + $.each($$('TH'), function(i,th){ if (th === el) return; th.className = null; }) + clearSel() + let ids=el.id.split('-'), tId=ids[1], cId=ids[2] + let tbl=tbls[tId].slice(0), h=uniqueKeys(tbl), col=keys(h)[cId], tbody=el.parentNode.parentNode.nextSibling + if (!el.className){ setTableBody(tbody, makeRows(h,tbls[tId])); return } + let d=el.className==='asc'?1:-1 + tbl.sort(function(a,b){ return cmp(a[col],b[col]) * d; }) + setTableBody(tbody, makeRows(h,tbl)) + }) + + return function(json) { + let model = typeof json == "string" ? JSON.parse(json) : json; + return val(model); + }; +})(); + diff --git a/tests/CheckWeb/js/underscore.min.js b/tests/CheckWeb/js/underscore.min.js new file mode 100644 index 00000000000..5983694cfbb --- /dev/null +++ b/tests/CheckWeb/js/underscore.min.js @@ -0,0 +1,27 @@ +// Underscore.js 1.1.7 +// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){var p=this,C=p._,m={},i=Array.prototype,n=Object.prototype,f=i.slice,D=i.unshift,E=n.toString,l=n.hasOwnProperty,s=i.forEach,t=i.map,u=i.reduce,v=i.reduceRight,w=i.filter,x=i.every,y=i.some,o=i.indexOf,z=i.lastIndexOf;n=Array.isArray;var F=Object.keys,q=Function.prototype.bind,b=function(a){return new j(a)};typeof module!=="undefined"&&module.exports?(module.exports=b,b._=b):p._=b;b.VERSION="1.1.7";var h=b.each=b.forEach=function(a,c,b){if(a!=null)if(s&&a.forEach===s)a.forEach(c,b);else if(a.length=== ++a.length)for(var e=0,k=a.length;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a, +c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;bd?1:0}),"value")};b.groupBy=function(a,b){var d={};h(a,function(a,f){var g=b(a,f);(d[g]||(d[g]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d|| +(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a,c){return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=f.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after= +function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}};b.keys=F||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)l.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){h(f.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){h(f.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,c){if(a===c)return!0;var d=typeof a;if(d!=typeof c)return!1;if(a==c)return!0;if(!a&&c||a&&!c)return!1;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual)return a.isEqual(c);if(c.isEqual)return c.isEqual(a);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return!1; +if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return!1;if(a.length&&a.length!==c.length)return!1;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return!1;for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return!1;return!0};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(l.call(a,c))return!1;return!0};b.isElement=function(a){return!!(a&&a.nodeType== +1)};b.isArray=n||function(a){return E.call(a)==="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return!(!a||!l.call(a,"callee"))};b.isFunction=function(a){return!(!a||!a.constructor||!a.call||!a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===!0||a===!1};b.isDate=function(a){return!(!a||!a.getTimezoneOffset|| +!a.setUTCFullYear)};b.isRegExp=function(a){return!(!a||!a.test||!a.exec||!(a.ignoreCase||a.ignoreCase===!1))};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){p._=C;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g}; +b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d}; +var j=function(a){this._wrapped=a};b.prototype=j.prototype;var r=function(a,c){return c?b(a).chain():a},H=function(a,c){j.prototype[a]=function(){var a=f.call(arguments);D.call(a,this._wrapped);return r(c.apply(b,a),this._chain)}};b.mixin(b);h(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=i[a];j.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});h(["concat","join","slice"],function(a){var b=i[a];j.prototype[a]=function(){return r(b.apply(this._wrapped, +arguments),this._chain)}});j.prototype.chain=function(){this._chain=!0;return this};j.prototype.value=function(){return this._wrapped}})(); diff --git a/tests/CheckWeb/register.htm b/tests/CheckWeb/register.htm new file mode 100644 index 00000000000..20b69304509 --- /dev/null +++ b/tests/CheckWeb/register.htm @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ Create your member account + +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+ + + +

+ + +

+
+
+
+ + +
+
+
+
+ Sign In + +
+ + + +
+
+ + + +
+
+
+
    +
  • + +
  • +
+
+ +
+ +

+ +

+ +

+ +

+
+
+
+
+

Auth Info

+
+ +
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/tests/CheckWeb/swagger-ui/patch-preload.js b/tests/CheckWeb/swagger-ui/patch-preload.js new file mode 100644 index 00000000000..c5f9663ec37 --- /dev/null +++ b/tests/CheckWeb/swagger-ui/patch-preload.js @@ -0,0 +1 @@ +console.log('patch-preload.js', window.swaggerUi); \ No newline at end of file diff --git a/tests/CheckWeb/swagger-ui/patch.js b/tests/CheckWeb/swagger-ui/patch.js new file mode 100644 index 00000000000..2ded0378d72 --- /dev/null +++ b/tests/CheckWeb/swagger-ui/patch.js @@ -0,0 +1 @@ +console.log('patch.js', window.swaggerUi); \ No newline at end of file diff --git a/tests/CheckWeb/test.cshtml b/tests/CheckWeb/test.cshtml new file mode 100644 index 00000000000..4a212a843fc --- /dev/null +++ b/tests/CheckWeb/test.cshtml @@ -0,0 +1,13 @@ + +

test

+ + + + + + \ No newline at end of file diff --git a/tests/CheckWebCore/CheckWebCore.csproj b/tests/CheckWebCore/CheckWebCore.csproj new file mode 100644 index 00000000000..281c13e41a2 --- /dev/null +++ b/tests/CheckWebCore/CheckWebCore.csproj @@ -0,0 +1,29 @@ + + + net6.0 + latest + true + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CheckWebCore/Configure.Auth.cs b/tests/CheckWebCore/Configure.Auth.cs new file mode 100644 index 00000000000..d3aee609775 --- /dev/null +++ b/tests/CheckWebCore/Configure.Auth.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using MyApp; +using ServiceStack; +using ServiceStack.Admin; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.FluentValidation; + +namespace CheckWebCore +{ + /// + /// Run before AppHost.Configure() + /// + public class ConfigureAuth : IConfigureAppHost + { + private IConfiguration configuration; + public ConfigureAuth(IConfiguration configuration) => this.configuration = configuration; + + public void Configure(IAppHost appHost) + { + var AppSettings = appHost.AppSettings; + appHost.Plugins.Add(new AuthFeature(() => new CustomUserSession(), + new IAuthProvider[] { + //new BasicAuthProvider(), //Sign-in with HTTP Basic Auth + new JwtAuthProvider(AppSettings) + { + AuthKey = AesUtils.CreateKey(), + RequireSecureConnection = false, + }, + new CredentialsAuthProvider { + SkipPasswordVerificationForInProcessRequests = true, + }, //HTML Form post of UserName/Password credentials + new ApiKeyAuthProvider(AppSettings), + new TwitterAuthProvider(AppSettings), + new GithubAuthProvider(AppSettings), + new GoogleAuthProvider(AppSettings), + new FacebookAuthProvider(AppSettings), + new MicrosoftGraphAuthProvider(AppSettings), +// new LinkedInAuthProvider(AppSettings), + }) { + HtmlRedirect = "/validation/server/login", + HtmlRedirectAccessDenied = "/forbidden", + }); + + appHost.Plugins.Add(new RegistrationFeature()); + + appHost.Plugins.Add(new AdminUsersFeature()); + + //override the default registration validation with your own custom implementation + appHost.RegisterAs>(); + + var authRepo = appHost.TryResolve(); + + var newAdmin = new AppUser {Email = "admin@email.com", DisplayName = "Admin User"}; + var user = authRepo.CreateUserAuth(newAdmin, "p@55wOrd"); + authRepo.AssignRoles(user, new List {"Admin"}); + + authRepo.CreateUserAuth(new AppUser {UserName = "test", DisplayName = "Test"}, "test"); + } + } + + public class CustomUserSession : AuthUserSession {} + + public class CustomRegistrationValidator : RegistrationValidator + { + public CustomRegistrationValidator() + { + RuleSet(ApplyTo.Post, () => + { + RuleFor(x => x.DisplayName).NotEmpty(); + RuleFor(x => x.ConfirmPassword).NotEmpty(); + }); + } + } + + [Route("/apikeyonly")] + public class ApiKeyOnly : IReturn {} + + [Authenticate(AuthenticateService.ApiKeyProvider)] + public class ApiKeyAuthServices : Service + { + public object Any(ApiKeyOnly request) => "OK"; + } + + [Route("/jwtonly")] + public class JwtOnly : IReturn {} + + [Authenticate(AuthenticateService.JwtProvider)] + public class JwtAuthServices : Service + { + public object Any(JwtOnly request) => "OK"; + } + +} \ No newline at end of file diff --git a/tests/CheckWebCore/Configure.AuthRepository.cs b/tests/CheckWebCore/Configure.AuthRepository.cs new file mode 100644 index 00000000000..b5333848853 --- /dev/null +++ b/tests/CheckWebCore/Configure.AuthRepository.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using ServiceStack; +using ServiceStack.Web; +using ServiceStack.Auth; +using ServiceStack.Configuration; + +namespace MyApp +{ + // Custom UserAuth Data Model with extended Metadata properties + public class AppUser : UserAuth + { + public string ProfileUrl { get; set; } + public string LastLoginIp { get; set; } + public DateTime? LastLoginDate { get; set; } + } + + public class AppUserAuthEvents : AuthEvents + { + public override void OnAuthenticated(IRequest req, IAuthSession session, IServiceBase authService, + IAuthTokens tokens, Dictionary authInfo) + { + var authRepo = HostContext.AppHost.GetAuthRepository(req); + using (authRepo as IDisposable) + { + var userAuth = (AppUser)authRepo.GetUserAuth(session.UserAuthId); + userAuth.ProfileUrl = session.GetProfileUrl(); + userAuth.LastLoginIp = req.UserHostAddress; + userAuth.LastLoginDate = DateTime.UtcNow; + authRepo.SaveUserAuth(userAuth); + } + } + } + + public class ConfigureAuthRepository : IConfigureAppHost, IConfigureServices, IPreInitPlugin + { + public void Configure(IServiceCollection services) + { + services.AddSingleton(c => + new InMemoryAuthRepository()); + } + + public void Configure(IAppHost appHost) + { + var authRepo = appHost.Resolve(); + authRepo.InitSchema(); + + //CreateUser(authRepo, "admin@email.com", "Admin User", "p@55wOrd", roles:new[]{ RoleNames.Admin }); + } + + public void BeforePluginsLoaded(IAppHost appHost) + { + appHost.AssertPlugin().AuthEvents.Add(new AppUserAuthEvents()); + } + + // Add initial Users to the configured Auth Repository + public void CreateUser(IAuthRepository authRepo, string email, string name, string password, string[] roles) + { + if (authRepo.GetUserAuthByUserName(email) == null) + { + var newAdmin = new AppUser { Email = email, DisplayName = name }; + var user = authRepo.CreateUserAuth(newAdmin, password); + authRepo.AssignRoles(user, roles); + } + } + } +} diff --git a/tests/CheckWebCore/Configure.OpenApi.cs b/tests/CheckWebCore/Configure.OpenApi.cs new file mode 100644 index 00000000000..cc988ca535b --- /dev/null +++ b/tests/CheckWebCore/Configure.OpenApi.cs @@ -0,0 +1,20 @@ +using ServiceStack; +using ServiceStack.Api.OpenApi; + +namespace CheckWebCore +{ + /// + /// Run after AppHost.Configure() + /// + [Priority(1)] + public class ConfigureOpenApi : IConfigureAppHost + { + public void Configure(IAppHost appHost) + { + appHost.Plugins.Add(new OpenApiFeature + { + UseBearerSecurity = true, + }); + } + } +} \ No newline at end of file diff --git a/tests/CheckWebCore/ConfigureValidation.cs b/tests/CheckWebCore/ConfigureValidation.cs new file mode 100644 index 00000000000..d43be57126b --- /dev/null +++ b/tests/CheckWebCore/ConfigureValidation.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using ServiceStack; + +namespace CheckWebCore +{ + public class DynamicIsAuthenticated : IReturn + { + public string Name { get; set; } + } + public class DynamicIsAdmin : IReturn + { + public string Name { get; set; } + } + public class DynamicHasRole : IReturn + { + public string Name { get; set; } + } + public class DynamicHasPermissions : IReturn + { + public string Name { get; set; } + } + + public class DynamicValidationServices : Service + { + public object Any(DynamicIsAuthenticated request) => request; + public object Any(DynamicIsAdmin request) => request; + public object Any(DynamicHasRole request) => request; + public object Any(DynamicHasPermissions request) => request; + } + + public class ConfigureValidation : IConfigureServices, IConfigureAppHost + { + public void Configure(IServiceCollection services) + { + services.AddSingleton(c => new MemoryValidationSource()); + } + + public void Configure(IAppHost appHost) + { + var validationSource = appHost.Resolve(); + validationSource.InitSchema(); + + validationSource.SaveValidationRulesAsync(new List { + new() { Type = nameof(DynamicIsAuthenticated), Validator = nameof(ValidateScripts.IsAuthenticated) }, + new() { Type = nameof(DynamicIsAdmin), Validator = nameof(ValidateScripts.IsAdmin) }, + new() { Type = nameof(DynamicHasRole), Validator = "HasRole('TheRole')" }, + new() { Type = nameof(DynamicHasPermissions), Validator = "HasPermissions(['Perm1','Perm2'])" }, + }); + } + } +} \ No newline at end of file diff --git a/tests/CheckWebCore/ContactServices.cs b/tests/CheckWebCore/ContactServices.cs new file mode 100644 index 00000000000..8dfc0cac18a --- /dev/null +++ b/tests/CheckWebCore/ContactServices.cs @@ -0,0 +1,305 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Drawing; +using System.Globalization; +using System.Threading; +using Microsoft.AspNetCore.Mvc.Rendering; +using ServiceStack; +using ServiceStack.FluentValidation; +using ServiceStack.Script; +using ServiceStack.DataAnnotations; + +namespace CheckWebCore +{ + namespace Data + { + using ServiceModel.Types; + + public class Contact // Data Model + { + public int Id { get; set; } + public int UserAuthId { get; set; } + public Title Title { get; set; } + public string Name { get; set; } + public string Color { get; set; } + public FilmGenres[] FilmGenres { get; set; } + public int Age { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } + } + } + + namespace ServiceModel + { + using Types; + + [Route("/contacts", "GET")] + public class GetContacts : IReturn {} + public class GetContactsResponse + { + public List Results { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/contacts/{Id}", "GET")] + public class GetContact : IReturn + { + public int Id { get; set; } + } + public class GetContactResponse + { + public Contact Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/contacts", "POST")] + public class CreateContact : IReturn + { + public Title Title { get; set; } + public string Name { get; set; } + public string Color { get; set; } + public FilmGenres[] FilmGenres { get; set; } + public int Age { get; set; } + public bool Agree { get; set; } + public string Continue { get; set; } + public string ErrorView { get; set; } + } + public class CreateContactResponse + { + public Contact Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [System.ComponentModel.Bindable(true)] + [Route("/contacts/{Id}", "POST PUT")] + public class UpdateContact : IReturn + { + public int Id { get; set; } + public Title Title { get; set; } + public string Name { get; set; } + public string Color { get; set; } + public FilmGenres[] FilmGenres { get; set; } + public int Age { get; set; } + + public string Continue { get; set; } + public string ErrorView { get; set; } + } + public class UpdateContactResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/contacts/{Id}", "DELETE")] + [Route("/contacts/{Id}/delete", "POST")] // more accessible from HTML + public class DeleteContact : IReturnVoid + { + public int Id { get; set; } + public string Continue { get; set; } + } + + namespace Types + { + [System.ComponentModel.Bindable(false)] + public class Contact // DTO + { + public int Id { get; set; } + public int UserAuthId { get; set; } + public Title Title { get; set; } + public string Name { get; set; } + public string Color { get; set; } + public FilmGenres[] FilmGenres { get; set; } + public int Age { get; set; } + } + + public enum Title + { + Unspecified=0, + [Description("Mr.")] Mr, + [Description("Mrs.")] Mrs, + [Description("Miss.")] Miss + } + + public enum FilmGenres + { + Action, + Adventure, + Comedy, + Drama, + } + } + } + + namespace ServiceInterface + { + using ServiceModel; + using ServiceModel.Types; + + public class CreateContactValidator : AbstractValidator + { + public CreateContactValidator() + { + RuleFor(r => r.Title).NotEqual(Title.Unspecified).WithMessage("Please choose a title"); + RuleFor(r => r.Name).NotEmpty(); + RuleFor(r => r.Color).Must(x => x.IsValidColor()).WithMessage("Must be a valid color"); + RuleFor(r => r.FilmGenres).NotEmpty().WithMessage("Please select at least 1 genre"); + RuleFor(r => r.Age).GreaterThan(13).WithMessage("Contacts must be older than 13"); + RuleFor(x => x.Agree).Equal(true).WithMessage("You must agree before submitting"); + } + } + + public class UpdateContactValidator : AbstractValidator + { + public UpdateContactValidator() + { + RuleFor(r => r.Id).GreaterThan(0); + RuleFor(r => r.Title).NotEqual(Title.Unspecified).WithMessage("Please choose a title"); + RuleFor(r => r.Name).NotEmpty(); + RuleFor(r => r.Color).Must(x => x.IsValidColor()).WithMessage("Must be a valid color"); + RuleFor(r => r.FilmGenres).NotEmpty().WithMessage("Please select at least 1 genre"); + RuleFor(r => r.Age).GreaterThan(13).WithMessage("Contacts must be older than 13"); + } + } + + [Authenticate] + [ErrorView(nameof(CreateContact.ErrorView))] // Display ErrorView if HTML request results in an Exception + [DefaultView("/validation/server/contacts")] + public class ContactServices : Service + { + private static int Counter = 0; + + internal static readonly ConcurrentDictionary Contacts = new ConcurrentDictionary(); + + public object Any(GetContacts request) + { + var userId = this.GetUserId(); + return new GetContactsResponse + { + Results = Contacts.Values + .Where(x => x.UserAuthId == userId) + .OrderByDescending(x => x.Id) + .Map(x => x.ConvertTo()) + }; + } + + public object Any(GetContact request) => + Contacts.TryGetValue(request.Id, out var contact) && contact.UserAuthId == this.GetUserId() + ? (object)new GetContactResponse { Result = contact.ConvertTo() } + : HttpError.NotFound($"Contact was not found"); + + public object Any(CreateContact request) + { + var newContact = request.ConvertTo(); + newContact.Id = Interlocked.Increment(ref Counter); + newContact.UserAuthId = this.GetUserId(); + newContact.CreatedDate = newContact.ModifiedDate = DateTime.UtcNow; + + var contacts = Contacts.Values.ToList(); + var alreadyExists = contacts.Any(x => x.UserAuthId == newContact.UserAuthId && x.Name == request.Name); + if (alreadyExists) + throw new ArgumentException($"You already have a contact named '{request.Name}'", nameof(request.Name)); + + Contacts[newContact.Id] = newContact; + return new CreateContactResponse { Result = newContact.ConvertTo() }; + } + + public object AnyHtml(CreateContact request) + { + Any(request); + return HttpResult.Redirect(request.Continue ?? Request.GetView()); + } + + public void Any(DeleteContact request) + { + if (Contacts.TryGetValue(request.Id, out var contact) && contact.UserAuthId == this.GetUserId()) + { + Contacts.TryRemove(request.Id, out _); + } + } + + public object PostHtml(DeleteContact request) // only called by html POST requests where it takes precedence + { + Any(request); + return HttpResult.Redirect(request.Continue ?? Request.GetView()); //added by [DefaultView] + } + } + + // Example of single 'pure' API supporting multiple HTML UIs + [ErrorView(nameof(UpdateContact.ErrorView))] // Display ErrorView if HTML request results in an Exception + public class UpdateContactServices : Service + { + public object Any(UpdateContact request) + { + if (!ContactServices.Contacts.TryGetValue(request.Id, out var contact) || contact.UserAuthId != this.GetUserId()) + throw HttpError.NotFound("Contact was not found"); + + contact.PopulateWith(request); + contact.ModifiedDate = DateTime.UtcNow; + + return request.Continue != null + ? (object) HttpResult.Redirect(request.Continue) + : new UpdateContactResponse(); + } + } + + public static class ContactServiceExtensions + { + public static int GetUserId(this Service service) => int.Parse(service.GetSession().UserAuthId); + + public static bool IsValidColor(this string color) => !string.IsNullOrEmpty(color) && + (color.FirstCharEquals('#') + ? int.TryParse(color.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _) + : Color.FromName(color).IsKnownColor); + + } + + /// + /// Custom filters for App data sources and re-usable UI snippets in Templates + /// + public class ContactServiceFilters : ScriptMethods + { + public List menuItems() => ViewUtils.GetNavItems("Menu"); + + static Dictionary Colors = new Dictionary + { + {"#ffa4a2","Red"}, + {"#b2fab4","Green"}, + {"#9be7ff","Blue"} + }; + public Dictionary contactColors() => Colors; + + private static List> Titles => EnumUtils.GetValues() + .Where(x => x != Title.Unspecified) + .ToKeyValuePairs(); + public List<KeyValuePair<string, string>> contactTitles() => Titles; + + private static List<string> FilmGenres => EnumUtils.GetValues<FilmGenres>().Map(x => x.ToDescription()); + public List<string> contactGenres() => FilmGenres; + } + + } + + /// <summary> + /// Razor Helpers for App data sources and re-usable UI snippets in Razor pages + /// </summary> + public static class RazorHelpers + { + internal static readonly ServiceInterface.ContactServiceFilters Instance = new ServiceInterface.ContactServiceFilters(); + + public static Dictionary<string, string> ContactColors(this IHtmlHelper html) => Instance.contactColors(); + public static List<KeyValuePair<string, string>> ContactTitles(this IHtmlHelper html) => Instance.contactTitles(); + public static List<string> ContactGenres(this IHtmlHelper html) => Instance.contactGenres(); + public static List<NavItem> MenuItems(this IHtmlHelper html) => ViewUtils.GetNavItems("Menu"); + } + + public class ContactsHostConfig : IConfigureAppHost + { + public void Configure(IAppHost appHost) + { + AutoMapping.RegisterConverter((Data.Contact from) => + from.ConvertTo<ServiceModel.Types.Contact>(skipConverters: true)); + } + } + +} \ No newline at end of file diff --git a/tests/CheckWebCore/Program.cs b/tests/CheckWebCore/Program.cs new file mode 100644 index 00000000000..874acbd508c --- /dev/null +++ b/tests/CheckWebCore/Program.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Hosting; +using ServiceStack; + +namespace CheckWebCore +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + // Additional configuration is required to successfully run gRPC on macOS. + // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { + webBuilder +// .ConfigureKestrel(options => { +// options.ListenLocalhost(5000, +// listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; }); +// }) + .UseModularStartup<Startup>(); + }); + } +} \ No newline at end of file diff --git a/tests/CheckWebCore/Properties/launchSettings.json b/tests/CheckWebCore/Properties/launchSettings.json new file mode 100644 index 00000000000..380c8bfd9b2 --- /dev/null +++ b/tests/CheckWebCore/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "https://localhost:5001/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "CheckWebCore": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001/" + } + } +} \ No newline at end of file diff --git a/tests/CheckWebCore/Startup.cs b/tests/CheckWebCore/Startup.cs new file mode 100644 index 00000000000..c3f52516d5f --- /dev/null +++ b/tests/CheckWebCore/Startup.cs @@ -0,0 +1,536 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Net; +using System.Reflection; +using System.Runtime.Serialization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using ServiceStack; +using ServiceStack.Api.OpenApi; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Configuration; +using ServiceStack.DataAnnotations; +using ServiceStack.FluentValidation.Validators; +using ServiceStack.Host; +using ServiceStack.Logging; +using ServiceStack.Mvc; +using ServiceStack.NativeTypes.CSharp; +using ServiceStack.NativeTypes.TypeScript; +using ServiceStack.Script; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; +using Container = Funq.Container; + +namespace CheckWebCore +{ + [Priority(-1)] + public class MyPreConfigureServices : IConfigureServices + { + public void Configure(IServiceCollection services) => "#1".Print(); // #1 + } + + public class MyConfigureServices : IConfigureServices + { + public void Configure(IServiceCollection services) => "#4".Print(); // #4 + } + + [Priority(-1)] + public class MyStartup : IStartup + { + public IServiceProvider ConfigureServices(IServiceCollection services) + { + "#2".Print(); // #2 + return null; + } + + public void Configure(IApplicationBuilder app) => "#6".Print(); // #6 + } + + public class Startup : ModularStartup + { + public Startup(IConfiguration configuration) : base(configuration) + { +// IgnoreTypes.Add(typeof(MyStartup)); + } + + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public new void ConfigureServices(IServiceCollection services) + { + "#3".Print(); // #3 + services.AddMvc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + "#8".Print(); // #8 + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + } + } + + [Priority(1)] + public class MyPostConfigureServices : IConfigureServices + { + public void Configure(IServiceCollection services) => "#5".Print(); // #5 + } + + [Priority(-1)] + public class MyPreConfigureApp : IConfigureApp + { + public void Configure(IApplicationBuilder app)=> "#7".Print(); // #7 + } + public class MyConfigureApp : IConfigureApp + { + public void Configure(IApplicationBuilder app)=> "#9".Print(); // #9 + } + + + public interface IAppHostConstraint{} + public class AppHostConstraint : IAppHostConstraint{} + public abstract class AppHostConstraintsBase<TServiceInterfaceAssembly> : AppHostBase + where TServiceInterfaceAssembly : IAppHostConstraint + { + protected AppHostConstraintsBase(string serviceName, params Assembly[] assembliesWithServices) + : base(serviceName, assembliesWithServices) + { + ConsoleLogFactory.Configure(); + } + } + + public class AppHost + //: AppHostConstraintsBase<AppHostConstraint>, IConfigureApp + : AppHostBase, IConfigureApp + { + public AppHost() : base("TestLogin", typeof(MyServices).Assembly) { } + + public void Configure(IApplicationBuilder app) + { + app.UseRouting(); + + app.UseServiceStack(new AppHost + { + // PathBase = "/api", + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + services.AddSingleton<ICacheClient>(new MemoryCacheClient()); + } + + // http://localhost:5000/auth/credentials?username=testman@test.com&&password=!Abc1234 + // Configure your AppHost with the necessary configuration and dependencies your App needs + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + AddRedirectParamsToQueryString = true, + //DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), false), + DebugMode = true, +// UseSameSiteCookies = true, // prevents OAuth providers which use Sessions like Twitter from working + UseSecureCookies = true, + AdminAuthSecret = "secretz", + CompressFilesWithExtensions = { "js", "css" }, + }); + + RegisterService<GetFileService>(); + + Plugins.Add(new GrpcFeature(App)); + + // enable server-side rendering, see: https://sharpscript.net + Plugins.Add(new SharpPagesFeature { + ScriptMethods = { new CustomScriptMethods() } + }); + + Plugins.Add(new ServerEventsFeature()); + Plugins.Add(new LispReplTcpServer { +// RequireAuthSecret = true, + AllowScriptingOfAllTypes = true, + }); + + ConfigurePlugin<UiFeature>(feature => { + feature.Info.BrandIcon.Uri = "https://vuejs.org/images/logo.svg"; + }); + + //not needed for /wwwroot/ui + //Plugins.AddIfDebug(new HotReloadFeature()); + + Plugins.Add(new RazorFormat()); // enable ServiceStack.Razor + + var cache = container.Resolve<ICacheClient>(); + + Plugins.Add(new ValidationFeature()); + +// Svg.CssFillColor["svg-auth"] = "#ccc"; + Svg.CssFillColor["svg-icons"] = "#e33"; + + this.CustomErrorHttpHandlers[HttpStatusCode.NotFound] = new RazorHandler("/notfound"); + this.CustomErrorHttpHandlers[HttpStatusCode.Forbidden] = new SharpPageHandler("/forbidden"); + + Svg.Load(RootDirectory.GetDirectory("/assets/svg")); + + Plugins.Add(new PostmanFeature()); + + var nativeTypesFeature = GetPlugin<NativeTypesFeature>(); + nativeTypesFeature + .ExportAttribute<BindableAttribute>(attr => { + var metaAttr = nativeTypesFeature.GetGenerator().ToMetadataAttribute(attr); + return metaAttr; + }); + + + CSharpGenerator.TypeFilter = (type, args) => { + if (type == "ResponseBase`1" && args[0] == "Dictionary<String,List`1>") + return "ResponseBase<Dictionary<string,List<object>>>"; + return null; + }; + + TypeScriptGenerator.TypeFilter = (type, args) => { + if (type == "ResponseBase`1" && args[0] == "Dictionary<String,List`1>") + return "ResponseBase<Map<string,Array<any>>>"; + return null; + }; + + TypeScriptGenerator.DeclarationTypeFilter = (type, args) => { + return null; + }; + + + //GetPlugin<SvgFeature>().ValidateFn = req => Config.DebugMode; // only allow in DebugMode + } + } + + public class CustomScriptMethods : ScriptMethods + { + public ITypeValidator CustomTypeValidator(string arg) => null; + public IPropertyValidator CustomPropertyValidator(string arg) => null; + } + + [Exclude(Feature.Metadata)] + [FallbackRoute("/{PathInfo*}", Matches="AcceptsHtml")] + public class FallbackForClientRoutes + { + public string PathInfo { get; set; } + } + + [Route("/hello")] + [Route("/hello/{Name}")] + public class Hello : IReturn<HelloResponse>, IGet + { + public string Name { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Restrict(VisibleLocalhostOnly = true)] + [Route("/testauth")] + [Tag("mobile")] + public class TestAuth : IReturn<TestAuth> {} + + [Route("/session")] + public class Session : IReturn<AuthUserSession> {} + + [Restrict(VisibilityTo = RequestAttributes.Localhost)] + [Route("/throw")] + [Tag("desktop")] + public class Throw {} + + [Route("/api/data/import/{Month}", "POST")] + public class ImportData : IReturn<ImportDataResponse> + { + public string Month { get; set; } + } + + public class ImportDataResponse : IHasResponseStatus + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class ResponseBase<T> + { + public T Result { get; set; } + } + [Tag("web")] + public class Campaign : IReturn<ResponseBase<Dictionary<string, List<object>>>> + { + public int Id { get; set; } + } + public class DataEvent + { + public int Id { get; set; } + } + + public enum EnumMemberTest + { + [EnumMember(Value = "No ne")] None = 0, + [EnumMember(Value = "Template")] Template = 1, + [EnumMember(Value = "Rule")] Rule = 3, + } + + public class Dummy + { + public Campaign Campaign { get; set; } + public DataEvent DataEvent { get; set; } + public ExtendsDictionary ExtendsDictionary { get; set; } + public EnumMemberTest EnumMemberTest { get; set; } + } + + public class ExtendsDictionary : Dictionary<Guid, string> { + } + + [Route("/hello/body")] + public class HelloBody : IReturn<HelloBodyResponse> + { + public string Name { get; set; } + } + + public class HelloBodyResponse + { + public string Message { get; set; } + public string Body { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/bookings/repeat", + Summary = "Create new bookings", + Notes = "Create new bookings if you are authorized to do so.", + Verbs = "POST")] + [ApiResponse(HttpStatusCode.Unauthorized, "You were unauthorized to call this service")] + //[Restrict(VisibleLocalhostOnly = true)] + [Tag("web"),Tag("mobile"),Tag("desktop")] + public class CreateBookings : CreateBookingBase ,IReturn<CreateBookingsResponse> + { + + [ApiMember( + Description = + "Set the dates you want to book and it's quantities. It's an array of dates and quantities.", + IsRequired = true)] + public List<DatesToRepeat> DatesToRepeat { get; set; } + + [ApiMember] + public IEnumerable<DatesToRepeat> DatesToRepeatIEnumerable { get; set; } + [ApiMember] + public DatesToRepeat[] DatesToRepeatArray { get; set; } + } + + public class CreateBookingBase + { + public int Id { get; set; } + } + + public class CreateBookingsResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class DatesToRepeat + { + public int Ticks { get; set; } + } + + + [Route("/swagger/search", "POST")] + public class SwaggerSearch : IReturn<EmptyResponse>, IPost + { + public List<SearchFilter> Filters { get; set; } + } + + public class SearchFilter + { + [ApiMember(Name = "Field")] + public string Field { get; set; } + + [ApiMember(Name = "Values")] + public List<string> Values { get; set; } + + [ApiMember(Name = "Type")] + public string Type { get; set; } + } + + [ValidateIsAuthenticated] + [ValidateIsAdmin] + [ValidateHasRole("TheRole")] + [ValidateHasPermission("ThePerm")] + public class TriggerAllValidators + : IReturn<IdResponse> + { + [ValidateCreditCard] + public string CreditCard { get; set; } + [ValidateEmail] + public string Email { get; set; } + [ValidateEmpty] + public string Empty { get; set; } + [ValidateEqual("Equal")] + public string Equal { get; set; } + [ValidateExclusiveBetween(10, 20)] + public int ExclusiveBetween { get; set; } + [ValidateGreaterThanOrEqual(10)] + public int GreaterThanOrEqual { get; set; } + [ValidateGreaterThan(10)] + public int GreaterThan { get; set; } + [ValidateInclusiveBetween(10, 20)] + public int InclusiveBetween { get; set; } + [ValidateExactLength(10)] + public string Length { get; set; } + [ValidateLessThanOrEqual(10)] + public int LessThanOrEqual { get; set; } + [ValidateLessThan(10)] + public int LessThan { get; set; } + [ValidateNotEmpty] + public string NotEmpty { get; set; } + [ValidateNotEqual("NotEqual")] + public string NotEqual { get; set; } + [ValidateNull] + public string Null { get; set; } + [ValidateRegularExpression("^[a-z]*$")] + public string RegularExpression { get; set; } + [ValidateScalePrecision(1,1)] + public decimal ScalePrecision { get; set; } + } + + [EmitCSharp("[Validate]")] + [EmitTypeScript("@Validate()")] + [EmitCode(Lang.Swift | Lang.Dart, "@validate()")] + public class User : IReturn<User> + { + [EmitCSharp("[IsNotEmpty]","[IsEmail]")] + [EmitTypeScript("@IsNotEmpty()", "@IsEmail()")] + [EmitCode(Lang.Swift | Lang.Dart, new[]{ "@isNotEmpty()", "@isEmail()" })] + public string Email { get; set; } + } + + + [ValidateIsAuthenticated] + [Route("/helloauth/{Name}")] + public class HelloAuth : IReturn<HelloResponse> + { + public string Name { get; set; } + } + + [ValidateHasRole("TheRole")] + [Route("/hellorole/{Name}")] + public class HelloRole : IReturn<HelloResponse> + { + public string Name { get; set; } + } + + // [Authenticate] + public class MyServices : Service + { + public object Any(User request) => request; + public object Any(CreateBookings request) => new CreateBookingsResponse(); + + public object Any(Dummy request) => request; + public object Any(Campaign request) => request; + + //Return index.html for unmatched requests so routing is handled on client + public object Any(FallbackForClientRoutes request) => + Request.GetPageResult("/"); +// new PageResult(Request.GetPage("/")) { Args = { [nameof(Request)] = Request } }; + + HelloResponse CreateResponse(object request, string name) => + new() { Result = $"{request.GetType().Name}, {name}!" }; + + public object Any(Hello request) => CreateResponse(request, request.Name); + public object Any(HelloAuth request) => CreateResponse(request, request.Name); + public object Any(HelloRole request) => CreateResponse(request, request.Name); + + public object Any(TestAuth request) => request; + + // [Authenticate] + // public object Any(Session request) => SessionAs<AuthUserSession>(); + + public object Any(Throw request) => HttpError.Conflict("Conflict message"); +// public object Any(Throw request) => new HttpResult +// {StatusCode = HttpStatusCode.Conflict, Response = "Error message"}; + + public object Any(TriggerAllValidators request) => new IdResponse(); + + [Authenticate] + public object Post(ImportData request) + { + if (Request.Files == null || Request.Files.Length <= 0) + { + throw new Exception("No import file was received by the server"); + } + + // This is always coming through as null + if (request.Month == null) + { + throw new Exception("No month was received by the server"); + } + + var file = (HttpFile)Request.Files[0]; + var month = request.Month.Replace('-', '/'); + + //ImportData(month, file); + + return new ImportDataResponse(); + } + + public object Any(HelloBody request) + { + var body = Request.GetRawBody(); + var to = new HelloBodyResponse { + Message = $"Hello, {request.Name}", + Body = body, + }; + return to; + } + + public object Any(ImpersonateUser request) + { + using (var service = base.ResolveService<AuthenticateService>()) //In Process + { + service.Post(new Authenticate { provider = "logout" }); + + return service.Post(new Authenticate { + provider = AuthenticateService.CredentialsProvider, + UserName = request.UserName, + }); + } + } + + public object Any(SwaggerSearch request) => new EmptyResponse(); + } + + // [RequiredRole("Admin")] + [Restrict(InternalOnly=true)] + [Route("/impersonate/{UserName}")] + public class ImpersonateUser + { + public string UserName { get; set; } + } + + + [Route("/sse-stats")] + public class GetSseStats {} + + public class ServerEventsStats : Service + { + public IServerEvents ServerEvents { get; set; } + + public object Any(GetSseStats request) + { + return ServerEvents.GetStats(); + } + } + +} + diff --git a/tests/CheckWebCore/Views/Hello.cshtml b/tests/CheckWebCore/Views/Hello.cshtml new file mode 100644 index 00000000000..6810cbb861e --- /dev/null +++ b/tests/CheckWebCore/Views/Hello.cshtml @@ -0,0 +1,12 @@ +@model HelloResponse + +<p>View Page for <a href="/hello?Name=World">/hello</a> API</p> + +<h1>@Model.Result</h1> + +<style> +.rule { + background-image: url("@Html.SvgDataUri("mysvg")"); + background-image: url("@Html.SvgDataUri("mysvg", "#333")"); +} +</style> diff --git a/tests/CheckWebCore/Views/Shared/MenuPartial.cshtml b/tests/CheckWebCore/Views/Shared/MenuPartial.cshtml new file mode 100644 index 00000000000..c3ab9f111bb --- /dev/null +++ b/tests/CheckWebCore/Views/Shared/MenuPartial.cshtml @@ -0,0 +1,7 @@ +<div class="collapse navbar-collapse" id="navbarResponsive"> + <ul class="navbar-nav ml-auto"> + @foreach (var item in @Html.MenuItems()) { + <li class="nav-item @(item.Href == Request.PathInfo ? "active" : "")"><a class="nav-link" href="@item.Href">@item.Label</a></li> + } + </ul> +</div> \ No newline at end of file diff --git a/tests/CheckWebCore/Views/Shared/_Layout.cshtml b/tests/CheckWebCore/Views/Shared/_Layout.cshtml new file mode 100644 index 00000000000..82367303c07 --- /dev/null +++ b/tests/CheckWebCore/Views/Shared/_Layout.cshtml @@ -0,0 +1,65 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <title>@ViewBag.Title + + + + + + + + + + + @if (DebugMode) { + + } + + + + + +
+
+
+

@ViewBag.Title

+ @RenderBody() +
+
+
+ +

+ Learn about ServiceStack Razor +

+ + + + + + + + + + + + @RenderSection("scripts", required: false) + + + \ No newline at end of file diff --git a/tests/CheckWebCore/Views/Shared/_RequiresAuth.cshtml b/tests/CheckWebCore/Views/Shared/_RequiresAuth.cshtml new file mode 100644 index 00000000000..fa9749f1ca2 --- /dev/null +++ b/tests/CheckWebCore/Views/Shared/_RequiresAuth.cshtml @@ -0,0 +1,8 @@ +@{ RedirectIfNotAuthenticated($"/validation/client-razor/login?continue={Request.PathInfo}"); } + +
+ + @UserSession.DisplayName + | Sign Out + +
diff --git a/tests/CheckWebCore/Views/Shared/_RequiresAuthServer.cshtml b/tests/CheckWebCore/Views/Shared/_RequiresAuthServer.cshtml new file mode 100644 index 00000000000..88d0eaf621c --- /dev/null +++ b/tests/CheckWebCore/Views/Shared/_RequiresAuthServer.cshtml @@ -0,0 +1,8 @@ +@{ RedirectIfNotAuthenticated($"/validation/server-razor/login?continue={Request.PathInfo}"); } + +
+ + @UserSession.DisplayName + | Sign Out + +
diff --git a/tests/CheckWebCore/Views/TestAuth.cshtml b/tests/CheckWebCore/Views/TestAuth.cshtml new file mode 100644 index 00000000000..8185ece8ebe --- /dev/null +++ b/tests/CheckWebCore/Views/TestAuth.cshtml @@ -0,0 +1,5 @@ +@model TestAuth + +@{ RedirectIfNotAuthenticated(); } + +

View Page for /testauth API

diff --git a/tests/CheckWebCore/Views/Throw.cshtml b/tests/CheckWebCore/Views/Throw.cshtml new file mode 100644 index 00000000000..7262aa7d268 --- /dev/null +++ b/tests/CheckWebCore/Views/Throw.cshtml @@ -0,0 +1,11 @@ +@model HelloResponse + +

View Page for /throw API

+ +

@Model

+ +

IsError: @IsError

+ +

GetErrorStatus(): @GetErrorStatus()

+ +@if (RenderErrorIfAny()) { return; } diff --git a/tests/CheckWebCore/Views/_ViewImports.cshtml b/tests/CheckWebCore/Views/_ViewImports.cshtml new file mode 100644 index 00000000000..144f9fd0c34 --- /dev/null +++ b/tests/CheckWebCore/Views/_ViewImports.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage + +@using ServiceStack +@using ServiceStack.Mvc +@using ServiceStack.Text +@using CheckWebCore + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/tests/CheckWebCore/package-lock.json b/tests/CheckWebCore/package-lock.json new file mode 100644 index 00000000000..2eab48f4a6f --- /dev/null +++ b/tests/CheckWebCore/package-lock.json @@ -0,0 +1,12 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "typescript": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz", + "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==", + "dev": true + } + } +} diff --git a/tests/CheckWebCore/src/components/home.js b/tests/CheckWebCore/src/components/home.js new file mode 100644 index 00000000000..1b46f5a195c --- /dev/null +++ b/tests/CheckWebCore/src/components/home.js @@ -0,0 +1,8 @@ +"use strict"; +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +new A().template = "TypeScript " + Date(); +//# sourceMappingURL=home.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/src/components/home.js.map b/tests/CheckWebCore/src/components/home.js.map new file mode 100644 index 00000000000..be2b3132025 --- /dev/null +++ b/tests/CheckWebCore/src/components/home.js.map @@ -0,0 +1 @@ +{"version":3,"file":"home.js","sourceRoot":"","sources":["home.ts"],"names":[],"mappings":";AAAA;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC;AAED,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG,gBAAc,IAAI,EAAI,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/src/components/home.ts b/tests/CheckWebCore/src/components/home.ts new file mode 100644 index 00000000000..515d5e6ad9c --- /dev/null +++ b/tests/CheckWebCore/src/components/home.ts @@ -0,0 +1,6 @@ +class A +{ + template: string; +} + +new A().template = `TypeScript ${Date()}`; diff --git a/tests/CheckWebCore/src/components/sub/SubB.js b/tests/CheckWebCore/src/components/sub/SubB.js new file mode 100644 index 00000000000..27880081a5e --- /dev/null +++ b/tests/CheckWebCore/src/components/sub/SubB.js @@ -0,0 +1,8 @@ +"use strict"; +var SubB = /** @class */ (function () { + function SubB() { + } + return SubB; +}()); +new SubB().template = "/src/components/sub/SubB.ts " + Date(); +//# sourceMappingURL=SubB.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/src/components/sub/SubB.js.map b/tests/CheckWebCore/src/components/sub/SubB.js.map new file mode 100644 index 00000000000..fe9be5c4c92 --- /dev/null +++ b/tests/CheckWebCore/src/components/sub/SubB.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SubB.js","sourceRoot":"","sources":["SubB.ts"],"names":[],"mappings":";AAAA;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAED,IAAI,IAAI,EAAE,CAAC,QAAQ,GAAG,iCAA+B,IAAI,EAAI,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/src/components/sub/SubB.ts b/tests/CheckWebCore/src/components/sub/SubB.ts new file mode 100644 index 00000000000..eeac0d0f52e --- /dev/null +++ b/tests/CheckWebCore/src/components/sub/SubB.ts @@ -0,0 +1,6 @@ +class SubB +{ + template: string; +} + +new SubB().template = `/src/components/sub/SubB.ts ${Date()}`; diff --git a/tests/CheckWebCore/src/components/sub/sub2/SubC.js b/tests/CheckWebCore/src/components/sub/sub2/SubC.js new file mode 100644 index 00000000000..2cbc69f8d39 --- /dev/null +++ b/tests/CheckWebCore/src/components/sub/sub2/SubC.js @@ -0,0 +1,8 @@ +"use strict"; +var SubC = /** @class */ (function () { + function SubC() { + } + return SubC; +}()); +new SubC().template = "/src/components/sub/sub2/SubC.ts " + Date(); +//# sourceMappingURL=SubC.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/src/components/sub/sub2/SubC.js.map b/tests/CheckWebCore/src/components/sub/sub2/SubC.js.map new file mode 100644 index 00000000000..533a9fd3ad4 --- /dev/null +++ b/tests/CheckWebCore/src/components/sub/sub2/SubC.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SubC.js","sourceRoot":"","sources":["SubC.ts"],"names":[],"mappings":";AAAA;IAAA;IAGA,CAAC;IAAD,WAAC;AAAD,CAAC,AAHD,IAGC;AAED,IAAI,IAAI,EAAE,CAAC,QAAQ,GAAG,sCAAoC,IAAI,EAAI,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/src/components/sub/sub2/SubC.ts b/tests/CheckWebCore/src/components/sub/sub2/SubC.ts new file mode 100644 index 00000000000..6a58e4ea199 --- /dev/null +++ b/tests/CheckWebCore/src/components/sub/sub2/SubC.ts @@ -0,0 +1,6 @@ +class SubC +{ + template: string; +} + +new SubC().template = `/src/components/sub/sub2/SubC.ts ${Date()}`; diff --git a/tests/CheckWebCore/src/source.js b/tests/CheckWebCore/src/source.js new file mode 100644 index 00000000000..0762d0fab7c --- /dev/null +++ b/tests/CheckWebCore/src/source.js @@ -0,0 +1 @@ +function source() { return "source.js"; } \ No newline at end of file diff --git a/tests/CheckWebCore/tsconfig.json b/tests/CheckWebCore/tsconfig.json new file mode 100644 index 00000000000..d5986fa0de6 --- /dev/null +++ b/tests/CheckWebCore/tsconfig.json @@ -0,0 +1,68 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + //"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "lib": [ "dom", "es2015" ], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + "strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + //"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + //"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + "baseUrl": ".", + "paths": { + "*": [ + "wwwroot/lib/*", + "wwwroot/lib/vue/dist/*", + "wwwroot/lib/vue/types/*" + ] + } + } +} diff --git a/tests/CheckWebCore/wwwroot/_ViewImports.cshtml b/tests/CheckWebCore/wwwroot/_ViewImports.cshtml new file mode 100644 index 00000000000..edf596ebea6 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_ViewImports.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage + +@using ServiceStack +@using ServiceStack.Mvc +@using ServiceStack.Text +@using CheckWebCore + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/tests/CheckWebCore/wwwroot/_bundle.ss b/tests/CheckWebCore/wwwroot/_bundle.ss new file mode 100644 index 00000000000..c7692c87a59 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_bundle.ss @@ -0,0 +1,21 @@ +{{ true | assignTo: debug }} + +{{ (debug ? '' : '[hash].min') | assignTo: min }} + +{{ [`/css/bundle${min}.css`,`/js/lib.bundle${min}.js`,`/js/bundle${min}.js`] + | map => it.replace('[hash]','.*').filesFind() + | flatten + | map => it.VirtualPath.fileDelete() | end }} + +{{ end | return }} + +{{ ['/assets/css/'] | bundleCss({ minify:!debug, cache:!debug, disk:!debug, out:`/css/bundle${min}.css` }) }} + +{{ ['content:/src/source.js', + 'content:/src/components/', + '/assets/js/jquery.min.js', + '/assets/js/', + '/js/ss-utils.js', + '/lib/@servicestack/client/index.js', + '/dtos.js', + ] | bundleJs({ minify:!debug, cache:!debug, disk:!debug, out:`/js/bundle${min}.js` }) }} diff --git a/tests/CheckWebCore/wwwroot/_init.html b/tests/CheckWebCore/wwwroot/_init.html new file mode 100644 index 00000000000..314e7f5e39b --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_init.html @@ -0,0 +1,29 @@ + + +{{#svg vue svg-icons}} + + + + + +{{/svg}} + +{{#svg vscode svg-icons}} + + + + + +{{/svg}} + +{{*#svg spirals svg-icons}} + + {{#each range(180) }} + {{ 120 + 100 * cos((5) * it * 0.02827) | assignTo: x }} + {{ 320 + 300 * sin((1) * it * 0.02827) | assignTo: y }} + + {{/each}} + +{{/svg*}} diff --git a/tests/CheckWebCore/wwwroot/_layout.html b/tests/CheckWebCore/wwwroot/_layout.html new file mode 100644 index 00000000000..89c9b21c9da --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_layout.html @@ -0,0 +1,94 @@ + + + + {{ title }} + + + + + + + {{#noop}} + {{ false | assignTo: debug }} + {{/noop}} + + {{ (debug ? '' : '[hash].min') | assignTo: min }} + + {{ ['!/assets/css/default.css','/assets/css/','/css/buttons.css','/css/svg-auth.css','/css/svg-icons.css'] + | bundleCss({ disk:!debug, out:`/css/lib.bundle${min}.css` }) }} + + {{ ['/assets/css/default.css'] + | bundleCss({ minify:!debug, cache:!debug, disk:!debug, out:`/css/bundle${min}.css` }) }} + + + + + + + + + +
+
+
+ {{#if title}}

{{ title }}

{{/if}} + {{ page }} +
+
+
+ + + + {{ [ + '!/assets/js/dtos.js', + '!/assets/js/default.js', + 'content:/src/source.js', + 'content:/src/components/', + '/assets/js/jquery.min.js', + '/assets/js/popper.min.js', + '/assets/js/', + '/lib/@servicestack/client/index.js', + ] | bundleJs({ minify:!debug, cache:!debug, disk:!debug, out:`/js/lib.bundle${min}.js` }) }} + + + {{ [ + '/assets/js/dtos.js', + '/assets/js/default.js', + ] | bundleJs({ minify:!debug, cache:!debug, disk:!debug, out:`/js/bundle${min}.js` }) }} + + + + {{ scripts | raw }} + +
Copyright © {{ now | dateFormat('yyyy') }}
+ + + diff --git a/tests/CheckWebCore/wwwroot/_menu-partial.html b/tests/CheckWebCore/wwwroot/_menu-partial.html new file mode 100644 index 00000000000..c1f78a129a5 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_menu-partial.html @@ -0,0 +1,11 @@ +{{ menuItems | assignTo: links }} + + diff --git a/tests/CheckWebCore/wwwroot/_script-layout.html b/tests/CheckWebCore/wwwroot/_script-layout.html new file mode 100644 index 00000000000..4c906a6fe36 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_script-layout.html @@ -0,0 +1,60 @@ + + + + +{{title}} + +{{ 'bootstrap' | cssIncludes }} + + + + + +

{{title}}

+ + {{page}} + + + diff --git a/tests/CheckWebCore/wwwroot/_signin-links-partial.html b/tests/CheckWebCore/wwwroot/_signin-links-partial.html new file mode 100644 index 00000000000..f6b14ffdf05 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/_signin-links-partial.html @@ -0,0 +1,5 @@ + diff --git a/tests/CheckWebCore/wwwroot/about.html b/tests/CheckWebCore/wwwroot/about.html new file mode 100644 index 00000000000..884a3a8539b --- /dev/null +++ b/tests/CheckWebCore/wwwroot/about.html @@ -0,0 +1,25 @@ + + +
+
+ +

+ About Us page. +

+ + +
+ + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/admin.html b/tests/CheckWebCore/wwwroot/admin.html new file mode 100644 index 00000000000..d7f7af3284e --- /dev/null +++ b/tests/CheckWebCore/wwwroot/admin.html @@ -0,0 +1,6 @@ + +{{ assertRole('admin') }} + +

Admin Page

+ + diff --git a/tests/CheckWebCore/wwwroot/assets/css/bootstrap.css b/tests/CheckWebCore/wwwroot/assets/css/bootstrap.css new file mode 100644 index 00000000000..9746051d909 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/css/bootstrap.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.1.2 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-label::after{border-color:#80bdff}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:2.25rem;padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:not(:disabled):not(.disabled){cursor:pointer}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease}@media screen and (prefers-reduced-motion:reduce){.carousel-item-next,.carousel-item-prev,.carousel-item.active{transition:none}}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/css/default.css b/tests/CheckWebCore/wwwroot/assets/css/default.css new file mode 100644 index 00000000000..a761b5b565d --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/css/default.css @@ -0,0 +1,38 @@ +body { + padding-top: 54px; +} +@media (min-width: 992px) { + body { + padding-top: 56px; + } +} +span[data-click] { + color: #007bff; + cursor: pointer; +} +span[data-click]:hover { + text-decoration: underline; +} +.quicklist span { + display: block; + margin-left: 1em; +} + +form { + padding: 10px; +} +table form { + padding: 0; +} +table#results button { + margin: 5px; +} +table#results td:first-child { + padding: 2px 10px; +} + +.form-check.form-control { + padding-left: 1.75rem; +} + + diff --git a/tests/CheckWebCore/wwwroot/assets/img/logo.png b/tests/CheckWebCore/wwwroot/assets/img/logo.png new file mode 100644 index 00000000000..6dbd73bc0eb Binary files /dev/null and b/tests/CheckWebCore/wwwroot/assets/img/logo.png differ diff --git a/tests/CheckWebCore/wwwroot/assets/js/bootstrap.min.js b/tests/CheckWebCore/wwwroot/assets/js/bootstrap.min.js new file mode 100644 index 00000000000..c4c0d1f95cd --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.3.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t=t||self).bootstrap={},t.jQuery,t.Popper)}(this,function(t,g,u){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)g(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Ee},je="show",He="out",Re={HIDE:"hide"+De,HIDDEN:"hidden"+De,SHOW:"show"+De,SHOWN:"shown"+De,INSERTED:"inserted"+De,CLICK:"click"+De,FOCUSIN:"focusin"+De,FOCUSOUT:"focusout"+De,MOUSEENTER:"mouseenter"+De,MOUSELEAVE:"mouseleave"+De},xe="fade",Fe="show",Ue=".tooltip-inner",We=".arrow",qe="hover",Me="focus",Ke="click",Qe="manual",Be=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(xe);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:We},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===He&&e._leave(null,e)};if(g(this.tip).hasClass(xe)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==je&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ke]=!1,this._activeTrigger[Me]=!1,this._activeTrigger[qe]=!1,g(this.tip).hasClass(xe)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Ae+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Ue)),this.getTitle()),g(t).removeClass(xe+" "+Fe)},t.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Se(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text())},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return Pe[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Qe){var e=t===qe?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===qe?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Me:qe]=!0),g(e.getTipElement()).hasClass(Fe)||e._hoverState===je?e._hoverState=je:(clearTimeout(e._timeout),e._hoverState=je,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===je&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Me:qe]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===He&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){var e=g(this.element).data();return Object.keys(e).forEach(function(t){-1!==Oe.indexOf(t)&&delete e[t]}),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(be,t,this.constructor.DefaultType),t.sanitize&&(t.template=Se(t.template,t.whiteList,t.sanitizeFn)),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ne);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(xe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ie),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ie,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Le}},{key:"NAME",get:function(){return be}},{key:"DATA_KEY",get:function(){return Ie}},{key:"Event",get:function(){return Re}},{key:"EVENT_KEY",get:function(){return De}},{key:"DefaultType",get:function(){return ke}}]),i}();g.fn[be]=Be._jQueryInterface,g.fn[be].Constructor=Be,g.fn[be].noConflict=function(){return g.fn[be]=we,Be._jQueryInterface};var Ve="popover",Ye="bs.popover",ze="."+Ye,Xe=g.fn[Ve],$e="bs-popover",Ge=new RegExp("(^|\\s)"+$e+"\\S+","g"),Je=l({},Be.Default,{placement:"right",trigger:"click",content:"",template:''}),Ze=l({},Be.DefaultType,{content:"(string|element|function)"}),tn="fade",en="show",nn=".popover-header",on=".popover-body",rn={HIDE:"hide"+ze,HIDDEN:"hidden"+ze,SHOW:"show"+ze,SHOWN:"shown"+ze,INSERTED:"inserted"+ze,CLICK:"click"+ze,FOCUSIN:"focusin"+ze,FOCUSOUT:"focusout"+ze,MOUSEENTER:"mouseenter"+ze,MOUSELEAVE:"mouseleave"+ze},sn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass($e+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(nn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(on),e),t.removeClass(tn+" "+en)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ge);null!==e&&0=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t +{ + createResponse(): T; +} + +export interface IReturnVoid +{ + createResponse(): void; +} + +export interface IHasSessionId +{ + sessionId: string; +} + +export interface IHasBearerToken +{ + bearerToken: string; +} + +export interface IPost +{ +} + +// @DataContract +export class ResponseError +{ + // @DataMember(Order=1, EmitDefaultValue=false) + public errorCode: string; + + // @DataMember(Order=2, EmitDefaultValue=false) + public fieldName: string; + + // @DataMember(Order=3, EmitDefaultValue=false) + public message: string; + + // @DataMember(Order=4, EmitDefaultValue=false) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class ResponseStatus +{ + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public message: string; + + // @DataMember(Order=3) + public stackTrace: string; + + // @DataMember(Order=4) + public errors: ResponseError[]; + + // @DataMember(Order=5) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export interface IAuthTokens +{ + provider: string; + userId: string; + accessToken: string; + accessTokenSecret: string; + refreshToken: string; + refreshTokenExpiry?: string; + requestToken: string; + requestTokenSecret: string; + items: { [index:string]: string; }; +} + +export enum Title +{ + Unspecified = 'Unspecified', + Mr = 'Mr', + Mrs = 'Mrs', + Miss = 'Miss', +} + +export class Contact +{ + public id: number; + public userAuthId: number; + public title: Title; + public name: string; + public color: string; + public filmGenres: FilmGenres[]; + public age: number; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export enum FilmGenres +{ + Action = 'Action', + Adventure = 'Adventure', + Comedy = 'Comedy', + Drama = 'Drama', +} + +export class HelloResponse +{ + public result: string; + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @Route("/testauth") +export class TestAuth implements IReturn +{ + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new TestAuth(); } + public getTypeName() { return 'TestAuth'; } +} + +// @DataContract +export class AuthUserSession +{ + // @DataMember(Order=1) + public referrerUrl: string; + + // @DataMember(Order=2) + public id: string; + + // @DataMember(Order=3) + public userAuthId: string; + + // @DataMember(Order=4) + public userAuthName: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public twitterUserId: string; + + // @DataMember(Order=7) + public twitterScreenName: string; + + // @DataMember(Order=8) + public facebookUserId: string; + + // @DataMember(Order=9) + public facebookUserName: string; + + // @DataMember(Order=10) + public firstName: string; + + // @DataMember(Order=11) + public lastName: string; + + // @DataMember(Order=12) + public displayName: string; + + // @DataMember(Order=13) + public company: string; + + // @DataMember(Order=14) + public email: string; + + // @DataMember(Order=15) + public primaryEmail: string; + + // @DataMember(Order=16) + public phoneNumber: string; + + // @DataMember(Order=17) + public birthDate: string; + + // @DataMember(Order=18) + public birthDateRaw: string; + + // @DataMember(Order=19) + public address: string; + + // @DataMember(Order=20) + public address2: string; + + // @DataMember(Order=21) + public city: string; + + // @DataMember(Order=22) + public state: string; + + // @DataMember(Order=23) + public country: string; + + // @DataMember(Order=24) + public culture: string; + + // @DataMember(Order=25) + public fullName: string; + + // @DataMember(Order=26) + public gender: string; + + // @DataMember(Order=27) + public language: string; + + // @DataMember(Order=28) + public mailAddress: string; + + // @DataMember(Order=29) + public nickname: string; + + // @DataMember(Order=30) + public postalCode: string; + + // @DataMember(Order=31) + public timeZone: string; + + // @DataMember(Order=32) + public requestTokenSecret: string; + + // @DataMember(Order=33) + public createdAt: string; + + // @DataMember(Order=34) + public lastModified: string; + + // @DataMember(Order=35) + public roles: string[]; + + // @DataMember(Order=36) + public permissions: string[]; + + // @DataMember(Order=37) + public isAuthenticated: boolean; + + // @DataMember(Order=38) + public fromToken: boolean; + + // @DataMember(Order=39) + public profileUrl: string; + + // @DataMember(Order=40) + public sequence: string; + + // @DataMember(Order=41) + public tag: number; + + // @DataMember(Order=42) + public authProvider: string; + + // @DataMember(Order=43) + public providerOAuthAccess: IAuthTokens[]; + + // @DataMember(Order=44) + public meta: { [index:string]: string; }; + + // @DataMember(Order=45) + public audiences: string[]; + + // @DataMember(Order=46) + public scopes: string[]; + + // @DataMember(Order=47) + public dns: string; + + // @DataMember(Order=48) + public rsa: string; + + // @DataMember(Order=49) + public sid: string; + + // @DataMember(Order=50) + public hash: string; + + // @DataMember(Order=51) + public homePhone: string; + + // @DataMember(Order=52) + public mobilePhone: string; + + // @DataMember(Order=53) + public webpage: string; + + // @DataMember(Order=54) + public emailConfirmed: boolean; + + // @DataMember(Order=55) + public phoneNumberConfirmed: boolean; + + // @DataMember(Order=56) + public twoFactorEnabled: boolean; + + // @DataMember(Order=57) + public securityStamp: string; + + // @DataMember(Order=58) + public type: string; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export class ImportDataResponse +{ + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export class GetContactsResponse +{ + public results: Contact[]; + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export class GetContactResponse +{ + public result: Contact; + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export class CreateContactResponse +{ + public result: Contact; + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +export class UpdateContactResponse +{ + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AuthenticateResponse implements IHasSessionId, IHasBearerToken +{ + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public referrerUrl: string; + + // @DataMember(Order=6) + public bearerToken: string; + + // @DataMember(Order=7) + public refreshToken: string; + + // @DataMember(Order=8) + public profileUrl: string; + + // @DataMember(Order=9) + public roles: string[]; + + // @DataMember(Order=10) + public permissions: string[]; + + // @DataMember(Order=11) + public responseStatus: ResponseStatus; + + // @DataMember(Order=12) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AssignRolesResponse +{ + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public meta: { [index:string]: string; }; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class UnAssignRolesResponse +{ + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public meta: { [index:string]: string; }; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class ConvertSessionToTokenResponse +{ + // @DataMember(Order=1) + public meta: { [index:string]: string; }; + + // @DataMember(Order=2) + public accessToken: string; + + // @DataMember(Order=3) + public refreshToken: string; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class GetAccessTokenResponse +{ + // @DataMember(Order=1) + public accessToken: string; + + // @DataMember(Order=2) + public meta: { [index:string]: string; }; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class RegisterResponse +{ + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public referrerUrl: string; + + // @DataMember(Order=5) + public bearerToken: string; + + // @DataMember(Order=6) + public refreshToken: string; + + // @DataMember(Order=7) + public responseStatus: ResponseStatus; + + // @DataMember(Order=8) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @Route("/hello") +// @Route("/hello/{Name}") +export class Hello implements IReturn +{ + public name: string; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'Hello'; } +} + +// @Route("/session") +export class Session implements IReturn +{ + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AuthUserSession(); } + public getTypeName() { return 'Session'; } +} + +// @Route("/throw") +export class Throw +{ + + public constructor(init?:Partial) { (Object as any).assign(this, init); } +} + +// @Route("/api/data/import/{Month}", "POST") +export class ImportData implements IReturn +{ + public month: string; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new ImportDataResponse(); } + public getTypeName() { return 'ImportData'; } +} + +// @Route("/contacts", "GET") +export class GetContacts implements IReturn +{ + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new GetContactsResponse(); } + public getTypeName() { return 'GetContacts'; } +} + +// @Route("/contacts/{Id}", "GET") +export class GetContact implements IReturn +{ + public id: number; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new GetContactResponse(); } + public getTypeName() { return 'GetContact'; } +} + +// @Route("/contacts", "POST") +export class CreateContact implements IReturn +{ + public title: Title; + public name: string; + public color: string; + public filmGenres: FilmGenres[]; + public age: number; + public agree: boolean; + public continue: string; + public errorView: string; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new CreateContactResponse(); } + public getTypeName() { return 'CreateContact'; } +} + +// @Route("/contacts/{Id}", "DELETE") +// @Route("/contacts/{Id}/delete", "POST") +export class DeleteContact implements IReturnVoid +{ + public id: number; + public continue: string; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() {} + public getTypeName() { return 'DeleteContact'; } +} + +// @Route("/contacts/{Id}", "POST PUT") +export class UpdateContact implements IReturn +{ + public id: number; + public title: Title; + public name: string; + public color: string; + public filmGenres: FilmGenres[]; + public age: number; + public continue: string; + public errorView: string; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new UpdateContactResponse(); } + public getTypeName() { return 'UpdateContact'; } +} + +// @Route("/auth") +// @Route("/auth/{provider}") +// @Route("/authenticate") +// @Route("/authenticate/{provider}") +// @DataContract +export class Authenticate implements IReturn, IPost +{ + // @DataMember(Order=1) + public provider: string; + + // @DataMember(Order=2) + public state: string; + + // @DataMember(Order=3) + public oauth_token: string; + + // @DataMember(Order=4) + public oauth_verifier: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public rememberMe: boolean; + + // @DataMember(Order=8) + public continue: string; + + // @DataMember(Order=9) + public errorView: string; + + // @DataMember(Order=10) + public nonce: string; + + // @DataMember(Order=11) + public uri: string; + + // @DataMember(Order=12) + public response: string; + + // @DataMember(Order=13) + public qop: string; + + // @DataMember(Order=14) + public nc: string; + + // @DataMember(Order=15) + public cnonce: string; + + // @DataMember(Order=16) + public useTokenCookie: boolean; + + // @DataMember(Order=17) + public accessToken: string; + + // @DataMember(Order=18) + public accessTokenSecret: string; + + // @DataMember(Order=19) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AuthenticateResponse(); } + public getTypeName() { return 'Authenticate'; } +} + +// @Route("/assignroles") +// @DataContract +export class AssignRoles implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + + // @DataMember(Order=4) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AssignRolesResponse(); } + public getTypeName() { return 'AssignRoles'; } +} + +// @Route("/unassignroles") +// @DataContract +export class UnAssignRoles implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + + // @DataMember(Order=4) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new UnAssignRolesResponse(); } + public getTypeName() { return 'UnAssignRoles'; } +} + +// @Route("/session-to-token") +// @DataContract +export class ConvertSessionToToken implements IReturn, IPost +{ + // @DataMember(Order=1) + public preserveSession: boolean; + + // @DataMember(Order=2) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new ConvertSessionToTokenResponse(); } + public getTypeName() { return 'ConvertSessionToToken'; } +} + +// @Route("/access-token") +// @DataContract +export class GetAccessToken implements IReturn, IPost +{ + // @DataMember(Order=1) + public refreshToken: string; + + // @DataMember(Order=2) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new GetAccessTokenResponse(); } + public getTypeName() { return 'GetAccessToken'; } +} + +// @Route("/register") +// @DataContract +export class Register implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public firstName: string; + + // @DataMember(Order=3) + public lastName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public email: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public confirmPassword: string; + + // @DataMember(Order=8) + public autoLogin: boolean; + + // @DataMember(Order=9) + public continue: string; + + // @DataMember(Order=10) + public errorView: string; + + // @DataMember(Order=11) + public meta: { [index:string]: string; }; + + public constructor(init?:Partial) { (Object as any).assign(this, init); } + public createResponse() { return new RegisterResponse(); } + public getTypeName() { return 'Register'; } +} + diff --git a/tests/CheckWebCore/wwwroot/assets/js/jquery.min.js b/tests/CheckWebCore/wwwroot/assets/js/jquery.min.js new file mode 100644 index 00000000000..07c00cd227d --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/js/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),le({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=fe({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},le(n,m,$(v)),le(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ge.FLIP:p=[n,i];break;case ge.CLOCKWISE:p=G(n);break;case ge.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u);(m||b||y)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),y&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=fe({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!me),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=H('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=fe({},E,e.attributes),e.styles=fe({},m,e.styles),e.arrowStyles=fe({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return j(e.instance.popper,e.styles),V(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&j(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),j(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ue}); +//# sourceMappingURL=popper.min.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/svg/app/add_alert.svg b/tests/CheckWebCore/wwwroot/assets/svg/app/add_alert.svg new file mode 100644 index 00000000000..274d222091c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/app/add_alert.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/svg/app/error.svg b/tests/CheckWebCore/wwwroot/assets/svg/app/error.svg new file mode 100644 index 00000000000..93b191c3d61 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/app/error.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/svg/app/error_outline.svg b/tests/CheckWebCore/wwwroot/assets/svg/app/error_outline.svg new file mode 100644 index 00000000000..3547ad0f3bf --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/app/error_outline.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/svg/app/warning.svg b/tests/CheckWebCore/wwwroot/assets/svg/app/warning.svg new file mode 100644 index 00000000000..ae4e60cc178 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/app/warning.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/svg/logos.html b/tests/CheckWebCore/wwwroot/assets/svg/logos.html new file mode 100644 index 00000000000..b9bf8507bd3 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/logos.html @@ -0,0 +1,13 @@ +{{#svg slack logos}} + + + +{{/svg}} + +{{#svg reddit logos}} + + + +{{/svg}} diff --git a/tests/CheckWebCore/wwwroot/assets/svg/material.html b/tests/CheckWebCore/wwwroot/assets/svg/material.html new file mode 100644 index 00000000000..17518c08c04 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/material.html @@ -0,0 +1,29 @@ +{{#svg format app}} + + + + +{{/svg}} + +{{#svg quotes app}} + + + + +{{/svg}} + +{{#svg vue app}} + + + + + +{{/svg}} + +{{#svg vscode app}} + + + + + +{{/svg}} diff --git a/tests/CheckWebCore/wwwroot/assets/svg/svg-icons/outline-cloud.svg b/tests/CheckWebCore/wwwroot/assets/svg/svg-icons/outline-cloud.svg new file mode 100644 index 00000000000..e1f0c8391a9 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/svg-icons/outline-cloud.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/assets/svg/svg-icons/spirals.html b/tests/CheckWebCore/wwwroot/assets/svg/svg-icons/spirals.html new file mode 100644 index 00000000000..a97caab29ab --- /dev/null +++ b/tests/CheckWebCore/wwwroot/assets/svg/svg-icons/spirals.html @@ -0,0 +1,7 @@ + +{{#each range(180) }} + {{ 120 + 100 * cos((5) * it * 0.02827) | assignTo: x }} + {{ 320 + 300 * sin((1) * it * 0.02827) | assignTo: y }} + +{{/each}} + diff --git a/tests/CheckWebCore/wwwroot/contact.html b/tests/CheckWebCore/wwwroot/contact.html new file mode 100644 index 00000000000..8412a1abea9 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/contact.html @@ -0,0 +1,7 @@ + + +

+ Contact Us page. +

\ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/contacts/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/contacts/_requires-auth-partial.html new file mode 100644 index 00000000000..15684be0fd3 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/contacts/_requires-auth-partial.html @@ -0,0 +1,8 @@ +{{ redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
\ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/contacts/index.html b/tests/CheckWebCore/wwwroot/contacts/index.html new file mode 100644 index 00000000000..9ec89095c1f --- /dev/null +++ b/tests/CheckWebCore/wwwroot/contacts/index.html @@ -0,0 +1,5 @@ +

+ View page from /contacts +

+ +Contacts page \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/contacts/sub/test.html b/tests/CheckWebCore/wwwroot/contacts/sub/test.html new file mode 100644 index 00000000000..4d5214e4712 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/contacts/sub/test.html @@ -0,0 +1,7 @@ +{{ 'requires-auth' | partial }} + +

 

+ +

+ Test Contacts page +

diff --git a/tests/CheckWebCore/wwwroot/css/bundle.1549858174979.min.css b/tests/CheckWebCore/wwwroot/css/bundle.1549858174979.min.css new file mode 100644 index 00000000000..71fa4071611 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/css/bundle.1549858174979.min.css @@ -0,0 +1 @@ +body{padding-top:54px}@media (min-width:992px){body{padding-top:56px}}span[data-click]{color:#007bff;cursor:pointer}span[data-click]:hover{text-decoration:underline}.quicklist span{display:block;margin-left:1em}form{padding:10px}table form{padding:0}#results button{margin:5px}#results td:first-child{padding:2px 10px}.form-check.form-control{padding-left:1.75rem} diff --git a/tests/CheckWebCore/wwwroot/css/default.css b/tests/CheckWebCore/wwwroot/css/default.css new file mode 100644 index 00000000000..1d1de6c3520 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/css/default.css @@ -0,0 +1,249 @@ +body { + font: 16px Arial; + overflow: hidden; + padding: 0; + margin: 0; + color: #444; + background: url(/img/bg.jpg) no-repeat left center fixed; + background-size: cover; + -webkit-background-size: cover; +} +::-webkit-scrollbar { + width: 6px; +} +::-webkit-scrollbar-button { + width: 6px; + height: 0px; +} +::-webkit-scrollbar-track { + background: #e6e6e6; + border: thin solid lightgray; + border-top: none; + box-shadow: 0px 0px 3px #dfdfdf inset; +} +::-webkit-scrollbar-thumb { + background: #666; + border: thin solid gray; + border-top: none; +} +::-webkit-scrollbar-thumb:hover { + background:#7d7d7d; +} +#top { + z-index: 1; + position: fixed; + top: 0; + width: 100%; + height: 40px; + background: #212121; + opacity: .80; +} +ul { + padding: 0; + margin: 0; + position: absolute; + top: 10px; + left: 10px; + list-style: none; +} +li { + display: block; + float: left; + padding: 4px 30px; + text-align: center; + background: #fff; + font-size: 18px; + cursor: pointer; + margin: 0 5px 0 0; + opacity: .5; +} +a img { + border: none; +} +#channels li.selected { + opacity: .9; +} +li:hover { + opacity: .8; +} +#announce { + z-index: 3; + display: none; + position: absolute; + top: 40px; + line-height: 50px; + width: 100%; + background: #ffc; + text-align: center; + box-shadow: 0px 2px 3px rgba(100, 100, 100, 0.75); +} +#tv { + z-index: 2; + position: absolute; + display: none; + text-align: center; + width: 85%; + top: 40px; +} +#right { + z-index: 1; + position: absolute; + top: 40px; + right: 0; + width: 18%; + min-width: 200px; + height: 100%; + color: #666; + background: #fff; + opacity: .85; + border-left: 1px solid #212121; +} +#examples { + position: fixed; + bottom: 10px; + right: .5%; + width: 17%; + min-width: 190px; + font-size: 12px; + background: #fcfcfc; + overflow: hidden; +} +#examples h4 { + margin: 0; + padding: 5px 10px; + background: #f1f1f1; +} +#examples a { + color: #428bca; + text-decoration: none; + font-size: 13px; +} +#examples a:hover { + color: #2a6496; +} +#examples div { + white-space: nowrap; + overflow: hidden; + cursor: pointer; + padding: 0 5px; + line-height: 28px; +} +#examples div:hover { + background: #ffe; + color: #222; +} +#examples span { + color: #999; + cursor: pointer; +} +#logs { + position: fixed; + left: -2px; + bottom: 50px; + width: 82%; + max-height: 100%; + overflow-y: auto; +} +#logs .channel { + background: #fff; + opacity: .85; + display: none; +} +#logs .channel.selected { + display: block; +} +#users .channel { + display: none; +} +#users .channel.selected { + display: block; +} + +#bottom { + position: fixed; + bottom: 0; + height: 49px; + width: 82%; + background: #212121; + opacity: .80; +} +#bottom input { + font-size: 16px; + margin: 6px 0 0 6px; + padding: 4px 8px; + width: 77%; +} +#bottom button { + padding: 4px 8px; +} +.open div { + color: green; +} +.error div { + color: red; +} +.event div { + color: blue; +} +#social { + float: right; + padding: 5px; +} +#social a { + display: inline-block; + width: 77px; + height: 20px; + margin: 5px 5px 0 0; +} +.twitter { background: url(/img/twitter_normal.png) no-repeat; } +.facebook { background: url(/img/facebook_normal.png) no-repeat; } +.github { background: url(/img/github_normal.png) no-repeat; } +#welcome { + float: left; + margin: 0 5px 0 0; + color: #f1f1f1; +} +#welcome span { + line-height: 24px; +} +#welcome img { + height: 24px; + margin: 0 0 0 5px; + vertical-align: bottom; +} +.user img { + height: 24px; + margin: 2px 5px 0 5px; + vertical-align: bottom; +} +.user span { + cursor: pointer; +} +.private { + color: red; +} +.msg { + border-top: 1px solid #eee; +} +.msg b, .msg div, .msg i { + line-height: 30px; + height: 30px; + display: inline-block; + padding: 0 0 0 10px; + font-style: normal; + font-weight: normal; +} +.msg b { + width: 200px; + background: #fafafa; +} +.msg div { +} +.msg i { + color: #999; + float: right; + padding: 0 10px 0 0; +} +.msg.highlight { + background: #ffc; +} diff --git a/tests/CheckWebCore/wwwroot/css/lib.bundle.1559852101161.min.css b/tests/CheckWebCore/wwwroot/css/lib.bundle.1559852101161.min.css new file mode 100644 index 00000000000..196185448e7 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/css/lib.bundle.1559852101161.min.css @@ -0,0 +1,4 @@ +/*! * Bootstrap v4.1.2 (https://getbootstrap.com/) * Copyright 2011-2018 The Bootstrap Authors * Copyright 2011-2018 Twitter,Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-label::after{border-color:#80bdff}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:2.25rem;padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:focus{outline:0;box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0;flex:1 0 0;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0;flex:1 0 0;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:not(:disabled):not(.disabled){cursor:pointer}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-ms-flex-align:center;align-items:center;width:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease}@media screen and (prefers-reduced-motion:reduce){.carousel-item-next,.carousel-item-prev,.carousel-item.active{transition:none}}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-fade .carousel-item{opacity:0;transition-duration:.6s;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-prev,.carousel-fade .carousel-item-next,.carousel-fade .carousel-item-prev,.carousel-fade .carousel-item.active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}}/*# sourceMappingURL=bootstrap.min.css.map */ +/* * Social Buttons for Bootstrap * * Copyright 2013-2016 Panayiotis Lipiridis * Licensed under the MIT License * * https://github.com/lipis/bootstrap-social */ .btn-social{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-social>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social.btn-lg{padding-left:61px}.btn-social.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social.btn-sm{padding-left:38px}.btn-social.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social.btn-xs{padding-left:30px}.btn-social.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:34px;width:34px;padding:0}.btn-social-icon>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social-icon.btn-lg{padding-left:61px}.btn-social-icon.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social-icon.btn-sm{padding-left:38px}.btn-social-icon.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social-icon.btn-xs{padding-left:30px}.btn-social-icon.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon>:first-child{border:none;text-align:center;width:100% !important}.btn-social-icon.btn-lg{height:45px;width:45px;padding-left:0;padding-right:0}.btn-social-icon.btn-sm{height:30px;width:30px;padding-left:0;padding-right:0}.btn-social-icon.btn-xs{height:22px;width:22px;padding-left:0;padding-right:0}.btn-facebook{color:#fff;background-color:#3b5998;border-color:rgba(0,0,0,0.2)}.btn-facebook:focus,.btn-facebook.focus{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:hover{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:active:hover,.btn-facebook.active:hover,.open>.dropdown-toggle.btn-facebook:hover,.btn-facebook:active:focus,.btn-facebook.active:focus,.open>.dropdown-toggle.btn-facebook:focus,.btn-facebook:active.focus,.btn-facebook.active.focus,.open>.dropdown-toggle.btn-facebook.focus{color:#fff;background-color:#23345a;border-color:rgba(0,0,0,0.2)}.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{background-image:none}.btn-facebook.disabled:hover,.btn-facebook[disabled]:hover,fieldset[disabled] .btn-facebook:hover,.btn-facebook.disabled:focus,.btn-facebook[disabled]:focus,fieldset[disabled] .btn-facebook:focus,.btn-facebook.disabled.focus,.btn-facebook[disabled].focus,fieldset[disabled] .btn-facebook.focus{background-color:#3b5998;border-color:rgba(0,0,0,0.2)}.btn-facebook .badge{color:#3b5998;background-color:#fff}.btn-github{color:#fff;background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-github:focus,.btn-github.focus{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:hover{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:active:hover,.btn-github.active:hover,.open>.dropdown-toggle.btn-github:hover,.btn-github:active:focus,.btn-github.active:focus,.open>.dropdown-toggle.btn-github:focus,.btn-github:active.focus,.btn-github.active.focus,.open>.dropdown-toggle.btn-github.focus{color:#fff;background-color:#191919;border-color:rgba(0,0,0,0.2)}.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{background-image:none}.btn-github.disabled:hover,.btn-github[disabled]:hover,fieldset[disabled] .btn-github:hover,.btn-github.disabled:focus,.btn-github[disabled]:focus,fieldset[disabled] .btn-github:focus,.btn-github.disabled.focus,.btn-github[disabled].focus,fieldset[disabled] .btn-github.focus{background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-github .badge{color:#444;background-color:#fff}.btn-google{color:#fff;background-color:#dd4b39;border-color:rgba(0,0,0,0.2)}.btn-google:focus,.btn-google.focus{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:hover{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:active:hover,.btn-google.active:hover,.open>.dropdown-toggle.btn-google:hover,.btn-google:active:focus,.btn-google.active:focus,.open>.dropdown-toggle.btn-google:focus,.btn-google:active.focus,.btn-google.active.focus,.open>.dropdown-toggle.btn-google.focus{color:#fff;background-color:#a32b1c;border-color:rgba(0,0,0,0.2)}.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{background-image:none}.btn-google.disabled:hover,.btn-google[disabled]:hover,fieldset[disabled] .btn-google:hover,.btn-google.disabled:focus,.btn-google[disabled]:focus,fieldset[disabled] .btn-google:focus,.btn-google.disabled.focus,.btn-google[disabled].focus,fieldset[disabled] .btn-google.focus{background-color:#dd4b39;border-color:rgba(0,0,0,0.2)}.btn-google .badge{color:#dd4b39;background-color:#fff}.btn-linkedin{color:#fff;background-color:#007bb6;border-color:rgba(0,0,0,0.2)}.btn-linkedin:focus,.btn-linkedin.focus{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:hover{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active:hover,.btn-linkedin.active:hover,.open>.dropdown-toggle.btn-linkedin:hover,.btn-linkedin:active:focus,.btn-linkedin.active:focus,.open>.dropdown-toggle.btn-linkedin:focus,.btn-linkedin:active.focus,.btn-linkedin.active.focus,.open>.dropdown-toggle.btn-linkedin.focus{color:#fff;background-color:#00405f;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{background-image:none}.btn-linkedin.disabled:hover,.btn-linkedin[disabled]:hover,fieldset[disabled] .btn-linkedin:hover,.btn-linkedin.disabled:focus,.btn-linkedin[disabled]:focus,fieldset[disabled] .btn-linkedin:focus,.btn-linkedin.disabled.focus,.btn-linkedin[disabled].focus,fieldset[disabled] .btn-linkedin.focus{background-color:#007bb6;border-color:rgba(0,0,0,0.2)}.btn-linkedin .badge{color:#007bb6;background-color:#fff}.btn-microsoft{color:#fff;background-color:#2672ec;border-color:rgba(0,0,0,0.2)}.btn-microsoft:focus,.btn-microsoft.focus{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:hover{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active:hover,.btn-microsoft.active:hover,.open>.dropdown-toggle.btn-microsoft:hover,.btn-microsoft:active:focus,.btn-microsoft.active:focus,.open>.dropdown-toggle.btn-microsoft:focus,.btn-microsoft:active.focus,.btn-microsoft.active.focus,.open>.dropdown-toggle.btn-microsoft.focus{color:#fff;background-color:#0f4bac;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{background-image:none}.btn-microsoft.disabled:hover,.btn-microsoft[disabled]:hover,fieldset[disabled] .btn-microsoft:hover,.btn-microsoft.disabled:focus,.btn-microsoft[disabled]:focus,fieldset[disabled] .btn-microsoft:focus,.btn-microsoft.disabled.focus,.btn-microsoft[disabled].focus,fieldset[disabled] .btn-microsoft.focus{background-color:#2672ec;border-color:rgba(0,0,0,0.2)}.btn-microsoft .badge{color:#2672ec;background-color:#fff}.btn-odnoklassniki{color:#fff;background-color:#f4731c;border-color:rgba(0,0,0,0.2)}.btn-odnoklassniki:focus,.btn-odnoklassniki.focus{color:#fff;background-color:#d35b0a;border-color:rgba(0,0,0,0.2)}.btn-odnoklassniki:hover{color:#fff;background-color:#d35b0a;border-color:rgba(0,0,0,0.2)}.btn-odnoklassniki:active,.btn-odnoklassniki.active,.open>.dropdown-toggle.btn-odnoklassniki{color:#fff;background-color:#d35b0a;border-color:rgba(0,0,0,0.2)}.btn-odnoklassniki:active:hover,.btn-odnoklassniki.active:hover,.open>.dropdown-toggle.btn-odnoklassniki:hover,.btn-odnoklassniki:active:focus,.btn-odnoklassniki.active:focus,.open>.dropdown-toggle.btn-odnoklassniki:focus,.btn-odnoklassniki:active.focus,.btn-odnoklassniki.active.focus,.open>.dropdown-toggle.btn-odnoklassniki.focus{color:#fff;background-color:#b14c09;border-color:rgba(0,0,0,0.2)}.btn-odnoklassniki:active,.btn-odnoklassniki.active,.open>.dropdown-toggle.btn-odnoklassniki{background-image:none}.btn-odnoklassniki.disabled:hover,.btn-odnoklassniki[disabled]:hover,fieldset[disabled] .btn-odnoklassniki:hover,.btn-odnoklassniki.disabled:focus,.btn-odnoklassniki[disabled]:focus,fieldset[disabled] .btn-odnoklassniki:focus,.btn-odnoklassniki.disabled.focus,.btn-odnoklassniki[disabled].focus,fieldset[disabled] .btn-odnoklassniki.focus{background-color:#f4731c;border-color:rgba(0,0,0,0.2)}.btn-odnoklassniki .badge{color:#f4731c;background-color:#fff}.btn-twitter{color:#fff;background-color:#55acee;border-color:rgba(0,0,0,0.2)}.btn-twitter:focus,.btn-twitter.focus{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:hover{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:active:hover,.btn-twitter.active:hover,.open>.dropdown-toggle.btn-twitter:hover,.btn-twitter:active:focus,.btn-twitter.active:focus,.open>.dropdown-toggle.btn-twitter:focus,.btn-twitter:active.focus,.btn-twitter.active.focus,.open>.dropdown-toggle.btn-twitter.focus{color:#fff;background-color:#1583d7;border-color:rgba(0,0,0,0.2)}.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{background-image:none}.btn-twitter.disabled:hover,.btn-twitter[disabled]:hover,fieldset[disabled] .btn-twitter:hover,.btn-twitter.disabled:focus,.btn-twitter[disabled]:focus,fieldset[disabled] .btn-twitter:focus,.btn-twitter.disabled.focus,.btn-twitter[disabled].focus,fieldset[disabled] .btn-twitter.focus{background-color:#55acee;border-color:rgba(0,0,0,0.2)}.btn-twitter .badge{color:#55acee;background-color:#fff}.btn-vk{color:#fff;background-color:#587ea3;border-color:rgba(0,0,0,0.2)}.btn-vk:focus,.btn-vk.focus{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:hover{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:active:hover,.btn-vk.active:hover,.open>.dropdown-toggle.btn-vk:hover,.btn-vk:active:focus,.btn-vk.active:focus,.open>.dropdown-toggle.btn-vk:focus,.btn-vk:active.focus,.btn-vk.active.focus,.open>.dropdown-toggle.btn-vk.focus{color:#fff;background-color:#3a526b;border-color:rgba(0,0,0,0.2)}.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{background-image:none}.btn-vk.disabled:hover,.btn-vk[disabled]:hover,fieldset[disabled] .btn-vk:hover,.btn-vk.disabled:focus,.btn-vk[disabled]:focus,fieldset[disabled] .btn-vk:focus,.btn-vk.disabled.focus,.btn-vk[disabled].focus,fieldset[disabled] .btn-vk.focus{background-color:#587ea3;border-color:rgba(0,0,0,0.2)}.btn-vk .badge{color:#587ea3;background-color:#fff}.btn-servicestack{color:#fff;background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-servicestack:focus,.btn-servicestack.focus{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-servicestack:hover{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-servicestack:active,.btn-servicestack.active,.open>.dropdown-toggle.btn-servicestack{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-servicestack:active:hover,.btn-servicestack.active:hover,.open>.dropdown-toggle.btn-servicestack:hover,.btn-servicestack:active:focus,.btn-servicestack.active:focus,.open>.dropdown-toggle.btn-servicestack:focus,.btn-servicestack:active.focus,.btn-servicestack.active.focus,.open>.dropdown-toggle.btn-servicestack.focus{color:#fff;background-color:#191919;border-color:rgba(0,0,0,0.2)}.btn-servicestack:active,.btn-servicestack.active,.open>.dropdown-toggle.btn-servicestack{background-image:none}.btn-servicestack.disabled:hover,.servicestack[disabled]:hover,fieldset[disabled] .btn-servicestack:hover,.btn-servicestack.disabled:focus,.btn-servicestack[disabled]:focus,fieldset[disabled] .btn-servicestack:focus,.btn-servicestack.disabled.focus,.btn-servicestack[disabled].focus,fieldset[disabled] .btn-servicestack.focus{background-color:#333;border-color:rgba(0,0,0,0.2)}.btn-servicestack .badge{color:#333;background-color:#fff} +.svg-servicestack,.fa-servicestack{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='servicestack-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m16.564516,43.33871c16.307057,2.035887 54.629638,20.41875 60.67742,46.306452l-78.241936,0c19.859879,-1.616734 36.825605,-27.344758 17.564516,-46.306452zm6.387097,-30.33871c6.446976,7.105645 9.520766,16.74617 9.26129,26.666129c16.546573,6.726411 41.376412,24.690121 46.625807,49.979033l19.161291,0c-8.123589,-43.132863 -54.529839,-73.551412 -75.048388,-76.645162z' /%3E%3C/g%3E%3C/svg%3E")}.svg-twitter,.fa-twitter{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='twitter-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m32.167025,90.818083c37.320006,0 57.741133,-30.948298 57.741133,-57.741133c0,-0.870668 0,-1.741336 -0.039576,-2.612005c3.957583,-2.84946 7.40068,-6.45086 10.131412,-10.52717c-3.640976,1.622609 -7.558983,2.691156 -11.674869,3.205642c4.195038,-2.493277 7.40068,-6.490436 8.944137,-11.239535c-3.918007,2.334974 -8.271348,3.997159 -12.90172,4.907403c-3.720128,-3.957583 -8.983713,-6.411284 -14.80136,-6.411284c-11.199959,0 -20.3024,9.10244 -20.3024,20.3024c0,1.583033 0.197879,3.12649 0.514486,4.630372c-16.859303,-0.831092 -31.818966,-8.944137 -41.83165,-21.212644c-1.741336,3.007763 -2.730732,6.490436 -2.730732,10.210564c0,7.044497 3.6014,13.257902 9.023289,16.898879c-3.32437,-0.118727 -6.45086,-1.028972 -9.181592,-2.532853c0,0.079152 0,0.158303 0,0.277031c0,9.814805 7.004922,18.046578 16.265665,19.906642c-1.701761,0.47491 -3.482673,0.712365 -5.342737,0.712365c-1.306002,0 -2.572429,-0.118727 -3.79928,-0.356182c2.572429,8.073469 10.091836,13.930692 18.956822,14.088995c-6.965346,5.461464 -15.711604,8.706682 -25.209803,8.706682c-1.622609,0 -3.245218,-0.079152 -4.828251,-0.277031c8.944137,5.698919 19.629611,9.062865 31.067025,9.062865' /%3E%3C/g%3E%3C/svg%3E")}.svg-github,.fa-github{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='github-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m49.974605,1.297c-27.058469,0 -48.974605,21.928379 -48.974605,48.974605c0,21.642694 14.031224,39.995927 33.486386,46.464656c2.44873,0.461178 3.346598,-1.052954 3.346598,-2.354862c0,-1.163147 -0.040812,-4.244466 -0.061218,-8.325683c-13.623103,2.954801 -16.496279,-6.570759 -16.496279,-6.570759c-2.228345,-5.652486 -5.448425,-7.162536 -5.448425,-7.162536c-4.436283,-3.036425 0.342822,-2.975207 0.342822,-2.975207c4.917867,0.342822 7.501277,5.044384 7.501277,5.044384c4.366902,7.489033 11.464139,5.325988 14.263854,4.073055c0.440771,-3.167024 1.701868,-5.325988 3.101725,-6.550353c-10.876443,-1.224365 -22.307932,-5.436181 -22.307932,-24.201617c0,-5.346394 1.897766,-9.713297 5.040303,-13.141519c-0.550964,-1.236609 -2.203857,-6.215694 0.428528,-12.961945c0,0 4.101623,-1.314152 13.468016,5.019897c3.917968,-1.089685 8.08081,-1.628406 12.243651,-1.652893c4.162841,0.024487 8.325683,0.563208 12.243651,1.652893c9.305175,-6.334049 13.406798,-5.019897 13.406798,-5.019897c2.632385,6.746252 0.979492,11.725337 0.489746,12.961945c3.122131,3.428222 5.019897,7.795125 5.019897,13.141519c0,18.814411 -11.447814,22.956846 -22.344663,24.160805c1.714111,1.469238 3.305786,4.473014 3.305786,9.060302c0,6.554435 -0.061218,11.819205 -0.061218,13.410879c0,1.285583 0.857056,2.81604 3.367004,2.326294c19.593923,-6.423836 33.612904,-24.789312 33.612904,-46.399357c0,-27.046225 -21.928379,-48.974605 -48.974605,-48.974605' /%3E%3C/g%3E%3C/svg%3E")}.svg-google,.fa-google{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='google-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m50.4849,43.206983l0,16.886897l27.930066,0c-1.128529,7.243104 -8.437293,21.232759 -27.930066,21.232759c-16.804822,0 -30.527734,-13.90758 -30.527734,-31.081739s13.727016,-31.081739 30.527734,-31.081739c9.561718,0 15.967659,4.0586 19.636404,7.587818l13.353575,-12.877541c-8.57682,-8.0064 -19.69796,-12.873438 -32.989979,-12.873438c-27.228326,0 -49.2449,22.016574 -49.2449,49.2449s22.016574,49.2449 49.2449,49.2449c28.422515,0 47.275104,-19.981118 47.275104,-48.120475c0,-3.233748 -0.348818,-5.704201 -0.775607,-8.162342l-46.499497,0z'/%3E%3C/g%3E%3C/svg%3E")}.svg-facebook,.fa-facebook{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='facebook-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m93.593662,1l-87.187329,0c-2.984917,0 -5.406333,2.421417 -5.406333,5.406333l0,87.187329c0,2.989 2.421417,5.406333 5.406333,5.406333l46.933831,0l0,-37.950498l-12.776749,0l0,-14.785749l12.776749,0l0,-10.922916c0,-12.654249 7.733833,-19.538749 19.024249,-19.538749c5.410416,0 10.061333,0.396083 11.416999,0.57575l0,13.229999l-7.844083,0c-6.125,0 -7.317333,2.944083 -7.317333,7.231583l0,9.436583l14.634666,0l-1.89875,14.822499l-12.735916,0l0,37.901498l24.969582,0c2.993083,0 5.410416,-2.417333 5.410416,-5.406333l0,-87.187329c0,-2.984917 -2.417333,-5.406333 -5.406333,-5.406333'/%3E%3C/g%3E%3C/svg%3E")}.svg-microsoft,.fa-microsoft{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='microsoft-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m47.550002,99.000004l-46.550002,0l0,-46.550002l46.550002,0l0,46.550002zm51.450002,0l-46.550002,0l0,-46.550002l46.550002,0l0,46.550002zm-51.450002,-51.450002l-46.550002,0l0,-46.550002l46.550002,0l0,46.550002zm51.450002,0l-46.550002,0l0,-46.550002l46.550002,0l0,46.550002z'/%3E%3C/g%3E%3C/svg%3E")}.svg-linkedin,.fa-linkedin{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='linkedin-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m84.491916,84.512333l-14.512167,0l0,-22.740083c0,-5.422667 -0.11025,-12.401083 -7.562333,-12.401083c-7.566417,0 -8.722,5.900417 -8.722,12.000917l0,23.14025l-14.512167,0l0,-46.762333l13.9405,0l0,6.374083l0.187833,0c1.94775,-3.675 6.684417,-7.554167 13.760833,-7.554167c14.704083,0 17.423583,9.6775 17.423583,22.274583l0,25.667833l-0.004083,0zm-61.699166,-53.160916c-4.671333,0 -8.423917,-3.781167 -8.423917,-8.432083c0,-4.646833 3.756667,-8.423917 8.423917,-8.423917c4.655,0 8.428,3.777083 8.428,8.423917c0,4.650917 -3.777083,8.432083 -8.428,8.432083zm7.2765,53.160916l-14.553,0l0,-46.762333l14.553,0l0,46.762333zm61.682833,-83.512332l-83.520499,0c-3.997583,0 -7.231583,3.1605 -7.231583,7.060083l0,83.879832c0,3.903667 3.234,7.060083 7.231583,7.060083l83.508249,0c3.9935,0 7.260167,-3.156417 7.260167,-7.060083l0,-83.879832c0,-3.899583 -3.266667,-7.060083 -7.260167,-7.060083l0.01225,0z'/%3E%3C/g%3E%3C/svg%3E")}.btn-social.btn-xs{padding:0 0 0 30px}.btn-social.btn .fab,.btn-social-icon.btn .fab,.btn-social.btn-md .fab,.btn-social-icon.btn-md .fab{width:36px;height:36px;background-size:28px 28px;background-position:3px 3px;background-repeat:no-repeat}.btn-social-icon.btn .fab,.btn-social-icon.btn-md .fab{background-position:2px 2px}.btn-social.btn-lg .fab,.btn-social-icon.btn-lg .fab{width:45px;height:45px;background-size:39px 39px;background-position:4px 4px;background-repeat:no-repeat}.btn-social-icon.btn-lg .fab{background-position:2px 2px}.btn-social.btn-sm .fab,.btn-social-icon.btn-sm .fab{width:30px;height:30px;background-size:24px 24px;background-position:2px 2px;background-repeat:no-repeat}.btn-social.btn-xs .fab,.btn-social-icon.btn-xs .fab{width:24px;height:24px;background-size:20px 20px;background-position:2px 2px;background-repeat:no-repeat}.btn-social-icon.btn-xs .fab{background-position:0 0}.svg-xs,.svg-sm,.svg-md,.svg-lg,.svg-2x,.svg-3x,.svg-4x,.svg-5x,.svg-6x,.svg-7x,.svg-8x,.svg-9x,.svg-10x,.svg-11x,.svg-12x,.svg-13x,.svg-14x{background-position:0;background-repeat:no-repeat;display:inline-block;background-size:contain;vertical-align:middle}.svg-xs{width:12px;height:12px}.svg-sm{width:14px;height:14px}.svg-md{width:18px;height:18px}.svg-lg{width:24px;height:24px}.svg-2x{width:32px;height:32px}.svg-3x{width:48px;height:48px}.svg-4x{width:64px;height:64px}.svg-5x{width:80px;height:80px}.svg-6x{width:96px;height:96px}.svg-7x{width:112px;height:112px}.svg-8x{width:128px;height:128px}.svg-9x{width:144px;height:144px}.svg-10x{width:160px;height:160px}.svg-11x{width:180px;height:180px}.svg-12x{width:204px;height:204px}.svg-13x{width:232px;height:232px}.svg-14x{width:264px;height:264px} +.svg-male,.fa-male{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='male-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m76.58509,57.864831c-11.431997,-3.734047 -16.184124,-8.377552 -16.184124,-8.377552l-0.382619,0.364719c-3.394958,3.19541 -7.149753,5.073926 -10.570341,5.073926l-0.322816,0c-3.420385,0 -7.17518,-1.878516 -10.570137,-5.073926l-0.382823,-0.364719c0,0 -4.751721,4.643302 -16.183921,8.377552c-16.875931,6.304166 -11.808717,31.96 -11.813599,32.158734c0.531517,2.857338 0.841315,3.839415 1.111244,3.949664c16.947126,7.54478 59.054571,7.54478 76.0019,0c0.269929,-0.11025 0.579726,-1.092326 1.111244,-3.949664c-0.004882,-0.198734 5.130068,-25.752658 -11.814006,-32.158734z'/%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m67.010047,25.134507l-0.141575,-0.153577c-0.94953,-0.869386 -0.875285,-0.81955 -0.875285,-0.81955s1.656186,-8.356804 0.328105,-12.308706c-2.08498,-6.311286 -14.538923,-10.541253 -17.036831,-11.032901c0.000407,-0.004678 -1.519289,-0.30878 -1.616317,-0.309391c0,0 -1.964763,-0.397265 -4.241968,0.595999c-1.483082,0.570573 -9.236564,4.086561 -11.437286,10.746293c-1.327878,3.951902 0.328308,12.308706 0.328308,12.308706s0.074246,-0.049836 -0.875488,0.81955l-0.141372,0.153577c-0.642377,0.729438 -0.483715,3.011728 0.218465,5.386165c0.636275,2.378912 1.465588,3.018238 1.664323,3.575385c2.014396,9.45808 9.018912,17.533564 16.156867,17.533564s13.772464,-8.075484 15.786859,-17.533564c0.198938,-0.556944 1.028251,-1.196473 1.664526,-3.575385c0.702181,-2.37464 0.879353,-4.813558 0.218669,-5.386165z'/%3E%3C/g%3E%3C/svg%3E")}.svg-female,.fa-female{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='female-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m85.60156,58.800256c-1.802974,-4.00837 -11.201255,-7.569957 -14.439638,-8.694836c-5.028682,-11.014303 -2.309962,-24.921604 -2.309962,-24.921604c-0.890397,3.951334 -2.031119,5.465959 -2.031119,5.465959c-0.884059,7.148524 -6.714416,13.035916 -6.714416,13.035916c-0.098229,1.920215 0.14259,3.552081 0.59571,4.943128c-8.999028,14.547372 -16.363021,6.936223 -19.997488,1.0013c0.693939,-1.600179 1.115372,-3.542575 0.988626,-5.944428c0,0 -5.830356,-5.887392 -6.720753,-13.035916c0,0 -1.131216,-1.514625 -2.018444,-5.465959c0,0 2.706046,13.859771 -2.294118,24.867737c-3.872117,1.660384 -7.769583,2.83913 -7.769583,2.83913c-4.207996,1.619191 -5.991958,4.043225 -5.991958,4.043225c-6.220103,9.227172 -6.948897,29.779178 -6.948897,29.779178c0.082385,4.695972 2.097661,5.17761 2.097661,5.17761c14.331903,6.388042 36.778774,7.525596 36.778774,7.525596c23.061594,0.487975 39.84288,-6.552813 39.84288,-6.552813c2.439877,-1.539975 2.512757,-2.747238 2.512757,-2.747238c1.698408,-14.734324 -5.580031,-31.315984 -5.580031,-31.315984z'/%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m60.844727,16.200632c0.247156,0.922084 1.736432,5.649742 6.717584,7.779089c0,0 0.183783,-1.936058 0.725626,-2.119841c0,0 0.611554,0.304192 0.792168,1.029818c0,0 1.299155,-12.421194 -4.356924,-17.056961l0.031687,-0.066542c-11.806471,-10.415424 -25.165592,-2.490576 -25.165592,-2.490576c-9.791196,6.29932 -7.053464,19.911934 -7.053464,19.911934c18.413152,1.739601 28.030071,-6.730259 28.308914,-6.986921z'/%3E%3C/g%3E%3C/svg%3E")}.svg-male-business,.fa-male-business{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='male-business-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m31.412893,31.445302c0.343588,1.580507 0.870424,2.603637 1.485066,3.241185c1.46216,10.177854 10.597796,18.851555 17.935319,18.488878c9.334154,-0.458118 15.950141,-10.517625 17.435207,-18.488878c0.614642,-0.63373 1.206377,-1.988996 1.561419,-3.580956c0.397036,-1.828654 0.824612,-4.584997 -0.274871,-6.04334c-0.0649,-0.076353 -0.484842,-0.461936 -0.557377,-0.526836c1.049854,-3.787109 3.355714,-10.544349 -2.386031,-16.61823c-3.111385,-3.290814 -7.432964,-4.943857 -11.33842,-6.249493c-11.529303,-3.852009 -19.668532,1.549966 -23.425099,10.532896c-0.271053,0.637548 -2.023354,4.672803 0.099259,12.334827c-0.206153,0.137435 -0.393218,0.313047 -0.549742,0.526836c-1.103301,1.454525 -0.385583,4.554456 0.015271,6.383111z'/%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m91.040766,87.419684c-0.320683,-7.005387 -0.717718,-18.107113 -6.837411,-27.189302c0,0 -1.744666,-2.378396 -5.882998,-3.958903c0,0 -8.986748,-2.737255 -13.12508,-5.695934l-1.889737,1.294183l0.209971,12.285197l-11.346055,30.289234c-0.248147,0.664271 -0.881877,1.103301 -1.588142,1.103301s-1.339995,-0.43903 -1.588142,-1.103301l-11.342238,-30.289234c0,0 0.209971,-12.247021 0.206153,-12.285197c0.026724,0.103077 -1.893554,-1.294183 -1.893554,-1.294183c-4.130697,2.958679 -13.121263,5.695934 -13.121263,5.695934c-4.138332,1.580507 -5.882998,3.958903 -5.882998,3.958903c-6.115875,9.082189 -6.520546,20.183915 -6.841229,27.189302c-0.221424,4.84078 0.794071,6.646528 2.069166,7.161911c15.827976,6.352569 60.94878,6.352569 76.780574,0c1.28273,-0.511565 2.29059,-2.321131 2.072984,-7.161911z'/%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m50.985984,57.088456l-0.511565,0.011453c-1.649225,0 -3.31372,-0.320683 -4.947674,-0.885695l4.497192,6.883223l-4.035256,3.894003l4.153603,25.223213c0.034359,0.217606 0.221424,0.37413 0.442847,0.37413c0.217606,0 0.404671,-0.156524 0.442847,-0.37413l4.153603,-25.223213l-4.039074,-3.894003l4.432291,-6.780146c-1.446889,0.423759 -2.977767,0.706265 -4.588815,0.771165z'/%3E%3C/g%3E%3C/svg%3E")}.svg-female-business,.fa-female-business{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='female-business-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m61.460569,63.399148l0,0l0,-4.153337c0,0 13.088078,0.405204 19.307953,-5.936233c0,0 -9.036041,-2.552783 -7.415227,-19.024311c1.620815,-16.451268 -2.026018,-30.896778 -15.255917,-29.681167c0,0 -5.733632,-6.908722 -17.140114,-2.552783c-3.910215,1.499253 -14.42525,5.247387 -13.898485,28.060352c0.526765,22.792705 -8.104073,22.934526 -8.104073,22.934526s4.45724,6.483258 19.571336,6.341437l0,4.254638l11.487523,33.550861l11.467263,-33.490081l-0.02026,-0.303903z'/%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m92.316826,97.679376l-2.309661,-12.763915c-0.749627,-4.133077 -3.423971,-7.678609 -7.192365,-9.542546l-14.46577,-7.131584c-0.830667,-0.405204 -1.641075,-0.871188 -2.451482,-1.316912l4.558541,13.452761l-6.381957,-0.486244l-14.060566,17.302195l-14.060566,-17.302195l-6.381957,0.486244l4.659842,-13.452761l-2.897206,1.478993l-14.121347,6.969503c-3.768394,1.863937 -6.442738,5.409469 -7.192365,9.542546l-2.309661,12.763915c-0.162081,0.931968 0.547025,1.803156 1.499253,1.803156l40.256982,0l1.053529,0l40.256982,0c0.992749,0 1.701855,-0.871188 1.539774,-1.803156z'/%3E%3C/g%3E%3C/svg%3E")}.svg-male-color,.fa-male-color{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='male-color-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m50.653881,0.00747c-27.500423,-0.469836 -50.176573,21.443301 -50.646409,48.943724c-0.266867,15.592907 6.682943,29.607166 17.748513,38.926827c0.723547,-0.631459 1.499716,-1.210297 2.362334,-1.680132l14.859963,-8.105605c1.948878,-1.063708 3.162934,-3.106554 3.162934,-5.327937l0,-6.089071c0,0 -4.361955,-5.217056 -6.025173,-12.465681c-1.379438,-0.892688 -2.304074,-2.435628 -2.304074,-4.192814l0,-6.66415c0,-1.465887 0.652132,-2.775789 1.665098,-3.692909l0,-9.633511c0,0 -1.978948,-14.991517 18.323592,-14.991517s18.323592,14.991517 18.323592,14.991517l0,9.633511c1.014845,0.917119 1.665098,2.227021 1.665098,3.692909l0,6.66415c0,2.240177 -1.503474,4.125157 -3.544441,4.754737c-1.137002,3.535044 -2.777669,6.904705 -4.94643,9.968034c-0.546889,0.77241 -1.05807,1.426421 -1.505354,1.935723l0,6.243177c0,2.298436 1.298626,4.401421 3.354627,5.427542l15.912395,7.955258c0.954706,0.477353 1.817324,1.080622 2.612286,1.751547c10.731047,-8.94943 17.663943,-22.330351 17.921413,-37.398922c0.473594,-27.500423 -21.437663,-50.176573 -48.939966,-50.646409z'/%3E%3Cpath stroke='null' fill='%23E7ECED' d='m34.898055,77.913534l-15.017499,8.056835c-0.88126,0.472613 -1.673254,1.053572 -2.410169,1.686836c8.755618,7.261052 20.058152,11.641593 32.407182,11.641593c12.257865,0 23.488227,-4.315161 32.219154,-11.477206c-0.805289,-0.668756 -1.678951,-1.270264 -2.647577,-1.744745l-16.081088,-7.907392c-2.077797,-1.021815 -3.39019,-3.110278 -3.39019,-5.394885l0,-6.205612c0.452025,-0.506237 0.968626,-1.156314 1.521312,-1.924076c2.191753,-3.044897 3.849813,-6.394283 4.998869,-9.908057c2.062603,-0.625792 3.582016,-2.499431 3.582016,-4.726128l0,-6.624052c0,-1.457067 -0.659045,-2.759088 -1.68275,-3.670689l0,-9.575547c0,0 1.999927,-14.901314 -18.517847,-14.901314s-18.517847,14.901314 -18.517847,14.901314l0,9.575547c-1.025604,0.911601 -1.68275,2.213621 -1.68275,3.670689l0,6.624052c0,1.744745 0.93254,3.280269 2.328501,4.167586c1.68275,7.205011 6.089048,12.390675 6.089048,12.390675l0,6.052433c-0.001899,2.204281 -1.228825,4.234835 -3.198365,5.292143z'/%3E%3C/g%3E%3C/svg%3E")}.svg-female-color,.fa-female-color{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='female-color-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m49.881625,0.193237c-27.496353,0 -49.785007,22.290532 -49.785007,49.785007c0,15.070767 6.706886,28.567201 17.287609,37.697583c1.12345,-1.489793 2.562519,-2.750387 4.294661,-3.616458l17.120406,-7.34188c0.928068,-0.464034 1.683297,-1.96322 2.214963,-3.032189c0.479063,-0.965641 -0.236714,-2.102242 -1.315076,-2.102242l-12.108089,0c0,0 -4.377323,-0.428339 -7.75331,-1.87868c-1.97825,-0.849163 -2.658332,-1.970735 -1.42216,-3.731058c3.616458,-5.147582 11.091724,-17.268822 11.334074,-29.786464c0,0 0.415188,-19.269616 19.425546,-19.425546c11.089845,0.092055 16.327604,6.618588 18.768008,12.042336c1.360164,3.026553 1.944433,6.325514 2.16236,9.635747c0.789045,11.931494 6.864695,22.844743 9.695865,27.507625c0.960005,1.581848 0.495971,3.687848 -1.091513,4.63846c-2.605728,1.557425 -5.793848,0.997579 -5.793848,0.997579l-12.188873,0c-1.191083,0 -1.717113,1.66451 -0.781531,2.402831c0.762744,0.601177 1.489793,1.144116 1.882437,1.358285l14.240391,8.617503c2.040246,1.112178 3.667182,2.75978 4.781239,4.706092c0.048846,0.046967 0.103327,0.090177 0.150294,0.140901c11.371647,-9.122868 18.66656,-23.117151 18.66656,-38.830427c0,-27.494475 -22.288654,-49.785007 -49.785007,-49.785007z'/%3E%3Cpath stroke='null' fill='%23E7ECED' d='m21.758902,83.967938l17.119332,-7.341419c0.928009,-0.464005 1.683191,-1.963097 2.214824,-3.031998c0.479033,-0.965581 -0.236699,-2.10211 -1.314993,-2.10211l-12.107329,0c0,0 -4.377048,-0.428312 -7.752824,-1.878562c-1.978125,-0.84911 -2.658165,-1.970611 -1.422071,-3.730823c3.616231,-5.147259 11.091027,-17.267738 11.333362,-29.784594c0,0 0.415162,-19.268406 19.424327,-19.424327c11.089149,0.09205 16.326579,6.618172 18.76683,12.04158c1.360079,3.026363 1.944311,6.325117 2.162224,9.635142c0.788996,11.930744 6.864264,22.843309 9.695256,27.505898c0.959945,1.581749 0.49594,3.687616 -1.091444,4.638168c-2.603686,1.557328 -5.791605,0.997516 -5.791605,0.997516l-12.188107,0c-1.191008,0 -1.717005,1.664406 -0.781482,2.40268c0.762696,0.60114 1.489699,1.144044 1.882319,1.3582l14.239497,8.616962c2.055146,1.121501 3.695131,2.785907 4.810996,4.750882c-8.545577,6.907471 -19.416812,11.049699 -31.261143,11.049699c-12.349664,0 -23.641697,-4.506669 -32.341316,-11.953287c1.13653,-1.549813 2.618715,-2.857292 4.403348,-3.749609z'/%3E%3C/g%3E%3C/svg%3E")}.svg-users,.fa-users{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='users-svg'%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m68.234601,75.454014l-15.811134,-7.90474c-1.491242,-0.746448 -2.418096,-2.245966 -2.418096,-3.914303l0,-5.59588c0.379017,-0.463427 0.777895,-0.991403 1.190014,-1.573997c2.050664,-2.896418 3.694175,-6.120546 4.889154,-9.597903c2.335341,-1.070847 3.851409,-3.379707 3.851409,-5.986483l0,-6.620385c0,-1.593858 -0.595835,-3.138062 -1.655096,-4.344628l0,-8.803457c0.092685,-0.910303 0.456807,-6.329088 -3.462461,-10.799503c-3.399568,-3.877891 -8.916003,-5.844145 -16.398694,-5.844145s-12.999126,1.966254 -16.398694,5.84249c-3.919268,4.470415 -3.555147,9.890855 -3.462461,10.799503l0,8.803457c-1.059262,1.206565 -1.655096,2.75077 -1.655096,4.344628l0,6.620385c0,2.014252 0.915268,3.892786 2.477679,5.145694c1.516068,6.003034 4.688888,10.526412 5.797802,11.977932l0,5.476713c0,1.602133 -0.873891,3.071859 -2.279068,3.839823l-14.765114,8.053698c-4.801434,2.621672 -7.782263,7.643234 -7.782263,13.111672l0,7.014298l76.134428,0l0,-6.691554c0,-5.691876 -3.162889,-10.807778 -8.25231,-13.353317l-0.000001,0z'/%3E%3Cpath fill='%23e33' class='path' stroke='null' d='m92.155708,77.335859l-16.092501,-6.967955c-0.380672,-0.190336 -0.802722,-0.655418 -1.165188,-1.276079l10.799503,-0.008275c0,0 0.623971,0.061239 1.592203,0.061239c1.775918,0 4.366144,-0.201922 6.620385,-1.170153c1.352214,-0.582594 2.358512,-1.732886 2.762356,-3.156269c0.407154,-1.436624 0.148959,-2.957657 -0.705071,-4.175808c-3.086754,-4.392625 -10.291388,-15.870718 -10.516482,-27.512665c-0.004965,-0.200267 -0.657073,-19.998528 -20.208725,-20.159072c-1.964599,0.016551 -3.821617,0.258195 -5.580985,0.683555c1.310836,3.465772 1.190014,6.567422 1.100639,7.57372l0,7.833571c1.072502,1.525999 1.655096,3.338329 1.655096,5.198657l0,6.620385c0,3.156269 -1.661717,6.077513 -4.314836,7.716059c-1.238012,3.346605 -2.876557,6.473081 -4.880879,9.303296c-0.248264,0.352536 -0.493219,0.68521 -0.733208,0.999678l0,4.733575c0,0.731553 0.390603,1.365454 1.044366,1.691508l15.811134,7.90474c5.93683,2.969243 9.624385,8.935865 9.624385,15.574456l0,6.694864l20.690358,0l0,-6.118891c0,-5.117558 -2.843455,-9.715415 -7.502551,-12.044135z'/%3E%3C/g%3E%3C/svg%3E")}.svg-vue,.fa-vue{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E %3Cg%3E %3Cpath fill='%23e33' stroke='null' d='m79.43253,10.80794l0.01231,-0.02461l-18.15085,0l-11.38274,19.68085l0,0.0082l-11.37043,-19.68906l-18.15085,0l0,0.02051l-19.70136,0l49.22265,85.26183l49.22265,-85.25773'/%3E %3C/g%3E %3C/svg%3E")}.svg-vscode,.fa-vscode{background-image:url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E %3Cg%3E %3Cpath fill='%23e33' stroke='null' d='m99.51625,10.84409l0,78.49178l-24.78688,10.32787l-74.36064,-22.72131l0,-2.31757l74.36064,6.38262l0,-80.49126l24.78688,10.32787zm-95.01637,43.83559l13.98393,-12.852l-13.98393,-12.852l5.85797,-3.41646l14.19049,10.69141l25.39416,-23.34098l12.39344,6.01495l0,45.80615l-12.39344,6.01495l-25.39416,-23.34098l-14.18636,10.69554l-5.8621,-3.42059zm27.44734,-12.852l17.99527,13.56255l0,-27.12511l-17.99527,13.56255z'/%3E %3C/g%3E %3C/svg%3E")}.svg-spirals,.fa-spirals{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='640' width='240'%3E %3Ccircle cx='220' cy='320' r='0' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.00267107309' cy='328.479870385976' r='0.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='216.030577592129' cy='336.952964171082' r='0.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='211.143002653157' cy='345.412510169899' r='0.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='204.437436653557' cy='353.851748023582' r='0.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='196.047632692183' cy='362.263933602329' r='0.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='186.140938652669' cy='370.642344394886' r='0.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='174.91495918573' cy='378.980284880769' r='0.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='162.59361417247' cy='387.271091880923' r='0.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='149.422672288893' cy='395.508139882531' r='0.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='135.664848761702' cy='403.684846333725' r='1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='121.594565098397' cy='411.794676903964' r='1.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='107.492475317123' cy='419.831150705876' r='1.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='93.6398678592534' cy='427.787845474394' r='1.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='80.313054847407' cy='435.65840269904' r='1.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='67.7778606039881' cy='443.436532705269' r='1.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='56.2843193654647' cy='451.116019680789' r='1.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='46.0616879548329' cy='458.690726642869' r='1.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='37.3138728923922' cy='466.154600342646' r='1.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='30.215363158323' cy='473.50167610251' r='1.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='24.9077497345402' cy='480.726082582724' r='2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='21.4969013490517' cy='487.822046473434' r='2.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.0508527570605' cy='494.783897108361' r='2.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.5984476803769' cy='501.606070996444' r='2.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='23.1287634738558' cy='508.283116267856' r='2.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='27.5913289947961' cy='514.809697030805' r='2.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='33.8971313295525' cy='521.180597635656' r='2.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='41.9203912966084' cy='527.390726842967' r='2.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='51.5010723108985' cy='533.435121892097' r='2.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='62.4480725661218' cy='539.308952467147' r='2.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='74.5430368619299' cy='545.007524557058' r='3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='87.5447120430797' cy='550.526284206776' r='3.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='101.193759174442' cy='555.860821156505' r='3.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='115.21792646544' cy='561.006872366119' r='3.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='129.33747976177' cy='565.960325421922' r='3.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='143.270782284683' cy='570.717221823047' r='3.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='156.73991232111' cy='575.273760144845' r='3.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='169.476206810936' cy='579.626299076761' r='3.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='181.225620255837' cy='583.771360332244' r='3.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='191.753792057754' cy='587.705631428388' r='3.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='200.850721210977' cy='591.425968333063' r='4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='208.334955103695' cy='594.929397977444' r='4.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='214.057208876769' cy='598.2131206319' r='4.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='217.903343145899' cy='601.274512143374' r='4.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.796640691816' cy='604.111126032447' r='4.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.699336706325' cy='606.720695448416' r='4.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='217.613372071015' cy='609.101134980824' r='4.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='213.580354643312' cy='611.250542325996' r='4.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='207.680729322084' cy='613.167199807242' r='4.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='200.032173447145' cy='614.849575747524' r='4.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='190.78724953896' cy='616.29632569348' r='5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='180.130362198343' cy='617.506293489827' r='5.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='168.274079865607' cy='618.478512203293' r='5.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='155.454894807471' cy='619.21220489533' r='5.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='141.928505905495' cy='619.706785242998' r='5.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='127.964718338249' cy='619.961858007519' r='5.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='113.842061891135' cy='619.977219350126' r='5.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='99.8422352401427' cy='619.752856994961' r='5.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='86.2444870270875' cy='619.288950238884' r='5.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='73.3200458046436' cy='618.58586980819' r='5.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='61.3267099547172' cy='617.644177562345' r='6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='50.5037054927735' cy='616.464626044986' r='6.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='41.0669143273324' cy='615.04815788253' r='6.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='33.2045681545236' cy='613.395905030884' r='6.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='27.0734938797776' cy='611.509187870856' r='6.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='22.7959854576394' cy='609.389514152986' r='6.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.4573645457988' cy='607.038577792641' r='6.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.104278629945' cy='604.458257516342' r='6.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='21.7437705660293' cy='601.650615360398' r='6.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='25.3431380993858' cy='598.617895023049' r='6.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='30.8305861628226' cy='595.362520071443' r='7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='38.0966589425679' cy='591.887092004862' r='7.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='46.9964231472564' cy='588.194388175766' r='7.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='57.3523589312079' cy='584.287359570293' r='7.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='68.957900807971' cy='580.169128450016' r='7.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='81.5815579250227' cy='575.842985856817' r='7.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='94.9715315142381' cy='571.312388982885' r='7.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='108.860737415796' cy='566.580958407936' r='7.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='122.972133493347' cy='561.652475205865' r='7.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='137.024245676747' cy='556.530877923139' r='7.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='150.736782406702' cy='551.220259431351' r='8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='163.83622549237' cy='545.724863656438' r='8.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='176.061285863437' cy='540.049082187198' r='8.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='187.168115393075' cy='534.197450765793' r='8.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='196.935170833763' cy='528.174645663059' r='8.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='205.167632847066' cy='521.985479941513' r='8.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='211.701291982871' cy='515.634899609042' r='8.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='216.405824096086' cy='509.127979666353' r='8.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.187389867428' cy='502.469920051338' r='8.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.99050657678' cy='495.666041483599' r='8.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='218.799154793624' cy='488.721781212447' r='9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='215.637097909869' cy='481.642688671782' r='9.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='210.567408141489' cy='474.434421045322' r='9.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='203.691208453614' cy='467.10273874572' r='9.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='195.145655503362' cy='459.653500811191' r='9.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='185.101203833807' cy='452.09266022332' r='9.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='173.75820588905' cy='444.426259149804' r='9.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='161.342915668454' cy='436.66042411591' r='9.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='148.102975733479' cy='428.801361108526' r='9.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='134.302477585879' cy='420.855350616717' r='9.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='120.216693945821' cy='412.82874261273' r='10' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='106.126588002954' cy='404.72795147748' r='10.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='92.3132091620794' cy='396.559450874569' r='10.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='79.052087069124' cy='388.329768576918' r='10.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='66.6077357374196' cy='380.04548125017' r='10.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='55.2283773981613' cy='371.713209197012' r='10.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='45.1409913161772' cy='363.339611066629' r='10.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='36.5467863301969' cy='354.931378533517' r='10.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='29.6171874249466' cy='346.495230949893' r='10.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='24.4904163892282' cy='338.037909976002' r='10.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='21.2687347641529' cy='329.566174192583' r='11' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.0164040752804' cy='321.086793699823' r='11.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.7584040350522' cy='312.606544707098' r='11.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='23.4799342829952' cy='304.132204117838' r='11.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='28.1267096022749' cy='295.670544113832' r='11.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='34.6060427240356' cy='287.228326743312' r='11.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='42.7886931212892' cy='278.812298517129' r='11.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='52.5114449152362' cy='270.429185017349' r='11.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='63.5803624736114' cy='262.085685522575' r='11.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='75.7746587630032' cy='253.788467654288' r='11.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='88.8510992947576' cy='245.544162048484' r='12' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='102.548853820808' cy='237.35935705687' r='12.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='116.594699004703' cy='229.240593481853' r='12.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='130.708468292347' cy='221.194359349522' r='12.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='144.608640276174' cy='213.227084724813' r='12.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='158.017954084014' cy='205.345136572983' r='12.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='170.668939784855' cy='197.554813671524' r='12.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='182.30925349883' cy='189.862341576552' r='12.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='192.706710794234' cy='182.273867647721' r='12.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='201.653917972527' cy='174.795456135626' r='12.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='208.972408863029' cy='167.433083335616' r='13' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='214.516204612411' cy='160.192632811904' r='13.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='218.17472546336' cy='153.079890695772' r='13.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.874996442387' cy='146.100541061648' r='13.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.583102960873' cy='139.260161384734' r='13.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='217.304867295073' cy='132.564218083827' r='13.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='213.085732451622' cy='126.018062152884' r='13.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='207.009855735039' cy='119.626924884834' r='13.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='199.198430097439' cy='113.395913691039' r='13.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='189.807266753799' cy='107.330008019763' r='13.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='179.023687281316' cy='101.434055376897' r='14' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='167.062787194863' cy='95.7127674521247' r='14.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='154.163145527401' cy='90.1707163536214' r='14.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='140.582065994564' cy='84.8123309543046' r='14.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='126.590444665889' cy='79.6418933525444' r='14.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='112.467366515083' cy='74.6635354501687' r='14.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='98.4945386296841' cy='69.881235650497' r='14.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='84.9506711185084' cy='65.2988156790399' r='14.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='72.1059177985786' cy='60.9199375294071' r='14.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='60.2164875507942' cy='56.7481005368628' r='14.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='49.5195338293678' cy='52.786638581868' r='15' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='40.2284242618229' cy='49.0387174258445' r='15.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='32.5284846948556' cy='45.5073321812893' r='15.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='26.5733025777777' cy='42.1953049182613' r='15.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='22.481663418397' cy='39.1052824091532' r='15.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.3351814185561' cy='36.2397340135507' r='15.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='20.1766715500455' cy='33.6009497048692' r='15.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='22.0092955424065' cy='31.1910382403451' r='15.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='25.7964988172447' cy='29.0119254758446' r='15.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='31.4627396269982' cy='27.0653528268355' r='15.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='38.8949958543389' cy='25.3528758767531' r='16' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='47.9450194167122' cy='23.8758631338719' r='16.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='58.4322933083589' cy='22.6354949376762' r='16.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='70.1476322969471' cy='21.6327625156039' r='16.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='82.8573554532394' cy='20.8684671909175' r='16.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='96.3079472861003' cy='20.343219742335' r='16.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='110.23111450915' cy='20.057439915932' r='16.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='124.349137573874' cy='20.0113560897063' r='16.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='138.380410224407' cy='20.2050050910718' r='16.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='152.045056578835' cy='20.6382321674285' r='16.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='165.070513695452' cy='21.3106911098309' r='17' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='177.196968270885' cy='22.2218445296581' r='17.1' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='188.182539026556' cy='23.3709642880616' r='17.2' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='197.8081014126' cy='24.7571320778504' r='17.3' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='205.881658392909' cy='26.3792401573467' r='17.4' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='212.242170129093' cy='28.2359922356257' r='17.5' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='216.762766174264' cy='30.3259045084341' r='17.6' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.353276104365' cy='32.647306843956' r='17.7' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='219.962028109623' cy='35.198344117482' r='17.8' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3Ccircle cx='218.576879670355' cy='37.9769776939126' r='17.9' fill='%23e33' stroke='black' stroke-width='1'%3E%3C/circle%3E %3C/svg%3E")}.btn-social.btn-xs{padding:0 0 0 30px}.btn-social.btn .fab,.btn-social-icon.btn .fab,.btn-social.btn-md .fab,.btn-social-icon.btn-md .fab{width:36px;height:36px;background-size:28px 28px;background-position:3px 3px;background-repeat:no-repeat}.btn-social-icon.btn .fab,.btn-social-icon.btn-md .fab{background-position:2px 2px}.btn-social.btn-lg .fab,.btn-social-icon.btn-lg .fab{width:45px;height:45px;background-size:39px 39px;background-position:4px 4px;background-repeat:no-repeat}.btn-social-icon.btn-lg .fab{background-position:2px 2px}.btn-social.btn-sm .fab,.btn-social-icon.btn-sm .fab{width:30px;height:30px;background-size:24px 24px;background-position:2px 2px;background-repeat:no-repeat}.btn-social.btn-xs .fab,.btn-social-icon.btn-xs .fab{width:24px;height:24px;background-size:20px 20px;background-position:2px 2px;background-repeat:no-repeat}.btn-social-icon.btn-xs .fab{background-position:0 0}.svg-xs,.svg-sm,.svg-md,.svg-lg,.svg-2x,.svg-3x,.svg-4x,.svg-5x,.svg-6x,.svg-7x,.svg-8x,.svg-9x,.svg-10x,.svg-11x,.svg-12x,.svg-13x,.svg-14x{background-position:0;background-repeat:no-repeat;display:inline-block;background-size:contain;vertical-align:middle}.svg-xs{width:12px;height:12px}.svg-sm{width:14px;height:14px}.svg-md{width:18px;height:18px}.svg-lg{width:24px;height:24px}.svg-2x{width:32px;height:32px}.svg-3x{width:48px;height:48px}.svg-4x{width:64px;height:64px}.svg-5x{width:80px;height:80px}.svg-6x{width:96px;height:96px}.svg-7x{width:112px;height:112px}.svg-8x{width:128px;height:128px}.svg-9x{width:144px;height:144px}.svg-10x{width:160px;height:160px}.svg-11x{width:180px;height:180px}.svg-12x{width:204px;height:204px}.svg-13x{width:232px;height:232px}.svg-14x{width:264px;height:264px} diff --git a/tests/CheckWebCore/wwwroot/forbidden.html b/tests/CheckWebCore/wwwroot/forbidden.html new file mode 100644 index 00000000000..9e734784189 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/forbidden.html @@ -0,0 +1,7 @@ +{{ 'role' | importRequestParams }} + +

You are not authorized to access this page

+ +{{#if role}} +

Missing role {role}

+{{/if}} diff --git a/tests/CheckWebCore/wwwroot/index.html b/tests/CheckWebCore/wwwroot/index.html new file mode 100644 index 00000000000..48d1c467674 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/index.html @@ -0,0 +1,88 @@ + + +

+ Complete with page layout, menu partial and responsive navigation! +

+ +
+
+ +
+ +
+
+
+ +
+

+
+
+
+ +
+

Validation

+
+ +
+

Auth and Registration

+ +

Sign In

+ {{ 'signin-links' | partial }} +
+ + +
+ +

/metadata/nav

+

/metadata/svg

+ +

/navitems

+

/svg-demo

+

/svg

+ +
+ + + + +
+ +{{#raw appendTo scripts}} + +{{/raw}} diff --git a/tests/CheckWebCore/wwwroot/js/bundle.1558481784842.min.js b/tests/CheckWebCore/wwwroot/js/bundle.1558481784842.min.js new file mode 100644 index 00000000000..e82730df0ed --- /dev/null +++ b/tests/CheckWebCore/wwwroot/js/bundle.1558481784842.min.js @@ -0,0 +1,455 @@ + +function source(){return"source.js";}; +"use strict";var SubC=(function(){function SubC(){} +return SubC;}());new SubC().template="/src/components/sub/sub2/SubC.ts "+Date();; +"use strict";var SubB=(function(){function SubB(){} +return SubB;}());new SubB().template="/src/components/sub/SubB.ts "+Date();; +"use strict";var A=(function(){function A(){} +return A;}());new A().template="TypeScript "+Date();; +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),le({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=fe({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},le(n,m,$(v)),le(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ge.FLIP:p=[n,i];break;case ge.CLOCKWISE:p=G(n);break;case ge.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u);(m||b||y)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),y&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=fe({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!me),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=H('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=fe({},E,e.attributes),e.styles=fe({},m,e.styles),e.arrowStyles=fe({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return j(e.instance.popper,e.styles),V(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&j(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),j(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ue}); +//# sourceMappingURL=popper.min.js.map +/*! + * Bootstrap v4.3.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t=t||self).bootstrap={},t.jQuery,t.Popper)}(this,function(t,g,u){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)g(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Ee},je="show",He="out",Re={HIDE:"hide"+De,HIDDEN:"hidden"+De,SHOW:"show"+De,SHOWN:"shown"+De,INSERTED:"inserted"+De,CLICK:"click"+De,FOCUSIN:"focusin"+De,FOCUSOUT:"focusout"+De,MOUSEENTER:"mouseenter"+De,MOUSELEAVE:"mouseleave"+De},xe="fade",Fe="show",Ue=".tooltip-inner",We=".arrow",qe="hover",Me="focus",Ke="click",Qe="manual",Be=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(xe);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:We},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===He&&e._leave(null,e)};if(g(this.tip).hasClass(xe)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==je&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ke]=!1,this._activeTrigger[Me]=!1,this._activeTrigger[qe]=!1,g(this.tip).hasClass(xe)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Ae+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Ue)),this.getTitle()),g(t).removeClass(xe+" "+Fe)},t.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Se(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text())},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return Pe[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Qe){var e=t===qe?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===qe?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Me:qe]=!0),g(e.getTipElement()).hasClass(Fe)||e._hoverState===je?e._hoverState=je:(clearTimeout(e._timeout),e._hoverState=je,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===je&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Me:qe]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===He&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){var e=g(this.element).data();return Object.keys(e).forEach(function(t){-1!==Oe.indexOf(t)&&delete e[t]}),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(be,t,this.constructor.DefaultType),t.sanitize&&(t.template=Se(t.template,t.whiteList,t.sanitizeFn)),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ne);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(xe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ie),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ie,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Le}},{key:"NAME",get:function(){return be}},{key:"DATA_KEY",get:function(){return Ie}},{key:"Event",get:function(){return Re}},{key:"EVENT_KEY",get:function(){return De}},{key:"DefaultType",get:function(){return ke}}]),i}();g.fn[be]=Be._jQueryInterface,g.fn[be].Constructor=Be,g.fn[be].noConflict=function(){return g.fn[be]=we,Be._jQueryInterface};var Ve="popover",Ye="bs.popover",ze="."+Ye,Xe=g.fn[Ve],$e="bs-popover",Ge=new RegExp("(^|\\s)"+$e+"\\S+","g"),Je=l({},Be.Default,{placement:"right",trigger:"click",content:"",template:''}),Ze=l({},Be.DefaultType,{content:"(string|element|function)"}),tn="fade",en="show",nn=".popover-header",on=".popover-body",rn={HIDE:"hide"+ze,HIDDEN:"hidden"+ze,SHOW:"show"+ze,SHOWN:"shown"+ze,INSERTED:"inserted"+ze,CLICK:"click"+ze,FOCUSIN:"focusin"+ze,FOCUSOUT:"focusout"+ze,MOUSEENTER:"mouseenter"+ze,MOUSELEAVE:"mouseleave"+ze},sn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass($e+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(nn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(on),e),t.removeClass(tn+" "+en)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ge);null!==e&&0=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t12?"PM":"AM");};$.ss.splitOnFirst=function(s,c){if(!s)return[s];var pos=s.indexOf(c);return pos>=0?[s.substring(0,pos),s.substring(pos+1)]:[s];};$.ss.splitOnLast=function(s,c){if(!s)return[s];var pos=s.lastIndexOf(c);return pos>=0?[s.substring(0,pos),s.substring(pos+1)]:[s];};$.ss.getSelection=function(){return window.getSelection?window.getSelection().toString():document.selection&&document.selection.type!=="Control"?document.selection.createRange().text:"";};$.ss.combinePaths=function(){var parts=[],i,l;for(i=0,l=arguments.length;i1?decodeURIComponent(p[1].replace(/\+/g,' ')):null;} +return map;};$.ss.toUrl=function(url,args){for(var k in args){url+=url.indexOf('?')>=0?'&':'?';url+=k+"="+$.ss.encodeValue(args[k]);} +return url;};$.ss.encodeValue=function(o){if(o==null)return"";if($.isArray(o)){var s="";for(var i=0;i0) +s+=',';s+=$.ss.encodeValue(o[i]);} +return s;} +return encodeURIComponent(o);};$.ss.bindAll=function(o){for(var k in o){if(typeof o[k]=='function') +o[k]=o[k].bind(o);} +return o;};$.ss.createPath=function(route,args){var argKeys={};for(var k in args){argKeys[k.toLowerCase()]=k;} +var parts=route.split('/');var url='';for(var i=0;i0)url+='/';url+=p;} +return route[0]==='/'?'/'+url:url;};$.ss.createUrl=function(route,args){var url=$.ss.createPath(route,args);return $.ss.toUrl(url,args);};function splitCase(t){return typeof t!='string'?t:t.replace(/([A-Z]|[0-9]+)/g,' $1').replace(/_/g,' ');} +$.ss.humanize=function(s){return!s||s.indexOf(' ')>=0?s:splitCase(s);};function toCamelCase(key){return!key?key:key.charAt(0).toLowerCase()+key.substring(1);} +$.ss.toCamelCase=toCamelCase;$.ss.toPascalCase=function(s){return!s?s:s.charAt(0).toUpperCase()+s.substring(1);};$.ss.normalizeKey=function(key){return typeof key=="string"?key.toLowerCase().replace(/_/g,''):key;};$.ss.normalize=function(dto,deep){if($.isArray(dto)){if(!deep)return dto;var to=[];for(var i=0;i-1;} +function addClass(el,cls){if(!hasClass(el,cls))el.className=(el.className+" "+cls).trim();} +function errorResponseExcept(status,fieldNames){if(typeof fieldNames=='string') +fieldNames=arguments.length==1?[fieldNames]:Array.prototype.slice.call(arguments);if(fieldNames&&!(status.errors==null||status.errors.length==0)){var lowerFieldsNames=fieldNames.map(function(x){return(x||'').toLowerCase();});for(var i=0,_a=status.errors;i<_a.length;i++){var field=_a[i];if(lowerFieldsNames.indexOf((field.fieldName||'').toLowerCase())!==-1){return undefined;}} +for(var _b=0,_c=status.errors;_b<_c.length;_b++){var field=_c[_b];if(lowerFieldsNames.indexOf((field.fieldName||'').toLowerCase())===-1){return field.message||field.errorCode;}}} +return status.message||status.errorCode||undefined;} +$.ss.errorResponseExcept=errorResponseExcept;$.fn.bootstrap=function(){$(this).find('[data-invalid]').each($.ss.showInvalidInputs);return this;};$.fn.setFieldError=function(name,msg){$(this).applyErrors({errors:[{fieldName:name,message:msg}]});};$.fn.serializeMap=function(){var o={};$.each($(this).serializeArray(),function(i,e){o[e.name]=e.value;});return o;};$.fn.applyErrors=function(status,opt){this.clearErrors();if(!status)return this;status=sanitize(status);this.addClass("has-errors");var bs4=opt&&opt.type==="bootstrap-v4";var o=$.extend({},$.ss.validation,opt);if(opt&&opt.messages){o.overrideMessages=true;$.extend(o.messages,$.ss.validation.messages);} +var filter=$.proxy(o.errorFilter,o),errors=status.errors;if(errors&&errors.length){var fieldMap={},fieldLabelMap={};this.find("input,textarea,select,button").each(function(){var $el=$(this);var $prev=$el.prev(),$next=$el.next();var isCheck=this.type==="radio"||this.type==="checkbox";var fieldId=(!isCheck?this.id:null)||$el.attr("name");if(!fieldId)return;var key=(fieldId).toLowerCase();fieldMap[key]=$el;if(!bs4){if($prev.hasClass("help-inline")||$prev.hasClass("help-block")){fieldLabelMap[key]=$prev;}else if($next.hasClass("help-inline")||$next.hasClass("help-block")){fieldLabelMap[key]=$next;}}});this.find(".help-inline[data-for],.help-block[data-for]").each(function(){var $el=$(this);var key=$el.data("for").toLowerCase();fieldLabelMap[key]=$el;});$.each(errors,function(i,error){var key=(error.fieldName||"").toLowerCase();var $field=fieldMap[key];if($field){if(!bs4){$field.addClass("error");$field.parent().addClass("has-error");}else{var type=$field.attr('type'),isCheck=type==="radio"||type==="checkbox";if(!isCheck)$field.addClass("is-invalid");$field.attr("data-invalid",filter(error.message,error.errorCode,"field"));}} +var $lblErr=fieldLabelMap[key];if(!$lblErr)return;$lblErr.addClass("error");$lblErr.html(filter(error.message,error.errorCode,"field"));$lblErr.show();});this.find("[data-validation-summary]").each(function(){var fields=this.getAttribute('data-validation-summary').split(',');var summaryMsg=errorResponseExcept(status,fields);if(summaryMsg) +this.innerHTML=bsAlert(summaryMsg);});}else{var htmlSummary=filter(status.message||splitCase(status.errorCode),status.errorCode,"summary");if(!bs4){this.find(".error-summary").html(htmlSummary).show();}else{this.find("[data-validation-summary]").html(htmlSummary[0]==="<"?htmlSummary:bsAlert(htmlSummary));}} +return this;};function bsAlert(msg){return'
'+msg+'
';} +$.fn.clearErrors=function(){this.removeClass("has-errors");this.find(".error-summary").html("").hide();this.find(".help-inline.error, .help-block.error").each(function(){$(this).html("");});this.find(".error").each(function(){$(this).removeClass("error");});this.find(".has-error").each(function(){$(this).removeClass("has-error");});this.find("[data-validation-summary]").html("");this.find('.form-check.is-invalid [data-invalid]').removeAttr('data-invalid');this.find('.form-check.is-invalid').removeClass('form-control');this.find('.is-invalid').removeClass('is-invalid').removeAttr('data-invalid');this.find('.is-valid').removeClass('is-valid');};$.fn.bindForm=function(orig){return this.each(function(){var f=$(this);if(orig.model) +$.ss.populateForm(this,orig.model);f.submit(function(e){e.preventDefault();return $(f).ajaxSubmit(orig);});});};$.fn.bootstrapForm=function(orig){return this.each(function(){var f=$(this);if(orig.model) +$.ss.populateForm(this,orig.model);f.submit(function(e){e.preventDefault();orig.type="bootstrap-v4";return $(f).ajaxSubmit(orig);});});};$.fn.ajaxSubmit=function(orig){orig=orig||{};var bs4=orig.type==="bootstrap-v4";if(orig.validation){$.extend($.ss.validation,orig.validation);} +return this.each(function(){var f=$(this);f.clearErrors();try{if(orig.validate&&orig.validate.call(f)===false) +return false;}catch(e){return false;} +f.addClass("loading");var $disable=$(orig.onSubmitDisable||$.ss.onSubmitDisable,f);$disable.attr("disabled","disabled");var opt=$.extend({},orig,{type:f.attr('method')||"POST",url:f.attr('action'),data:f.serialize(),accept:"application/json",error:function(jq,jqStatus,statusText){var err,errMsg="The request failed with "+(statusText||jq.statusText);try{err=JSON.parse(jq.responseText);}catch(e){} +if(!err){f.addClass("has-errors");f.find(".error-summary").html(errMsg);if(bs4){var elSummary=f.find('[data-validation-summary]');elSummary.html('
'+errMsg+'
');}}else{f.applyErrors(err.ResponseStatus||err.responseStatus,{type:orig.type});} +if(orig.error){orig.error.apply(this,arguments);} +if(bs4){f.find('[data-invalid]').each($.ss.showInvalidInputs);}},complete:function(jq){f.removeClass("loading");$disable.removeAttr("disabled");if(orig.complete){orig.complete.apply(this,arguments);} +var loc=jq.getResponseHeader("X-Location");if(loc){location.href=loc;} +var evt=jq.getResponseHeader("X-Trigger");if(evt){var pos=evt.indexOf(':');var cmd=pos>=0?evt.substring(0,pos):evt;var data=pos>=0?evt.substring(pos+1):null;f.trigger(cmd,data?[data]:[]);}},dataType:"json"});$.ajax(opt);return false;});};$.fn.applyValues=function(map){return this.each(function(){var $el=$(this);$.each(map,function(k,v){$el.find("#"+k+",[name="+k+"]").val(v);});$el.find("[data-html]").each(function(){$(this).html(map[$(this).data("html")]||"");});$el.find("[data-val]").each(function(){$(this).val(map[$(this).data("val")]||"");});$el.find("[data-src]").each(function(){$(this).attr("src",map[$(this).data("src")]||"");});$el.find("[data-href]").each(function(){$(this).attr("href",map[$(this).data("href")]||"");});});};$.ss.__call=$.ss.__call||function(e){var $el=$(e.target);var attr=$el.data(e.type)||$el.closest("[data-"+e.type+"]").data(e.type);if(!attr)return;var pos=attr.indexOf(':'),fn;if(pos>=0){var cmd=attr.substring(0,pos);var data=attr.substring(pos+1);if(cmd==='trigger'){$el.trigger(data,[e.target]);}else{fn=$.ss.handlers[cmd];if(fn){fn.apply(e.target,data.split(','));}}}else{fn=$.ss.handlers[attr];if(fn){fn.apply(e.target,[].slice.call(arguments));}}};$.ss.listenOn='click dblclick change focus blur focusin focusout select keydown keypress keyup hover toggle';$.fn.bindHandlers=function(handlers){$.extend($.ss.handlers,handlers||{});return this.each(function(){var $el=$(this);$el.off($.ss.listenOn,$.ss.__call);$el.on($.ss.listenOn,$.ss.__call);});};$.ss.populateForm=function(form,model){if(!model) +return;var toggleCase=function(s){return!s?s:s[0]===s[0].toUpperCase()?exports.toCamelCase(s):s[0]===s[0].toLowerCase()?exports.toPascalCase(s):s;};for(var key in model){var val=model[key];if(typeof val=='undefined'||val===null) +val='';var el=form.elements.namedItem(key)||form.elements.namedItem(toggleCase(key));var input=el;if(!el) +continue;var type=input.type||el[0].type;switch(type){case'radio':case'checkbox':var len=el.length;for(var i=0;i-1);} +break;case'select-multiple':var values=$.isArray(val)?val:[val];var select=el;for(var i=0;i-1);} +break;case'select':case'select-one':input.value=val.toString()||val;break;case'date':var d=exports.toDate(val);if(d) +input.value=d.toISOString().split('T')[0];break;default:input.value=val;break;}}};$.fn.setActiveLinks=function(){var url=window.location.href;return this.each(function(){$(this).filter(function(){return this.href===url;}).addClass('active').closest("li").addClass('active');});};$.ss.eventSourceStop=false;$.ss.eventOptions={};$.ss.eventReceivers={};$.ss.eventChannels=[];$.ss.eventSourceUrl=null;$.ss.updateSubscriberUrl=null;$.ss.updateChannels=function(channels){$.ss.eventChannels=channels;if(!$.ss.eventSource)return;var url=$.ss.eventSource.url;var qs=$.ss.queryString(url);qs['channels']=channels;delete qs['channel'];$.ss.eventSourceUrl=$.ss.toUrl(url.substring(0,Math.min(url.indexOf('?'),url.length)),qs);};$.ss.updateSubscriberInfo=function(subscribe,unsubscribe){var sub=typeof subscribe=="string"?subscribe.split(','):subscribe;var unsub=typeof unsubscribe=="string"?unsubscribe.split(','):unsubscribe;var channels=[];for(var i in $.ss.eventChannels){var c=$.ss.eventChannels[i];if(unsub==null||$.inArray(c,unsub)===-1){channels.push(c);}} +if(sub){for(var i in sub){var c=sub[i];if($.inArray(c,channels)===-1){channels.push(c);}}} +$.ss.updateChannels(channels);};$.ss.subscribeToChannels=function(channels,cb,cbError){return $.ss.updateSubscriber({SubscribeChannels:channels.join(',')},cb,cbError);};$.ss.unsubscribeFromChannels=function(channels,cb,cbError){return $.ss.updateSubscriber({UnsubscribeChannels:channels.join(',')},cb,cbError);};$.ss.updateSubscriber=function(data,cb,cbError){if(!$.ss.updateSubscriberUrl) +throw new Error("updateSubscriberUrl was not populated");return $.ajax({type:"POST",url:$.ss.updateSubscriberUrl,data:data,dataType:"json",success:function(r){$.ss.updateSubscriberInfo(data.SubscribeChannels,data.UnsubscribeChannels);r.channels=$.ss.eventChannels;if(cb!=null) +cb(r);},error:function(e){$.ss.reconnectServerEvents({errorArgs:arguments});if(cbError!=null) +cbError(e);}});};$.ss.reconnectServerEvents=function(opt){if($.ss.eventSourceStop)return;opt=opt||{};var hold=$.ss.eventSource;var es=new EventSource(opt.url||$.ss.eventSourceUrl||hold.url,{withCredentials:hold.withCredentials});es.onerror=opt.onerror||hold.onerror;es.onmessage=opt.onmessage||hold.onmessage;var fn=$.ss.handlers["onReconnect"];if(fn!=null) +fn.apply(es,opt.errorArgs);hold.close();return $.ss.eventSource=es;};$.ss.invokeReceiver=function(r,cmd,el,msg,e,name){if(r){if(typeof(r[cmd])=="function"){r[cmd].call(el||r[cmd],msg,e);}else{r[cmd]=msg;}}};$.fn.handleServerEvents=function(opt){$.ss.eventSource=this[0];$.ss.eventOptions=opt=opt||{};if(opt.handlers){$.extend($.ss.handlers,opt.handlers||{});} +function onMessage(e){var parts=$.ss.splitOnFirst(e.data,' ');var selector=parts[0];var selParts=$.ss.splitOnFirst(selector,'@');if(selParts.length>1){e.channel=selParts[0];selector=selParts[1];} +var json=parts[1];var msg=json?JSON.parse(json):null;parts=$.ss.splitOnFirst(selector,'.');if(parts.length<=1) +throw"invalid selector format: "+selector;var op=parts[0],target=parts[1].replace(new RegExp("%20",'g')," ");if(opt.validate&&opt.validate(op,target,msg,json)===false) +return;var tokens=$.ss.splitOnFirst(target,'$'),cmd=tokens[0],cssSel=tokens[1],$els=cssSel&&$(cssSel),el=$els&&$els[0];$.extend(e,{cmd:cmd,op:op,selector:selector,"$target":target,cssSelector:cssSel,json:json});if(op==="cmd"){if(cmd==="onConnect"){$.extend(opt,msg);if(opt.heartbeatUrl){if(opt.heartbeat){window.clearInterval(opt.heartbeat);} +opt.heartbeat=window.setInterval(function(){if($.ss.eventSource.readyState===2) +{window.clearInterval(opt.heartbeat);var stopFn=$.ss.handlers["onStop"];if(stopFn!=null) +stopFn.apply($.ss.eventSource);$.ss.reconnectServerEvents({errorArgs:{error:'CLOSED'}});return;} +$.ajax({type:"POST",url:opt.heartbeatUrl,data:null,dataType:"text",success:function(r){},error:function(){$.ss.reconnectServerEvents({errorArgs:arguments});}});},parseInt(opt.heartbeatIntervalMs)||10000);} +if(opt.unRegisterUrl){$(window).on("unload",function(){$.ajax({type:'POST',url:opt.unRegisterUrl,async:false});});} +$.ss.updateSubscriberUrl=opt.updateSubscriberUrl;$.ss.updateChannels((opt.channels||"").split(','));} +var fn=$.ss.handlers[cmd];if(fn){fn.call(el||document.body,msg,e);}} +else if(op==="trigger"){$(el||document).trigger(cmd,[msg,e]);} +else if(op==="css"){$($els||document.body).css(cmd,msg,e);} +else{var r=opt.receivers&&opt.receivers[op]||$.ss.eventReceivers[op];$.ss.invokeReceiver(r,cmd,el,msg,e,op);} +var fn=$.ss.handlers["onMessage"];if(fn)fn.call(el||document.body,msg,e);if(opt.success)opt.success(selector,msg,e);} +$.ss.eventSource.onmessage=onMessage;var hold=$.ss.eventSource.onerror;$.ss.eventSource.onerror=function(){var args=arguments;window.setTimeout(function(){$.ss.reconnectServerEvents({errorArgs:args});if(hold) +hold.apply(args);},10000);};};});; + +var __assign=(this&&this.__assign)||Object.assign||function(t){for(var s,i=1,n=arguments.length;i1){channel=selParts[0];selector=selParts[1];} +var json=parts[1];var body=null;try{body=json?JSON.parse(json):null;} +catch(ignore){} +parts=exports.splitOnFirst(selector,".");if(parts.length<=1) +throw"invalid selector format: "+selector;var op=parts[0],target=parts[1].replace(new RegExp("%20","g")," ");var tokens=exports.splitOnFirst(target,"$");var cmd=tokens[0],cssSelector=tokens[1];var els=cssSelector&&$(cssSelector);var el=els&&els[0];var eventId=parseInt(e.lastEventId);var data=e.data;var type=TypeMap[cmd]||"ServerEventMessage";var request={eventId:eventId,data:data,type:type,channel:channel,selector:selector,json:json,body:body,op:op,target:tokens[0],cssSelector:cssSelector,meta:{}};var mergedBody=typeof body=="object"?Object.assign({},request,body):request;if(opt.validate&&opt.validate(request)===false) +return;var headers=new Headers();headers.set("Content-Type","text/plain");if(op==="cmd"){if(cmd==="onConnect"){_this.connectionInfo=mergedBody;if(typeof body.heartbeatIntervalMs=="string") +_this.connectionInfo.heartbeatIntervalMs=parseInt(body.heartbeatIntervalMs);if(typeof body.idleTimeoutMs=="string") +_this.connectionInfo.idleTimeoutMs=parseInt(body.idleTimeoutMs);Object.assign(opt,body);var fn=opt.handlers["onConnect"];if(fn){fn.call(el||document.body,_this.connectionInfo,request);if(_this.stopped) +return;} +if(opt.heartbeatUrl){if(opt.heartbeat){clearInterval(opt.heartbeat);} +opt.heartbeat=setInterval(function(){if(_this.eventSource.readyState===EventSource.CLOSED){clearInterval(opt.heartbeat);var stopFn=opt.handlers["onStop"];if(stopFn!=null) +stopFn.apply(_this.eventSource);_this.reconnectServerEvents({error:new Error("EventSource is CLOSED")});return;} +fetch(new Request(opt.heartbeatUrl,{method:"POST",mode:"cors",headers:headers,credentials:_this.serviceClient.credentials})).then(function(res){if(!res.ok) +throw new Error(res.status+" - "+res.statusText);}).catch(function(error){return _this.reconnectServerEvents({error:error});});},(_this.connectionInfo&&_this.connectionInfo.heartbeatIntervalMs)||opt.heartbeatIntervalMs||10000);} +if(opt.unRegisterUrl){if(typeof window!="undefined"){window.onunload=function(){return _this.stop();};}} +_this.updateSubscriberUrl=opt.updateSubscriberUrl;_this.updateChannels((opt.channels||"").split(","));} +else{var isCmdMsg=cmd=="onJoin"||cmd=="onLeave"||cmd=="onUpdate";var fn=opt.handlers[cmd];if(fn){if(isCmdMsg){fn.call(el||document.body,mergedBody);} +else{fn.call(el||document.body,body,request);}} +else{if(!isCmdMsg){var r=opt.receivers&&opt.receivers["cmd"];_this.invokeReceiver(r,cmd,el,request,"cmd");}} +if(isCmdMsg){fn=opt.handlers["onCommand"];if(fn){fn.call(el||document.body,mergedBody);}}}} +else if(op==="trigger"){_this.raiseEvent(target,request);} +else if(op==="css"){exports.css(els||$("body"),cmd,body);} +var r=opt.receivers&&opt.receivers[op];_this.invokeReceiver(r,cmd,el,request,op);if(!TypeMap[cmd]){var fn=opt.handlers["onMessage"];if(fn){fn.call(el||document.body,mergedBody);}} +if(opt.onTick) +opt.onTick();};this.onError=function(error){if(_this.stopped) +return;if(!error) +error=event;var fn=_this.options.onException;if(fn!=null) +fn.call(_this.eventSource,error);if(_this.options.onTick) +_this.options.onTick();};if(this.channels.length===0) +throw"at least 1 channel is required";this.resolver=this.options.resolver||new NewInstanceResolver();this.eventStreamUri=exports.combinePaths(baseUrl,"event-stream")+"?";this.updateChannels(channels);this.serviceClient=new JsonServiceClient(baseUrl);this.listeners={};this.withCredentials=true;if(!this.options.handlers) +this.options.handlers={};} +ServerEventsClient.prototype.getEventSourceOptions=function(){return{withCredentials:this.withCredentials};};ServerEventsClient.prototype.reconnectServerEvents=function(opt){var _this=this;if(opt===void 0){opt={};} +if(this.stopped) +return;if(opt.error) +this.onError(opt.error);var hold=this.eventSource;var url=opt.url||this.eventStreamUri||hold.url;if(this.options.resolveStreamUrl!=null){url=this.options.resolveStreamUrl(url);} +var es=this.EventSource?new this.EventSource(url,this.getEventSourceOptions()):new EventSource(url,this.getEventSourceOptions());es.addEventListener('error',function(e){return opt.onerror||hold.onerror||_this.onError;});es.addEventListener('message',opt.onmessage||hold.onmessage||this.onMessage);var fn=this.options.onReconnect;if(fn!=null) +fn.call(es,opt.error);if(hold.removeEventListener){hold.removeEventListener('error',this.onError);hold.removeEventListener('message',this.onMessage);} +hold.close();return this.eventSource=es;};ServerEventsClient.prototype.start=function(){var _this=this;this.stopped=false;if(this.eventSource==null||this.eventSource.readyState===EventSource.CLOSED){var url=this.eventStreamUri;if(this.options.resolveStreamUrl!=null){url=this.options.resolveStreamUrl(url);} +this.eventSource=this.EventSource?new this.EventSource(url,this.getEventSourceOptions()):new EventSource(url,this.getEventSourceOptions());this.eventSource.addEventListener('error',this.onError);this.eventSource.addEventListener('message',function(e){return _this.onMessage(e);});} +return this;};ServerEventsClient.prototype.stop=function(){this.stopped=true;if(this.eventSource){this.eventSource.close();} +var opt=this.options;if(opt&&opt.heartbeat){clearInterval(opt.heartbeat);} +var hold=this.connectionInfo;if(hold==null||hold.unRegisterUrl==null) +return new Promise(function(resolve,reject){return resolve();});this.connectionInfo=null;return fetch(new Request(hold.unRegisterUrl,{method:"POST",mode:"cors",credentials:this.serviceClient.credentials})).then(function(res){if(!res.ok) +throw new Error(res.status+" - "+res.statusText);}).catch(this.onError);};ServerEventsClient.prototype.invokeReceiver=function(r,cmd,el,request,name){if(r){if(typeof r=="function"){r=this.resolver.tryResolve(r);} +cmd=cmd.replace("-","");r.client=this;r.request=request;if(typeof(r[cmd])=="function"){r[cmd].call(el||r,request.body,request);} +else if(cmd in r){r[cmd]=request.body;} +else{var cmdLower=cmd.toLowerCase();for(var k in r){if(k.toLowerCase()==cmdLower){if(typeof r[k]=="function"){r[k].call(el||r,request.body,request);} +else{r[k]=request.body;} +return;}} +var noSuchMethod=r["noSuchMethod"];if(typeof noSuchMethod=="function"){noSuchMethod.call(el||r,request.target,request);}}}};ServerEventsClient.prototype.hasConnected=function(){return this.connectionInfo!=null;};ServerEventsClient.prototype.registerHandler=function(name,fn){if(!this.options.handlers) +this.options.handlers={};this.options.handlers[name]=fn;return this;};ServerEventsClient.prototype.setResolver=function(resolver){this.options.resolver=resolver;return this;};ServerEventsClient.prototype.registerReceiver=function(receiver){return this.registerNamedReceiver("cmd",receiver);};ServerEventsClient.prototype.registerNamedReceiver=function(name,receiver){if(!this.options.receivers) +this.options.receivers={};this.options.receivers[name]=receiver;return this;};ServerEventsClient.prototype.unregisterReceiver=function(name){if(name===void 0){name="cmd";} +if(this.options.receivers){delete this.options.receivers[name];} +return this;};ServerEventsClient.prototype.updateChannels=function(channels){this.channels=channels;var url=this.eventSource!=null?this.eventSource.url:this.eventStreamUri;this.eventStreamUri=url.substring(0,Math.min(url.indexOf("?"),url.length))+"?channels="+channels.join(",")+"&t="+new Date().getTime();};ServerEventsClient.prototype.update=function(subscribe,unsubscribe){var sub=typeof subscribe=="string"?subscribe.split(','):subscribe;var unsub=typeof unsubscribe=="string"?unsubscribe.split(','):unsubscribe;var channels=[];for(var i in this.channels){var c=this.channels[i];if(unsub==null||unsub.indexOf(c)===-1){channels.push(c);}} +if(sub){for(var i in sub){var c=sub[i];if(channels.indexOf(c)===-1){channels.push(c);}}} +this.updateChannels(channels);};ServerEventsClient.prototype.addListener=function(eventName,handler){var handlers=this.listeners[eventName]||(this.listeners[eventName]=[]);handlers.push(handler);return this;};ServerEventsClient.prototype.removeListener=function(eventName,handler){var handlers=this.listeners[eventName];if(handlers){var pos=handlers.indexOf(handler);if(pos>=0){handlers.splice(pos,1);}} +return this;};ServerEventsClient.prototype.raiseEvent=function(eventName,msg){var _this=this;var handlers=this.listeners[eventName];if(handlers){handlers.forEach(function(x){try{x(msg);} +catch(e){_this.onError(e);}});}};ServerEventsClient.prototype.getConnectionInfo=function(){if(this.connectionInfo==null) +throw"Not Connected";return this.connectionInfo;};ServerEventsClient.prototype.getSubscriptionId=function(){return this.getConnectionInfo().id;};ServerEventsClient.prototype.updateSubscriber=function(request){var _this=this;if(request.id==null) +request.id=this.getSubscriptionId();return this.serviceClient.post(request).then(function(x){_this.update(request.subscribeChannels,request.unsubscribeChannels);}).catch(this.onError);};ServerEventsClient.prototype.subscribeToChannels=function(){var _this=this;var channels=[];for(var _i=0;_i=0?[s.substring(0,pos),s.substring(pos+1)]:[s];};exports.splitOnLast=function(s,c){if(!s) +return[s];var pos=s.lastIndexOf(c);return pos>=0?[s.substring(0,pos),s.substring(pos+1)]:[s];};var splitCase=function(t){return typeof t!='string'?t:t.replace(/([A-Z]|[0-9]+)/g,' $1').replace(/_/g,' ').trim();};exports.humanize=function(s){return(!s||s.indexOf(' ')>=0?s:splitCase(s));};exports.queryString=function(url){if(!url||url.indexOf('?')===-1) +return{};var pairs=exports.splitOnFirst(url,'?')[1].split('&');var map={};for(var i=0;i1?decodeURIComponent(p[1].replace(/\+/g,' ')):null;} +return map;};exports.combinePaths=function(){var paths=[];for(var _i=0;_i0) +url+="/";url+=p;} +return url;};exports.createUrl=function(route,args){var url=exports.createPath(route,args);return exports.appendQueryString(url,args);};exports.appendQueryString=function(url,args){for(var k in args){if(args.hasOwnProperty(k)){url+=url.indexOf("?")>=0?"&":"?";url+=k+"="+qsValue(args[k]);}} +return url;};var qsValue=function(arg){if(arg==null) +return"";if(typeof Uint8Array!="undefined"&&arg instanceof Uint8Array) +return exports.bytesToBase64(arg);return encodeURIComponent(arg)||"";};exports.bytesToBase64=function(aBytes){var eqLen=(3-(aBytes.length%3))%3,sB64Enc="";for(var nMod3,nLen=aBytes.length,nUint24=0,nIdx=0;nIdx>>nMod3&24);if(nMod3===2||aBytes.length-nIdx===1){sB64Enc+=String.fromCharCode(uint6ToB64(nUint24>>>18&63),uint6ToB64(nUint24>>>12&63),uint6ToB64(nUint24>>>6&63),uint6ToB64(nUint24&63));nUint24=0;}} +return eqLen===0?sB64Enc:sB64Enc.substring(0,sB64Enc.length-eqLen)+(eqLen===1?"=":"==");};var uint6ToB64=function(nUint6){return nUint6<26?nUint6+65:nUint6<52?nUint6+71:nUint6<62?nUint6-4:nUint6===62?43:nUint6===63?47:65;};var _btoa=typeof btoa=='function'?btoa:function(str){return new Buffer(str).toString('base64');};JsonServiceClient.toBase64=function(str){return _btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,function(match,p1){return String.fromCharCode(new Number('0x'+p1).valueOf());}));};exports.stripQuotes=function(s){return s&&s[0]=='"'&&s[s.length]=='"'?s.slice(1,-1):s;};exports.tryDecode=function(s){try{return decodeURIComponent(s);} +catch(e){return s;}};exports.parseCookie=function(setCookie){if(!setCookie) +return null;var to=null;var pairs=setCookie.split(/; */);for(var i=0;i1?exports.tryDecode(exports.stripQuotes(parts[1].trim())):null;if(i==0){to={name:name,value:value,path:"/"};} +else{var lower=name.toLowerCase();if(lower=="httponly"){to.httpOnly=true;} +else if(lower=="secure"){to.secure=true;} +else if(lower=="expires"){to.expires=new Date(value);if(to.expires.toString()==="Invalid Date"){to.expires=new Date(value.replace(/-/g," "));}} +else{to[name]=value;}}} +return to;};exports.normalizeKey=function(key){return key.toLowerCase().replace(/_/g,'');};var isArray=function(o){return Object.prototype.toString.call(o)==='[object Array]';};exports.normalize=function(dto,deep){if(isArray(dto)){if(!deep) +return dto;var to=[];for(var i=0;i12?"PM":"AM");};var bsAlert=function(msg){return'
'+msg+'
';};var attr=function(e,name){return e.getAttribute(name);};var sattr=function(e,name,value){return e.setAttribute(name,value);};var rattr=function(e,name){return e.removeAttribute(name);};var keyAliases={className:'class',htmlFor:'for'};function createElement(tagName,options,attrs){var el=document.createElement(tagName);if(attrs){for(var key in attrs){sattr(el,keyAliases[key]||key,attrs[key]);}} +if(options&&options.insertAfter){options.insertAfter.parentNode.insertBefore(el,options.insertAfter.nextSibling);} +return el;} +exports.createElement=createElement;function showInvalidInputs(){var errorMsg=attr(this,'data-invalid');if(errorMsg){var isCheck=this.type==="checkbox"||this.type==="radio"||hasClass(this,'form-check');var elFormCheck=isCheck?parent(this,'form-check'):null;if(!isCheck) +addClass(this,'is-invalid');else +addClass(elFormCheck||this.parentElement,'is-invalid form-control');var elNext=this.nextElementSibling;var elLast=elNext&&(attr(elNext,'for')===this.id||elNext.tagName==="SMALL")?(isCheck?elFormCheck||elNext.parentElement:elNext):this;var elError=elLast!=null&&elLast.nextElementSibling&&hasClass(elLast.nextElementSibling,'invalid-feedback')?elLast.nextElementSibling:createElement("div",{insertAfter:elLast},{className:'invalid-feedback'});elError.innerHTML=errorMsg;}} +function parent(el,cls){while(el!=null&&!hasClass(el,cls)) +el=el.parentElement;return el;} +var hasClass=function(el,cls){return!el?false:el.classList?el.classList.contains(cls):(" "+el.className+" ").replace(/[\n\t\r]/g," ").indexOf(" "+cls+" ")>-1;};var addClass=function(el,cls){return!el?null:el.classList?(_a=el.classList).add.apply(_a,cls.split(' ')):!hasClass(el,cls)?el.className=(el.className+" "+cls).trim():null;var _a;};var remClass=function(el,cls){return!el?null:el.classList?el.classList.remove(cls):hasClass(el,cls)?el.className=el.className.replace(/(\s|^)someclass(\s|$)/,' '):null;};function bootstrap(el){var els=(el||document).querySelectorAll('[data-invalid]');for(var i=0;i=0){var cmd=x.substring(0,pos);var data=x.substring(pos+1);var fn=handlers[cmd];if(fn){fn.apply(evt.target,data.split(','));}} +else{var fn=handlers[x];if(fn){fn.apply(evt.target,[].slice.call(arguments));}}});} +exports.bindHandlers=bindHandlers;function bootstrapForm(form,options){if(!form) +return;if(options.model) +populateForm(form,options.model);form.onsubmit=function(evt){evt.preventDefault();options.type="bootstrap-v4";return ajaxSubmit(form,options);};} +exports.bootstrapForm=bootstrapForm;var validation={overrideMessages:false,messages:{NotEmpty:"Required",NotNull:"Required",Email:"Invalid email",AlreadyExists:"Already exists"},errorFilter:function(errorMsg,errorCode,type){return this.overrideMessages?this.messages[errorCode]||errorMsg||splitCase(errorCode):errorMsg||splitCase(errorCode);}};function applyErrors(f,status,opt){clearErrors(f);if(!status) +return;status=exports.sanitize(status);addClass(f,"has-errors");var bs4=opt&&opt.type==="bootstrap-v4";var v=__assign({},validation,opt);if(opt.messages){v.overrideMessages=true;} +var filter=v.errorFilter.bind(v);var errors=status.errors;var $=f.querySelectorAll.bind(f);if(errors&&errors.length){var fieldMap_1={},fieldLabelMap_1={};$("input,textarea,select,button").forEach(function(x){var el=x;var prev=el.previousElementSibling;var next=el.nextElementSibling;var isCheck=el.type==="radio"||el.type==="checkbox";var fieldId=(!isCheck?el.id:null)||attr(el,"name");if(!fieldId) +return;var key=fieldId.toLowerCase();fieldMap_1[key]=el;if(!bs4){if(hasClass(prev,"help-inline")||hasClass(prev,"help-block")){fieldLabelMap_1[key]=prev;} +else if(hasClass(next,"help-inline")||hasClass(next,"help-block")){fieldLabelMap_1[key]=next;}}});$(".help-inline[data-for],.help-block[data-for]").forEach(function(el){var key=attr(el,"data-for").toLowerCase();fieldLabelMap_1[key]=el;});for(var _i=0,errors_1=errors;_i=0?evt.substring(0,pos):evt;var data=pos>=0?evt.substring(pos+1):null;triggerEvent(f,cmd,data?[data]:[]);}} +function ajaxSubmit(f,options){if(options===void 0){options={};} +var type=options.type;var bs4=type==="bootstrap-v4";clearErrors(f);try{if(options.validate&&options.validate.call(f)===false) +return false;} +catch(e){return false;} +var $=f.querySelectorAll.bind(f);addClass(f,'loading');var disableSel=options.onSubmitDisable==null?"[type=submit]":options.onSubmitDisable;var disable=disableSel!=null&&disableSel!="";if(disable){$(disableSel).forEach(function(el){sattr(el,'disabled','disabled');});} +function handleError(errMsg,err){if(err===void 0){err=null;} +if(err){applyErrors(f,err.ResponseStatus||err.responseStatus,__assign({},options));} +else if(errMsg){addClass(f,"has-errors");var errorSummary=$(".error-summary")[0];if(errorSummary){errorSummary.innerHTML=errMsg;} +if(bs4){var elSummary=$('[data-validation-summary]')[0];if(elSummary){elSummary.innerHTML=bsAlert(errMsg);}}} +if(options.error){options.error.call(f,err);} +if(bs4){$('[data-invalid]').forEach(function(el){return showInvalidInputs.call(el);});}} +var submitFn=options.submit||formSubmit;return submitFn.call(f,options).then(function(obj){if(options.success) +options.success.call(f,obj);return false;}).catch(function(e){if(e.responseStatus) +handleError(null,e);else +handleError(""+(e.message||e),null);}).finally(function(){remClass(f,'loading');if(disable){$(disableSel).forEach(function(el){rattr(el,'disabled');});} +if(options.complete){options.complete.call(f);}});} +exports.ajaxSubmit=ajaxSubmit;function fromResponse(r){var contentType=r.headers.get("content-type");var isJson=contentType&&contentType.indexOf(Types.Json)!==-1;if(isJson) +return r.json();var len=r.headers.get("content-length");if(len==="0"||(len==null&&!isJson)) +return null;return r.json();} +function serializeForm(form,contentType){if(contentType===void 0){contentType=null;} +return contentType===Types.MultiPart?new FormData(form):contentType==Types.Json?JSON.stringify(exports.serializeToObject(form)):serializeToUrlEncoded(form);} +exports.serializeForm=serializeForm;function formEntries(form,state,fn){var field,f=form;var len=f.elements.length;for(var i=0;i=0;j--){if(field.options[j].selected) +fn(state,field.name,field.options[j].value);}} +else if((field.type!='checkbox'&&field.type!='radio')||field.checked){fn(state,field.name,field.value);}}} +return state;} +exports.serializeToObject=function(form){return formEntries(form,{},function(to,name,value){return to[name]=value;});};function serializeToUrlEncoded(form){var to=formEntries(form,[],function(s,name,value){return typeof value=='string'?s.push(encodeURIComponent(name)+"="+encodeURIComponent(value)):null;});return to.join('&').replace(/%20/g,'+');} +exports.serializeToUrlEncoded=serializeToUrlEncoded;exports.serializeToFormData=function(form){return formEntries(form,new FormData(),function(to,name,value){return to.append(name,value);});};function triggerEvent(el,name,data){if(data===void 0){data=null;} +if(document.createEvent){var evt=document.createEvent(name=='click'||name.startsWith('mouse')?'MouseEvents':'HTMLEvents');evt.initEvent(name,true,true);evt.data=data;el.dispatchEvent(evt);} +else{var evt=document.createEventObject();el.fireEvent("on"+name,evt);}} +exports.triggerEvent=triggerEvent;function populateForm(form,model){if(!model) +return;var toggleCase=function(s){return!s?s:s[0]===s[0].toUpperCase()?exports.toCamelCase(s):s[0]===s[0].toLowerCase()?exports.toPascalCase(s):s;};for(var key in model){var val=model[key];if(typeof val=='undefined'||val===null) +val='';var el=form.elements.namedItem(key)||form.elements.namedItem(toggleCase(key));var input=el;if(!el) +continue;var type=input.type||el[0].type;switch(type){case'radio':case'checkbox':var len=el.length;for(var i=0;i-1);} +break;case'select-multiple':var values=isArray(val)?val:[val];var select=el;for(var i=0;i-1);} +break;case'select':case'select-one':input.value=val.toString()||val;break;case'date':var d=exports.toDate(val);if(d) +input.value=d.toISOString().split('T')[0];break;default:input.value=val;break;}}} +exports.populateForm=populateForm;function trimEnd(s,c){var end=s.length;while(end>0&&s[end-1]===c){--end;} +return(end=0){to[k]=o[k];}} +return to;} +exports.pick=pick;function omit(o,keys){var to={};for(var k in o){if(o.hasOwnProperty(k)&&keys.indexOf(k)<0){to[k]=o[k];}} +return to;} +exports.omit=omit;function activeClassNav(x,activePath){return x.href!=null&&(x.exact||activePath.length<=1?trimEnd(activePath,'/').toLowerCase()===trimEnd((x.href),'/').toLowerCase():trimEnd(activePath,'/').toLowerCase().startsWith(trimEnd((x.href),'/').toLowerCase()))?'active':null;} +exports.activeClassNav=activeClassNav;function activeClass(href,activePath,exact){return href!=null&&(exact||activePath.length<=1?trimEnd(activePath,'/').toLowerCase()===trimEnd(href,'/').toLowerCase():trimEnd(activePath,'/').toLowerCase().startsWith(trimEnd(href,'/').toLowerCase()))?'active':null;} +exports.activeClass=activeClass;exports.BootstrapColors=['primary','secondary','success','info','warning','danger','light','dark'];function btnColorClass(props){for(var _i=0,BootstrapColors_1=exports.BootstrapColors;_i=0){return false;} +return true;};NavDefaults.navClass='nav';NavDefaults.navItemClass='nav-item';NavDefaults.navLinkClass='nav-link';NavDefaults.childNavItemClass='nav-item dropdown';NavDefaults.childNavLinkClass='nav-link dropdown-toggle';NavDefaults.childNavMenuClass='dropdown-menu';NavDefaults.childNavMenuItemClass='dropdown-item';NavDefaults.parseIconHtml=null;return NavDefaults;}());exports.NavDefaults=NavDefaults;var NavLinkDefaults=(function(){function NavLinkDefaults(){} +NavLinkDefaults.forNavLink=function(options){return options||NavDefaults.create();};return NavLinkDefaults;}());exports.NavLinkDefaults=NavLinkDefaults;var NavbarDefaults=(function(){function NavbarDefaults(){} +NavbarDefaults.create=function(){return new NavOptions({navClass:NavbarDefaults.navClass});};NavbarDefaults.forNavbar=function(options){return NavDefaults.overrideDefaults(options,NavbarDefaults.create());};NavbarDefaults.navClass='navbar-nav';return NavbarDefaults;}());exports.NavbarDefaults=NavbarDefaults;var NavButtonGroupDefaults=(function(){function NavButtonGroupDefaults(){} +NavButtonGroupDefaults.create=function(){return new NavOptions({navClass:NavButtonGroupDefaults.navClass,navItemClass:NavButtonGroupDefaults.navItemClass});};NavButtonGroupDefaults.forNavButtonGroup=function(options){return NavDefaults.overrideDefaults(options,NavButtonGroupDefaults.create());};NavButtonGroupDefaults.navClass='btn-group';NavButtonGroupDefaults.navItemClass='btn btn-primary';return NavButtonGroupDefaults;}());exports.NavButtonGroupDefaults=NavButtonGroupDefaults;var LinkButtonDefaults=(function(){function LinkButtonDefaults(){} +LinkButtonDefaults.create=function(){return new NavOptions({navItemClass:LinkButtonDefaults.navItemClass});};LinkButtonDefaults.forLinkButton=function(options){return NavDefaults.overrideDefaults(options||null,LinkButtonDefaults.create());};LinkButtonDefaults.navItemClass='btn';return LinkButtonDefaults;}());exports.LinkButtonDefaults=LinkButtonDefaults;var UserAttributes=(function(){function UserAttributes(){} +UserAttributes.fromSession=function(session){var to=[];if(session!=null){to.push('auth');if(session.roles){to.push.apply(to,session.roles.map(function(x){return'role:'+x;}));} +if(session.permissions){to.push.apply(to,session.permissions.map(function(x){return'perm:'+x;}));}} +return to;};return UserAttributes;}());exports.UserAttributes=UserAttributes;var NavOptions=(function(){function NavOptions(init){this.attributes=[];this.navClass=NavDefaults.navClass;this.navItemClass=NavDefaults.navItemClass;this.navLinkClass=NavDefaults.navLinkClass;this.childNavItemClass=NavDefaults.childNavItemClass;this.childNavLinkClass=NavDefaults.childNavLinkClass;this.childNavMenuClass=NavDefaults.childNavMenuClass;this.childNavMenuItemClass=NavDefaults.childNavMenuItemClass;Object.assign(this,init);} +NavOptions.fromSession=function(session,to){to=to||new NavOptions();to.attributes=UserAttributes.fromSession(session);return to;};return NavOptions;}());exports.NavOptions=NavOptions;});; +"use strict";Object.defineProperty(exports,"__esModule",{value:true});var ResponseError=(function(){function ResponseError(init){Object.assign(this,init);} +return ResponseError;}());exports.ResponseError=ResponseError;var ResponseStatus=(function(){function ResponseStatus(init){Object.assign(this,init);} +return ResponseStatus;}());exports.ResponseStatus=ResponseStatus;var Title;(function(Title){Title["Unspecified"]="Unspecified";Title["Mr"]="Mr";Title["Mrs"]="Mrs";Title["Miss"]="Miss";})(Title=exports.Title||(exports.Title={}));var Contact=(function(){function Contact(init){Object.assign(this,init);} +return Contact;}());exports.Contact=Contact;var FilmGenres;(function(FilmGenres){FilmGenres["Action"]="Action";FilmGenres["Adventure"]="Adventure";FilmGenres["Comedy"]="Comedy";FilmGenres["Drama"]="Drama";})(FilmGenres=exports.FilmGenres||(exports.FilmGenres={}));var HelloResponse=(function(){function HelloResponse(init){Object.assign(this,init);} +return HelloResponse;}());exports.HelloResponse=HelloResponse;var TestAuth=(function(){function TestAuth(init){Object.assign(this,init);} +TestAuth.prototype.createResponse=function(){return new TestAuth();};TestAuth.prototype.getTypeName=function(){return'TestAuth';};return TestAuth;}());exports.TestAuth=TestAuth;var AuthUserSession=(function(){function AuthUserSession(init){Object.assign(this,init);} +return AuthUserSession;}());exports.AuthUserSession=AuthUserSession;var ImportDataResponse=(function(){function ImportDataResponse(init){Object.assign(this,init);} +return ImportDataResponse;}());exports.ImportDataResponse=ImportDataResponse;var GetContactsResponse=(function(){function GetContactsResponse(init){Object.assign(this,init);} +return GetContactsResponse;}());exports.GetContactsResponse=GetContactsResponse;var GetContactResponse=(function(){function GetContactResponse(init){Object.assign(this,init);} +return GetContactResponse;}());exports.GetContactResponse=GetContactResponse;var CreateContactResponse=(function(){function CreateContactResponse(init){Object.assign(this,init);} +return CreateContactResponse;}());exports.CreateContactResponse=CreateContactResponse;var UpdateContactResponse=(function(){function UpdateContactResponse(init){Object.assign(this,init);} +return UpdateContactResponse;}());exports.UpdateContactResponse=UpdateContactResponse;var AuthenticateResponse=(function(){function AuthenticateResponse(init){Object.assign(this,init);} +return AuthenticateResponse;}());exports.AuthenticateResponse=AuthenticateResponse;var AssignRolesResponse=(function(){function AssignRolesResponse(init){Object.assign(this,init);} +return AssignRolesResponse;}());exports.AssignRolesResponse=AssignRolesResponse;var UnAssignRolesResponse=(function(){function UnAssignRolesResponse(init){Object.assign(this,init);} +return UnAssignRolesResponse;}());exports.UnAssignRolesResponse=UnAssignRolesResponse;var ConvertSessionToTokenResponse=(function(){function ConvertSessionToTokenResponse(init){Object.assign(this,init);} +return ConvertSessionToTokenResponse;}());exports.ConvertSessionToTokenResponse=ConvertSessionToTokenResponse;var GetAccessTokenResponse=(function(){function GetAccessTokenResponse(init){Object.assign(this,init);} +return GetAccessTokenResponse;}());exports.GetAccessTokenResponse=GetAccessTokenResponse;var RegisterResponse=(function(){function RegisterResponse(init){Object.assign(this,init);} +return RegisterResponse;}());exports.RegisterResponse=RegisterResponse;var Hello=(function(){function Hello(init){Object.assign(this,init);} +Hello.prototype.createResponse=function(){return new HelloResponse();};Hello.prototype.getTypeName=function(){return'Hello';};return Hello;}());exports.Hello=Hello;var Session=(function(){function Session(init){Object.assign(this,init);} +Session.prototype.createResponse=function(){return new AuthUserSession();};Session.prototype.getTypeName=function(){return'Session';};return Session;}());exports.Session=Session;var Throw=(function(){function Throw(init){Object.assign(this,init);} +return Throw;}());exports.Throw=Throw;var ImportData=(function(){function ImportData(init){Object.assign(this,init);} +ImportData.prototype.createResponse=function(){return new ImportDataResponse();};ImportData.prototype.getTypeName=function(){return'ImportData';};return ImportData;}());exports.ImportData=ImportData;var GetContacts=(function(){function GetContacts(init){Object.assign(this,init);} +GetContacts.prototype.createResponse=function(){return new GetContactsResponse();};GetContacts.prototype.getTypeName=function(){return'GetContacts';};return GetContacts;}());exports.GetContacts=GetContacts;var GetContact=(function(){function GetContact(init){Object.assign(this,init);} +GetContact.prototype.createResponse=function(){return new GetContactResponse();};GetContact.prototype.getTypeName=function(){return'GetContact';};return GetContact;}());exports.GetContact=GetContact;var CreateContact=(function(){function CreateContact(init){Object.assign(this,init);} +CreateContact.prototype.createResponse=function(){return new CreateContactResponse();};CreateContact.prototype.getTypeName=function(){return'CreateContact';};return CreateContact;}());exports.CreateContact=CreateContact;var DeleteContact=(function(){function DeleteContact(init){Object.assign(this,init);} +DeleteContact.prototype.createResponse=function(){};DeleteContact.prototype.getTypeName=function(){return'DeleteContact';};return DeleteContact;}());exports.DeleteContact=DeleteContact;var UpdateContact=(function(){function UpdateContact(init){Object.assign(this,init);} +UpdateContact.prototype.createResponse=function(){return new UpdateContactResponse();};UpdateContact.prototype.getTypeName=function(){return'UpdateContact';};return UpdateContact;}());exports.UpdateContact=UpdateContact;var Authenticate=(function(){function Authenticate(init){Object.assign(this,init);} +Authenticate.prototype.createResponse=function(){return new AuthenticateResponse();};Authenticate.prototype.getTypeName=function(){return'Authenticate';};return Authenticate;}());exports.Authenticate=Authenticate;var AssignRoles=(function(){function AssignRoles(init){Object.assign(this,init);} +AssignRoles.prototype.createResponse=function(){return new AssignRolesResponse();};AssignRoles.prototype.getTypeName=function(){return'AssignRoles';};return AssignRoles;}());exports.AssignRoles=AssignRoles;var UnAssignRoles=(function(){function UnAssignRoles(init){Object.assign(this,init);} +UnAssignRoles.prototype.createResponse=function(){return new UnAssignRolesResponse();};UnAssignRoles.prototype.getTypeName=function(){return'UnAssignRoles';};return UnAssignRoles;}());exports.UnAssignRoles=UnAssignRoles;var ConvertSessionToToken=(function(){function ConvertSessionToToken(init){Object.assign(this,init);} +ConvertSessionToToken.prototype.createResponse=function(){return new ConvertSessionToTokenResponse();};ConvertSessionToToken.prototype.getTypeName=function(){return'ConvertSessionToToken';};return ConvertSessionToToken;}());exports.ConvertSessionToToken=ConvertSessionToToken;var GetAccessToken=(function(){function GetAccessToken(init){Object.assign(this,init);} +GetAccessToken.prototype.createResponse=function(){return new GetAccessTokenResponse();};GetAccessToken.prototype.getTypeName=function(){return'GetAccessToken';};return GetAccessToken;}());exports.GetAccessToken=GetAccessToken;var Register=(function(){function Register(init){Object.assign(this,init);} +Register.prototype.createResponse=function(){return new RegisterResponse();};Register.prototype.getTypeName=function(){return'Register';};return Register;}());exports.Register=Register;; diff --git a/tests/CheckWebCore/wwwroot/js/jquery.min.js b/tests/CheckWebCore/wwwroot/js/jquery.min.js new file mode 100644 index 00000000000..644d35e274f --- /dev/null +++ b/tests/CheckWebCore/wwwroot/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"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){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(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 qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(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){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.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===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!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 ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.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},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.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=ga.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=ga.selectors={cacheLength:50,createPseudo:ia,match:V,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(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===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]||ga.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]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.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(_,aa).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("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.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.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},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,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(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),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).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:oa(!1),disabled:oa(!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 X.test(a.nodeName)},input:function(a){return W.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:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), +a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.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 W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), +null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r(" + + diff --git a/tests/CheckWebCore/wwwroot/modules/ui/docs/CreateBookingsDocs.html b/tests/CheckWebCore/wwwroot/modules/ui/docs/CreateBookingsDocs.html new file mode 100644 index 00000000000..aff10229525 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/modules/ui/docs/CreateBookingsDocs.html @@ -0,0 +1,34 @@ + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/modules/ui/docs/GetContactsDocs.html b/tests/CheckWebCore/wwwroot/modules/ui/docs/GetContactsDocs.html new file mode 100644 index 00000000000..c8b5a59d8a4 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/modules/ui/docs/GetContactsDocs.html @@ -0,0 +1,41 @@ + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/navitems.html b/tests/CheckWebCore/wwwroot/navitems.html new file mode 100644 index 00000000000..efce4c1414b --- /dev/null +++ b/tests/CheckWebCore/wwwroot/navitems.html @@ -0,0 +1,173 @@ + + +

Embed JSON in Page

+ + + +
+{{#raw}}script> NAV_ITEMS = {{ 'GetNavItems' | sendToGateway | json }} /script>{{/raw}}    
+
+ +

With external dependencies

+
+link src="fontawesome.css" />
+link src="bootstrap-social.css" />
+{{#raw}}{{ navItems('auth').navButtonGroup() }}{{/raw}}    
+
+ +

No external dependencies

+ +{{ 'buttons,svg-auth' | cssIncludes }} + +
+{{#raw}}
+{{ 'buttons,svg-auth' | cssIncludes }}
+{{/raw}}
+
+ + +

Examples

+ +
+{{#raw}}{{ navItems('auth').navButtonGroup() }}{{/raw}}
+
+ +{{ navItems('auth').navButtonGroup() }} + +
+{{#raw}}{{ navItems('auth').navButtonGroup({ navClass:'' }) }}{{/raw}}
+
+ +{{ navItems('auth').navButtonGroup({ navClass:'' }) }} + + +

Without SVG Icons

+ +
+style>
+.btn-social { padding-left: 1em; }
+.btn-social i { display: none; }
+/style>
+
+ + +
+{{ navItems('auth').navButtonGroup() }} + +
+ +{{ navItems('auth').navButtonGroup({ navClass:'' }) }} +
+ +

Vertical

+ +
+{{#raw}}{{ navItems('auth').navButtonGroup({ navClass:'btn-group-vertical' }) }}{{/raw}}
+
+ +{{ navItems('auth').navButtonGroup({ navClass:'btn-group-vertical' }) }} + +
+{{#raw}}{{ navItems('auth').navButtonGroup({ navClass:'col-sm-3', navItemClass:'btn btn-block' }) }}{{/raw}}
+
+ +{{ navItems('auth').navButtonGroup({ navClass:'col-sm-3', navItemClass:'btn btn-block' }) }} + + + + +
+{{#raw}}{{ navItems('footer').nav({ navClass: 'nav nav-tabs' }) }}{{/raw}}
+
+ +{{ navItems('footer').nav({ navClass: 'nav nav-tabs' }) }} + +
+{{#raw}}{{ navItems('footer').nav({ navClass: 'nav nav-tabs' }) }}{{/raw}}
+
+ +{{ navItems('footer').nav({ navClass: 'nav nav-pills' }) }} + +
+{{#raw}}{{ navItems('footer').nav({ navClass: 'nav nav-pills' }) }}{{/raw}}
+
+ +{{ navItems('footer').nav({ navClass: 'col-sm-3 nav flex-column nav-pills' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup() }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-primary' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup() }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-primary' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-secondary' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-secondary' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-secondary' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-secondary' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-success' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-success' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-success' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-success' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-info' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-info' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-info' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-info' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-warning' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-warning' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-warning' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-warning' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-danger' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-danger' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-danger' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-danger' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-light' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-light text-dark' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-light' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-light text-dark' }) }} + +
+{{#raw}}{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-dark' }) }}
+{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-dark' }) }}{{/raw}}
+
+ +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-dark' }) }} +{{ navItems('footer').navButtonGroup({ navItemClass:'btn btn-outline-dark' }) }} + +
\ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/notfound.cshtml b/tests/CheckWebCore/wwwroot/notfound.cshtml new file mode 100644 index 00000000000..46d0044438b --- /dev/null +++ b/tests/CheckWebCore/wwwroot/notfound.cshtml @@ -0,0 +1,63 @@ +@{ + Layout = ""; + var search = (@Request.PathInfo ?? "").LastRightPart('/'); +} + + + + Page Not Found + + + + +

Page Not Found

+ +
+ +

+ We're sorry @Request.PathInfo is no longer here. +

+ + @if (!string.IsNullOrEmpty(search)) + { +

+ Maybe Google has it? +

+ +
+
+
+ +
+
+ +
+
+
+ } +
+ + diff --git a/tests/CheckWebCore/wwwroot/profile.html b/tests/CheckWebCore/wwwroot/profile.html new file mode 100644 index 00000000000..73e2beaf96c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/profile.html @@ -0,0 +1,8 @@ + +{{ redirectIfNotAuthenticated }} + +

Profile Page

+ +

+ /auth/logout?continue=/validation/server/login +

diff --git a/tests/CheckWebCore/wwwroot/services.html b/tests/CheckWebCore/wwwroot/services.html new file mode 100644 index 00000000000..6813961ef76 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/services.html @@ -0,0 +1,7 @@ + + +

+ Services page. +

\ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/sse.html b/tests/CheckWebCore/wwwroot/sse.html new file mode 100644 index 00000000000..3868ef31041 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/sse.html @@ -0,0 +1,280 @@ + + + + + + {{ title }} + + + {{#if debug}}{{/if}} + + + + + + + +{{ var channels = qs.channels ?? 'home' }} +
+ + + +
+
+ {{#if !isAuthenticated}} + {{#each ['twitter', 'facebook', 'github']}}{{/each}} + {{/if}} +
+
    +
  • + +
  • +
  • + clear +
  • +
+
+
+
+ + +
+
+ + +
+ + + +{{ scripts | raw }} + + + diff --git a/tests/CheckWebCore/wwwroot/svg-demo.html b/tests/CheckWebCore/wwwroot/svg-demo.html new file mode 100644 index 00000000000..85e6363dcb5 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/svg-demo.html @@ -0,0 +1,80 @@ + + +
Brand Icons: https://github.com/simple-icons/simple-icons
+
SVG Encoder: https://yoksel.github.io/url-encoder/
+ + + +{{ 'navitems,svg-auth' | cssIncludes }} + +

svg-auth

+ + +.svg-custom, .svg-servicestack, .svg-twitter, .svg-github, .svg-google, .svg-facebook, .svg-microsoft, .svg-linkedin +.fa-custom, .fa-servicestack, .fa-twitter, .fa-github, .fa-google, .fa-facebook, .fa-microsoft, .fa-linkedin + + +
+
+
+
+
+
+
+
+
+ +
+ {{ 'navitems,svg-auth' | cssIncludes | replace('svg-','svgdark-') | replace('ffffff','343a40') | raw }} + +
+
+
+
+
+
+
+
+
+
+ + +{{ 'svg-icons' | cssIncludes }} + +

svg-icons

+ + + .svg-male, .svg-female, .svg-male-business, .svg-female-business, .svg-male-color, .svg-female-color, .svg-users + .fa-male, .fa-female, .fa-male-business, .fa-female-business, .fa-male-color, .fa-female-color, .fa-users + + +
+
+
+
+
+
+
+
+
+ + diff --git a/tests/CheckWebCore/wwwroot/svg.html b/tests/CheckWebCore/wwwroot/svg.html new file mode 100644 index 00000000000..7b0d95e09b4 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/svg.html @@ -0,0 +1,386 @@ + + +{{ 'id' | importRequestParams }} + + + +{{ 'buttons' | cssIncludes }} + +<back + +
+
+{{#each svgCssFiles}} +
+ +

/css/{{it.Key}}.css

+ + {{ it.Key | cssIncludes }} + + {{#each name in it.Value}} +
+ {{name}} + +
+ +
+
+ .svg-{{name}} +
+ {{/each}} + +{{#if it.Value.Count > 0}} + + {{ (id && it.Value.contains(id) ? id : it.Value[0]) | assignTo: name }} + + {{ ['lg','md','sm','xs'] | assignTo: sizes }} + + + + + + + +
+
+

Buttons

+<button class="btn btn-block btn-social btn-{{name}}"> + <i class="fab fa-{{name}}"></i> +</button> +
+ {{#each size in sizes}} + + {{/each}} +
+
+
+

Button Icons

+<button class="btn btn-social-icon btn-{{name}}"> + <i class="fab fa-{{name}}"></i> +</button> +
+ {{#each size in sizes}} + + {{/each}} +
+
+
+

Image Sizes

+<i class="svg-{{name}} svg-{size}"></i> +
+ {{#each size in ['5x','4x','3x','2x','lg','md','sm','xs'].reverse()}} + svg-{{size}} + {{/each}} +
+
+ Sizes: xs sm md lg 2x 3x 4x 5x ... 14x +
+
+
+

#Script

+
+
<img src="{{#raw}}{{{{/raw}}{{`'${name}'`}}.svgDataUri(){{#raw}}}}{{/raw}}">
+
+
+ +
+
+
+
+
<img src="{{#raw}}{{{{/raw}}{{`'${name}'`}}.svgDataUri('#e33'){{#raw}}}}{{/raw}}">
+
+
+ +
+
+
+
{{#raw}} {{ {{/raw}} {{ `'${name}'` }}.svgImage('#e33') {{#raw}} }} {{/raw}}
+
{{#raw}} {{ {{/raw}} {{ `'${name}'` }}.svgImage() {{#raw}} }} {{/raw}}
+
+.svg-bg { + {{#raw}}{{{{/raw}}{{`'${name}'`}}.svgBackgroundImageCss(){{#raw}}}}{{/raw}} +} +
+
+

Razor

+ +
<img src="@Html.SvgDataUri("{{ `${name}` }}")">
+
<img src="@Html.SvgDataUri("{{ `${name}` }}","#e33")">
+ +
@Html.SvgImage("{{ `${name}` }}")
+
@Html.SvgImage("{{ `${name}` }}", "#e33")
+ +
+.svg-bg-example { + width: 150px; + height: 150px; + background-size: 142px 142px; + background-position: 4px 4px; + background-repeat: no-repeat; + @Html.SvgBackgroundImageCss("female") +} + +
+
+ + Click to copy to clipboard + + +
+
+

Reference all svg images using .css

+ + + + + + + + + + + + + +
Link stylesheet + <link rel="stylesheet" href="/css/buttons.css">
+ <link rel="stylesheet" href="/css/{{it.Key}}.css"> +
#Script inline style + {{#raw}} {{ {{/raw}} 'buttons,{{it.Key}}' | cssIncludes{{#raw}} }} {{/raw}} +
Razor inline style + @Html.CssIncludes("buttons","{{it.Key}}") +
+
+ +
+

Individual SVG Links

+ + + + + + + + + + + + + +
Image + {{name}}.svg + {{name}}.svg?fill=#e33 +
CSS + {{name}}.css + {{name}}.css?fill=#e33 +
Data URI + {{name}}.datauri + + + copy for url + +
+
+
+{{/if}} + +
+ +{{/each}} + + + + +
+ +
+
+

Find out more

+ + See the SVG documentation to find out how to register + your own SVG images and see more usage examples. +
+
+ +
+ diff --git a/tests/CheckWebCore/wwwroot/testauth.html b/tests/CheckWebCore/wwwroot/testauth.html new file mode 100644 index 00000000000..d8213b70048 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/testauth.html @@ -0,0 +1,74 @@ + + + + + + + TestLogin + + {{ ifDebug | select: }} + + + + + +
+
+
+

+
+
+
+
+
+ +

forgot password?

+
+ + Logout +
+
+
+ +
+    User: 
+    - IsAuthenticated       {{ isAuthenticated }}
+    - IsAuthenticated       {{ userSession | select: { it.IsAuthenticated } }}
+    - UserName              {{ userName }} / {{ userSession | select: { it.UserName } }}
+    - LastName              {{ userSession | select: { it.LastName } }}
+    - Is Admin              {{ userHasRole('Admin') }}
+    - Has Permission        {{ userHasPermission('ThePermission') }}
+
+ + + + + + + diff --git a/tests/CheckWebCore/wwwroot/validation/authcheck.html b/tests/CheckWebCore/wwwroot/validation/authcheck.html new file mode 100644 index 00000000000..e11790018e1 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/authcheck.html @@ -0,0 +1,13 @@ +{{#if isAuthenticated}} + Hi {{userSession.DisplayName}}! +

+ Sign Out. +

+

Secure Pages

+ +{{else}} + You're not authenticated, please Sign In: + {{ 'signin-links' | partial }} +{{/if}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-jquery/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/validation/client-jquery/_requires-auth-partial.html new file mode 100644 index 00000000000..b079f76f844 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-jquery/_requires-auth-partial.html @@ -0,0 +1,9 @@ +{{ `/validation/client-jquery/login?continue=${PathInfo}` + | redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
diff --git a/tests/CheckWebCore/wwwroot/validation/client-jquery/contacts/_id/edit.html b/tests/CheckWebCore/wwwroot/validation/client-jquery/contacts/_id/edit.html new file mode 100644 index 00000000000..9f2bdab5c79 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-jquery/contacts/_id/edit.html @@ -0,0 +1,75 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/client-jquery/contacts/' | assignTo: continue }} + +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} + +{{#with response.Result}} +

Update Contact

+ +
+
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+ +
+
+ + cancel +
+
+ + {{#capture appendTo scripts}} + + {{/capture}} + +{{else if ex}} +
+
{{ex.Message}}
+

< back

+
+{{/with}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/client-jquery/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/client-jquery/contacts/index.html new file mode 100644 index 00000000000..e1c6a194729 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-jquery/contacts/index.html @@ -0,0 +1,115 @@ +{{ 'requires-auth' | partial }} + +

Add new Contact

+ +
+
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ +
+ +
+ +
+
+ Your first and last name +
+
+ + +
+
+ +
+ {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+ +
+
+
+ + +
+
+
+ + reset +
+
+ +
+ +{{#capture appendTo scripts}} + +{{/capture}} + +{{#raw appendTo scripts}} + +{{/raw}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/client-jquery/index.html b/tests/CheckWebCore/wwwroot/validation/client-jquery/index.html new file mode 100644 index 00000000000..fa61ae7601b --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-jquery/index.html @@ -0,0 +1,17 @@ +

Ajax Forms with jQuery Validation Examples

+ +{{#if isAuthenticated}} + Hi {{userSession.DisplayName}}! + +{{else}} +

+ You're not authenticated, please Sign In: +

+ +{{/if}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-jquery/login.html b/tests/CheckWebCore/wwwroot/validation/client-jquery/login.html new file mode 100644 index 00000000000..d276a386d40 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-jquery/login.html @@ -0,0 +1,60 @@ +

Sign In using credentials

+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com +
+
+ +{{#capture appendTo scripts}} + +{{/capture}} + +{{#raw appendTo scripts}} + +{{/raw}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-jquery/register.html b/tests/CheckWebCore/wwwroot/validation/client-jquery/register.html new file mode 100644 index 00000000000..066d824ad9d --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-jquery/register.html @@ -0,0 +1,50 @@ +

Register New User

+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ Quick Populate: +
+ new@user.com +
+
+
+ +{{#raw appendTo scripts}} + +{{/raw}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-razor/_ViewImports.cshtml b/tests/CheckWebCore/wwwroot/validation/client-razor/_ViewImports.cshtml new file mode 100644 index 00000000000..abcecebb4a9 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-razor/_ViewImports.cshtml @@ -0,0 +1,10 @@ +@inherits ViewPage + +@using ServiceStack +@using ServiceStack.Mvc +@using ServiceStack.Text +@using CheckWebCore +@using CheckWebCore.ServiceModel +@using CheckWebCore.ServiceModel.Types + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-razor/contacts/_id/edit.cshtml b/tests/CheckWebCore/wwwroot/validation/client-razor/contacts/_id/edit.cshtml new file mode 100644 index 00000000000..32bc2ddee8c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-razor/contacts/_id/edit.cshtml @@ -0,0 +1,88 @@ +@await Html.PartialAsync("_RequiresAuth") + +@{ + var Continue = "/validation/client-razor/contacts/"; + var id = int.Parse(ViewBag.id); + Exception error = null; + Contact contact = null; + try { + contact = (await Gateway.SendAsync(new GetContact { Id = id })).Result; + } catch (Exception ex) { + error = ex; + } +} + +@if (contact != null) +{ +

Update Contact

+ +
+
+ +
+
+ @foreach (var it in Html.ContactTitles()) + { +
+ + +
+ } +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ @foreach (var it in Html.ContactGenres()) + { +
+ + +
+ } +
+
+
+ +
+
+ + cancel +
+
+ + @section scripts + { + + } + +} +else +{ +
+
@(error?.Message ?? "Contact does not exist")
+

< back

+
+} diff --git a/tests/CheckWebCore/wwwroot/validation/client-razor/contacts/default.cshtml b/tests/CheckWebCore/wwwroot/validation/client-razor/contacts/default.cshtml new file mode 100644 index 00000000000..ed447c06d7a --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-razor/contacts/default.cshtml @@ -0,0 +1,110 @@ +@await Html.PartialAsync("_RequiresAuth") + +

Add new Contact

+ +
+
+ +
+
+ @foreach (var it in Html.ContactTitles()) + { +
+ + +
+ } +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ @foreach (var it in Html.ContactGenres()) + { +
+ + +
+ } +
+
+
+ +
+
+
+ + +
+
+
+ + reset +
+
+ +
+ +@section scripts +{ + +} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-razor/default.cshtml b/tests/CheckWebCore/wwwroot/validation/client-razor/default.cshtml new file mode 100644 index 00000000000..9514f4ebea8 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-razor/default.cshtml @@ -0,0 +1,22 @@ +

Razor + Ajax Forms with jQuery Validation Examples

+ +@if (IsAuthenticated) +{ +
+ Hi @GetSession().DisplayName! + +
+} +else +{ +

+ You're not authenticated, please Sign In: +

+ +} diff --git a/tests/CheckWebCore/wwwroot/validation/client-razor/login.cshtml b/tests/CheckWebCore/wwwroot/validation/client-razor/login.cshtml new file mode 100644 index 00000000000..f5dfe401af5 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-razor/login.cshtml @@ -0,0 +1,63 @@ +@{ +} + +

Sign In using credentials

+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@@email.com + new@@user.com +
+
+ +@section scripts { + + + +} diff --git a/tests/CheckWebCore/wwwroot/validation/client-razor/register.cshtml b/tests/CheckWebCore/wwwroot/validation/client-razor/register.cshtml new file mode 100644 index 00000000000..b8b9a3d0b23 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-razor/register.cshtml @@ -0,0 +1,51 @@ +

Register New User

+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ Quick Populate: +
+ new@@user.com +
+
+
+ +@section scripts +{ + +} diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/validation/client-ts/_requires-auth-partial.html new file mode 100644 index 00000000000..9bc9325be11 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/_requires-auth-partial.html @@ -0,0 +1,9 @@ +{{ `/validation/client-ts/login?continue=${PathInfo}` + | redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/_id/edit.html b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/_id/edit.html new file mode 100644 index 00000000000..5a15c0de408 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/_id/edit.html @@ -0,0 +1,67 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/client-ts/contacts/' | assignTo: continue }} + +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} + +{{#with response.Result}} +

Update Contact

+ +
+
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+ +
+
+ + cancel +
+
+ + {{#capture appendTo scripts}} + + + {{/capture}} + +{{else if ex}} +
+
{{ex.Message}}
+

< back

+
+{{/with}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.js b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.js new file mode 100644 index 00000000000..8ad94880efa --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +var form = document.querySelector("form"); +client_1.bootstrapForm(form, { + model: CONTACT, + success: function () { + location.href = '/validation/client-ts/contacts/'; + } +}); +//# sourceMappingURL=edit.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.js.map b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.js.map new file mode 100644 index 00000000000..ed637ab68ad --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"edit.js","sourceRoot":"","sources":["edit.ts"],"names":[],"mappings":";;AAAA,+CAAqD;AAIrD,IAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAE,CAAC;AAC7C,sBAAa,CAAC,IAAI,EAAC;IACf,KAAK,EAAE,OAAO;IACd,OAAO,EAAE;QACL,QAAQ,CAAC,IAAI,GAAG,iCAAiC,CAAC;IACtD,CAAC;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.ts b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.ts new file mode 100644 index 00000000000..b7547f64f25 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/edit.ts @@ -0,0 +1,11 @@ +import { bootstrapForm } from "@servicestack/client"; + +declare var CONTACT:any; + +const form = document.querySelector("form")!; +bootstrapForm(form,{ + model: CONTACT, + success: function () { + location.href = '/validation/client-ts/contacts/'; + } +}); diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.html new file mode 100644 index 00000000000..888c9eb14c9 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.html @@ -0,0 +1,68 @@ +{{ 'requires-auth' | partial }} + +

Add new Contact

+ +
+
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+ +
+
+
+ + +
+
+
+ + reset +
+
+ +
+ +{{#capture appendTo scripts}} + +{{/capture}} + +{{#raw appendTo scripts}} + +{{/raw}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.js b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.js new file mode 100644 index 00000000000..f6bbcefd3a0 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.js @@ -0,0 +1,88 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +var dtos_1 = require("../../../dtos"); +var client = new client_1.JsonServiceClient(); +var form = document.querySelector("form"); +client_1.bootstrapForm(form, { + success: function (r) { + form.reset(); + CONTACTS.push(r.result); + render(); + } +}); +client_1.bindHandlers({ + deleteContact: function (id) { + return __awaiter(this, void 0, void 0, function () { + var response; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!confirm('Are you sure?')) + return [2 /*return*/]; + return [4 /*yield*/, client.delete(new dtos_1.DeleteContact({ id: id }))]; + case 1: + _a.sent(); + return [4 /*yield*/, client.get(new dtos_1.GetContacts())]; + case 2: + response = _a.sent(); + CONTACTS = response.results; + render(); + return [2 /*return*/]; + } + }); + }); + } +}); +var contactRow = function (contact) { + return "\n " + contact.title + " " + contact.name + " (" + contact.age + ")\n edit\n \n "; +}; +function render() { + var sb = ""; + if (CONTACTS.length > 0) { + for (var i = 0; i < CONTACTS.length; i++) { + sb += contactRow(CONTACTS[i]); + } + } + else { + sb = "There are no contacts."; + } + document.querySelector("#results").innerHTML = "" + sb + ""; +} +render(); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.js.map b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.js.map new file mode 100644 index 00000000000..d01786dd02a --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAsF;AACtF,sCAA8E;AAI9E,IAAM,MAAM,GAAG,IAAI,0BAAiB,EAAE,CAAC;AAEvC,IAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAE,CAAC;AAC7C,sBAAa,CAAC,IAAI,EAAC;IACf,OAAO,EAAE,UAAU,CAAkB;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACxB,MAAM,EAAE,CAAC;IACb,CAAC;CACJ,CAAC,CAAC;AACH,qBAAY,CAAC;IACT,aAAa,EAAE,UAAe,EAAS;;;;;;wBACnC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;4BACzB,sBAAO;wBAEX,qBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,oBAAa,CAAC,EAAE,EAAE,IAAA,EAAE,CAAC,CAAC,EAAA;;wBAA9C,SAA8C,CAAC;wBAC9B,qBAAM,MAAM,CAAC,GAAG,CAAC,IAAI,kBAAW,EAAE,CAAC,EAAA;;wBAA9C,QAAQ,GAAG,SAAmC;wBACpD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC;wBAC5B,MAAM,EAAE,CAAC;;;;;KACZ;CACJ,CAAC,CAAC;AAEH,IAAM,UAAU,GAAG,UAAC,OAAe;IAC/B,OAAA,4BAAyB,OAAO,CAAC,KAAK,yBAC5B,OAAO,CAAC,KAAK,SAAI,OAAO,CAAC,IAAI,UAAK,OAAO,CAAC,GAAG,qEACL,OAAO,CAAC,EAAE,+GACe,OAAO,CAAC,EAAE,uCAC/E;AAJN,CAIM,CAAC;AAEX,SAAS,MAAM;IACX,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;QACrB,KAAK,IAAI,CAAC,GAAC,CAAC,EAAE,CAAC,GAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAClC,EAAE,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;SAChC;KACJ;SAAM;QACH,EAAE,GAAG,0CAA0C,CAAC;KACnD;IACD,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAE,CAAC,SAAS,GAAG,YAAU,EAAE,aAAU,CAAC;AAC3E,CAAC;AAED,MAAM,EAAE,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.ts b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.ts new file mode 100644 index 00000000000..539dc3116c5 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/contacts/index.ts @@ -0,0 +1,47 @@ +import { bootstrapForm, bindHandlers, JsonServiceClient } from "@servicestack/client"; +import {Contact, DeleteContact, GetContact, GetContacts} from "../../../dtos"; + +declare var CONTACTS:Contact[]; + +const client = new JsonServiceClient(); + +const form = document.querySelector("form")!; +bootstrapForm(form,{ + success: function (r:{result:Contact}) { + form.reset(); + CONTACTS.push(r.result); + render(); + } +}); +bindHandlers({ + deleteContact: async function(id:number) { + if (!confirm('Are you sure?')) + return; + + await client.delete(new DeleteContact({ id })); + const response = await client.get(new GetContacts()); + CONTACTS = response.results; + render(); + } +}); + +const contactRow = (contact:Contact) => + ` + ${contact.title} ${contact.name} (${contact.age}) + edit + + `; + +function render() { + let sb = ""; + if (CONTACTS.length > 0) { + for (let i=0; i${sb}`; +} + +render(); diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/index.html b/tests/CheckWebCore/wwwroot/validation/client-ts/index.html new file mode 100644 index 00000000000..754bb94475c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/index.html @@ -0,0 +1,17 @@ +

Ajax Forms with TypeScript Validation Examples

+ +{{#if isAuthenticated}} + Hi {{userSession.DisplayName}}! + +{{else}} +

+ You're not authenticated, please Sign In: +

+ +{{/if}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/login.html b/tests/CheckWebCore/wwwroot/validation/client-ts/login.html new file mode 100644 index 00000000000..f7c9d49fb9c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/login.html @@ -0,0 +1,44 @@ +

Sign In using credentials

+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com +
+
+ +{{#capture appendTo scripts}} + + +{{/capture}} diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/login.js b/tests/CheckWebCore/wwwroot/validation/client-ts/login.js new file mode 100644 index 00000000000..e9eaa56315d --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/login.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +client_1.bootstrapForm(document.querySelector('form'), { + success: function (r) { + location.href = CONTINUE; + } +}); +client_1.bindHandlers({ + switchUser: function (u) { + document.querySelector("[name=userName]").value = u; + document.querySelector("[name=password]").value = 'p@55wOrd'; + } +}); +//# sourceMappingURL=login.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/login.js.map b/tests/CheckWebCore/wwwroot/validation/client-ts/login.js.map new file mode 100644 index 00000000000..1d57b58d87d --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/login.js.map @@ -0,0 +1 @@ +{"version":3,"file":"login.js","sourceRoot":"","sources":["login.ts"],"names":[],"mappings":";;AAAA,+CAAmE;AAKnE,sBAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE;IAC1C,OAAO,EAAE,UAAC,CAAuB;QAC7B,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC;IAC7B,CAAC;CACJ,CAAC,CAAC;AAEH,qBAAY,CAAC;IACT,UAAU,EAAE,UAAC,CAAS;QACjB,QAAQ,CAAC,aAAa,CAAC,iBAAiB,CAAsB,CAAC,KAAK,GAAG,CAAC,CAAC;QACzE,QAAQ,CAAC,aAAa,CAAC,iBAAiB,CAAsB,CAAC,KAAK,GAAG,UAAU,CAAC;IACvF,CAAC;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/login.ts b/tests/CheckWebCore/wwwroot/validation/client-ts/login.ts new file mode 100644 index 00000000000..3bc194a7c36 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/login.ts @@ -0,0 +1,17 @@ +import { bindHandlers, bootstrapForm } from "@servicestack/client"; +import {AuthenticateResponse} from "../../dtos"; + +declare var CONTINUE:string; + +bootstrapForm(document.querySelector('form'), { + success: (r: AuthenticateResponse) => { + location.href = CONTINUE; + } +}); + +bindHandlers({ + switchUser: (u: string) => { + (document.querySelector("[name=userName]") as HTMLInputElement).value = u; + (document.querySelector("[name=password]") as HTMLInputElement).value = 'p@55wOrd'; + } +}); diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/register.html b/tests/CheckWebCore/wwwroot/validation/client-ts/register.html new file mode 100644 index 00000000000..969e4958ae0 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/register.html @@ -0,0 +1,35 @@ +

Register New User

+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ Quick Populate: +
+ new@user.com +
+
+
+ +{{#capture appendTo scripts}} + +{{/capture}} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/register.js b/tests/CheckWebCore/wwwroot/validation/client-ts/register.js new file mode 100644 index 00000000000..f2009ce18de --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/register.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +client_1.bootstrapForm(document.querySelector('form'), { + success: function (r) { + location.href = '/validation/client-ts/'; + } +}); +client_1.bindHandlers({ + newUser: function (u) { + var $ = function (sel) { return document.querySelector(sel); }; + var names = u.split('@'); + $("[name=displayName]").value = client_1.toPascalCase(names[0]) + " " + client_1.toPascalCase(client_1.splitOnFirst(names[1], '.')[0]); + $("[name=email]").value = u; + $("[name=password]").value = $("[name=confirmPassword]").value = 'p@55wOrd'; + } +}); +//# sourceMappingURL=register.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/register.js.map b/tests/CheckWebCore/wwwroot/validation/client-ts/register.js.map new file mode 100644 index 00000000000..969c8d08a88 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/register.js.map @@ -0,0 +1 @@ +{"version":3,"file":"register.js","sourceRoot":"","sources":["register.ts"],"names":[],"mappings":";;AAAA,+CAA6F;AAG7F,sBAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE;IAC1C,OAAO,EAAE,UAAC,CAAsB;QAC5B,QAAQ,CAAC,IAAI,GAAG,wBAAwB,CAAC;IAC7C,CAAC;CACJ,CAAC,CAAC;AAEH,qBAAY,CAAC;IACT,OAAO,EAAE,UAAC,CAAS;QACf,IAAM,CAAC,GAAG,UAAC,GAAU,IAAK,OAAA,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAqB,EAA/C,CAA+C,CAAC;QAE1E,IAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC,CAAC,oBAAoB,CAAC,CAAC,KAAK,GAAG,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,qBAAY,CAAC,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3G,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QAC5B,CAAC,CAAC,iBAAiB,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,wBAAwB,CAAC,CAAC,KAAK,GAAG,UAAU,CAAC;IAChF,CAAC;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/client-ts/register.ts b/tests/CheckWebCore/wwwroot/validation/client-ts/register.ts new file mode 100644 index 00000000000..fad43a294cb --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/client-ts/register.ts @@ -0,0 +1,19 @@ +import {bindHandlers, bootstrapForm, splitOnFirst, toPascalCase} from "@servicestack/client"; +import {AuthenticateResponse} from "../../dtos"; + +bootstrapForm(document.querySelector('form'), { + success: (r:AuthenticateResponse) => { + location.href = '/validation/client-ts/'; + } +}); + +bindHandlers({ + newUser: (u: string) => { + const $ = (sel:string) => document.querySelector(sel) as HTMLInputElement; + + const names = u.split('@'); + $("[name=displayName]").value = toPascalCase(names[0]) + " " + toPascalCase(splitOnFirst(names[1],'.')[0]); + $("[name=email]").value = u; + $("[name=password]").value = $("[name=confirmPassword]").value = 'p@55wOrd'; + } +}); diff --git a/tests/CheckWebCore/wwwroot/validation/server-jquery/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/validation/server-jquery/_requires-auth-partial.html new file mode 100644 index 00000000000..99966ff16a5 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-jquery/_requires-auth-partial.html @@ -0,0 +1,9 @@ +{{ `/validation/server-jquery/login?continue=${PathInfo}` + | redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
diff --git a/tests/CheckWebCore/wwwroot/validation/server-jquery/contacts/_id/edit.html b/tests/CheckWebCore/wwwroot/validation/server-jquery/contacts/_id/edit.html new file mode 100644 index 00000000000..d4cadc1b14c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-jquery/contacts/_id/edit.html @@ -0,0 +1,76 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/server-jquery/contacts' | assignTo: contactsDir }} + +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} + +{{#with response.Result}} +

Update Contact

+ +
+
+ {{ '
{0}
' | htmlFormat(errorResponseExcept('title,name,color,filmGenres,age')) }} + + +
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{#each contactGenres}} +
+ formValue('filmGenres',x) == toString(it))} | htmlAttrs }}> + +
+ {{/each}} +
+
+
+ +
+
+ + cancel +
+
+{{else if ex}} +
+
{{ex.Message}}
+

< back

+
+{{/with}} + +{{#capture appendTo scripts}} + +{{/capture}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/server-jquery/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/server-jquery/contacts/index.html new file mode 100644 index 00000000000..6c0b4b6f10e --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-jquery/contacts/index.html @@ -0,0 +1,116 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/server-jquery/contacts/' | assignTo: continue }} + +

Add new Contact

+ +
+ +
+ {{ '
{0}
' | htmlFormat(errorResponseExcept('title,name,color,filmGenres,age,agree')) }} + + +
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{ 'filmGenres' | formValues | assignTo: selectedGenres }} + {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+ +
+
+
+ + +
+
+
+ + reset +
+
+ +
+ +{{#capture appendTo scripts}} + +{{/capture}} + +{{#raw appendTo scripts}} + +{{/raw}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/server-jquery/index.html b/tests/CheckWebCore/wwwroot/validation/server-jquery/index.html new file mode 100644 index 00000000000..4793990d303 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-jquery/index.html @@ -0,0 +1,17 @@ +

Server HTML Forms with jQuery Validation Examples

+ +{{#if isAuthenticated}} + Hi {{userSession.DisplayName}}! + +{{else}} +

+ You're not authenticated, please Sign In: +

+ +{{/if}} diff --git a/tests/CheckWebCore/wwwroot/validation/server-jquery/login.html b/tests/CheckWebCore/wwwroot/validation/server-jquery/login.html new file mode 100644 index 00000000000..b2620aa9c9c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-jquery/login.html @@ -0,0 +1,56 @@ +

Sign In using credentials

+ +
+
+
+ {{ '
{0}
' | htmlFormat(errorResponseExcept(['userName','password'])) }} + + +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com +
+
+ +{{#raw appendTo scripts}} + +{{/raw}} diff --git a/tests/CheckWebCore/wwwroot/validation/server-jquery/register.html b/tests/CheckWebCore/wwwroot/validation/server-jquery/register.html new file mode 100644 index 00000000000..30553cc8fff --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-jquery/register.html @@ -0,0 +1,52 @@ +

Register New User

+ +
+
+ {{ '
{0}
' + | htmlFormat(errorResponseExcept('displayName,email,password,confirmPassword')) }} + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ Quick Populate: +
+ new@user.com +
+
+
+ +{{#raw appendTo scripts}} + +{{/raw}} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/_ViewImports.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/_ViewImports.cshtml new file mode 100644 index 00000000000..abcecebb4a9 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/_ViewImports.cshtml @@ -0,0 +1,10 @@ +@inherits ViewPage + +@using ServiceStack +@using ServiceStack.Mvc +@using ServiceStack.Text +@using CheckWebCore +@using CheckWebCore.ServiceModel +@using CheckWebCore.ServiceModel.Types + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/_id/edit.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/_id/edit.cshtml new file mode 100644 index 00000000000..f8ddc9a6b6a --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/_id/edit.cshtml @@ -0,0 +1,88 @@ +@await Html.PartialAsync("_RequiresAuthServer") + +@{ + var Continue = "/validation/server-razor/contacts/"; + var id = int.Parse(ViewBag.id); + Exception error = null; + Contact contact = null; + try { + contact = (await Gateway.SendAsync(new GetContact { Id = id })).Result; + } catch (Exception ex) { + error = ex; + } +} + +@if (contact != null) +{ +

Update Contact

+ +
+
+ @Html.ValidationSummary(new[]{ "title","name","color","age","filmGenres" }) + @Html.HiddenInputs(new { + @continue = Continue, + errorView = $"{Continue}{ViewBag.id}/edit", + }) +
+
+ @Html.FormInput(new { + id = "title", + type = "radio", + value=@contact.Title + }, new InputOptions { + Values = Html.ContactTitles(), + Inline = true, + }) +
+
+ @Html.FormInput(new { + id = "name", + value = contact.Name + }, new InputOptions { + Label = "Name", + }) +
+
+ @Html.FormSelect(new { + id = "color", + @class = "col-4", + value = contact.Color, + }, new InputOptions { + Label = "Favorite color", + Values = Html.ContactColors(), + }) +
+
+ @Html.FormInput(new { + id = "filmGenres", + type = "checkbox", + value = contact.FilmGenres, + }, new InputOptions { + Label = "Favorite Film Genres", + Help = "choose one or more", + Values = Html.ContactGenres() + }) +
+
+ @Html.FormInput(new { + id = "age", + type = "number", + min = 13, + placeholder = "Age", + @class = "col-3", + value = contact.Age, + }) +
+
+ + cancel +
+
+} +else +{ +
+
@(error?.Message ?? "Contact does not exist")
+

< back

+
+} diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/default.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/default.cshtml new file mode 100644 index 00000000000..1af63bcac11 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/default.cshtml @@ -0,0 +1,92 @@ +@await Html.PartialAsync("_RequiresAuthServer") + +@{ var Continue = "/validation/server-razor/contacts/"; } + +

Add new Contact

+ +
+
+ @Html.ValidationSummary(new[]{ "title","name","color","age","filmGenres","agree" }) + @Html.HiddenInputs(new { @continue = Continue, errorView = Continue }) +
+
+ @Html.FormInput(new { + id = "title", + type = "radio", + }, new InputOptions { + Values = Html.ContactTitles(), + Inline = true, + }) +
+
+ @Html.FormInput(new { + id = "name", + placeholder = "Name", + }, new InputOptions { + Label = "Full Name", + Help = "Your first and last name", + }) +
+
+ @Html.FormSelect(new { + id = "color", + @class = "col-4", + }, new InputOptions { + Label = "Favorite color", + Values = new Dictionary { {"",""} }.Merge(Html.ContactColors()), + }) +
+
+ @Html.FormInput(new { + id = "filmGenres", + type = "checkbox", + }, new InputOptions { + Label = "Favorite Film Genres", + Help = "choose one or more", + Values = Html.ContactGenres() + }) +
+
+ @Html.FormInput(new { + id = "age", + type = "number", + min = 13, + placeholder = "Age", + @class = "col-3", + }) +
+
+ @Html.FormInput(new { + id = "agree", + type = "checkbox", + }, + new InputOptions { Label = "Agree to terms and conditions" }) +
+
+ + reset +
+
+ +@{ var response = await Gateway.SendAsync(new GetContacts()); } + + + + @foreach (var c in response.Results) + { + + + + + + } + @if (response.Results.IsEmpty()) + { + + + + } + +
@c.Title @c.Name (@c.Age)edit
+ +
There are no contacts.
diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/edit/_id.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/edit/_id.cshtml new file mode 100644 index 00000000000..f8ddc9a6b6a --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/contacts/edit/_id.cshtml @@ -0,0 +1,88 @@ +@await Html.PartialAsync("_RequiresAuthServer") + +@{ + var Continue = "/validation/server-razor/contacts/"; + var id = int.Parse(ViewBag.id); + Exception error = null; + Contact contact = null; + try { + contact = (await Gateway.SendAsync(new GetContact { Id = id })).Result; + } catch (Exception ex) { + error = ex; + } +} + +@if (contact != null) +{ +

Update Contact

+ +
+
+ @Html.ValidationSummary(new[]{ "title","name","color","age","filmGenres" }) + @Html.HiddenInputs(new { + @continue = Continue, + errorView = $"{Continue}{ViewBag.id}/edit", + }) +
+
+ @Html.FormInput(new { + id = "title", + type = "radio", + value=@contact.Title + }, new InputOptions { + Values = Html.ContactTitles(), + Inline = true, + }) +
+
+ @Html.FormInput(new { + id = "name", + value = contact.Name + }, new InputOptions { + Label = "Name", + }) +
+
+ @Html.FormSelect(new { + id = "color", + @class = "col-4", + value = contact.Color, + }, new InputOptions { + Label = "Favorite color", + Values = Html.ContactColors(), + }) +
+
+ @Html.FormInput(new { + id = "filmGenres", + type = "checkbox", + value = contact.FilmGenres, + }, new InputOptions { + Label = "Favorite Film Genres", + Help = "choose one or more", + Values = Html.ContactGenres() + }) +
+
+ @Html.FormInput(new { + id = "age", + type = "number", + min = 13, + placeholder = "Age", + @class = "col-3", + value = contact.Age, + }) +
+
+ + cancel +
+
+} +else +{ +
+
@(error?.Message ?? "Contact does not exist")
+

< back

+
+} diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/default.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/default.cshtml new file mode 100644 index 00000000000..3371d934a82 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/default.cshtml @@ -0,0 +1,21 @@ +

Server HTML Forms Validation Examples

+ +@if (IsAuthenticated) { +
+ Hi @UserSession.DisplayName! + +
+} else { +
+

+ You're not authenticated, please Sign In: +

+ +
+} diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/login.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/login.cshtml new file mode 100644 index 00000000000..45c82f97445 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/login.cshtml @@ -0,0 +1,62 @@ +

Sign In using credentials

+ +
+
+ @Html.ValidationSummary(new[]{ "userName","password" }, + new { @class = "alert alert-warning" }) + + @Html.HiddenInputs(new { + @continue = Html.Query("continue") ?? "/validation/server-razor/", + errorView = "/validation/server-razor/login" + }) +
+
+ @Html.FormInput(new { id = "userName" }, new InputOptions { + Label = "Email", + Help = "Email you signed up with", + Size = "lg", + }) +
+
+ @Html.FormInput(new { id = "password", type = "password" }, new InputOptions { + Label = "Password", + Help = "6 characters or more", + Size = "lg", + PreserveValue = false, + }) +
+
+ @Html.FormInput(new { + id = "rememberMe", + type = "checkbox", + @checked = true, + }, + new InputOptions { Label = "Remember Me" }) +
+
+ +
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com +
+
+ +@section scripts +{ + +} diff --git a/tests/CheckWebCore/wwwroot/validation/server-razor/register.cshtml b/tests/CheckWebCore/wwwroot/validation/server-razor/register.cshtml new file mode 100644 index 00000000000..401e6423d16 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-razor/register.cshtml @@ -0,0 +1,71 @@ +

Register New User

+ +
+
+ @Html.ValidationSummary(new[]{ "displayName","email","password","confirmPassword" }) + + @Html.HiddenInputs(new { + @continue = "/validation/server-razor/", + errorView = "/validation/server-razor/register" + }) +
+
+ @Html.FormInput(new { id = "displayName" }, new InputOptions { + Label = "Name", + Help = "Your first and last name", + Size = "lg", + }) +
+
+ @Html.FormInput(new { id = "email" }, new InputOptions { + Label = "Email", + Help = "Email you signed up with", + Size = "lg", + }) +
+
+ @Html.FormInput(new { id = "password", type = "password" }, new InputOptions { + Label = "Password", + Help = "6 characters or more", + Size = "lg", + }) +
+
+ @Html.FormInput(new { id = "confirmPassword", type = "password" }, new InputOptions { + Label = "Confirm Password", + Size = "lg", + }) +
+
+ @Html.FormInput(new { + id = "autoLogin", + type = "checkbox", + @checked = true, + }, + new InputOptions { Label = "Auto Login" }) +
+
+ +
+
+ +
+ Quick Populate: +
+ new@user.com +
+
+ +@section scripts +{ + +} diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/validation/server-ts/_requires-auth-partial.html new file mode 100644 index 00000000000..86323012bb9 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/_requires-auth-partial.html @@ -0,0 +1,9 @@ +{{ `/validation/server-ts/login?continue=${PathInfo}` + | redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/_id/edit.html b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/_id/edit.html new file mode 100644 index 00000000000..63cf0f0c88d --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/_id/edit.html @@ -0,0 +1,75 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/server-ts/contacts' | assignTo: contactsDir }} + +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} + +{{#with response.Result}} +

Update Contact

+ +
+
+ {{ '
{0}
' | htmlFormat(errorResponseExcept('title,name,color,filmGenres,age')) }} + + +
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{#each contactGenres}} +
+ formValue('filmGenres',x) == toString(it))} | htmlAttrs }}> + +
+ {{/each}} +
+
+
+ +
+
+ + cancel +
+
+{{else if ex}} +
+
{{ex.Message}}
+

< back

+
+{{/with}} + + +{{#capture appendTo scripts}} + +{{/capture}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.js b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.js new file mode 100644 index 00000000000..65132c63228 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +client_1.bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. +//# sourceMappingURL=edit.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.js.map b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.js.map new file mode 100644 index 00000000000..9a380b48f1f --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"edit.js","sourceRoot":"","sources":["edit.ts"],"names":[],"mappings":";;AAAA,+CAAiD;AAEjD,kBAAS,EAAE,CAAC,CAAC,oEAAoE"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.ts b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.ts new file mode 100644 index 00000000000..536c0764cea --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/edit.ts @@ -0,0 +1,3 @@ +import { bootstrap } from "@servicestack/client"; + +bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.html new file mode 100644 index 00000000000..f9d7858d4f0 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.html @@ -0,0 +1,81 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/server-ts/contacts/' | assignTo: continue }} + +

Add new Contact

+ +
+ +
+ {{ '
{0}
' | htmlFormat(errorResponseExcept('title,name,color,filmGenres,age,agree')) }} + + +
+ +
+
+ {{#each contactTitles}} +
+ + +
+ {{/each}} +
+
+
+ + + Your first and last name +
+
+ + +
+
+ +
+ {{ 'filmGenres' | formValues | assignTo: selectedGenres }} + {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+ +
+
+
+ + +
+
+
+ + reset +
+
+ +
+ +{{#capture appendTo scripts}} + +{{/capture}} + +{{#raw appendTo scripts}} + +{{/raw}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.js b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.js new file mode 100644 index 00000000000..9cce5398486 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.js @@ -0,0 +1,81 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +var dtos_1 = require("../../../dtos"); +var client = new client_1.JsonServiceClient(); +client_1.bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. +client_1.bindHandlers({ + deleteContact: function (id) { + return __awaiter(this, void 0, void 0, function () { + var response; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!confirm('Are you sure?')) + return [2 /*return*/]; + return [4 /*yield*/, client.delete(new dtos_1.DeleteContact({ id: id }))]; + case 1: + _a.sent(); + return [4 /*yield*/, client.get(new dtos_1.GetContacts())]; + case 2: + response = _a.sent(); + CONTACTS = response.results; + render(); + return [2 /*return*/]; + } + }); + }); + } +}); +var contactRow = function (contact) { + return "\n " + contact.title + " " + contact.name + " (" + contact.age + ")\n edit\n \n "; +}; +function render() { + var sb = ""; + if (CONTACTS.length > 0) { + for (var i = 0; i < CONTACTS.length; i++) { + sb += contactRow(CONTACTS[i]); + } + } + else { + sb = "There are no contacts."; + } + document.querySelector("#results").innerHTML = "" + sb + ""; +} +render(); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.js.map b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.js.map new file mode 100644 index 00000000000..0f5e5df0d40 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAgF;AAChF,sCAAkE;AAIlE,IAAM,MAAM,GAAG,IAAI,0BAAiB,EAAE,CAAC;AAEvC,kBAAS,EAAE,CAAC,CAAC,oEAAoE;AAEjF,qBAAY,CAAC;IACT,aAAa,EAAE,UAAe,EAAS;;;;;;wBACnC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;4BACzB,sBAAO;wBAEX,qBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,oBAAa,CAAC,EAAE,EAAE,IAAA,EAAE,CAAC,CAAC,EAAA;;wBAA9C,SAA8C,CAAC;wBAC9B,qBAAM,MAAM,CAAC,GAAG,CAAC,IAAI,kBAAW,EAAE,CAAC,EAAA;;wBAA9C,QAAQ,GAAG,SAAmC;wBACpD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC;wBAC5B,MAAM,EAAE,CAAC;;;;;KACZ;CACJ,CAAC,CAAC;AAEH,IAAM,UAAU,GAAG,UAAC,OAAe;IAC/B,OAAA,4BAAyB,OAAO,CAAC,KAAK,yBAC5B,OAAO,CAAC,KAAK,SAAI,OAAO,CAAC,IAAI,UAAK,OAAO,CAAC,GAAG,qEACL,OAAO,CAAC,EAAE,+GACe,OAAO,CAAC,EAAE,uCAC/E;AAJN,CAIM,CAAC;AAEX,SAAS,MAAM;IACX,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;QACrB,KAAK,IAAI,CAAC,GAAC,CAAC,EAAE,CAAC,GAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAClC,EAAE,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;SAChC;KACJ;SAAM;QACH,EAAE,GAAG,0CAA0C,CAAC;KACnD;IACD,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAE,CAAC,SAAS,GAAG,YAAU,EAAE,aAAU,CAAC;AAC3E,CAAC;AAED,MAAM,EAAE,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.ts b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.ts new file mode 100644 index 00000000000..cf2032fbb45 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/contacts/index.ts @@ -0,0 +1,41 @@ +import {bindHandlers, bootstrap, JsonServiceClient} from "@servicestack/client"; +import {Contact, DeleteContact, GetContacts} from "../../../dtos"; + +declare var CONTACTS:Contact[]; + +const client = new JsonServiceClient(); + +bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. + +bindHandlers({ + deleteContact: async function(id:number) { + if (!confirm('Are you sure?')) + return; + + await client.delete(new DeleteContact({ id })); + const response = await client.get(new GetContacts()); + CONTACTS = response.results; + render(); + } +}); + +const contactRow = (contact:Contact) => + ` + ${contact.title} ${contact.name} (${contact.age}) + edit + + `; + +function render() { + let sb = ""; + if (CONTACTS.length > 0) { + for (let i=0; i${sb}`; +} + +render(); diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/index.html b/tests/CheckWebCore/wwwroot/validation/server-ts/index.html new file mode 100644 index 00000000000..665f27e9995 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/index.html @@ -0,0 +1,17 @@ +

Server HTML Forms with TypeScript Validation Examples

+ +{{#if isAuthenticated}} + Hi {{userSession.DisplayName}}! + +{{else}} +

+ You're not authenticated, please Sign In: +

+ +{{/if}} diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/login.html b/tests/CheckWebCore/wwwroot/validation/server-ts/login.html new file mode 100644 index 00000000000..691fb2b9d24 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/login.html @@ -0,0 +1,49 @@ +

Sign In using credentials

+ +
+
+
+ {{ '
{0}
' | htmlFormat(errorResponseExcept(['userName','password'])) }} + + +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com +
+
+ +{{#raw appendTo scripts}} + +{{/raw}} diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/login.js b/tests/CheckWebCore/wwwroot/validation/server-ts/login.js new file mode 100644 index 00000000000..5918b909282 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/login.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +client_1.bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. +client_1.bindHandlers({ + switchUser: function (u) { + document.querySelector("[name=userName]").value = u; + document.querySelector("[name=password]").value = 'p@55wOrd'; + } +}); +//# sourceMappingURL=login.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/login.js.map b/tests/CheckWebCore/wwwroot/validation/server-ts/login.js.map new file mode 100644 index 00000000000..80520b981b3 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/login.js.map @@ -0,0 +1 @@ +{"version":3,"file":"login.js","sourceRoot":"","sources":["login.ts"],"names":[],"mappings":";;AAAA,+CAA6D;AAE7D,kBAAS,EAAE,CAAC,CAAC,oEAAoE;AAEjF,qBAAY,CAAC;IACT,UAAU,EAAE,UAAC,CAAS;QACjB,QAAQ,CAAC,aAAa,CAAC,iBAAiB,CAAsB,CAAC,KAAK,GAAG,CAAC,CAAC;QACzE,QAAQ,CAAC,aAAa,CAAC,iBAAiB,CAAsB,CAAC,KAAK,GAAG,UAAU,CAAC;IACvF,CAAC;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/login.ts b/tests/CheckWebCore/wwwroot/validation/server-ts/login.ts new file mode 100644 index 00000000000..e3ca623a6b1 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/login.ts @@ -0,0 +1,10 @@ +import {bindHandlers, bootstrap} from "@servicestack/client"; + +bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. + +bindHandlers({ + switchUser: (u: string) => { + (document.querySelector("[name=userName]") as HTMLInputElement).value = u; + (document.querySelector("[name=password]") as HTMLInputElement).value = 'p@55wOrd'; + } +}); diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/register.html b/tests/CheckWebCore/wwwroot/validation/server-ts/register.html new file mode 100644 index 00000000000..17fc4eb23ff --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/register.html @@ -0,0 +1,43 @@ +

Register New User

+ +
+
+ {{ '
{0}
' + | htmlFormat(errorResponseExcept('displayName,email,password,confirmPassword')) }} + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ Quick Populate: +
+ new@user.com +
+
+
+ +{{#raw appendTo scripts}} + +{{/raw}} diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/register.js b/tests/CheckWebCore/wwwroot/validation/server-ts/register.js new file mode 100644 index 00000000000..a15245b3106 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/register.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +client_1.bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. +client_1.bindHandlers({ + newUser: function (u) { + var $ = function (sel) { return document.querySelector(sel); }; + var names = u.split('@'); + $("[name=displayName]").value = client_1.toPascalCase(names[0]) + " " + client_1.toPascalCase(client_1.splitOnFirst(names[1], '.')[0]); + $("[name=email]").value = u; + $("[name=password]").value = $("[name=confirmPassword]").value = 'p@55wOrd'; + } +}); +//# sourceMappingURL=register.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/register.js.map b/tests/CheckWebCore/wwwroot/validation/server-ts/register.js.map new file mode 100644 index 00000000000..ac084e6a914 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/register.js.map @@ -0,0 +1 @@ +{"version":3,"file":"register.js","sourceRoot":"","sources":["register.ts"],"names":[],"mappings":";;AAAA,+CAA2F;AAE3F,kBAAS,EAAE,CAAC,CAAC,oEAAoE;AAEjF,qBAAY,CAAC;IACT,OAAO,EAAE,UAAC,CAAS;QACf,IAAM,CAAC,GAAG,UAAC,GAAU,IAAK,OAAA,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAqB,EAA/C,CAA+C,CAAC;QAE1E,IAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC,CAAC,oBAAoB,CAAC,CAAC,KAAK,GAAG,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,qBAAY,CAAC,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3G,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QAC5B,CAAC,CAAC,iBAAiB,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,wBAAwB,CAAC,CAAC,KAAK,GAAG,UAAU,CAAC;IAChF,CAAC;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server-ts/register.ts b/tests/CheckWebCore/wwwroot/validation/server-ts/register.ts new file mode 100644 index 00000000000..902482a4180 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server-ts/register.ts @@ -0,0 +1,14 @@ +import { bindHandlers, bootstrap, splitOnFirst, toPascalCase } from "@servicestack/client"; + +bootstrap(); //converts data-invalid attributes into Bootstrap v4 error messages. + +bindHandlers({ + newUser: (u: string) => { + const $ = (sel:string) => document.querySelector(sel) as HTMLInputElement; + + const names = u.split('@'); + $("[name=displayName]").value = toPascalCase(names[0]) + " " + toPascalCase(splitOnFirst(names[1],'.')[0]); + $("[name=email]").value = u; + $("[name=password]").value = $("[name=confirmPassword]").value = 'p@55wOrd'; + } +}); diff --git a/tests/CheckWebCore/wwwroot/validation/server/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/validation/server/_requires-auth-partial.html new file mode 100644 index 00000000000..475e62d9358 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server/_requires-auth-partial.html @@ -0,0 +1,9 @@ +{{ `/validation/server/login?continue=${PathInfo}` + | redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
diff --git a/tests/CheckWebCore/wwwroot/validation/server/contacts/_id/edit.html b/tests/CheckWebCore/wwwroot/validation/server/contacts/_id/edit.html new file mode 100644 index 00000000000..958a4745760 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server/contacts/_id/edit.html @@ -0,0 +1,43 @@ +{{ 'requires-auth' | partial }} + +{{ '/validation/server/contacts/' | assignTo: continue }} + +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} + +{{#with response.Result}} +

Update Contact

+ +
+
+ {{ 'title,name,color,filmGenres,age' | validationSummary }} + {{ {continue,errorView:`/validation/server/contacts/${id}/edit`} | htmlHiddenInputs }} +
+
+ {{ {id:'title',type:'radio',value:Title} | formInput({values:contactTitles,inline:true}) }} +
+
+ {{ {id:'name',value:Name} | formInput({label:'Name'}) }} +
+
+ {{ {id:'color',class:'col-4',value:Color} + | formSelect({label:'Favorite color',values:contactColors}) }} +
+
+ {{ {id:'filmGenres',type:'checkbox',value:FilmGenres} | formInput({label:'Favorite Film Genres',values:contactGenres,help:"choose one or more"}) }} +
+
+ {{ {id:'age',type:'number',min:13,value:Age,class:'col-3'} | formInput({label:'Age'}) }} +
+
+ + cancel +
+
+{{else if ex}} +
+
{{ex.Message}}
+

< back

+
+{{/with}} + +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html new file mode 100644 index 00000000000..dce89ac85d5 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html @@ -0,0 +1,53 @@ +{{ 'requires-auth' | partial }} + +

Add new Contact

+ +
+
+ {{ 'title,name,color,age,filmGenres,agree' | validationSummary }} +
+
+ {{ {id:'title',type:'radio'} | formInput({values:contactTitles,inline:true}) }} +
+
+ {{ {id:'name',placeholder:'Name'} | formInput({label:'Full Name',help:'Your first and last name'}) }} +
+
+ {{ {id:'color',class:'col-4'} + | formSelect({label:'Favorite color',values:{'', ...contactColors}}) }} +
+
+ {{ {id:'filmGenres',type:'checkbox'} | formInput({label:'Favorite Film Genres',values:contactGenres,help:"choose one or more"}) }} +
+
+ {{ {id:'age',type:'number',min:13,placeholder:'Age',class:'col-3'} | formInput }} +
+
+ {{ {id:'agree',type:'checkbox'} | formInput({label:'Agree to terms and conditions'}) }} +
+
+ + reset +
+
+ +{{ sendToGateway('GetContacts') | assignTo: response }} + + + + {{#each response.Results}} + + + + + + {{else}} + + + + {{/each}} + +
{{Title}} {{Name}} ({{Age}})edit
+
There are no contacts.
+ +{{ htmlError }} diff --git a/tests/CheckWebCore/wwwroot/validation/server/index.html b/tests/CheckWebCore/wwwroot/validation/server/index.html new file mode 100644 index 00000000000..000879d9f5f --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server/index.html @@ -0,0 +1,17 @@ +

Server HTML Forms Validation Examples

+ +{{#if isAuthenticated}} + Hi {{userSession.DisplayName}}! + +{{else}} +

+ You're not authenticated, please Sign In: +

+ +{{/if}} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server/login.html b/tests/CheckWebCore/wwwroot/validation/server/login.html new file mode 100644 index 00000000000..0f37b3ad31e --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server/login.html @@ -0,0 +1,44 @@ +

Sign In using credentials

+ +
+
+ {{ ['userName','password'] | validationSummary({class:'alert alert-warning'}) }} + {{ { continue: qs.continue ?? '/validation/server/', errorView:'/validation/server/login' } | htmlHiddenInputs }} +
+
+ {{ {id:'userName'} + | formInput({label:'Email',help:'Email you signed up with',size:'lg'}) }} +
+
+ {{ {id:'password',type:'password'} + | formInput({label:'Password',help:'6 characters or more',size:'lg',preserveValue:false}) }} +
+
+ {{ {id:'rememberMe',type:'checkbox',checked:true} | formInput({label:'Remember Me'}) }} +
+
+ +
+ +
+ +
+ Quick Login: +
+ admin@email.com + new@user.com +
+
+ +{{#raw appendTo scripts}} + +{{/raw}} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/server/register.html b/tests/CheckWebCore/wwwroot/validation/server/register.html new file mode 100644 index 00000000000..2f605ac607f --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/server/register.html @@ -0,0 +1,50 @@ +

Register New User

+ +
+
+ {{ 'displayName,email,password,confirmPassword' | validationSummary }} + {{ { continue: '/validation/server/', errorView:'/validation/server/register' } | htmlHiddenInputs }} +
+
+ {{ {id:'displayName'} + | formInput({label:'Name',help:'Your first and last name',size:'lg'}) }} +
+
+ {{ {id:'email'} + | formInput({label:'Email',size:'lg'}) }} +
+
+ {{ {id:'password',type:'password'} + | formInput({label:'Password',help:'6 characters or more',size:'lg'}) }} +
+
+ {{ {id:'confirmPassword',type:'password'} + | formInput({label:'Confirm Password',size:'lg'}) }} +
+
+ {{ {id:'autoLogin',type:'checkbox',checked:true} | formInput({label:'Auto Login'}) }} +
+
+ +
+
+ +
+ Quick Populate: +
+ new@user.com +
+
+ +{{#raw appendTo scripts}} + +{{/raw}} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/_layout.html b/tests/CheckWebCore/wwwroot/validation/vuetify/_layout.html new file mode 100644 index 00000000000..bb27c1b6735 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/_layout.html @@ -0,0 +1,77 @@ + + + + + + {{#if debug}}{{/if}} + + +
+ + + + + + {{ page }} + + + + +
+ + + + + {{#if !debug}} + + + + + + {{else}} + {{ ['/lib/vue/dist/vue.js', + '/lib/vuetify/dist/vuetify.js', + '/lib/@servicestack/client/index.js', + '/dtos.js', + '/validation/vuetify/shared.js', + ] | bundleJs({ out: '/validation/vuetify/bundle.js' }) }} + {{/if}} + + + + +{{ scripts ?? `` | raw }} + + + \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/_requires-auth-partial.html b/tests/CheckWebCore/wwwroot/validation/vuetify/_requires-auth-partial.html new file mode 100644 index 00000000000..6cf89ca5d0c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/_requires-auth-partial.html @@ -0,0 +1,9 @@ +{{ `/validation/vuetify/login?continue=${PathInfo}` + | redirectIfNotAuthenticated }} + +
+ + {{ userSession.DisplayName }} + | Sign Out + +
diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.html new file mode 100644 index 00000000000..dfb76dd9fd7 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.html @@ -0,0 +1,123 @@ +{{ 'requires-auth' | partial }} + +{{#raw}} + +{{/raw}} + + +{{#capture appendTo scripts}} + + +{{/capture}} diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.js b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.js new file mode 100644 index 00000000000..4225971341c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.js @@ -0,0 +1,182 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var vue_1 = require("vue"); +var client_1 = require("@servicestack/client"); +var shared_1 = require("../shared"); +var dtos_1 = require("../../../dtos"); +new vue_1.Vue({ + el: '#app', + computed: { + heading: function () { + return this.update ? 'Edit new Contact' : 'Add new Contact'; + }, + action: function () { + return this.update ? 'Update Contact' : 'Add Contact'; + }, + errorSummary: function () { + return client_1.errorResponseExcept.call(this, 'title,name,color,filmGenres,age,agree'); + }, + }, + methods: { + submit: function () { + return __awaiter(this, void 0, void 0, function () { + var form, request, e_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + form = this.$refs.form; + if (!form.validate()) return [3 /*break*/, 10]; + _a.label = 1; + case 1: + _a.trys.push([1, 6, 7, 8]); + this.loading = true; + request = { + title: this.title, + name: this.name, + color: this.color, + filmGenres: this.filmGenres, + age: this.age, + }; + if (!this.update) return [3 /*break*/, 3]; + return [4 /*yield*/, shared_1.client.post(new dtos_1.UpdateContact(__assign({}, request, { id: this.id })))]; + case 2: + _a.sent(); + return [3 /*break*/, 5]; + case 3: return [4 /*yield*/, shared_1.client.post(new dtos_1.CreateContact(__assign({}, request, { agree: this.agree })))]; + case 4: + _a.sent(); + _a.label = 5; + case 5: + this.update = false; + this.responseStatus = null; + form.reset(); + return [3 /*break*/, 8]; + case 6: + e_1 = _a.sent(); + this.responseStatus = e_1.responseStatus || e_1; + return [3 /*break*/, 8]; + case 7: + this.loading = false; + form.resetValidation(); + return [7 /*endfinally*/]; + case 8: return [4 /*yield*/, this.refresh()]; + case 9: + _a.sent(); + _a.label = 10; + case 10: return [2 /*return*/]; + } + }); + }); + }, + refresh: function () { + return __awaiter(this, void 0, void 0, function () { + var _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + _a = this; + return [4 /*yield*/, shared_1.client.get(new dtos_1.GetContacts())]; + case 1: + _a.contacts = (_b.sent()).results; + return [2 /*return*/]; + } + }); + }); + }, + reset: function () { + this.$refs.form.reset(); + }, + cancel: function () { + this.reset(); + this.update = false; + }, + edit: function (id) { + return __awaiter(this, void 0, void 0, function () { + var contact; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + this.update = true; + return [4 /*yield*/, shared_1.client.get(new dtos_1.GetContact({ id: id }))]; + case 1: + contact = (_a.sent()).result; + console.log(contact); + Object.assign(this, contact); + return [2 /*return*/]; + } + }); + }); + }, + remove: function (id) { + return __awaiter(this, void 0, void 0, function () { + var response; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!confirm('Are you sure?')) + return [2 /*return*/]; + return [4 /*yield*/, shared_1.client.delete(new dtos_1.DeleteContact({ id: id }))]; + case 1: + _a.sent(); + return [4 /*yield*/, shared_1.client.get(new dtos_1.GetContacts())]; + case 2: + response = _a.sent(); + return [4 /*yield*/, this.refresh()]; + case 3: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }, + errorResponse: client_1.errorResponse + }, + data: function () { return (__assign({ loading: false, valid: true, update: false }, DATA, { id: 0, title: "", name: "", color: "", filmGenres: [], age: 13, agree: false, nameRules: shared_1.nameRules, responseStatus: null })); }, +}); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.js.map b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.js.map new file mode 100644 index 00000000000..fa59f6965a6 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2BAA0B;AAC1B,+CAAsG;AACtG,oCAA+C;AAC/C,sCAA0G;AAI1G,IAAI,SAAG,CAAC;IACJ,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE;QACN,OAAO,EAAE;YACL,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,iBAAiB,CAAC;QAChE,CAAC;QACD,MAAM,EAAE;YACJ,OAAO,IAAI,CAAC,MAAM,CAAA,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,aAAa,CAAC;QACzD,CAAC;QACD,YAAY,EAAE;YACV,OAAO,4BAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,uCAAuC,CAAC,CAAC;QACnF,CAAC;KACJ;IACD,OAAO,EAAE;QACC,MAAM;;;;;;4BACF,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,IAAwB,CAAC;iCAC9C,IAAI,CAAC,QAAQ,EAAE,EAAf,yBAAe;;;;4BAEX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;4BAEd,OAAO,GAAG;gCACZ,KAAK,EAAE,IAAI,CAAC,KAAc;gCAC1B,IAAI,EAAE,IAAI,CAAC,IAAI;gCACf,KAAK,EAAE,IAAI,CAAC,KAAK;gCACjB,UAAU,EAAE,IAAI,CAAC,UAAU;gCAC3B,GAAG,EAAE,IAAI,CAAC,GAAG;6BAChB,CAAC;iCAEE,IAAI,CAAC,MAAM,EAAX,wBAAW;4BACX,qBAAM,eAAM,CAAC,IAAI,CAAC,IAAI,oBAAa,cAAK,OAAO,IAAE,EAAE,EAAE,IAAI,CAAC,EAAE,IAAG,CAAC,EAAA;;4BAAhE,SAAgE,CAAC;;gCAEjE,qBAAM,eAAM,CAAC,IAAI,CAAC,IAAI,oBAAa,cAAK,OAAO,IAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAG,CAAC,EAAA;;4BAAtE,SAAsE,CAAC;;;4BAG3E,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;4BACpB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;4BAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;;;;4BAGb,IAAI,CAAC,cAAc,GAAG,GAAC,CAAC,cAAc,IAAI,GAAC,CAAC;;;4BAE5C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;4BACrB,IAAI,CAAC,eAAe,EAAE,CAAC;;gCAE3B,qBAAM,IAAI,CAAC,OAAO,EAAE,EAAA;;4BAApB,SAAoB,CAAC;;;;;;SAE5B;QACK,OAAO;;;;;;4BACT,KAAA,IAAI,CAAA;4BAAa,qBAAM,eAAM,CAAC,GAAG,CAAC,IAAI,kBAAW,EAAE,CAAC,EAAA;;4BAApD,GAAK,QAAQ,GAAG,CAAC,SAAmC,CAAC,CAAC,OAAO,CAAC;;;;;SACjE;QACD,KAAK;YACA,IAAI,CAAC,KAAK,CAAC,IAAwB,CAAC,KAAK,EAAE,CAAC;QACjD,CAAC;QACD,MAAM;YACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACxB,CAAC;QACK,IAAI,YAAC,EAAS;;;;;;4BAClB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;4BACF,qBAAM,eAAM,CAAC,GAAG,CAAC,IAAI,iBAAU,CAAC,EAAE,EAAE,IAAA,EAAE,CAAC,CAAC,EAAA;;4BAAnD,OAAO,GAAG,CAAC,SAAwC,CAAC,CAAC,MAAM;4BACjE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;4BACrB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;;;;;SAC9B;QACK,MAAM,YAAC,EAAS;;;;;;4BAClB,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;gCACzB,sBAAO;4BAEX,qBAAM,eAAM,CAAC,MAAM,CAAC,IAAI,oBAAa,CAAC,EAAE,EAAE,IAAA,EAAE,CAAC,CAAC,EAAA;;4BAA9C,SAA8C,CAAC;4BAC9B,qBAAM,eAAM,CAAC,GAAG,CAAC,IAAI,kBAAW,EAAE,CAAC,EAAA;;4BAA9C,QAAQ,GAAG,SAAmC;4BACpD,qBAAM,IAAI,CAAC,OAAO,EAAE,EAAA;;4BAApB,SAAoB,CAAC;;;;;SACxB;QACD,aAAa,wBAAA;KAChB;IACD,IAAI,EAAE,cAAM,OAAA,YACR,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,IAAI,EACX,MAAM,EAAE,KAAK,IACV,IAAI,IAEP,EAAE,EAAC,CAAC,EACJ,KAAK,EAAE,EAAE,EACT,IAAI,EAAE,EAAE,EACR,KAAK,EAAE,EAAE,EACT,UAAU,EAAE,EAAE,EACd,GAAG,EAAE,EAAE,EACP,KAAK,EAAE,KAAK,EACZ,SAAS,oBAAA,EACT,cAAc,EAAE,IAAI,IACtB,EAfU,CAeV;CACL,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.ts b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.ts new file mode 100644 index 00000000000..3e5d16f3169 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/contacts/index.ts @@ -0,0 +1,97 @@ +import { Vue } from 'vue'; +import { errorResponse, errorResponseExcept, splitOnFirst, toPascalCase } from '@servicestack/client'; +import { client, nameRules, } from '../shared'; +import {CreateContact, DeleteContact, GetContact, GetContacts, Title, UpdateContact} from '../../../dtos'; + +declare var DATA:any; + +new Vue({ + el: '#app', + computed: { + heading: function() { + return this.update ? 'Edit new Contact' : 'Add new Contact'; + }, + action: function() { + return this.update? 'Update Contact' : 'Add Contact'; + }, + errorSummary: function() { + return errorResponseExcept.call(this, 'title,name,color,filmGenres,age,agree'); + }, + }, + methods: { + async submit() { + const form = (this.$refs.form as HTMLFormElement); + if (form.validate()) { + try { + this.loading = true; + + const request = { + title: this.title as Title, + name: this.name, + color: this.color, + filmGenres: this.filmGenres, + age: this.age, + }; + + if (this.update) { + await client.post(new UpdateContact({...request, id: this.id })); + } else { + await client.post(new CreateContact({...request, agree: this.agree })); + } + + this.update = false; + this.responseStatus = null; + form.reset(); + + } catch (e) { + this.responseStatus = e.responseStatus || e; + } finally { + this.loading = false; + form.resetValidation(); + } + await this.refresh(); + } + }, + async refresh() { + this.contacts = (await client.get(new GetContacts())).results; + }, + reset() { + (this.$refs.form as HTMLFormElement).reset(); + }, + cancel() { + this.reset(); + this.update = false; + }, + async edit(id:number) { + this.update = true; + const contact = (await client.get(new GetContact({ id }))).result; + console.log(contact); + Object.assign(this, contact); + }, + async remove(id:number) { + if (!confirm('Are you sure?')) + return; + + await client.delete(new DeleteContact({ id })); + const response = await client.get(new GetContacts()); + await this.refresh(); + }, + errorResponse + }, + data: () => ({ + loading: false, + valid: true, + update: false, + ...DATA, + + id:0, + title: "", + name: "", + color: "", + filmGenres: [], + age: 13, + agree: false, + nameRules, + responseStatus: null + }), +}); diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/index.html b/tests/CheckWebCore/wwwroot/validation/vuetify/index.html new file mode 100644 index 00000000000..3b132b4e942 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/index.html @@ -0,0 +1,42 @@ + diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/login.html b/tests/CheckWebCore/wwwroot/validation/vuetify/login.html new file mode 100644 index 00000000000..856cfd2f0b1 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/login.html @@ -0,0 +1,70 @@ +{{#raw}} + +{{/raw}} + +{{#capture appendTo scripts}} + + +{{/capture}} diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/login.js b/tests/CheckWebCore/wwwroot/validation/vuetify/login.js new file mode 100644 index 00000000000..79cd53b55bc --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/login.js @@ -0,0 +1,101 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var vue_1 = require("vue"); +var client_1 = require("@servicestack/client"); +var shared_1 = require("./shared"); +var dtos_1 = require("../../dtos"); +new vue_1.Vue({ + el: '#app', + computed: { + errorSummary: function () { + return client_1.errorResponseExcept.call(this, 'userName,password'); + }, + }, + methods: { + submit: function () { + return __awaiter(this, void 0, void 0, function () { + var form, response, e_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + form = this.$refs.form; + if (!form.validate()) return [3 /*break*/, 5]; + _a.label = 1; + case 1: + _a.trys.push([1, 3, 4, 5]); + this.loading = true; + return [4 /*yield*/, shared_1.client.post(new dtos_1.Authenticate({ + provider: 'credentials', + userName: this.userName, + password: this.password, + rememberMe: this.rememberMe, + }))]; + case 2: + response = _a.sent(); + location.href = CONTINUE; + return [3 /*break*/, 5]; + case 3: + e_1 = _a.sent(); + this.responseStatus = e_1.responseStatus || e_1; + return [3 /*break*/, 5]; + case 4: + this.loading = false; + form.resetValidation(); + return [7 /*endfinally*/]; + case 5: return [2 /*return*/]; + } + }); + }); + }, + switchUser: function (email) { + this.userName = email; + this.password = 'p@55wOrd'; + }, + errorResponse: client_1.errorResponse + }, + data: function () { return ({ + loading: false, + valid: true, + userName: "", + password: "", + rememberMe: true, + emailRules: shared_1.emailRules, passwordRules: shared_1.passwordRules, + responseStatus: null + }); }, +}); +//# sourceMappingURL=login.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/login.js.map b/tests/CheckWebCore/wwwroot/validation/vuetify/login.js.map new file mode 100644 index 00000000000..ad0a0ec2f44 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/login.js.map @@ -0,0 +1 @@ +{"version":3,"file":"login.js","sourceRoot":"","sources":["login.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2BAA0B;AAC1B,+CAA0E;AAC1E,mCAA6D;AAC7D,mCAA0C;AAI1C,IAAI,SAAG,CAAC;IACJ,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE;QACN,YAAY,EAAE;YACV,OAAO,4BAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAC/D,CAAC;KACJ;IACD,OAAO,EAAE;QACC,MAAM;;;;;;4BACF,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,IAAwB,CAAC;iCAC9C,IAAI,CAAC,QAAQ,EAAE,EAAf,wBAAe;;;;4BAEX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;4BAEH,qBAAM,eAAM,CAAC,IAAI,CAAC,IAAI,mBAAY,CAAC;oCAChD,QAAQ,EAAE,aAAa;oCACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oCACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oCACvB,UAAU,EAAE,IAAI,CAAC,UAAU;iCAC9B,CAAC,CAAC,EAAA;;4BALG,QAAQ,GAAG,SAKd;4BAEH,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC;;;;4BAEzB,IAAI,CAAC,cAAc,GAAG,GAAC,CAAC,cAAc,IAAI,GAAC,CAAC;;;4BAE5C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;4BACrB,IAAI,CAAC,eAAe,EAAE,CAAC;;;;;;SAGlC;QACD,UAAU,YAAC,KAAY;YACnB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC;QAC/B,CAAC;QACD,aAAa,wBAAA;KAChB;IACD,IAAI,EAAE,cAAM,OAAA,CAAC;QACT,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,IAAI;QAChB,UAAU,qBAAA,EAAE,aAAa,wBAAA;QACzB,cAAc,EAAE,IAAI;KACvB,CAAC,EARU,CAQV;CACL,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/login.ts b/tests/CheckWebCore/wwwroot/validation/vuetify/login.ts new file mode 100644 index 00000000000..3fefa3d7d71 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/login.ts @@ -0,0 +1,54 @@ +import { Vue } from 'vue'; +import { errorResponse, errorResponseExcept } from '@servicestack/client'; +import { client, emailRules, passwordRules } from './shared'; +import { Authenticate } from "../../dtos"; + +declare var CONTINUE:any; + +new Vue({ + el: '#app', + computed: { + errorSummary: function() { + return errorResponseExcept.call(this, 'userName,password'); + }, + }, + methods: { + async submit() { + const form = (this.$refs.form as HTMLFormElement); + if (form.validate()) { + try { + this.loading = true; + + const response = await client.post(new Authenticate({ + provider: 'credentials', + userName: this.userName, + password: this.password, + rememberMe: this.rememberMe, + })); + + location.href = CONTINUE; + } catch (e) { + this.responseStatus = e.responseStatus || e; + } finally { + this.loading = false; + form.resetValidation(); + } + } + }, + switchUser(email:string) { + this.userName = email; + this.password = 'p@55wOrd'; + }, + errorResponse + }, + data: () => ({ + loading: false, + valid: true, + userName: "", + password: "", + rememberMe: true, + emailRules, passwordRules, + responseStatus: null + }), +}); + diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/register.html b/tests/CheckWebCore/wwwroot/validation/vuetify/register.html new file mode 100644 index 00000000000..6706b787290 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/register.html @@ -0,0 +1,82 @@ +{{#raw}} + +{{/raw}} + +{{#capture appendTo scripts}} + +{{/capture}} diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/register.js b/tests/CheckWebCore/wwwroot/validation/vuetify/register.js new file mode 100644 index 00000000000..ad403a2b0db --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/register.js @@ -0,0 +1,106 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var vue_1 = require("vue"); +var client_1 = require("@servicestack/client"); +var shared_1 = require("./shared"); +var dtos_1 = require("../../dtos"); +new vue_1.Vue({ + el: '#app', + computed: { + errorSummary: function () { + return client_1.errorResponseExcept.call(this, 'displayName,email,password,confirmPassword'); + }, + }, + methods: { + submit: function () { + return __awaiter(this, void 0, void 0, function () { + var form, response, e_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + form = this.$refs.form; + if (!form.validate()) return [3 /*break*/, 5]; + _a.label = 1; + case 1: + _a.trys.push([1, 3, 4, 5]); + this.loading = true; + return [4 /*yield*/, shared_1.client.post(new dtos_1.Register({ + displayName: this.displayName, + email: this.email, + password: this.password, + confirmPassword: this.confirmPassword, + autoLogin: this.autoLogin, + }))]; + case 2: + response = _a.sent(); + location.href = '/validation/vuetify/'; + return [3 /*break*/, 5]; + case 3: + e_1 = _a.sent(); + this.responseStatus = e_1.responseStatus || e_1; + return [3 /*break*/, 5]; + case 4: + this.loading = false; + form.resetValidation(); + return [7 /*endfinally*/]; + case 5: return [2 /*return*/]; + } + }); + }); + }, + switchUser: function (email) { + var names = email.split('@'); + this.displayName = client_1.toPascalCase(names[0]) + ' ' + client_1.toPascalCase(client_1.splitOnFirst(names[1], '.')[0]); + this.email = email; + this.password = this.confirmPassword = 'p@55wOrd'; + }, + errorResponse: client_1.errorResponse + }, + data: function () { return ({ + loading: false, + valid: true, + displayName: "", + email: "", + password: "", + confirmPassword: "", + autoLogin: true, + nameRules: shared_1.nameRules, emailRules: shared_1.emailRules, passwordRules: shared_1.passwordRules, confirmPasswordRules: shared_1.confirmPasswordRules, + responseStatus: null + }); }, +}); +//# sourceMappingURL=register.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/register.js.map b/tests/CheckWebCore/wwwroot/validation/vuetify/register.js.map new file mode 100644 index 00000000000..8ad2b65c081 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/register.js.map @@ -0,0 +1 @@ +{"version":3,"file":"register.js","sourceRoot":"","sources":["register.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2BAA0B;AAC1B,+CAAsG;AACtG,mCAA8F;AAC9F,mCAAsC;AAItC,IAAI,SAAG,CAAC;IACJ,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE;QACN,YAAY,EAAE;YACV,OAAO,4BAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,4CAA4C,CAAC,CAAC;QACxF,CAAC;KACJ;IACD,OAAO,EAAE;QACC,MAAM;;;;;;4BACF,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,IAAwB,CAAC;iCAC9C,IAAI,CAAC,QAAQ,EAAE,EAAf,wBAAe;;;;4BAEX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;4BAEH,qBAAM,eAAM,CAAC,IAAI,CAAC,IAAI,eAAQ,CAAC;oCAC5C,WAAW,EAAE,IAAI,CAAC,WAAW;oCAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;oCACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oCACvB,eAAe,EAAE,IAAI,CAAC,eAAe;oCACrC,SAAS,EAAE,IAAI,CAAC,SAAS;iCAC5B,CAAC,CAAC,EAAA;;4BANG,QAAQ,GAAG,SAMd;4BAEH,QAAQ,CAAC,IAAI,GAAG,sBAAsB,CAAC;;;;4BAEvC,IAAI,CAAC,cAAc,GAAG,GAAC,CAAC,cAAc,IAAI,GAAC,CAAC;;;4BAE5C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;4BACrB,IAAI,CAAC,eAAe,EAAE,CAAC;;;;;;SAGlC;QACD,UAAU,YAAC,KAAY;YACnB,IAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,WAAW,GAAG,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,qBAAY,CAAC,qBAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/F,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;QACtD,CAAC;QACD,aAAa,wBAAA;KAChB;IACD,IAAI,EAAE,cAAM,OAAA,CAAC;QACT,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,EAAE;QACf,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,EAAE;QACZ,eAAe,EAAE,EAAE;QACnB,SAAS,EAAE,IAAI;QACf,SAAS,oBAAA,EAAE,UAAU,qBAAA,EAAE,aAAa,wBAAA,EAAE,oBAAoB,+BAAA;QAC1D,cAAc,EAAE,IAAI;KACvB,CAAC,EAVU,CAUV;CACL,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/register.ts b/tests/CheckWebCore/wwwroot/validation/vuetify/register.ts new file mode 100644 index 00000000000..56edec7fa5b --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/register.ts @@ -0,0 +1,58 @@ +import { Vue } from 'vue'; +import { errorResponse, errorResponseExcept, splitOnFirst, toPascalCase } from '@servicestack/client'; +import { client, nameRules, emailRules, passwordRules, confirmPasswordRules } from './shared'; +import { Register } from '../../dtos'; + +declare var CONTINUE:any; + +new Vue({ + el: '#app', + computed: { + errorSummary: function() { + return errorResponseExcept.call(this, 'displayName,email,password,confirmPassword'); + }, + }, + methods: { + async submit() { + const form = (this.$refs.form as HTMLFormElement); + if (form.validate()) { + try { + this.loading = true; + + const response = await client.post(new Register({ + displayName: this.displayName, + email: this.email, + password: this.password, + confirmPassword: this.confirmPassword, + autoLogin: this.autoLogin, + })); + + location.href = '/validation/vuetify/'; + } catch (e) { + this.responseStatus = e.responseStatus || e; + } finally { + this.loading = false; + form.resetValidation(); + } + } + }, + switchUser(email:string) { + const names = email.split('@'); + this.displayName = toPascalCase(names[0]) + ' ' + toPascalCase(splitOnFirst(names[1], '.')[0]); + this.email = email; + this.password = this.confirmPassword = 'p@55wOrd'; + }, + errorResponse + }, + data: () => ({ + loading: false, + valid: true, + displayName: "", + email: "", + password: "", + confirmPassword: "", + autoLogin: true, + nameRules, emailRules, passwordRules, confirmPasswordRules, + responseStatus: null + }), +}); diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/shared.js b/tests/CheckWebCore/wwwroot/validation/vuetify/shared.js new file mode 100644 index 00000000000..0a60aac1608 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/shared.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var client_1 = require("@servicestack/client"); +exports.client = new client_1.JsonServiceClient(); +exports.nameRules = [ + function (v) { return !!v || 'Name is required'; }, +]; +exports.emailRules = [ + function (v) { return !!v || 'E-mail is required'; }, + function (v) { return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mail must be valid'; } +]; +exports.passwordRules = [ + function (v) { return !!v || 'Password is required'; }, + function (v) { return v.length > 6 || 'Password must be grater than 6 characters'; } +]; +exports.confirmPasswordRules = [ + function (v) { return !!v || 'Password is required'; } +]; +//# sourceMappingURL=shared.js.map \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/shared.js.map b/tests/CheckWebCore/wwwroot/validation/vuetify/shared.js.map new file mode 100644 index 00000000000..95a663280a4 --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/shared.js.map @@ -0,0 +1 @@ +{"version":3,"file":"shared.js","sourceRoot":"","sources":["shared.ts"],"names":[],"mappings":";;AAAA,+CAAyD;AAE5C,QAAA,MAAM,GAAG,IAAI,0BAAiB,EAAE,CAAC;AAEjC,QAAA,SAAS,GAAG;IACrB,UAAC,CAAQ,IAAK,OAAA,CAAC,CAAC,CAAC,IAAI,kBAAkB,EAAzB,CAAyB;CAC1C,CAAC;AAEW,QAAA,UAAU,GAAG;IACtB,UAAC,CAAQ,IAAK,OAAA,CAAC,CAAC,CAAC,IAAI,oBAAoB,EAA3B,CAA2B;IACzC,UAAC,CAAQ,IAAK,OAAA,+CAA+C,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,sBAAsB,EAAjF,CAAiF;CAClG,CAAC;AAEW,QAAA,aAAa,GAAG;IACzB,UAAC,CAAQ,IAAK,OAAA,CAAC,CAAC,CAAC,IAAI,sBAAsB,EAA7B,CAA6B;IAC3C,UAAC,CAAQ,IAAK,OAAA,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,2CAA2C,EAA3D,CAA2D;CAC5E,CAAC;AAEW,QAAA,oBAAoB,GAAG;IAChC,UAAC,CAAQ,IAAK,OAAA,CAAC,CAAC,CAAC,IAAI,sBAAsB,EAA7B,CAA6B;CAC9C,CAAC"} \ No newline at end of file diff --git a/tests/CheckWebCore/wwwroot/validation/vuetify/shared.ts b/tests/CheckWebCore/wwwroot/validation/vuetify/shared.ts new file mode 100644 index 00000000000..e9a4cc8540c --- /dev/null +++ b/tests/CheckWebCore/wwwroot/validation/vuetify/shared.ts @@ -0,0 +1,21 @@ +import { JsonServiceClient } from "@servicestack/client"; + +export const client = new JsonServiceClient(); + +export const nameRules = [ + (v:string) => !!v || 'Name is required', +]; + +export const emailRules = [ + (v:string) => !!v || 'E-mail is required', + (v:string) => /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mail must be valid' +]; + +export const passwordRules = [ + (v:string) => !!v || 'Password is required', + (v:string) => v.length > 6 || 'Password must be grater than 6 characters' +]; + +export const confirmPasswordRules = [ + (v:string) => !!v || 'Password is required' +]; diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props new file mode 100644 index 00000000000..7eb7717eab3 --- /dev/null +++ b/tests/Directory.Build.props @@ -0,0 +1,29 @@ + + + + 6.0.3 + latest + false + + + + DEBUG + + + + $(DefineConstants);NETFX;NET472 + + + + $(DefineConstants);NETCORE;NETSTANDARD2_0 + + + + $(DefineConstants);NET6_0;NET6_0_OR_GREATER + + + + $(DefineConstants);NETCORE;NETCORE_SUPPORT + + + diff --git a/tests/MasterHost/Global.asax b/tests/MasterHost/Global.asax deleted file mode 100644 index 3f2deff3e92..00000000000 --- a/tests/MasterHost/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="MasterHost.Global" Language="C#" %> diff --git a/tests/MasterHost/Global.asax.cs b/tests/MasterHost/Global.asax.cs deleted file mode 100644 index 6f4bba140a9..00000000000 --- a/tests/MasterHost/Global.asax.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.Serialization; -using ServiceStack.Common.Utils; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Support; - -namespace MasterHost -{ - [DataContract] - [Description("ServiceStack's Hello World web service.")] - [RestService("/hello")] - [RestService("/hello/{Name}")] - [RestService("/hi/{Name}")] - public class Hello - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class HelloResponse - { - [DataMember] - public string Result { get; set; } - } - - public class HelloService : IService - { - public object Execute(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } - } - - public class AppConfig - { - public AppConfig() {} - - public AppConfig(IResourceManager appSettings) - { - this.RunOnBaseUrl = appSettings.GetString("RunOnBaseUrl"); - this.TestPaths = appSettings.GetList("TestPaths"); - - this.HandlerHosts = appSettings.GetList("HandlerHosts"); - this.HandlerHostNames = appSettings.GetList("HandlerHostNames"); - } - - public string RunOnBaseUrl { get; set; } - public IList TestPaths { get; set; } - - public IList HandlerHosts { get; set; } - public IList HandlerHostNames { get; set; } - } - - public class AppHost : AppHostBase - { - public AppHost() - : base("Master Test Host", typeof(HelloService).Assembly) { } - - public override void Configure(Funq.Container container) - { - SetConfig(new EndpointHostConfig { DebugMode = true }); - - container.Register(c => - new OrmLiteConnectionFactory( - "~/reports.sqlite".MapHostAbsolutePath(), - SqliteOrmLiteDialectProvider.Instance)); - - container.Register(new AppConfig(new ConfigurationResourceManager())); - - //Create Report table if not exists - container.Resolve().Exec(dbCmd => - { - dbCmd.CreateTable(false); - dbCmd.CreateTable(false); - }); - } - } - - public class Global : System.Web.HttpApplication - { - protected void Application_Start(object sender, EventArgs e) - { - new AppHost().Init(); - } - } -} - diff --git a/tests/MasterHost/MasterHost.csproj b/tests/MasterHost/MasterHost.csproj deleted file mode 100644 index e5009b9a22f..00000000000 --- a/tests/MasterHost/MasterHost.csproj +++ /dev/null @@ -1,159 +0,0 @@ - - - - Debug - AnyCPU - - - 2.0 - {12FA52E0-E648-42B3-9F67-782011AD20C4} - {349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - MasterHost - MasterHost - v3.5 - false - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - AnyCPU - - - pdbonly - true - bin\ - TRACE - prompt - 4 - AnyCPU - - - bin\ - TRACE - true - pdbonly - AnyCPU - bin\MasterHost.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - - - - ..\..\lib\tests\Mono.Data.Sqlite.dll - - - ..\..\lib\tests\nunit.framework.dll - - - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - - - - - - - - - - - - - - - - ..\..\lib\ServiceStack.Text.dll - - - - - sqlite3.dll - - - - - - - - - Designer - - - - - - Global.asax - - - - - - - - - - - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface - - - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} - ServiceStack - - - - - - - - - True - True - 1262 - / - http://localhost/MasterHost - False - False - - - False - - - - - - - - - - - \ No newline at end of file diff --git a/tests/MasterHost/Properties/AssemblyInfo.cs b/tests/MasterHost/Properties/AssemblyInfo.cs deleted file mode 100644 index e8d468b444b..00000000000 --- a/tests/MasterHost/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MasterHosts")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("MasterHosts")] -[assembly: AssemblyCopyright("Copyright © 2011")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("d5f40e74-c6ff-4174-b434-dcb24193d232")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/MasterHost/ReportTests.cs b/tests/MasterHost/ReportTests.cs deleted file mode 100644 index 3cf148b78b6..00000000000 --- a/tests/MasterHost/ReportTests.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support; - -namespace MasterHost -{ - [TestFixture] - public class ReportTests - { - //IIS7.0 - //private readonly AppConfig Config = new AppConfig - //{ - // RunOnBaseUrl = "http://localhost", - // TestPaths = "/,/metadata,/metadata/,/hello,/hello/,/hello/world,/hello/world/1,/hello/world/2,/hello/world/2/3".To>(), - // HandlerHosts = "/ApiPath35/api,/CustomPath35/api,/CustomPath40/api,/RootPath35,/RootPath40,:82,:83,:5001/api,:5002/api,:5003,:5004".To>(), - // HandlerHostNames = "IIS7+3.5,IIS7+3.5,IIS7+4.0,IIS7+3.5,IIS7+4.0,ConsoleApp,WindowsService,WebServer20,WebServer40,WebServer20,WebServer40".To>(), - //}; - - //MONO+FastCGI + xsp :8080 + ConsoleApp + :82 - //private readonly AppConfig Config = new AppConfig - //{ - // RunOnBaseUrl = "http://servicestack.net", - // TestPaths = "/,/metadata,/metadata/,/hello,/hello/,/hello/world,/hello/world/1,/hello/world/2,/hello/world/2/3".To>(), - // HandlerHosts = "/ApiPath35/api,/CustomPath35/api,/CustomPath40/api,/RootPath35,/RootPath40,:82,:8080/ApiPath35/api,:8080/CustomPath35/api,:8080/CustomPath40/api,:8080/RootPath35,:8080/RootPath40".To>(), - // HandlerHostNames = "Nginx/FastCGI,Nginx/FastCGI,Nginx/FastCGI,Nginx/FastCGI,Nginx/FastCGI,ConsoleApp,xsp2,xsp4,xsp2,xsp4".To>(), - //}; - - //MONO + Apache+mod_mono - private readonly AppConfig Config = new AppConfig - { - RunOnBaseUrl = "http://api.servicestack.net", - TestPaths = "/,/metadata,/metadata/,/hello,/hello/,/hello/world,/hello/world/1,/hello/world/2,/hello/world/2/3".To>(), - HandlerHosts = "/ApiPath35/api,/CustomPath35/api,/CustomPath40/api,/RootPath35,/RootPath40".To>(), - HandlerHostNames = "Apache+mod_mono2,Apache+mod_mono2,Apache+mod_mono2,Apache+mod_mono2,Apache+mod_mono2".To>(), - }; - - private const string DbPath = @"C:\src\ServiceStack\tests\MasterHost\\reports.sqlite"; - - private readonly IDbConnectionFactory DbFactory = new OrmLiteConnectionFactory( - DbPath, SqliteOrmLiteDialectProvider.Instance); - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - DbFactory.Exec(dbCmd => - { - dbCmd.CreateTable(false); - dbCmd.CreateTable(false); - }); - } - - //[Test] - //public void Run_RunReportsService() - //{ - // var appHost = new BasicAppHost(); - // appHost.Container.Register(c => new ReportsService { DbFactory = DbFactory }); - // var service = new RunReportsService - // { - // Config = Config, - // DbFactory = DbFactory, - // AppHost = appHost, - // }; - - // var response = service.Get(new RunReports { RunType = "all" }); - - // Console.WriteLine(response.Dump()); - //} - } -} \ No newline at end of file diff --git a/tests/MasterHost/ReportsService.cs b/tests/MasterHost/ReportsService.cs deleted file mode 100644 index 98f647e1cad..00000000000 --- a/tests/MasterHost/ReportsService.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.Serialization; -using ServiceStack.Common; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace MasterHost -{ - [DataContract] - [Description("View last results of ServiceStack's runners")] - [RestService("/reports")] - [RestService("/reports/{Name}")] - public class Reports - { - [DataMember] - public string FilterHost { get; set; } - } - - [DataContract] - public class ReportsResponse : IHasResponseStatus - { - public ReportsResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Results = new List(); - } - - [DataMember] - public List Results { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - [DataContract] - public class Report - { - public Report() - { - this.Tests = new List(); - } - - //[DataMember] - public string Id { get; set; } - - [DataMember] - public string HostEnvironment { get; set; } - - [DataMember] - public string BaseUrl { get; set; } - - [DataMember] - public DateTime LastModified { get; set; } - - [DataMember] - public string Host { get; set; } - - [DataMember] - public string ServiceName { get; set; } - - [DataMember] - public string UserHostAddress { get; set; } - - [DataMember] - public int MaxStatusCode { get; set; } - - [DataMember] - public List Tests { get; set; } - } - - [DataContract] - public class ReportTest - { - [DataMember] - public string RequestPath { get; set; } - - [DataMember] - public string AbsoluteUri { get; set; } - - [DataMember] - public string RawUrl { get; set; } - - [DataMember] - public string PathInfo { get; set; } - - [DataMember] - public string ResponseContentType { get; set; } - - [DataMember] - public int StatusCode { get; set; } - - [DataMember] - public string ErrorCode { get; set; } - - [DataMember] - public string ErrorMessage { get; set; } - - [DataMember] - public string StackTrace { get; set; } - } - - - public class ReportsService : RestServiceBase - { - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnGet(Reports request) - { - var response = new ReportsResponse - { - Results = request.FilterHost.IsNullOrEmpty() - ? DbFactory.Exec(dbCmd => dbCmd.Select()) - : DbFactory.Exec(dbCmd => dbCmd.Select("ServiceName = {0}", request.FilterHost)) - }; - return response; - } - } - - -} \ No newline at end of file diff --git a/tests/MasterHost/RunReportsService.cs b/tests/MasterHost/RunReportsService.cs deleted file mode 100644 index 8bf16258479..00000000000 --- a/tests/MasterHost/RunReportsService.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Net; -using System.Runtime.Serialization; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.OrmLite; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints.Support; - -namespace MasterHost -{ - [DataContract] - [Description("RunType=[all|pathsonly|portsonly], Filter=[PathHostNameFilter|PortFilter], e.g [handler.wildcard35|5000]")] - [RestService("/runreports")] - [RestService("/runreports/{RunType}")] - [RestService("/runreports/{RunType}/{Filter}")] - public class RunReports - { - [DataMember] - public string RunType { get; set; } - - [DataMember] - public string Filter { get; set; } - } - - [DataContract] - public class RunReportsResponse : IHasResponseStatus - { - public RunReportsResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class RunReportsService : RestServiceBase - { - public AppConfig Config { get; set; } - - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnGet(RunReports request) - { - if (!request.RunType.IsNullOrEmpty()) - { - var runType = request.RunType.ToLower(); - if (runType != "all" && runType != "pathsonly" && runType != "portsonly") - throw new ArgumentException("RunType=[all|pathsonly|portsonly]", "RunType"); - - var runPaths = runType == "all" || runType == "pathsonly"; - var runPorts = runType == "all" || runType == "portsonly"; - - for (var i = 0; i < Config.HandlerHosts.Count; i++) - { - var hostPath = Config.HandlerHosts[i]; - var hostName = Config.HandlerHostNames[i]; - - if (!request.Filter.IsNullOrEmpty() && hostPath != request.Filter) continue; - - var isPort = hostPath.Contains(":"); - var isPath = !isPort; - if (isPort && !runPorts) continue; - if (isPath && !runPaths) continue; - - var baseUrl = Config.RunOnBaseUrl + hostPath; - DoRequestInfo(new Report - { - Id = hostName + "-" + hostPath, - HostEnvironment = hostName, - BaseUrl = baseUrl, - }, - Config.TestPaths); - } - } - - return base.ResolveService().Get( - new Reports { FilterHost = request.Filter }); - } - - private void DoRequestInfo(Report report, IEnumerable testPaths) - { - report.LastModified = DateTime.UtcNow; - var restClient = new JsonServiceClient(report.BaseUrl); - - report.MaxStatusCode = 0; - foreach (var testPath in testPaths) - { - var test = new ReportTest { RequestPath = testPath }; - report.Tests.Add(test); - try - { - if (testPath.Contains("_requestinfo")) - { - var requestInfo = restClient.Get(testPath); - - if (report.ServiceName == null) - { - report.Host = requestInfo.Host; - report.ServiceName = requestInfo.ServiceName; - report.UserHostAddress = requestInfo.UserHostAddress; - } - - test.StatusCode = 200; - test.AbsoluteUri = requestInfo.AbsoluteUri; - test.PathInfo = requestInfo.PathInfo; - test.RawUrl = requestInfo.RawUrl; - test.ResponseContentType = requestInfo.ResponseContentType; - } - else - { - var webReq = (HttpWebRequest)WebRequest.Create(report.BaseUrl + testPath); - webReq.Accept = ContentType.Json; - - var webRes = (HttpWebResponse)webReq.GetResponse(); - test.ResponseContentType = webRes.ContentType; - test.StatusCode = (int)webRes.StatusCode; - } - - report.MaxStatusCode = Math.Max(report.MaxStatusCode, (int)HttpStatusCode.OK); - } - catch (WebServiceException webEx) - { - report.MaxStatusCode = Math.Max(report.MaxStatusCode, webEx.StatusCode); - test.StatusCode = webEx.StatusCode; - test.ErrorCode = webEx.ErrorCode; - test.ErrorMessage = webEx.ErrorMessage; - //report.StackTrace = webEx.ServerStackTrace; - } - catch (Exception ex) - { - var webEx = ex as WebException; - if (webEx != null) - { - report.MaxStatusCode = Math.Max(report.MaxStatusCode, - (int)webEx.Status == default(int) ? 600 : (int)webEx.Status); - - test.ErrorCode = ex.GetType().Name; - test.ErrorMessage = ex.Message; - } - else - { - report.MaxStatusCode = Math.Max(report.MaxStatusCode, 600); - - test.ErrorCode = ex.GetType().Name; - test.ErrorMessage = ex.Message; - } - //report.StackTrace = ex.StackTrace; - } - finally - { - DbFactory.Exec(dbCmd => dbCmd.Save(report)); - } - } - } - } -} \ No newline at end of file diff --git a/tests/MasterHost/RunRequestInfoService.cs b/tests/MasterHost/RunRequestInfoService.cs deleted file mode 100644 index 78fed0b8d3f..00000000000 --- a/tests/MasterHost/RunRequestInfoService.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Net; -using System.Runtime.Serialization; -using ServiceStack; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support; - -namespace MasterHost -{ - [DataContract] - [Description("RunType=[all|pathsonly|portsonly]")] - [RestService("/requestinfo")] - [RestService("/requestinfo/{RunType}")] - public class RunRequestInfo - { - [DataMember] - public string RunType { get; set; } - - [DataMember] - public string Filter { get; set; } - } - - [DataContract] - public class RunRequestInfoResponse : IHasResponseStatus - { - public RunRequestInfoResponse() - { - this.ResponseStatus = new ResponseStatus(); - - this.Results = new List(); - } - - [DataMember] - public List Results { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class RunRequestInfoService : RestServiceBase - { - static RunRequestInfoService() - { - //Tell OrmLite what to use for the primary key - ModelConfig.Id(x => x.Host); - } - - public AppConfig Config { get; set; } - - public IDbConnectionFactory DbFactory { get; set; } - - public override object OnGet(RunRequestInfo request) - { - if (!request.RunType.IsNullOrEmpty()) - { - var runType = request.RunType.ToLower(); - if (runType != "all" && runType != "pathsonly" && runType != "portsonly") - throw new ArgumentException("Required [ all | pathsonly | portsonly ]", "RunType"); - - var runPaths = runType == "all" || runType == "pathsonly"; - var runPorts = runType == "all" || runType == "portsonly"; - - for (var i = 0; i < Config.HandlerHosts.Count; i++) - { - var hostPath = Config.HandlerHosts[i]; - var hostName = Config.HandlerHostNames[i]; - - if (!request.Filter.IsNullOrEmpty() && hostPath != request.Filter) continue; - - var isPort = hostPath.Contains(":"); - var isPath = !isPort; - if (isPort && !runPorts) continue; - if (isPath && !runPaths) continue; - - var baseUrl = Config.RunOnBaseUrl + hostPath; - DoRequestInfo(hostName, hostPath, baseUrl, new[] { "/_requestinfo" }); - } - } - - return new RunRequestInfoResponse - { - Results = DbFactory.Exec(dbCmd => dbCmd.Select()) - }; - } - - public void DoRequestInfo(string hostName, string hostPath, string baseUrl, IEnumerable testPaths) - { - foreach (var testPath in testPaths) - { - var requestUrl = PathUtils.CombinePaths(baseUrl, testPath); - RequestInfoResponse requestInfo = null; - - try - { - var webReq = (HttpWebRequest)WebRequest.Create(requestUrl); - webReq.Accept = ContentType.Json; - var webRes = (HttpWebResponse)webReq.GetResponse(); - - var contents = new StreamReader(webRes.GetResponseStream()).ReadToEnd(); - - if (webRes.ContentType.StartsWith(ContentType.Json)) - { - requestInfo = JsonSerializer.DeserializeFromString(contents); - } - else - { - requestInfo = new RequestInfoResponse - { - Host = requestUrl, - Path = testPath, - ContentType = webRes.ContentType, - }; - } - requestInfo.Host = "

" + testPath + "

" + requestInfo.Host; - requestInfo.Status = (int)webRes.StatusCode; - requestInfo.ContentLength = webRes.ContentLength; - } - catch (Exception ex) - { - requestInfo = new RequestInfoResponse - { - Host = "

" + testPath + "

" + requestUrl, - Path = testPath, - ErrorCode = ex.GetType().Name, - ErrorMessage = ex.Message, - Status = 600, - }; - var webEx = ex as WebException; - if (webEx != null) - { - requestInfo.Status = (int)webEx.Status; - } - } - finally - { - DbFactory.Exec(dbCmd => dbCmd.Save(requestInfo)); - } - } - } - } - -} \ No newline at end of file diff --git a/tests/MasterHost/Web.config b/tests/MasterHost/Web.config deleted file mode 100644 index b1f38c3a443..00000000000 --- a/tests/MasterHost/Web.config +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - -
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/MasterHost/default.htm b/tests/MasterHost/default.htm deleted file mode 100644 index 30fada4d992..00000000000 --- a/tests/MasterHost/default.htm +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/tests/MasterHost/reports.sqlite b/tests/MasterHost/reports.sqlite deleted file mode 100644 index 2b60d52f31d..00000000000 Binary files a/tests/MasterHost/reports.sqlite and /dev/null differ diff --git a/tests/MasterHost/testreports/2011-03-05/RunReports-Windows.htm b/tests/MasterHost/testreports/2011-03-05/RunReports-Windows.htm deleted file mode 100644 index 71968a73109..00000000000 --- a/tests/MasterHost/testreports/2011-03-05/RunReports-Windows.htm +++ /dev/null @@ -1,372 +0,0 @@ - - - -RunReports Snapshot of 05/03/2011 00:59:35 - - - - - -
- -

Snapshot of RunReports generated by ServiceStack on 05/03/2011 00:59:35

- -
- view json datasource - from original url: - http://localhost/MasterHost/runreports - in other formats: - json - xml - csv - jsv -
- -
- -
-

This reports json data source

- - -
- -
Results
Host Environment Base Url Last Modified Max Status Code Tests
IIS7+3.5http://localhost/CustomPath35/api2011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+4.0http://localhost/CustomPath40/api2011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+3.5http://localhost/RootPath352011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+4.0http://localhost/RootPath402011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
ConsoleApphttp://localhost:822011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WindowsServicehttp://localhost:832011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer20http://localhost:5001/api2011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer40http://localhost:5002/api2011/03/05200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer20http://localhost:50032011/03/05200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer40http://localhost:50042011/03/05200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Response Status
Errors
- -
- - - - - - \ No newline at end of file diff --git a/tests/MasterHost/testreports/2011-03-09/RunReports-Linux.htm b/tests/MasterHost/testreports/2011-03-09/RunReports-Linux.htm deleted file mode 100644 index 4d17743cdd3..00000000000 --- a/tests/MasterHost/testreports/2011-03-09/RunReports-Linux.htm +++ /dev/null @@ -1,372 +0,0 @@ - - - -RunReports Snapshot of 14/03/2011 23:27:35 - - - - - -
- -

Snapshot of RunReports generated by ServiceStack on 14/03/2011 23:27:35

- -
- view json datasource - from original url: - http://localhost/MasterHost/runreports - in other formats: - json - xml - csv - jsv -
- -
- -
-

This reports json data source

- - -
- -
Results
Host Environment Base Url Last Modified Max Status Code Tests
Nginx/FastCGIhttp://servicestack.net/ApiPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
Nginx/FastCGIhttp://servicestack.net/CustomPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
Nginx/FastCGIhttp://servicestack.net/CustomPath40/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
Nginx/FastCGIhttp://servicestack.net/RootPath352011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
Nginx/FastCGIhttp://servicestack.net/RootPath402011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
ConsoleApphttp://servicestack.net:822011/03/14200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
xsp2http://servicestack.net:8080/ApiPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
xsp4http://servicestack.net:8080/CustomPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
xsp2http://servicestack.net:8080/CustomPath40/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
xsp4http://servicestack.net:8080/RootPath352011/03/14200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html; charset=utf-8200
/metadata/text/html; charset=utf-8200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Apache+mod_mono2http://api.servicestack.net/ApiPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
Apache+mod_mono2http://api.servicestack.net/CustomPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
Apache+mod_mono2http://api.servicestack.net/CustomPath40/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
Apache+mod_mono2http://api.servicestack.net/RootPath352011/03/14200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html; charset=utf-8200
/metadata/text/html; charset=utf-8200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Apache+mod_mono2http://api.servicestack.net/RootPath402011/03/14200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html; charset=utf-8200
/metadata/text/html; charset=utf-8200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Response Status
Errors
- -
- - - - - - \ No newline at end of file diff --git a/tests/MasterHost/testreports/2011-03-09/RunReports-Windows.htm b/tests/MasterHost/testreports/2011-03-09/RunReports-Windows.htm deleted file mode 100644 index 2f9252fe1b7..00000000000 --- a/tests/MasterHost/testreports/2011-03-09/RunReports-Windows.htm +++ /dev/null @@ -1,372 +0,0 @@ - - - -RunReports Snapshot of 09/03/2011 00:55:23 - - - - - -
- -

Snapshot of RunReports generated by ServiceStack on 09/03/2011 00:55:23

- -
- view json datasource - from original url: - http://localhost/MasterHost/runreports - in other formats: - json - xml - csv - jsv -
- -
- -
-

This reports json data source

- - -
- -
Results
Host Environment Base Url Last Modified Max Status Code Tests
IIS7+3.5http://localhost/ApiPath35/api2011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+3.5http://localhost/CustomPath35/api2011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+4.0http://localhost/CustomPath40/api2011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+3.5http://localhost/RootPath352011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
IIS7+4.0http://localhost/RootPath402011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
ConsoleApphttp://localhost:822011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WindowsServicehttp://localhost:832011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer20http://localhost:5001/api2011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer40http://localhost:5002/api2011/03/09200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer20http://localhost:50032011/03/09200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
WebServer40http://localhost:50042011/03/09200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Response Status
Errors
- -
- - - - - - \ No newline at end of file diff --git a/tests/MasterHost/testreports/2011-03-15/RunReports-Linux.htm b/tests/MasterHost/testreports/2011-03-15/RunReports-Linux.htm deleted file mode 100644 index 35ef6d34955..00000000000 --- a/tests/MasterHost/testreports/2011-03-15/RunReports-Linux.htm +++ /dev/null @@ -1,372 +0,0 @@ - - - -RunReports Snapshot of 15/03/2011 22:27:39 - - - - - -
- -

Snapshot of RunReports generated by ServiceStack on 15/03/2011 22:27:39

- -
- view json datasource - from original url: - http://localhost/MasterHost/runreports - in other formats: - json - xml - csv - jsv -
- -
- -
-

This reports json data source

- - -
- -
Results
Host Environment Base Url Last Modified Max Status Code Tests
Nginx/FastCGIhttp://servicestack.net/ApiPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
Nginx/FastCGIhttp://servicestack.net/CustomPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
Nginx/FastCGIhttp://servicestack.net/RootPath352011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
Nginx/FastCGIhttp://servicestack.net/RootPath402011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/0WebExceptionThe remote server returned an error: (404) Not Found.
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
ConsoleApphttp://servicestack.net:822011/03/14200
Request Path Response Content Type Status Code
/text/html200
/metadatatext/html200
/metadata/text/html200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
xsp2http://servicestack.net:8080/ApiPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
xsp4http://servicestack.net:8080/CustomPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
xsp4http://servicestack.net:8080/RootPath352011/03/14200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html; charset=utf-8200
/metadata/text/html; charset=utf-8200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Apache+mod_mono2http://api.servicestack.net/ApiPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world200application/json
/hello/world/1200application/json
/hello/world/2200application/json
/hello/world/2/3200application/json
Apache+mod_mono2http://api.servicestack.net/CustomPath35/api2011/03/14200
Request Path Status Code Error Code Error Message Response Content Type
/0WebExceptionThe remote server returned an error: (404) Not Found.
/metadata200text/html; charset=utf-8
/metadata/200text/html; charset=utf-8
/hello200application/json
/hello/200application/json
/hello/world0WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/10WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/20WebExceptionThe remote server returned an error: (404) Not Found.
/hello/world/2/30WebExceptionThe remote server returned an error: (404) Not Found.
Apache+mod_mono2http://api.servicestack.net/RootPath352011/03/14200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html; charset=utf-8200
/metadata/text/html; charset=utf-8200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Apache+mod_mono2http://api.servicestack.net/RootPath402011/03/14200
Request Path Response Content Type Status Code
/text/html; charset=utf-8200
/metadatatext/html; charset=utf-8200
/metadata/text/html; charset=utf-8200
/helloapplication/json200
/hello/application/json200
/hello/worldapplication/json200
/hello/world/1application/json200
/hello/world/2application/json200
/hello/world/2/3application/json200
Response Status
Errors
- -
- - - - - - \ No newline at end of file diff --git a/tests/NetCoreTests/ContainerTests.cs b/tests/NetCoreTests/ContainerTests.cs new file mode 100644 index 00000000000..1a934bb0549 --- /dev/null +++ b/tests/NetCoreTests/ContainerTests.cs @@ -0,0 +1,90 @@ +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using NUnit.Framework; +using ServiceStack; + +namespace NetCoreTests +{ + public class ContainerTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ContainerTests), typeof(ContainerTests).Assembly) + { + Configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json") + .Build(); + AppSettings = new NetCoreAppSettings(Configuration); + } + + public override void Configure(Container container) + { + var String = AppSettings.GetString("String"); + var Num = AppSettings.Get("Num"); + } + } + + [Route("/haskeys")] + class HasQueryStringKeysTestDto {} + + [Route("/numberofkeys")] + class NumberOfKeysTestDto {} + + class HasKeysService : Service + { + public string Get(HasQueryStringKeysTestDto request) + { + return this.Request.QueryString.HasKeys().ToString(); + } + + public string Get(NumberOfKeysTestDto request) + { + return this.Request.QueryString.Count.ToString(); + } + } + + + [Test] + public void Can_resolve_dependency_in_multiple_AppHosts() + { + using (var appHost = new AppHost().Init().Start("http://localhost:2000/")) + { + var logFactory = appHost.TryResolve(); + var log = logFactory.CreateLogger("categoryName"); + } + + using (var appHost = new AppHost().Init().Start("http://localhost:2000/")) + { + var logFactory = appHost.TryResolve(); + var log = logFactory.CreateLogger("categoryName"); + } + } + + [Test] + public async Task Can_use_haskeys() + { + using (var appHost = new AppHost().Init().Start("http://localhost:2000/")) + { + var client = new HttpClient(); + var result = await client.GetStringAsync("http://localhost:2000/haskeys?test=foo"); + Assert.That(result.ToLower(), Is.EqualTo("true")); + } + } + + [Test] + public async Task Can_use_AllKeys() + { + using (var appHost = new AppHost().Init().Start("http://localhost:2000/")) + { + var client = new HttpClient(); + var result = await client.GetStringAsync("http://localhost:2000/numberofkeys?test=foo"); + Assert.That(result, Is.EqualTo("1")); + } + } + } +} \ No newline at end of file diff --git a/tests/NetCoreTests/NetCoreTests.csproj b/tests/NetCoreTests/NetCoreTests.csproj new file mode 100644 index 00000000000..cd65e034dd3 --- /dev/null +++ b/tests/NetCoreTests/NetCoreTests.csproj @@ -0,0 +1,26 @@ + + + net6.0 + portable + Library + enable + + + + + + + + + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/tests/NetCoreTests/PublishTasks.cs b/tests/NetCoreTests/PublishTasks.cs new file mode 100644 index 00000000000..1accc867a66 --- /dev/null +++ b/tests/NetCoreTests/PublishTasks.cs @@ -0,0 +1,148 @@ +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Admin; +using ServiceStack.Auth; +using ServiceStack.HtmlModules; +using ServiceStack.IO; +using ServiceStack.NativeTypes; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace NetCoreTests; + +[Category("Publish Tasks")] +public class PublishTasks +{ + readonly string ProjectDir = Path.GetFullPath("../../../../NorthwindAuto"); + string FromModulesDir => Path.GetFullPath("."); + string ToModulesDir => Path.GetFullPath("../../src/ServiceStack/modules"); + string[] IgnoreUiFiles = { }; + string[] IgnoreAdminUiFiles = { }; + + FilesTransformer transformOptions => FilesTransformer.Defaults(debugMode: true); + + [Test] + public void Print_paths() + { + Directory.SetCurrentDirectory(ProjectDir); + FromModulesDir.Print(); + ToModulesDir.Print(); + } + + /* publish.bat: + call npm run ui:build + RD /q /s ..\..\src\ServiceStack\modules\ui + XCOPY /Y /E /H /C /I ui ..\..\src\ServiceStack\modules\ui + DEL ..\..\src\ServiceStack\modules\ui\index.css + RD /q /s ..\..\src\ServiceStack\modules\shared + XCOPY /Y /E /H /C /I shared ..\..\src\ServiceStack\modules\shared + */ + [Test] + public async Task Publish_ui() + { + Directory.SetCurrentDirectory(ProjectDir); + FromModulesDir.Print(); + ToModulesDir.Print(); + + //publish tailwind + await ProcessUtils.RunShellAsync("npm run ui:build", + onOut: Console.WriteLine, + onError: Console.Error.WriteLine); + + // copy to modules/ui + transformOptions.CopyAll( + source: new FileSystemVirtualFiles(FromModulesDir.CombineWith("ui")), + target: new FileSystemVirtualFiles(ToModulesDir.CombineWith("ui").AssertDir()), + cleanTarget: true, + ignore: file => IgnoreUiFiles.Contains(file.VirtualPath), + afterCopy: (file, contents) => $"{file.VirtualPath} ({contents.Length})".Print()); + + // copy to modules/admin-ui + transformOptions.CopyAll( + source: new FileSystemVirtualFiles(FromModulesDir.CombineWith("admin-ui")), + target: new FileSystemVirtualFiles(ToModulesDir.CombineWith("admin-ui").AssertDir()), + cleanTarget: true, + ignore: file => IgnoreAdminUiFiles.Contains(file.VirtualPath), + afterCopy: (file, contents) => $"{file.VirtualPath} ({contents.Length})".Print()); + + // copy to modules/shared + transformOptions.CopyAll( + source: new FileSystemVirtualFiles(FromModulesDir.CombineWith("shared")), + target: new FileSystemVirtualFiles(ToModulesDir.CombineWith("shared").AssertDir()), + cleanTarget: true, + afterCopy: (file, contents) => $"{file.VirtualPath} ({contents.Length})".Print()); + } + + [Test] + public void Publish_Bookings_and_Todos_cs() + { + Directory.SetCurrentDirectory(ProjectDir); + + string[] ResolveTargetDirs(string name) => new[] + { + $"../../tests/ServiceStack.Blazor.Tests/" + (name == "ServiceModel" ? name : "Server/" + name) + "/", + $"../../../NetCoreTemplates/blazor-wasm/MyApp.{name}/", + $"../../../NetCoreTemplates/vue-vite/api/MyApp.{name}/", + $"../../../NetCoreTemplates/vue-ssg/api/MyApp.{name}/", + $"../../../NetCoreTemplates/nextjs/api/MyApp.{name}/", + }; + + void CopyFile(string copyFile, string fileName, string[] targetDirs) + { + $"Copying {Path.GetFullPath(copyFile)}...".Print(); + foreach (var folder in targetDirs) + { + var toFile = Path.GetFullPath(folder.CombineWith(fileName)); + $"Writing to {toFile}".Print(); + File.Copy(copyFile, toFile, overwrite: true); + } + "".Print(); + } + + CopyFile("ServiceModel/Bookings.cs", "Bookings.cs", ResolveTargetDirs("ServiceModel")); + CopyFile("ServiceModel/Todos.cs", "Todos.cs", ResolveTargetDirs("ServiceModel")); + // TodosServices.cs specific to: Learn, Blazor, WASM + // CopyFile("ServiceInterface/TodosServices.cs", "TodosServices.cs", ResolveTargetDirs("ServiceInterface")); + } + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(PublishTasks), typeof(MetadataAppService)) {} + public override void Configure(Container container) + { + Metadata.ForceInclude = new() { + typeof(MetadataApp), + typeof(AppMetadata), + typeof(AdminQueryUsers), + typeof(AdminGetUser), + typeof(AdminCreateUser), + typeof(AdminUpdateUser), + typeof(AdminDeleteUser), + }; + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), new [] { + new CredentialsAuthProvider(AppSettings), + })); + + Plugins.Add(new AdminUsersFeature()); + } + } + + [Test] + public void Generate_AppMetadata_details() + { + var baseUrl = "http://localhost:20000"; + using var appHost = new AppHost().Init().Start(baseUrl); + + var dtos = baseUrl.CombineWith("/types/typescript").GetStringFromUrl(); + dtos += @" +// declare Types used in /ui +export declare var APP:AppMetadata +"; + + Directory.SetCurrentDirectory(ProjectDir); + File.WriteAllText(Path.GetFullPath("./lib/types.ts"), dtos); + } +} \ No newline at end of file diff --git a/tests/NetCoreTests/appsettings.json b/tests/NetCoreTests/appsettings.json new file mode 100644 index 00000000000..ca8e1e51809 --- /dev/null +++ b/tests/NetCoreTests/appsettings.json @@ -0,0 +1,11 @@ +{ + "Num": 1, + "String": "ABC", + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} \ No newline at end of file diff --git a/tests/NorthwindAuto/Configure.AppHost.cs b/tests/NorthwindAuto/Configure.AppHost.cs new file mode 100644 index 00000000000..f8d05f3e787 --- /dev/null +++ b/tests/NorthwindAuto/Configure.AppHost.cs @@ -0,0 +1,84 @@ +using Funq; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using MyApp.ServiceInterface; +using ServiceStack.HtmlModules; +using ServiceStack.Text; +using ServiceStack.Web; + +[assembly: HostingStartup(typeof(MyApp.AppHost))] + +namespace MyApp +{ + public class AppHost : AppHostBase, IHostingStartup + { + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices(services => services.AddHttpUtilsClient()) + .Configure(app => { + if (!HasInit) + app.UseServiceStack(new AppHost()); + }); + + public AppHost() : base("Northwind Auto", typeof(MyServices).Assembly) { } + + // Configure your AppHost with the necessary configuration and dependencies your App needs + public override void Configure(Container container) + { + // JsConfig.Init(new Config { TextCase = TextCase.PascalCase }); + + SetConfig(new HostConfig + { + DebugMode = false, + //DebugMode = true, + AdminAuthSecret = "secret", + }); + + // Register Database Connection, see: https://github.com/ServiceStack/ServiceStack.OrmLite#usage + container.AddSingleton(c => + new OrmLiteConnectionFactory(MapProjectPath("~/northwind.sqlite"), SqliteDialect.Provider)); + + // For TodosService + Plugins.Add(new AutoQueryDataFeature()); + + // For NorthwindAuto + Bookings + Plugins.Add(new AutoQueryFeature { + MaxLimit = 100, + GenerateCrudServices = new GenerateCrudServices {} + }); + + ConfigurePlugin(feature => { + Console.WriteLine("ConfigurePlugin..."); + //feature.Module.EnableHttpCaching = true; + feature.Module.Configure((appHost, module) => + { + module.VirtualFiles = appHost.VirtualFiles; + module.DirPath = module.DirPath.Replace("/modules", ""); + }); + feature.Handlers.Cast().Each(x => + x.SharedDir = x.SharedDir.Replace("/modules", "")); + }); + + // Not needed in `dotnet watch` and in /wwwroot/modules/ui which can use _framework/aspnetcore-browser-refresh.js" + // Plugins.AddIfDebug(new HotReloadFeature + // { + // VirtualFiles = VirtualFiles, + // DefaultPattern = "*.html;*.js;*.css" + // }); + + //Plugins.Add(new PostmanFeature()); + } + + public override string? GetCompressionType(IRequest request) + { + if (request.RequestPreferences.AcceptsDeflate && StreamCompressors.SupportsEncoding(CompressionTypes.Deflate)) + return CompressionTypes.Deflate; + + if (request.RequestPreferences.AcceptsGzip && StreamCompressors.SupportsEncoding(CompressionTypes.GZip)) + return CompressionTypes.GZip; + + return null; + } + + } +} \ No newline at end of file diff --git a/tests/NorthwindAuto/Configure.Auth.cs b/tests/NorthwindAuto/Configure.Auth.cs new file mode 100644 index 00000000000..efd42de1e1d --- /dev/null +++ b/tests/NorthwindAuto/Configure.Auth.cs @@ -0,0 +1,55 @@ +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.FluentValidation; + +[assembly: HostingStartup(typeof(MyApp.ConfigureAuth))] + +namespace MyApp; + +// Add any additional metadata properties you want to store in the Users Typed Session +public class CustomUserSession : AuthUserSession +{ +} + +// Custom Validator to add custom validators to built-in /register Service requiring DisplayName and ConfirmPassword +public class CustomRegistrationValidator : RegistrationValidator +{ + public CustomRegistrationValidator() + { + RuleSet(ApplyTo.Post, () => + { + RuleFor(x => x.DisplayName).NotEmpty(); + RuleFor(x => x.ConfirmPassword).NotEmpty(); + }); + } +} + +public class ConfigureAuth : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) => builder + //.ConfigureServices(services => services.AddSingleton(new MemoryCacheClient())) + .ConfigureAppHost(appHost => + { + var appSettings = appHost.AppSettings; + appHost.Plugins.Add(new AuthFeature(() => new CustomUserSession(), + new IAuthProvider[] { + new JwtAuthProvider(appSettings) { + AuthKeyBase64 = appSettings.GetString("AuthKeyBase64") ?? "cARl12kvS/Ra4moVBIaVsrWwTpXYuZ0mZf/gNLUhDW5=", + }, + new CredentialsAuthProvider(appSettings), /* Sign In with Username / Password credentials */ + new FacebookAuthProvider(appSettings), /* Create App https://developers.facebook.com/apps */ + new GoogleAuthProvider(appSettings), /* Create App https://console.developers.google.com/apis/credentials */ + new MicrosoftGraphAuthProvider(appSettings), /* Create App https://apps.dev.microsoft.com */ + }) + { + // IncludeDefaultLogin = false + ProfileImages = new PersistentImagesHandler("/auth-profiles", Svg.GetStaticContent(Svg.Icons.Female), + appHost.VirtualFiles, "/App_Data/auth-profiles") + }); + + appHost.Plugins.Add(new RegistrationFeature()); //Enable /register Service + + //override the default registration validation with your own custom implementation + appHost.RegisterAs>(); + }); +} \ No newline at end of file diff --git a/tests/NorthwindAuto/Configure.AuthRepository.cs b/tests/NorthwindAuto/Configure.AuthRepository.cs new file mode 100644 index 00000000000..2d7c01ea877 --- /dev/null +++ b/tests/NorthwindAuto/Configure.AuthRepository.cs @@ -0,0 +1,140 @@ +using ServiceStack; +using ServiceStack.Web; +using ServiceStack.Data; +using ServiceStack.Html; +using ServiceStack.Auth; +using ServiceStack.Configuration; + +[assembly: HostingStartup(typeof(MyApp.ConfigureAuthRepository))] + +namespace MyApp; + +public enum Department +{ + None, + Marketing, + Accounts, + Legal, + HumanResources, +} + +// Custom User Table with extended Metadata properties +public class AppUser : UserAuth +{ + public Department Department { get; set; } + public string? ProfileUrl { get; set; } + public string? LastLoginIp { get; set; } + + public bool IsArchived { get; set; } + public DateTime? ArchivedDate { get; set; } + + public DateTime? LastLoginDate { get; set; } +} + +public class AppUserAuthEvents : AuthEvents +{ + public override async Task OnAuthenticatedAsync(IRequest httpReq, IAuthSession session, IServiceBase authService, + IAuthTokens tokens, Dictionary authInfo, CancellationToken token = default) + { + var authRepo = HostContext.AppHost.GetAuthRepositoryAsync(httpReq); + using (authRepo as IDisposable) + { + var userAuth = (AppUser)await authRepo.GetUserAuthAsync(session.UserAuthId, token); + userAuth.ProfileUrl = session.GetProfileUrl(); + userAuth.LastLoginIp = httpReq.UserHostAddress; + userAuth.LastLoginDate = DateTime.UtcNow; + await authRepo.SaveUserAuthAsync(userAuth, token); + } + } +} + +public class ConfigureAuthRepository : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices(services => services.AddSingleton(c => + new OrmLiteAuthRepository(c.Resolve()) { + UseDistinctRoleTables = true + })) + .ConfigureAppHost(appHost => { + var authRepo = appHost.Resolve(); + authRepo.InitSchema(); + CreateUser(authRepo, "admin@email.com", "Admin User", "p@55wOrd", roles: new[] { RoleNames.Admin }); + CreateUser(authRepo, "manager@email.com", "The Manager", "p@55wOrd", roles: new[] { "Employee", "Manager" }); + CreateUser(authRepo, "employee@email.com", "A Employee", "p@55wOrd", roles: new[] { "Employee" }); + + //Populate with lots of demo users + for (var i = 1; i < 102; i++) + { + CreateUser(authRepo, $"employee{i}@email.com", $"Employee {i}", "p@55wOrd", roles: new[] { "Employee" }); + } + + // Removing unused UserName in Admin Users UI + appHost.Plugins.Add(new ServiceStack.Admin.AdminUsersFeature { + /* + */ + // Show custom fields in Search Results + QueryUserAuthProperties = new() { + nameof(AppUser.Id), + nameof(AppUser.Email), + nameof(AppUser.DisplayName), + nameof(AppUser.Department), + nameof(AppUser.CreatedDate), + nameof(AppUser.LastLoginDate), + }, + + QueryMediaRules = new() + { + MediaRules.ExtraSmall.Show(x => new { x.Id, x.Email, x.DisplayName }), + MediaRules.Small.Show(x => x.Department), + }, + + // Add Custom Fields to Create/Edit User Forms + UserFormLayout = new() { + new() + { + Input.For(x => x.Email), + }, + new() + { + Input.For(x => x.DisplayName), + }, + new() + { + Input.For(x => x.Company), + Input.For(x => x.Department), + }, + new() { + Input.For(x => x.PhoneNumber, c => c.Type = Input.Types.Tel) + }, + new() { + Input.For(x => x.Nickname, c => { + c.Help = "Public alias (3-12 lower alpha numeric chars)"; + c.Pattern = "^[a-z][a-z0-9_.-]{3,12}$"; + //c.Required = true; + }) + }, + new() { + Input.For(x => x.ProfileUrl, c => c.Type = Input.Types.Url) + }, + new() { + Input.For(x => x.IsArchived), Input.For(x => x.ArchivedDate), + }, + } + }); + + }, + afterConfigure: appHost => { + appHost.AssertPlugin().AuthEvents.Add(new AppUserAuthEvents()); + }); + + // Add initial Users to the configured Auth Repository + public void CreateUser(IAuthRepository authRepo, string email, string name, string password, string[] roles) + { + if (authRepo.GetUserAuthByUserName(email) == null) + { + var newAdmin = new AppUser { Email = email, DisplayName = name }; + var user = authRepo.CreateUserAuth(newAdmin, password); + authRepo.AssignRoles(user, roles); + } + } +} \ No newline at end of file diff --git a/tests/NorthwindAuto/Configure.AutoQuery.cs b/tests/NorthwindAuto/Configure.AutoQuery.cs new file mode 100644 index 00000000000..9fe0711c965 --- /dev/null +++ b/tests/NorthwindAuto/Configure.AutoQuery.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Hosting; +using ServiceStack; +using ServiceStack.Data; + +// In Configure.AppHost +// [assembly: HostingStartup(typeof(MyApp.ConfigureAutoQuery))] + +namespace MyApp +{ + public class ConfigureAutoQuery : IHostingStartup + { + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices(services => { + // Enable Audit History + services.AddSingleton(c => + new OrmLiteCrudEvents(c.Resolve())); + }) + .ConfigureAppHost(appHost => { + + // For TodosService + appHost.Plugins.Add(new AutoQueryDataFeature()); + + // For Bookings https://github.com/NetCoreApps/BookingsCrud + appHost.Plugins.Add(new AutoQueryFeature { + MaxLimit = 1000, + //IncludeTotal = true, + }); + + appHost.Resolve().InitSchema(); + }); + } +} \ No newline at end of file diff --git a/tests/NorthwindAuto/Configure.Db.cs b/tests/NorthwindAuto/Configure.Db.cs new file mode 100644 index 00000000000..641d855b9d4 --- /dev/null +++ b/tests/NorthwindAuto/Configure.Db.cs @@ -0,0 +1,50 @@ +using MyApp.ServiceModel; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using System.Data; + +[assembly: HostingStartup(typeof(MyApp.ConfigureDb))] + +namespace MyApp +{ + public class ConfigureDb : IHostingStartup + { + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices((context,services) => services.AddSingleton(new OrmLiteConnectionFactory( + context.Configuration.GetConnectionString("DefaultConnection") ?? ":memory:", + SqliteDialect.Provider))) + .ConfigureAppHost(appHost => + { + // Create non-existing Table and add Seed Data Example + using var db = appHost.Resolve().Open(); + if (db.CreateTableIfNotExists()) + { + db.CreateBooking("First Booking!", RoomType.Queen, 10, 100, "employee@email.com"); + db.CreateBooking("Booking 2", RoomType.Double, 12, 120, "manager@email.com"); + db.CreateBooking("Booking the 3rd", RoomType.Suite, 13, 130, "employee@email.com"); + } + }); + } + + public static class ConfigureDbUtils + { + static int bookingId = 0; + public static void CreateBooking(this IDbConnection db, string name, RoomType type, int roomNo, decimal cost, string by) => + db.Insert(new Booking + { + Id = ++bookingId, + Name = name, + RoomType = type, + RoomNumber = roomNo, + Cost = cost, + BookingStartDate = DateTime.UtcNow.AddDays(bookingId), + BookingEndDate = DateTime.UtcNow.AddDays(bookingId + 7), + CreatedBy = by, + CreatedDate = DateTime.UtcNow, + ModifiedBy = by, + ModifiedDate = DateTime.UtcNow, + }); + + } +} diff --git a/tests/NorthwindAuto/NorthwindAuto.csproj b/tests/NorthwindAuto/NorthwindAuto.csproj new file mode 100644 index 00000000000..8f1918dbb2f --- /dev/null +++ b/tests/NorthwindAuto/NorthwindAuto.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + enable + enable + MyApp + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/NorthwindAuto/Program.cs b/tests/NorthwindAuto/Program.cs new file mode 100644 index 00000000000..894ed395b19 --- /dev/null +++ b/tests/NorthwindAuto/Program.cs @@ -0,0 +1,14 @@ +var builder = WebApplication.CreateBuilder(args); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + app.UseHttpsRedirection(); +} + +app.Run(); \ No newline at end of file diff --git a/tests/NorthwindAuto/Properties/launchSettings.json b/tests/NorthwindAuto/Properties/launchSettings.json new file mode 100644 index 00000000000..ba86cbd6676 --- /dev/null +++ b/tests/NorthwindAuto/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "NorthwindAuto": { + "commandName": "Project", + "applicationUrl": "https://*:5001;http://*:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/tests/NorthwindAuto/README.md b/tests/NorthwindAuto/README.md new file mode 100644 index 00000000000..1676c876527 --- /dev/null +++ b/tests/NorthwindAuto/README.md @@ -0,0 +1,87 @@ +# Northwind Auto + +An empty Example App only configured with `northwind.sqlite` database and AutoQuery to showcase [AutoGen to instantly servicify existing systems](https://docs.servicestack.net/servicify) by generating AutoQuery Services for all configured RDBMS Tables including [Typed Services for the most popular Web, Mobile & Desktop languages](https://docs.servicestack.net/add-servicestack-reference) that's maintainable by an instant UI in [ServiceStack Studio](https://docs.servicestack.net/studio). + +![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/apps/NorthwindAuto.png) + +### Code Generation of AutoQuery & CRUD Services + +Now with [AutoCrud](https://docs.servicestack.net/autogen) we can add a lot more value in this area as AutoCrud's declarative nature allows us to easily generate AutoQuery & Crud Services by just emitting declarative Request DTOs. + +You can then add the generated DTOs to your ServiceModel's to quickly enable AutoQuery Services for your existing databases. + + + +To enable this feature you you just need to initialize `GenerateCrudServices` in your `AutoQueryFeature` plugin, e.g: + +```csharp +Plugins.Add(new AutoQueryFeature { + MaxLimit = 1000, + GenerateCrudServices = new GenerateCrudServices {} +}); +``` + +If you don't have an existing database, you can quickly test this out with a Northwind SQLite database available from [https://github.com/NetCoreApps/NorthwindAuto](github.com/NetCoreApps/NorthwindAuto): + + $ x download NetCoreApps/NorthwindAuto + +As you'll need to use 2 terminal windows, I'd recommend opening the project with **VS Code** which has great multi-terminal support: + + $ code NorthwindAuto + +The important parts of this project is the registering the OrmLite DB Connection, the above configuration and the local **northwind.sqlite** database, i.e: + +```csharp +container.AddSingleton(c => + new OrmLiteConnectionFactory(MapProjectPath("~/northwind.sqlite"), SqliteDialect.Provider)); + +Plugins.Add(new AutoQueryFeature { + MaxLimit = 1000, + GenerateCrudServices = new GenerateCrudServices {} +}); +``` + +#### Generating AutoQuery Types & Services + +The development experience is essentially the same as [Add ServiceStack Reference](https://docs.servicestack.net/add-servicestack-reference) where you'll need to run the .NET Core App in 1 terminal: + + $ dotnet run + +Then use the `x` dotnet tool to download all the AutoQuery & Crud Services for all tables in the configured DB connection: + + $ x csharp https://localhost:5001 -path /crud/all/csharp + +#### Updating Generated Services + +If your RDBMS schema changes you'd just need to restart your .NET Core App, then you can update all existing `dtos.cs` with: + + $ x csharp + +i.e. the same experience as updating normal DTOs. + +You can do the same for all other ServiceStack's supported languages as shown in autodto at the start of this release. + +## AutoRegister AutoGen AutoQuery Services + +To recap we've now got an integrated scaffolding solution where we can quickly generate code-first AutoQuery Services and integrate them into our App to quickly build an AutoQuery Service layer around our existing database. + +But we can raise the productivity level even higher by instead of manually importing the code-generated Services into our project we just tell ServiceStack to do it for us. + +This is what the magical `AutoRegister` flag does for us: + +```csharp +Plugins.Add(new AutoQueryFeature { + GenerateCrudServices = new GenerateCrudServices { + AutoRegister = true, + //.... + } +}); +``` + +### Instantly Servicify Northwind DB with gRPC + +To show the exciting potential of this feature we'll demonstrate one valuable use-case of creating a [grpc](https://docs.servicestack.net/grpc) project, mixing in AutoQuery configuration to instantly Servicifying the Northwind DB, browsing the generated Services from ServiceStack's [Metadata Page](https://docs.servicestack.net/metadata-page), explore the gRPC RPC Services `.proto` then create a new Dart App to consume the gRPC Services: + +> YouTube: [youtu.be/5NNCaWMviXU](https://youtu.be/5NNCaWMviXU) + +[![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v5.9/autogen-grpc.png)](https://youtu.be/5NNCaWMviXU) \ No newline at end of file diff --git a/tests/NorthwindAuto/ServiceInterface/ImageServices.cs b/tests/NorthwindAuto/ServiceInterface/ImageServices.cs new file mode 100644 index 00000000000..f33ffa408e0 --- /dev/null +++ b/tests/NorthwindAuto/ServiceInterface/ImageServices.cs @@ -0,0 +1,64 @@ +#nullable enable +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using ServiceStack; +using ServiceStack.Text; +using ServiceStack.Auth; +using MyApp.ServiceModel; + +namespace MyApp.ServiceInterface; + + +[Route("/profile-image")] +[Route("/profile-image/{Type}")] +[Route("/profile-image/{Type}/{Size}")] +public class GetProfileImage : IReturn +{ + public string Type { get; set; } + public string? Size { get; set; } +} + +public class ImageServices : Service +{ + public async Task Any(GetProfileImage request) + { + var authSession = await GetSessionAsync(); + var userAuthId = authSession.UserAuthId; + var userDetails = await AuthRepositoryAsync.GetUserAuthDetailsAsync(userAuthId); + var accessToken = userDetails.FirstOrDefault(x => x.Provider == "microsoftgraph")?.AccessToken + ?? throw HttpError.NotFound("No profile image for userAuthId: " + userAuthId); + + async Task GetImage() => + await MicrosoftGraphAuthProvider.PhotoUrl(null) + .GetStreamFromUrlAsync(requestFilter: req => req.AddBearerToken(accessToken)).ConfigAwait(); + + if (request.Type == "original") + { + await using var imageStream = await GetImage(); + Response.ContentType = MimeTypes.ImagePng; + await imageStream.CopyToAsync(Response.OutputStream); + } + else if (request.Type == "resize") + { + await using var imageStream = await GetImage(); + await using var resizedImage = ImageProvider.Instance.Resize(imageStream, 64, 64); + Response.ContentType = MimeTypes.ImagePng; + await resizedImage.CopyToAsync(Response.OutputStream); + } + else if (request.Type == "gateway") + { + var dataUri = await new AuthHttpGateway() + .CreateMicrosoftPhotoUrlAsync(accessToken, request.Size ?? "64x64"); + Response.ContentType = MimeTypes.PlainText; + await Response.WriteAsync(dataUri); + } + else + { + Response.ContentType = MimeTypes.PlainText; + return authSession.ProfileUrl; + } + return null; + } +} diff --git a/tests/NorthwindAuto/ServiceInterface/MyServices.cs b/tests/NorthwindAuto/ServiceInterface/MyServices.cs new file mode 100644 index 00000000000..784c463043c --- /dev/null +++ b/tests/NorthwindAuto/ServiceInterface/MyServices.cs @@ -0,0 +1,26 @@ +using ServiceStack; +using MyApp.ServiceModel; + +namespace MyApp.ServiceInterface; + +public class MyServices : Service +{ + public static string AssertName(string Name) => Name.IsNullOrEmpty() + ? throw new ArgumentNullException(nameof(Name)) + : Name; + + public object Get(Greet request) => + new HelloResponse { Result = "Welcome!" }; + + public object Get(Hello request) => + new HelloResponse { Result = $"Hello, {AssertName(request.Name)}!" }; + + public object Any(HelloVeryLongOperationNameVersions request) => + new HelloResponse { Result = $"Hello, {AssertName(request.Name)}!" }; + + // public object Any(HelloVeryLongOperationNameVersionsAndThenSome request) => + // new HelloResponse { Result = $"Hello, {AssertName(request.Name)}!" }; + + public object Any(HelloSecure request) => + new HelloResponse { Result = $"Hello, {AssertName(request.Name)}!" }; +} diff --git a/tests/NorthwindAuto/ServiceInterface/TodosServices.cs b/tests/NorthwindAuto/ServiceInterface/TodosServices.cs new file mode 100644 index 00000000000..98626aa32c4 --- /dev/null +++ b/tests/NorthwindAuto/ServiceInterface/TodosServices.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using ServiceStack; +using MyApp.ServiceModel; + +namespace MyApp.ServiceInterface; + +public class TodosServices : Service +{ + public IAutoQueryData AutoQuery { get; set; } + + static readonly PocoDataSource Todos = PocoDataSource.Create(new Todo[] + { + new () { Id = 1, Text = "Learn" }, + new () { Id = 2, Text = "Blazor", IsFinished = true }, + new () { Id = 3, Text = "WASM!" }, + }, nextId: x => x.Select(e => e.Id).Max()); + + public object Get(QueryTodos query) + { + var db = Todos.ToDataSource(query, Request); + return AutoQuery.Execute(query, AutoQuery.CreateQuery(query, Request, db), db); + } + + public Todo Post(CreateTodo request) + { + var newTodo = new Todo { Id = Todos.NextId(), Text = request.Text }; + Todos.Add(newTodo); + return newTodo; + } + + public Todo Put(UpdateTodo request) + { + var todo = request.ConvertTo(); + Todos.TryUpdateById(todo, todo.Id); + return todo; + } + + // Handles Deleting the Todo item + public void Delete(DeleteTodo request) => Todos.TryDeleteById(request.Id); + + public void Delete(DeleteTodos request) => Todos.TryDeleteByIds(request.Ids); +} diff --git a/tests/NorthwindAuto/ServiceModel/Bookings.cs b/tests/NorthwindAuto/ServiceModel/Bookings.cs new file mode 100644 index 00000000000..7417bbc9b92 --- /dev/null +++ b/tests/NorthwindAuto/ServiceModel/Bookings.cs @@ -0,0 +1,96 @@ +// Complete declarative AutoQuery services for Bookings CRUD example: +// https://docs.servicestack.net/autoquery-crud-bookings + +using System; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace MyApp.ServiceModel; + +[Description("Booking Details")] +[Notes("Captures a Persons Name & Room Booking information")] +public class Booking : AuditBase +{ + [AutoIncrement] + public int Id { get; set; } + public string Name { get; set; } + public RoomType RoomType { get; set; } + public int RoomNumber { get; set; } + public DateTime BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + public decimal Cost { get; set; } + public string? Notes { get; set; } + public bool? Cancelled { get; set; } +} + +public enum RoomType +{ + Single, + Double, + Queen, + Twin, + Suite, +} + +[Tag("bookings"), Description("Find Bookings")] +[Notes("Find out how to quickly create a C# Bookings App from Scratch")] +[Route("/bookings", "GET")] +[Route("/bookings/{Id}", "GET")] +[AutoApply(Behavior.AuditQuery)] +public class QueryBookings : QueryDb +{ + public int? Id { get; set; } +} + +// Uncomment below to enable DeletedBookings API to view deleted bookings: +// [Route("/bookings/deleted")] +// [AutoFilter(QueryTerm.Ensure, nameof(AuditBase.DeletedDate), Template = SqlTemplate.IsNotNull)] +// public class DeletedBookings : QueryDb {} + +[Tag("bookings"), Description("Create a new Booking")] +[Route("/bookings", "POST")] +[ValidateHasRole("Employee")] +[AutoApply(Behavior.AuditCreate)] +public class CreateBooking : ICreateDb, IReturn +{ + [Description("Name this Booking is for"), ValidateNotEmpty] + public string Name { get; set; } + public RoomType RoomType { get; set; } + [ValidateGreaterThan(0)] + public int RoomNumber { get; set; } + [ValidateGreaterThan(0)] + public decimal Cost { get; set; } + public DateTime BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + [Input(Type = "textarea")] + public string? Notes { get; set; } +} + +[Tag("bookings"), Description("Update an existing Booking")] +[Route("/booking/{Id}", "PATCH")] +[ValidateHasRole("Employee")] +[AutoApply(Behavior.AuditModify)] +public class UpdateBooking : IPatchDb, IReturn +{ + public int Id { get; set; } + public string? Name { get; set; } + public RoomType? RoomType { get; set; } + [ValidateGreaterThan(0)] + public int? RoomNumber { get; set; } + [ValidateGreaterThan(0)] + public decimal? Cost { get; set; } + public DateTime? BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + // [Input(Type = "textarea")] + public string? Notes { get; set; } + public bool? Cancelled { get; set; } +} + +[Tag("bookings"), Description("Delete a Booking")] +[Route("/booking/{Id}", "DELETE")] +[ValidateHasRole("Manager")] +[AutoApply(Behavior.AuditSoftDelete)] +public class DeleteBooking : IDeleteDb, IReturnVoid +{ + public int Id { get; set; } +} diff --git a/tests/NorthwindAuto/ServiceModel/Hello.cs b/tests/NorthwindAuto/ServiceModel/Hello.cs new file mode 100644 index 00000000000..a278e698dfc --- /dev/null +++ b/tests/NorthwindAuto/ServiceModel/Hello.cs @@ -0,0 +1,50 @@ +using ServiceStack; + +namespace MyApp.ServiceModel; + +[Tag("hello"), Tag("todos"), Tag("auth")] +[Route("/greet/{Name}")] +public class Greet : IReturn {} + +[Tag("hello")] +[Route("/hello/{Name}")] +[ValidateHasRole("Employee")] +public class Hello : IReturn +{ + public string Name { get; set; } +} + +[Tag("hello")] +[Route("/hellosecure/{Name}", "PUT")] +[ValidateIsAuthenticated] +public class HelloSecure : IReturn +{ + public string Name { get; set; } +} + +[Tag("hello")] +[Route("/hello-long/{Name}", "PATCH,PUT")] +[Route("/hello-very-long/{Name}", "GET,POST,PUT")] +[ValidateHasRole("Employee")] +[ValidateHasPermission("ThePermission")] +[ValidateIsAuthenticated] +public class HelloVeryLongOperationNameVersions : IReturn, IGet, IPost, IPut, IPatch +{ + public string Name { get; set; } + public string[] Names { get; set; } + public int[] Ids { get; set; } +} + +[Tag("hello")] +[Route("/hello-long/{Name}")] +[ValidateIsAuthenticated] +public class HelloVeryLongOperationNameVersionsAndThenSome : IReturn +{ + public string Name { get; set; } +} + +public class HelloResponse +{ + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } +} \ No newline at end of file diff --git a/tests/NorthwindAuto/ServiceModel/Todos.cs b/tests/NorthwindAuto/ServiceModel/Todos.cs new file mode 100644 index 00000000000..274b60c7762 --- /dev/null +++ b/tests/NorthwindAuto/ServiceModel/Todos.cs @@ -0,0 +1,53 @@ +using ServiceStack; +using ServiceStack.Model; +using System.Collections.Generic; + +namespace MyApp.ServiceModel; + +[Tag("todos")] +[Route("/todos", "GET")] +public class QueryTodos : QueryData +{ + public int? Id { get; set; } + public List? Ids { get; set; } + public string? TextContains { get; set; } +} + +[Tag("todos")] +[Route("/todos", "POST")] +public class CreateTodo : IPost, IReturn +{ + [ValidateNotEmpty] + public string Text { get; set; } +} + +[Tag("todos")] +[Route("/todos/{Id}", "PUT")] +public class UpdateTodo : IPut, IReturn +{ + public long Id { get; set; } + [ValidateNotEmpty] + public string Text { get; set; } + public bool IsFinished { get; set; } +} + +[Tag("todos")] +[Route("/todos/{Id}", "DELETE")] +public class DeleteTodo : IDelete, IReturnVoid +{ + public long Id { get; set; } +} + +[Tag("todos")] +[Route("/todos", "DELETE")] +public class DeleteTodos : IDelete, IReturnVoid +{ + public List Ids { get; set; } +} + +public class Todo : IHasId +{ + public long Id { get; set; } + public string Text { get; set; } + public bool IsFinished { get; set; } +} diff --git a/tests/NorthwindAuto/admin-ui/components/AdminUsers.html b/tests/NorthwindAuto/admin-ui/components/AdminUsers.html new file mode 100644 index 00000000000..b8ba3ead31d --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/components/AdminUsers.html @@ -0,0 +1,524 @@ + + + + + + + + + + + + diff --git a/tests/NorthwindAuto/admin-ui/components/Dashboard.html b/tests/NorthwindAuto/admin-ui/components/Dashboard.html new file mode 100644 index 00000000000..d1047fe8321 --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/components/Dashboard.html @@ -0,0 +1,91 @@ + + + + diff --git a/tests/NorthwindAuto/admin-ui/components/Sidebar.html b/tests/NorthwindAuto/admin-ui/components/Sidebar.html new file mode 100644 index 00000000000..b63f0b7937a --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/components/Sidebar.html @@ -0,0 +1,89 @@ + + + + + + diff --git a/tests/NorthwindAuto/admin-ui/css/app.css b/tests/NorthwindAuto/admin-ui/css/app.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/NorthwindAuto/admin-ui/index.html b/tests/NorthwindAuto/admin-ui/index.html new file mode 100644 index 00000000000..1a26585009d --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/index.html @@ -0,0 +1,123 @@ + + + + + + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+
+

{{store.link.label}}

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/tests/NorthwindAuto/admin-ui/js/appInit.js b/tests/NorthwindAuto/admin-ui/js/appInit.js new file mode 100644 index 00000000000..ffd9903bb86 --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/js/appInit.js @@ -0,0 +1,21 @@ +import { JsonServiceClient, lastLeftPart, trimEnd } from "@servicestack/client" +import { APP } from "../../lib/types" + +/*minify:*/ +let BASE_URL = lastLeftPart(trimEnd(document.baseURI,'/'),'/') +let bearerToken = null +let authsecret = null + +function createClient(fn) { + return new JsonServiceClient(BASE_URL).apply(c => { + c.bearerToken = bearerToken + c.enableAutoRefreshToken = false + if (authsecret) c.headers.set('authsecret', authsecret) + let apiFmt = APP.httpHandlers['ApiHandlers.Json'] + if (apiFmt) + c.basePath = apiFmt.replace('/{Request}', '') + if (fn) fn(c) + }) +} +let client = createClient() +/*:minify*/ diff --git a/tests/NorthwindAuto/admin-ui/js/dtos.js b/tests/NorthwindAuto/admin-ui/js/dtos.js new file mode 100644 index 00000000000..792d05ea3ec --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/js/dtos.js @@ -0,0 +1,93 @@ +/*minify:*/ +exports.AdminDeleteUser = exports.AdminUpdateUser = exports.AdminCreateUser = exports.AdminQueryUsers = exports.AdminGetUser = exports.AdminDeleteUserResponse = exports.AdminUsersResponse = exports.AdminUserResponse = exports.AdminUserBase = void 0; +var AdminUserBase = /** @class */ (function () { + function AdminUserBase(init) { + Object.assign(this, init); + } + return AdminUserBase; +}()); +var AdminUserResponse = /** @class */ (function () { + function AdminUserResponse(init) { + Object.assign(this, init); + } + return AdminUserResponse; +}()); +exports.AdminUserResponse = AdminUserResponse; + +var AdminUsersResponse = /** @class */ (function () { + function AdminUsersResponse(init) { + Object.assign(this, init); + } + return AdminUsersResponse; +}()); +exports.AdminUsersResponse = AdminUsersResponse; + +var AdminDeleteUserResponse = /** @class */ (function () { + function AdminDeleteUserResponse(init) { + Object.assign(this, init); + } + return AdminDeleteUserResponse; +}()); +exports.AdminDeleteUserResponse = AdminDeleteUserResponse; + +var AdminGetUser = /** @class */ (function () { + function AdminGetUser(init) { + Object.assign(this, init); + } + AdminGetUser.prototype.createResponse = function () { return new AdminUserResponse(); }; + AdminGetUser.prototype.getTypeName = function () { return 'AdminGetUser'; }; + AdminGetUser.prototype.getMethod = function () { return 'GET'; }; + return AdminGetUser; +}()); +exports.AdminGetUser = AdminGetUser; + +var AdminQueryUsers = /** @class */ (function () { + function AdminQueryUsers(init) { + Object.assign(this, init); + } + AdminQueryUsers.prototype.createResponse = function () { return new AdminUsersResponse(); }; + AdminQueryUsers.prototype.getTypeName = function () { return 'AdminQueryUsers'; }; + AdminQueryUsers.prototype.getMethod = function () { return 'GET'; }; + return AdminQueryUsers; +}()); +exports.AdminQueryUsers = AdminQueryUsers; + +var AdminCreateUser = /** @class */ (function (_super) { + __extends(AdminCreateUser, _super); + function AdminCreateUser(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + AdminCreateUser.prototype.createResponse = function () { return new AdminUserResponse(); }; + AdminCreateUser.prototype.getTypeName = function () { return 'AdminCreateUser'; }; + AdminCreateUser.prototype.getMethod = function () { return 'POST'; }; + return AdminCreateUser; +}(AdminUserBase)); +exports.AdminCreateUser = AdminCreateUser; + +var AdminUpdateUser = /** @class */ (function (_super) { + __extends(AdminUpdateUser, _super); + function AdminUpdateUser(init) { + var _this = _super.call(this, init) || this; + Object.assign(_this, init); + return _this; + } + AdminUpdateUser.prototype.createResponse = function () { return new AdminUserResponse(); }; + AdminUpdateUser.prototype.getTypeName = function () { return 'AdminUpdateUser'; }; + AdminUpdateUser.prototype.getMethod = function () { return 'PUT'; }; + return AdminUpdateUser; +}(AdminUserBase)); +exports.AdminUpdateUser = AdminUpdateUser; + +var AdminDeleteUser = /** @class */ (function () { + function AdminDeleteUser(init) { + Object.assign(this, init); + } + AdminDeleteUser.prototype.createResponse = function () { return new AdminDeleteUserResponse(); }; + AdminDeleteUser.prototype.getTypeName = function () { return 'AdminDeleteUser'; }; + AdminDeleteUser.prototype.getMethod = function () { return 'DELETE'; }; + return AdminDeleteUser; +}()); +exports.AdminDeleteUser = AdminDeleteUser; +/*:minify*/ diff --git a/tests/NorthwindAuto/admin-ui/js/stores.js b/tests/NorthwindAuto/admin-ui/js/stores.js new file mode 100644 index 00000000000..dfb38908411 --- /dev/null +++ b/tests/NorthwindAuto/admin-ui/js/stores.js @@ -0,0 +1,130 @@ +import { APP, Authenticate } from "../../lib/types" + +/*minify:*/ +App.useTransitions({ sidebar: true }) + +/**: SignIn:provider */ +let routes = App.usePageRoutes({ + page:'admin', + queryKeys:'tab,provider,q,page,sort,new,edit'.split(','), + handlers: { + nav(state) { console.log('nav', state) } /*debug*/ + } +}) + +let store = PetiteVue.reactive({ + copied: false, + filter: '', + debug: APP.config.debugMode, + api: null, + auth: window.AUTH, + baseUrl: BASE_URL, + + init() { + setBodyClass({ page: routes.admin }) + }, + + get adminUsers() { return APP.plugins.adminUsers }, + + adminLink(id) { return APP.ui.adminLinks.find(x => x.id === id) }, + + get adminLinks() { return APP.ui.adminLinks }, + + get link() { return this.adminLink(routes.admin) }, + + cachedFetch(url) { + return new Promise((resolve,reject) => { + let src = CACHE[url] + if (src) { + resolve(src) + } else { + fetch(url) + .then(r => { + if (r.ok) return r.text() + else throw r.statusText + }) + .then(src => { + resolve(CACHE[url] = src) + }) + .catch(e => { + console.error(`fetchCache (${url}):`, e) + reject(e) + }) + } + }) + }, + + SignIn() { + return APP.plugins.auth + ? SignIn({ + plugin: APP.plugins.auth, + provider:() => routes.provider, + login:args => this.login(args), + api: () => this.api, + }) + : NoAuth({ message:`${APP.app.serviceName} API Explorer` }) + }, + + login(args) { + let provider = routes.provider || 'credentials' + let authProvider = APP.plugins.auth.authProviders.find(x => x.name === provider) + if (!authProvider) + throw new Error("!authProvider") + let auth = new Authenticate() + bearerToken = authsecret = null + if (authProvider.type === 'Bearer') { + bearerToken = client.bearerToken = (args['BearerToken'] || '').trim() + } else if (authProvider.type === 'authsecret') { + authsecret = (args['authsecret'] || '').trim() + client.headers.set('authsecret',authsecret) + } else { + auth = new Authenticate({ provider, ...args }) + } + client.api(auth, { jsconfig: 'eccn' }) + .then(r => { + this.api = r + if (r.error && !r.error.message) + r.error.message = HttpErrors[r.errorCode] || r.errorCode + if (this.api.succeeded) { + this.auth = this.api.response + setBodyClass({ auth: this.auth }) + } + }) + }, + + logout() { + setBodyClass({ auth: this.auth }) + client.api(new Authenticate({ provider: 'logout' })) + authsecret = bearerToken = client.bearerToken = null + client.headers.delete('authsecret') + this.auth = null + }, + + /**: v-if doesn't protect against nested access so need to guard against deep NRE access */ + get authRoles() { return this.auth && this.auth.roles || [] }, + get authPermissions() { return this.auth && this.auth.permissions || [] }, + get authProfileUrl() { return this.auth && this.auth.profileUrl }, + get isAdmin() { return this.authRoles.indexOf('Admin') >= 0 }, + + get authLinks() { + let to = [] + let roleLinks = this.auth && APP.plugins.auth && APP.plugins.auth.roleLinks || {} + if (Object.keys(roleLinks).length > 0) { + this.authRoles.forEach(role => { + if (!roleLinks[role]) return; + roleLinks[role].forEach(link => to.push(link)) + }) + } + return to + }, + + get displayName() { + let auth = this.auth + return auth + ? auth.displayName || (auth.firstName ? `${auth.firstName} ${auth.lastName}` : null) || auth.userName || auth.email + : null + }, +}) + +App.events.subscribe('route:nav', args => store.init()) +/*:minify*/ diff --git a/tests/NorthwindAuto/appsettings.json b/tests/NorthwindAuto/appsettings.json new file mode 100644 index 00000000000..88270e935fc --- /dev/null +++ b/tests/NorthwindAuto/appsettings.json @@ -0,0 +1,18 @@ +{ + "DebugMode": true, + "oauth.RedirectUrl": "http://localhost:5000/", + "oauth.CallbackUrl": "http://localhost:5000/auth/{0}", + "oauth.facebook.Permissions": [ "email", "user_location" ], + "oauth.facebook.Permissions2": "email,user_location", + "oauth.facebook.AppId": "531608123577340", + "oauth.facebook.AppSecret": "9e1e6591a7f15cbc1b305729f4b14c0b", + "oauth.twitter.ConsumerKey": "JvWZokH73rdghDdCFCFkJtCEU", + "oauth.twitter.ConsumerSecret": "WNeOT6YalxXDR4iWZjc4jVjFaydoDcY8jgRrGc5FVLjsVlY2Y8", + "oauth.github.Scopes": [ "user" ], + "oauth.github.ClientId": "04cc321f8fdac2260fa7", + "oauth.github.ClientSecret": "868d2b4c7b1632d1b774d6209b1c6ae522fe1954", + "oauth.microsoftgraph.AppId": "8208d98e-400d-4ce9-89ba-d92610c67e13", + "oauth.microsoftgraph.AppSecret": "hsrMP46|_kfkcYCWSW516?%", + "oauth.microsoftgraph.SavePhoto": "true", + "oauth.microsoftgraph.SavePhotoSize": "96x96" +} diff --git a/tests/NorthwindAuto/dtos.ts b/tests/NorthwindAuto/dtos.ts new file mode 100644 index 00000000000..c8eb19654fb --- /dev/null +++ b/tests/NorthwindAuto/dtos.ts @@ -0,0 +1,694 @@ +/* Options: +Date: 2022-01-01 14:52:29 +Version: 5.133 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: https://localhost:5001 + +//GlobalNamespace: +//MakePropertiesOptional: False +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ + + +export interface IReturn +{ + createResponse(): T; +} + +export interface IReturnVoid +{ + createResponse(): void; +} + +export interface IHasSessionId +{ + sessionId: string; +} + +export interface IHasBearerToken +{ + bearerToken: string; +} + +export interface IPost +{ +} + +export interface IPut +{ +} + +export interface IDelete +{ +} + +export interface ICreateDb +{ +} + +export interface IPatchDb
+{ +} + +export interface IDeleteDb
+{ +} + +// @DataContract +export class QueryBase +{ + // @DataMember(Order=1) + public skip?: number; + + // @DataMember(Order=2) + public take?: number; + + // @DataMember(Order=3) + public orderBy: string; + + // @DataMember(Order=4) + public orderByDesc: string; + + // @DataMember(Order=5) + public include: string; + + // @DataMember(Order=6) + public fields: string; + + // @DataMember(Order=7) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class QueryData extends QueryBase +{ + + public constructor(init?: Partial>) { super(init); (Object as any).assign(this, init); } +} + +export class QueryDb extends QueryBase +{ + + public constructor(init?: Partial>) { super(init); (Object as any).assign(this, init); } +} + +// @DataContract +export class AuditBase +{ + // @DataMember(Order=1) + public createdDate: string; + + // @DataMember(Order=2) + // @Required() + public createdBy: string; + + // @DataMember(Order=3) + public modifiedDate: string; + + // @DataMember(Order=4) + // @Required() + public modifiedBy: string; + + // @DataMember(Order=5) + public deletedDate?: string; + + // @DataMember(Order=6) + public deletedBy: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export enum RoomType +{ + Single = 'Single', + Double = 'Double', + Queen = 'Queen', + Twin = 'Twin', + Suite = 'Suite', +} + +export class Booking extends AuditBase +{ + public id: number; + public name: string; + public roomType: RoomType; + public roomNumber: number; + public bookingStartDate: string; + public bookingEndDate?: string; + public cost: number; + public notes: string; + public cancelled?: boolean; + + public constructor(init?: Partial) { super(init); (Object as any).assign(this, init); } +} + +// @DataContract +export class ResponseError +{ + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public fieldName: string; + + // @DataMember(Order=3) + public message: string; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class ResponseStatus +{ + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public message: string; + + // @DataMember(Order=3) + public stackTrace: string; + + // @DataMember(Order=4) + public errors: ResponseError[]; + + // @DataMember(Order=5) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class HelloResponse +{ + public result: string; + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class QueryResponse +{ + // @DataMember(Order=1) + public offset: number; + + // @DataMember(Order=2) + public total: number; + + // @DataMember(Order=3) + public results: T[]; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + // @DataMember(Order=5) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial>) { (Object as any).assign(this, init); } +} + +export class Todo +{ + public id: number; + public text: string; + public isFinished: boolean; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AuthenticateResponse implements IHasSessionId, IHasBearerToken +{ + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public referrerUrl: string; + + // @DataMember(Order=6) + public bearerToken: string; + + // @DataMember(Order=7) + public refreshToken: string; + + // @DataMember(Order=8) + public profileUrl: string; + + // @DataMember(Order=9) + public roles: string[]; + + // @DataMember(Order=10) + public permissions: string[]; + + // @DataMember(Order=11) + public responseStatus: ResponseStatus; + + // @DataMember(Order=12) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AssignRolesResponse +{ + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public meta: { [index: string]: string; }; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class UnAssignRolesResponse +{ + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public meta: { [index: string]: string; }; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class RegisterResponse implements IHasSessionId, IHasBearerToken +{ + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public referrerUrl: string; + + // @DataMember(Order=5) + public bearerToken: string; + + // @DataMember(Order=6) + public refreshToken: string; + + // @DataMember(Order=7) + public roles: string[]; + + // @DataMember(Order=8) + public permissions: string[]; + + // @DataMember(Order=9) + public responseStatus: ResponseStatus; + + // @DataMember(Order=10) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class IdResponse +{ + // @DataMember(Order=1) + public id: string; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @Route("/hello/{Name}") +export class Hello implements IReturn +{ + public name: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'Hello'; } + public getMethod() { return 'POST'; } +} + +// @Route("/hello-long/{Name}") +// @ValidateRequest(Validator="IsAuthenticated") +export class HelloVeryLongOperationNameVersions implements IReturn +{ + public name: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'HelloVeryLongOperationNameVersions'; } + public getMethod() { return 'POST'; } +} + +// @Route("/hellosecure/{Name}") +// @ValidateRequest(Validator="IsAuthenticated") +export class HelloSecure implements IReturn +{ + public name: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new HelloResponse(); } + public getTypeName() { return 'HelloSecure'; } + public getMethod() { return 'POST'; } +} + +// @Route("/todos", "GET") +export class QueryTodos extends QueryData implements IReturn> +{ + public id?: number; + public ids: number[]; + public textContains: string; + + public constructor(init?: Partial) { super(init); (Object as any).assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryTodos'; } + public getMethod() { return 'GET'; } +} + +// @Route("/todos", "POST") +export class CreateTodo implements IReturn, IPost +{ + public text: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new Todo(); } + public getTypeName() { return 'CreateTodo'; } + public getMethod() { return 'POST'; } +} + +// @Route("/todos/{Id}", "PUT") +export class UpdateTodo implements IReturn, IPut +{ + public id: number; + public text: string; + public isFinished: boolean; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new Todo(); } + public getTypeName() { return 'UpdateTodo'; } + public getMethod() { return 'PUT'; } +} + +// @Route("/todos/{Id}", "DELETE") +export class DeleteTodo implements IReturnVoid, IDelete +{ + public id: number; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() {} + public getTypeName() { return 'DeleteTodo'; } + public getMethod() { return 'DELETE'; } +} + +// @Route("/todos", "DELETE") +export class DeleteTodos implements IReturnVoid, IDelete +{ + public ids: number[]; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() {} + public getTypeName() { return 'DeleteTodos'; } + public getMethod() { return 'DELETE'; } +} + +/** +* Sign In +*/ +// @Route("/auth") +// @Route("/auth/{provider}") +// @Api(Description="Sign In") +// @DataContract +export class Authenticate implements IReturn, IPost +{ + /** + * AuthProvider, e.g. credentials + */ + // @DataMember(Order=1) + // @ApiMember(Description="AuthProvider, e.g. credentials") + public provider: string; + + // @DataMember(Order=2) + public state: string; + + // @DataMember(Order=3) + public oauth_token: string; + + // @DataMember(Order=4) + public oauth_verifier: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public rememberMe?: boolean; + + // @DataMember(Order=9) + public errorView: string; + + // @DataMember(Order=10) + public nonce: string; + + // @DataMember(Order=11) + public uri: string; + + // @DataMember(Order=12) + public response: string; + + // @DataMember(Order=13) + public qop: string; + + // @DataMember(Order=14) + public nc: string; + + // @DataMember(Order=15) + public cnonce: string; + + // @DataMember(Order=17) + public accessToken: string; + + // @DataMember(Order=18) + public accessTokenSecret: string; + + // @DataMember(Order=19) + public scope: string; + + // @DataMember(Order=20) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AuthenticateResponse(); } + public getTypeName() { return 'Authenticate'; } + public getMethod() { return 'POST'; } +} + +// @Route("/assignroles") +// @DataContract +export class AssignRoles implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AssignRolesResponse(); } + public getTypeName() { return 'AssignRoles'; } + public getMethod() { return 'POST'; } +} + +// @Route("/unassignroles") +// @DataContract +export class UnAssignRoles implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new UnAssignRolesResponse(); } + public getTypeName() { return 'UnAssignRoles'; } + public getMethod() { return 'POST'; } +} + +/** +* Sign Up +*/ +// @Route("/register") +// @Api(Description="Sign Up") +// @DataContract +export class Register implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public firstName: string; + + // @DataMember(Order=3) + public lastName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public email: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public confirmPassword: string; + + // @DataMember(Order=8) + public autoLogin?: boolean; + + // @DataMember(Order=10) + public errorView: string; + + // @DataMember(Order=11) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new RegisterResponse(); } + public getTypeName() { return 'Register'; } + public getMethod() { return 'POST'; } +} + +/** +* Find Bookings +*/ +// @Api(Description="Find Bookings") +export class QueryBookings extends QueryDb implements IReturn> +{ + public id?: number; + + public constructor(init?: Partial) { super(init); (Object as any).assign(this, init); } + public createResponse() { return new QueryResponse(); } + public getTypeName() { return 'QueryBookings'; } + public getMethod() { return 'GET'; } +} + +/** +* Create a new Booking +*/ +// @Api(Description="Create a new Booking") +// @ValidateRequest(Validator="HasRole(`Employee`)") +// @ValidateRequest(Validator="HasPermission(`ThePermission`)") +export class CreateBooking implements IReturn, ICreateDb +{ + /** + * Name this Booking is for + */ + public name: string; + public roomType: RoomType; + // @Validate(Validator="GreaterThan(0)") + public roomNumber: number; + + public bookingStartDate: string; + public bookingEndDate?: string; + // @Validate(Validator="GreaterThan(0)") + public cost: number; + + public notes: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new IdResponse(); } + public getTypeName() { return 'CreateBooking'; } + public getMethod() { return 'POST'; } +} + +/** +* Update an existing Booking +*/ +// @Api(Description="Update an existing Booking") +// @ValidateRequest(Validator="HasRole(`Employee`)") +export class UpdateBooking implements IReturn, IPatchDb +{ + public id: number; + public name: string; + public roomType?: RoomType; + // @Validate(Validator="GreaterThan(0)") + public roomNumber?: number; + + public bookingStartDate?: string; + public bookingEndDate?: string; + // @Validate(Validator="GreaterThan(0)") + public cost?: number; + + public notes: string; + public cancelled?: boolean; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new IdResponse(); } + public getTypeName() { return 'UpdateBooking'; } + public getMethod() { return 'PATCH'; } +} + +/** +* Delete a Booking +*/ +// @Api(Description="Delete a Booking") +// @ValidateRequest(Validator="HasRole(`Manager`)") +export class DeleteBooking implements IReturnVoid, IDeleteDb +{ + public id: number; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() {} + public getTypeName() { return 'DeleteBooking'; } + public getMethod() { return 'DELETE'; } +} + diff --git a/tests/NorthwindAuto/index.css b/tests/NorthwindAuto/index.css new file mode 100644 index 00000000000..3ccfed6ea6e --- /dev/null +++ b/tests/NorthwindAuto/index.css @@ -0,0 +1,45 @@ +@tailwind base; +@tailwind components; + +/* custom shared css */ +b { + font-weight: 500; +} +::-webkit-scrollbar{width:8px;height:8px} +::-webkit-scrollbar-thumb{background-color:#ccc} +em { + color: #3b82f6; + font-weight: 400; + background-color: #eff6ff; + border-radius: 0.25rem; + padding: 0.125em 0.5rem; + margin-left: 0.125em; + margin-right: 0.125em; + font-style: normal; +} +.svg-lock { + background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%221em%22%20height%3D%221em%22%20preserveAspectRatio%3D%22xMidYMid%20meet%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20fill%3D%22%23B1B4B5%22%20d%3D%22M376.749%20349.097c-13.531%200-24.5-10.969-24.5-24.5V181.932c0-48.083-39.119-87.203-87.203-87.203c-48.083%200-87.203%2039.119-87.203%2087.203v82.977c0%2013.531-10.969%2024.5-24.5%2024.5s-24.5-10.969-24.5-24.5v-82.977c0-75.103%2061.1-136.203%20136.203-136.203s136.203%2061.1%20136.203%20136.203v142.665c0%2013.531-10.969%2024.5-24.5%2024.5z%22%2F%3E%3Cpath%20fill%3D%22%23FFB636%22%20d%3D%22M414.115%20497.459H115.977c-27.835%200-50.4-22.565-50.4-50.4V274.691c0-27.835%2022.565-50.4%2050.4-50.4h298.138c27.835%200%2050.4%2022.565%2050.4%2050.4v172.367c0%2027.836-22.565%2050.401-50.4%2050.401z%22%2F%3E%3Cpath%20fill%3D%22%23FFD469%22%20d%3D%22M109.311%20456.841h-2.525c-7.953%200-14.4-6.447-14.4-14.4V279.309c0-7.953%206.447-14.4%2014.4-14.4h2.525c7.953%200%2014.4%206.447%2014.4%2014.4v163.132c0%207.953-6.447%2014.4-14.4%2014.4z%22%2F%3E%3C%2Fsvg%3E') no-repeat; + background-size: cover; +} +.svg-external { + background: url("data:image/svg+xml,%3Csvg width='1.25rem' height='1.25rem' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none'%3E%3Cpath d='M10 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-4M14 4h6m0 0v6m0-6L10 14' stroke='%231E40AF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/g%3E%3C/svg%3E") no-repeat bottom right; + padding-right: 1.35rem; +} + +.loading .app { display: none } +.when-loading { display: none } +.loading .when-loading { display: block } + +.sm\:noauth-nopage\:hidden { display: block } +.sm\:noauth-nopage\:block { display: none } +.auth .sm\:auth\:hidden, .noauth .sm\:noauth\:hidden, .page .sm\:page\:hidden, .nopage .sm\:nopage\:hidden { display: block } +.auth .sm\:auth\:block, .noauth .sm\:noauth\:block, .page .sm\:page\:block, .nopage .sm\:nopage\:block { display: none } + +@media (max-width: 640px) { + .auth .sm\:auth\:hidden, .noauth .sm\:noauth\:hidden, .page .sm\:page\:hidden, .nopage .sm\:nopage\:hidden { display: none } + .auth .sm\:auth\:block, .noauth .sm\:noauth\:block, .page .sm\:page\:block, .nopage .sm\:nopage\:block { display: block } + .noauth.nopage .sm\:noauth-nopage\:hidden { display: none } + .noauth.nopage .sm\:noauth-nopage\:block { display: block } +} + +@tailwind utilities; diff --git a/tests/NorthwindAuto/lib/types.ts b/tests/NorthwindAuto/lib/types.ts new file mode 100644 index 00000000000..a88217b79f4 --- /dev/null +++ b/tests/NorthwindAuto/lib/types.ts @@ -0,0 +1,919 @@ +/* Options: +Date: 2022-01-13 07:18:45 +Version: 5.133 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:20000 + +//GlobalNamespace: +//MakePropertiesOptional: False +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddImplicitVersion: +//AddDescriptionAsComments: True +//IncludeTypes: +//ExcludeTypes: +//DefaultImports: +*/ + + +export interface IReturn +{ + createResponse(): T; +} + +export interface IReturnVoid +{ + createResponse(): void; +} + +export interface IHasSessionId +{ + sessionId: string; +} + +export interface IHasBearerToken +{ + bearerToken: string; +} + +export interface IPost +{ +} + +export interface IGet +{ +} + +export interface IPut +{ +} + +export interface IDelete +{ +} + +// @DataContract +export class AdminUserBase +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public firstName: string; + + // @DataMember(Order=3) + public lastName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public email: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public profileUrl: string; + + // @DataMember(Order=8) + public userAuthProperties: { [index: string]: string; }; + + // @DataMember(Order=9) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class AppInfo +{ + public baseUrl: string; + public serviceStackVersion: string; + public serviceName: string; + public serviceDescription: string; + public serviceIconUrl: string; + public brandUrl: string; + public brandImageUrl: string; + public textColor: string; + public linkColor: string; + public backgroundColor: string; + public backgroundImageUrl: string; + public iconUrl: string; + public jsTextCase: string; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class ImageInfo +{ + public svg: string; + public uri: string; + public alt: string; + public cls: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class LinkInfo +{ + public id: string; + public href: string; + public label: string; + public icon: ImageInfo; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class UiInfo +{ + public brandIcon: ImageInfo; + public hideTags: string[]; + public alwaysHideTags: string[]; + public adminLinks: LinkInfo[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class ConfigInfo +{ + public debugMode?: boolean; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class NavItem +{ + public label: string; + public href: string; + public exact?: boolean; + public id: string; + public className: string; + public iconClass: string; + public show: string; + public hide: string; + public children: NavItem[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class InputInfo +{ + public id: string; + public name: string; + public type: string; + public value: string; + public placeholder: string; + public help: string; + public label: string; + public title: string; + public size: string; + public pattern: string; + public readOnly?: boolean; + public required?: boolean; + public disabled?: boolean; + public autocomplete: string; + public autofocus: string; + public min: string; + public max: string; + public step?: number; + public minLength?: number; + public maxLength?: number; + public allowableValues: string[]; + public allowableEntries: KeyValuePair[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetaAuthProvider +{ + public name: string; + public label: string; + public type: string; + public navItem: NavItem; + public icon: ImageInfo; + public formLayout: InputInfo[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class AuthInfo +{ + public hasAuthSecret?: boolean; + public hasAuthRepository?: boolean; + public includesRoles?: boolean; + public includesOAuthTokens?: boolean; + public htmlRedirect: string; + public authProviders: MetaAuthProvider[]; + public roleLinks: { [index: string]: LinkInfo[]; }; + public serviceRoutes: { [index: string]: string[]; }; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class AutoQueryConvention +{ + public name: string; + public value: string; + public types: string; + public valueType: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class AutoQueryInfo +{ + public maxLimit?: number; + public untypedQueries?: boolean; + public rawSqlFilters?: boolean; + public autoQueryViewer?: boolean; + public async?: boolean; + public orderByPrimaryKey?: boolean; + public crudEvents?: boolean; + public crudEventsServices?: boolean; + public accessRole: string; + public namedConnection: string; + public viewerConventions: AutoQueryConvention[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class ScriptMethodType +{ + public name: string; + public paramNames: string[]; + public paramTypes: string[]; + public returnType: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class ValidationInfo +{ + public hasValidationSource?: boolean; + public hasValidationSourceAdmin?: boolean; + public serviceRoutes: { [index: string]: string[]; }; + public typeValidators: ScriptMethodType[]; + public propertyValidators: ScriptMethodType[]; + public accessRole: string; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class SharpPagesInfo +{ + public apiPath: string; + public scriptAdminRole: string; + public metadataDebugAdminRole: string; + public metadataDebug?: boolean; + public spaFallback?: boolean; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class RequestLogsInfo +{ + public requiredRoles: string[]; + public requestLogger: string; + public serviceRoutes: { [index: string]: string[]; }; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataTypeName +{ + public name: string; + public namespace: string; + public genericArgs: string[]; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataDataContract +{ + public name: string; + public namespace: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataDataMember +{ + public name: string; + public order?: number; + public isRequired?: boolean; + public emitDefaultValue?: boolean; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataAttribute +{ + public name: string; + public constructorArgs: MetadataPropertyType[]; + public args: MetadataPropertyType[]; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataPropertyType +{ + public name: string; + public type: string; + public isValueType?: boolean; + public isSystemType?: boolean; + public isEnum?: boolean; + public isPrimaryKey?: boolean; + public typeNamespace: string; + public genericArgs: string[]; + public value: string; + public description: string; + public dataMember: MetadataDataMember; + public readOnly?: boolean; + public paramType: string; + public displayType: string; + public isRequired?: boolean; + public allowableValues: string[]; + public allowableMin?: number; + public allowableMax?: number; + public attributes: MetadataAttribute[]; + public input: InputInfo; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataType +{ + public name: string; + public namespace: string; + public genericArgs: string[]; + public inherits: MetadataTypeName; + public implements: MetadataTypeName[]; + public displayType: string; + public description: string; + public notes: string; + public isNested?: boolean; + public isEnum?: boolean; + public isEnumInt?: boolean; + public isInterface?: boolean; + public isAbstract?: boolean; + public dataContract: MetadataDataContract; + public properties: MetadataPropertyType[]; + public attributes: MetadataAttribute[]; + public innerTypes: MetadataTypeName[]; + public enumNames: string[]; + public enumValues: string[]; + public enumMemberValues: string[]; + public enumDescriptions: string[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MediaRule +{ + public size: string; + public rule: string; + public applyTo: string[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class AdminUsersInfo +{ + public accessRole: string; + public enabled: string[]; + public userAuth: MetadataType; + public allRoles: string[]; + public allPermissions: string[]; + public queryUserAuthProperties: string[]; + public queryMediaRules: MediaRule[]; + public userFormLayout: InputInfo[][]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class PluginInfo +{ + public loaded: string[]; + public auth: AuthInfo; + public autoQuery: AutoQueryInfo; + public validation: ValidationInfo; + public sharpPages: SharpPagesInfo; + public requestLogs: RequestLogsInfo; + public adminUsers: AdminUsersInfo; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class CustomPluginInfo +{ + public accessRole: string; + public serviceRoutes: { [index: string]: string[]; }; + public enabled: string[]; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataTypesConfig +{ + public baseUrl: string; + public usePath: string; + public makePartial: boolean; + public makeVirtual: boolean; + public makeInternal: boolean; + public baseClass: string; + public package: string; + public addReturnMarker: boolean; + public addDescriptionAsComments: boolean; + public addDataContractAttributes: boolean; + public addIndexesToDataMembers: boolean; + public addGeneratedCodeAttributes: boolean; + public addImplicitVersion?: number; + public addResponseStatus: boolean; + public addServiceStackTypes: boolean; + public addModelExtensions: boolean; + public addPropertyAccessors: boolean; + public excludeGenericBaseTypes: boolean; + public settersReturnThis: boolean; + public makePropertiesOptional: boolean; + public exportAsTypes: boolean; + public excludeImplementedInterfaces: boolean; + public addDefaultXmlNamespace: string; + public makeDataContractsExtensible: boolean; + public initializeCollections: boolean; + public addNamespaces: string[]; + public defaultNamespaces: string[]; + public defaultImports: string[]; + public includeTypes: string[]; + public excludeTypes: string[]; + public treatTypesAsStrings: string[]; + public exportValueTypes: boolean; + public globalNamespace: string; + public excludeNamespace: boolean; + public dataClass: string; + public dataClassJson: string; + public ignoreTypes: string[]; + public exportTypes: string[]; + public exportAttributes: string[]; + public ignoreTypesInNamespaces: string[]; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataRoute +{ + public path: string; + public verbs: string; + public notes: string; + public summary: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataOperationType +{ + public request: MetadataType; + public response: MetadataType; + public actions: string[]; + public returnsVoid: boolean; + public method: string; + public returnType: MetadataTypeName; + public routes: MetadataRoute[]; + public dataModel: MetadataTypeName; + public viewModel: MetadataTypeName; + public requiresAuth: boolean; + public requiredRoles: string[]; + public requiresAnyRole: string[]; + public requiredPermissions: string[]; + public requiresAnyPermission: string[]; + public tags: string[]; + public formLayout: InputInfo[][]; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class MetadataTypes +{ + public config: MetadataTypesConfig; + public namespaces: string[]; + public types: MetadataType[]; + public operations: MetadataOperationType[]; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class ResponseError +{ + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public fieldName: string; + + // @DataMember(Order=3) + public message: string; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class ResponseStatus +{ + // @DataMember(Order=1) + public errorCode: string; + + // @DataMember(Order=2) + public message: string; + + // @DataMember(Order=3) + public stackTrace: string; + + // @DataMember(Order=4) + public errors: ResponseError[]; + + // @DataMember(Order=5) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +export class KeyValuePair +{ + public key: TKey; + public value: TValue; + + public constructor(init?: Partial>) { (Object as any).assign(this, init); } +} + +export class AppMetadata +{ + public app: AppInfo; + public ui: UiInfo; + public config: ConfigInfo; + public contentTypeFormats: { [index: string]: string; }; + public httpHandlers: { [index: string]: string; }; + public plugins: PluginInfo; + public customPlugins: { [index: string]: CustomPluginInfo; }; + public api: MetadataTypes; + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AuthenticateResponse implements IHasSessionId, IHasBearerToken +{ + // @DataMember(Order=1) + public userId: string; + + // @DataMember(Order=2) + public sessionId: string; + + // @DataMember(Order=3) + public userName: string; + + // @DataMember(Order=4) + public displayName: string; + + // @DataMember(Order=5) + public referrerUrl: string; + + // @DataMember(Order=6) + public bearerToken: string; + + // @DataMember(Order=7) + public refreshToken: string; + + // @DataMember(Order=8) + public profileUrl: string; + + // @DataMember(Order=9) + public roles: string[]; + + // @DataMember(Order=10) + public permissions: string[]; + + // @DataMember(Order=11) + public responseStatus: ResponseStatus; + + // @DataMember(Order=12) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AssignRolesResponse +{ + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public meta: { [index: string]: string; }; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class UnAssignRolesResponse +{ + // @DataMember(Order=1) + public allRoles: string[]; + + // @DataMember(Order=2) + public allPermissions: string[]; + + // @DataMember(Order=3) + public meta: { [index: string]: string; }; + + // @DataMember(Order=4) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AdminUserResponse +{ + // @DataMember(Order=1) + public id: string; + + // @DataMember(Order=2) + public result: { [index: string]: Object; }; + + // @DataMember(Order=3) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AdminUsersResponse +{ + // @DataMember(Order=1) + public results: { [index:string]: Object; }[]; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @DataContract +export class AdminDeleteUserResponse +{ + // @DataMember(Order=1) + public id: string; + + // @DataMember(Order=2) + public responseStatus: ResponseStatus; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } +} + +// @Route("/metadata/app") +// @DataContract +export class MetadataApp implements IReturn +{ + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AppMetadata(); } + public getTypeName() { return 'MetadataApp'; } + public getMethod() { return 'POST'; } +} + +/** +* Sign In +*/ +// @Route("/auth") +// @Route("/auth/{provider}") +// @Api(Description="Sign In") +// @DataContract +export class Authenticate implements IReturn, IPost +{ + /** + * AuthProvider, e.g. credentials + */ + // @DataMember(Order=1) + // @ApiMember(Description="AuthProvider, e.g. credentials") + public provider: string; + + // @DataMember(Order=2) + public state: string; + + // @DataMember(Order=3) + public oauth_token: string; + + // @DataMember(Order=4) + public oauth_verifier: string; + + // @DataMember(Order=5) + public userName: string; + + // @DataMember(Order=6) + public password: string; + + // @DataMember(Order=7) + public rememberMe?: boolean; + + // @DataMember(Order=9) + public errorView: string; + + // @DataMember(Order=10) + public nonce: string; + + // @DataMember(Order=11) + public uri: string; + + // @DataMember(Order=12) + public response: string; + + // @DataMember(Order=13) + public qop: string; + + // @DataMember(Order=14) + public nc: string; + + // @DataMember(Order=15) + public cnonce: string; + + // @DataMember(Order=17) + public accessToken: string; + + // @DataMember(Order=18) + public accessTokenSecret: string; + + // @DataMember(Order=19) + public scope: string; + + // @DataMember(Order=20) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AuthenticateResponse(); } + public getTypeName() { return 'Authenticate'; } + public getMethod() { return 'POST'; } +} + +// @Route("/assignroles") +// @DataContract +export class AssignRoles implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AssignRolesResponse(); } + public getTypeName() { return 'AssignRoles'; } + public getMethod() { return 'POST'; } +} + +// @Route("/unassignroles") +// @DataContract +export class UnAssignRoles implements IReturn, IPost +{ + // @DataMember(Order=1) + public userName: string; + + // @DataMember(Order=2) + public permissions: string[]; + + // @DataMember(Order=3) + public roles: string[]; + + // @DataMember(Order=4) + public meta: { [index: string]: string; }; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new UnAssignRolesResponse(); } + public getTypeName() { return 'UnAssignRoles'; } + public getMethod() { return 'POST'; } +} + +// @DataContract +export class AdminGetUser implements IReturn, IGet +{ + // @DataMember(Order=10) + public id: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AdminUserResponse(); } + public getTypeName() { return 'AdminGetUser'; } + public getMethod() { return 'GET'; } +} + +// @DataContract +export class AdminQueryUsers implements IReturn, IGet +{ + // @DataMember(Order=1) + public query: string; + + // @DataMember(Order=2) + public orderBy: string; + + // @DataMember(Order=3) + public skip?: number; + + // @DataMember(Order=4) + public take?: number; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AdminUsersResponse(); } + public getTypeName() { return 'AdminQueryUsers'; } + public getMethod() { return 'GET'; } +} + +// @DataContract +export class AdminCreateUser extends AdminUserBase implements IReturn, IPost +{ + // @DataMember(Order=10) + public roles: string[]; + + // @DataMember(Order=11) + public permissions: string[]; + + public constructor(init?: Partial) { super(init); (Object as any).assign(this, init); } + public createResponse() { return new AdminUserResponse(); } + public getTypeName() { return 'AdminCreateUser'; } + public getMethod() { return 'POST'; } +} + +// @DataContract +export class AdminUpdateUser extends AdminUserBase implements IReturn, IPut +{ + // @DataMember(Order=10) + public id: string; + + // @DataMember(Order=11) + public lockUser?: boolean; + + // @DataMember(Order=12) + public unlockUser?: boolean; + + // @DataMember(Order=13) + public addRoles: string[]; + + // @DataMember(Order=14) + public removeRoles: string[]; + + // @DataMember(Order=15) + public addPermissions: string[]; + + // @DataMember(Order=16) + public removePermissions: string[]; + + public constructor(init?: Partial) { super(init); (Object as any).assign(this, init); } + public createResponse() { return new AdminUserResponse(); } + public getTypeName() { return 'AdminUpdateUser'; } + public getMethod() { return 'PUT'; } +} + +// @DataContract +export class AdminDeleteUser implements IReturn, IDelete +{ + // @DataMember(Order=10) + public id: string; + + public constructor(init?: Partial) { (Object as any).assign(this, init); } + public createResponse() { return new AdminDeleteUserResponse(); } + public getTypeName() { return 'AdminDeleteUser'; } + public getMethod() { return 'DELETE'; } +} + + +// declare Types used in /ui +export declare var APP:AppMetadata diff --git a/tests/NorthwindAuto/northwind.sqlite b/tests/NorthwindAuto/northwind.sqlite new file mode 100644 index 00000000000..9e592d59b90 Binary files /dev/null and b/tests/NorthwindAuto/northwind.sqlite differ diff --git a/tests/NorthwindAuto/package-lock.json b/tests/NorthwindAuto/package-lock.json new file mode 100644 index 00000000000..258a1eef74e --- /dev/null +++ b/tests/NorthwindAuto/package-lock.json @@ -0,0 +1,2103 @@ +{ + "name": "my-app", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "my-app", + "version": "1.0.0", + "dependencies": { + "@servicestack/client": "^1.1.17", + "@tailwindcss/forms": "^0.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "peer": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "peer": true + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@servicestack/client": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@servicestack/client/-/client-1.1.17.tgz", + "integrity": "sha512-iX1WUCQ9jszyRTg2RgPcDPQWKo1ZmhhCp2beiwX0qfgD9G+RRd3l9MmuK3EBQpxSBnsVhDHZ+qsaPVmZ/HAhGg==", + "dependencies": { + "cross-fetch": "^3.1.4", + "es6-shim": "^0.35.6", + "eventsource": "^1.1.0" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.4.0.tgz", + "integrity": "sha512-DeaQBx6EgEeuZPQACvC+mKneJsD8am1uiJugjgQK1+/Vt+Ai0GpFBC2T2fqnUad71WgOxyrZPE6BG1VaI6YqfQ==", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "peer": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "peer": true, + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "peer": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", + "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", + "peer": true + }, + "node_modules/autoprefixer": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", + "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "peer": true, + "dependencies": { + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001297", + "fraction.js": "^4.1.2", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "peer": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001299", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz", + "integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "peer": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "peer": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", + "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", + "dependencies": { + "node-fetch": "2.6.1" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "peer": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "peer": true + }, + "node_modules/detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "peer": true, + "dependencies": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "peer": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.42", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.42.tgz", + "integrity": "sha512-JJLT8bjdswJzk8sNRnQjee0MGtO4zTn1t7eWwYPr8gPTadQgNRR/wFRKLGD6HZVZby39yHERkvuCVKNm10r7Dg==", + "peer": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "peer": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-shim": { + "version": "0.35.6", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", + "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "dependencies": { + "original": "^1.0.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/fast-glob": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz", + "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==", + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "peer": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", + "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "peer": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "peer": true + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "peer": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "peer": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "peer": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "peer": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "peer": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "peer": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "peer": true + }, + "node_modules/lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "peer": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "peer": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.3.tgz", + "integrity": "sha512-gSfqpMRC8IxghvMcxzzmMnWpXAChSA+vy4cia33RgerMS8Fex95akUyQZPbxJJmeBGiGmK7n/1OpUX8ksRjIdA==", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "peer": true + }, + "node_modules/nanoid": { + "version": "3.1.31", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.31.tgz", + "integrity": "sha512-ZivnJm0o9bb13p2Ot5CpgC2rQdzB9Uxm/mFZweqm5eMViqOJe3PV6LU2E30SiLgheesmcPrjquqraoolONSA0A==", + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "peer": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dependencies": { + "url-parse": "^1.4.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "peer": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "peer": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "peer": true, + "dependencies": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", + "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "peer": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", + "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", + "peer": true, + "dependencies": { + "lilconfig": "^2.0.4", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^6.0.6" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", + "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "peer": true + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "peer": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/resolve": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", + "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "peer": true, + "dependencies": { + "is-core-module": "^2.8.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/source-map-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", + "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.13.tgz", + "integrity": "sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==", + "peer": true, + "dependencies": { + "arg": "^5.0.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color-name": "^1.1.4", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.8", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.21.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "autoprefixer": "^10.0.2", + "postcss": "^8.0.9" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "peer": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz", + "integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "peer": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "peer": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "peer": true, + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "peer": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "peer": true + }, + "@babel/highlight": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "peer": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "peer": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "peer": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "peer": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "peer": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "peer": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@servicestack/client": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@servicestack/client/-/client-1.1.17.tgz", + "integrity": "sha512-iX1WUCQ9jszyRTg2RgPcDPQWKo1ZmhhCp2beiwX0qfgD9G+RRd3l9MmuK3EBQpxSBnsVhDHZ+qsaPVmZ/HAhGg==", + "requires": { + "cross-fetch": "^3.1.4", + "es6-shim": "^0.35.6", + "eventsource": "^1.1.0" + } + }, + "@tailwindcss/forms": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.4.0.tgz", + "integrity": "sha512-DeaQBx6EgEeuZPQACvC+mKneJsD8am1uiJugjgQK1+/Vt+Ai0GpFBC2T2fqnUad71WgOxyrZPE6BG1VaI6YqfQ==", + "requires": { + "mini-svg-data-uri": "^1.2.3" + } + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "peer": true + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "peer": true + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "peer": true, + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "peer": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "peer": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", + "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", + "peer": true + }, + "autoprefixer": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", + "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "peer": true, + "requires": { + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001297", + "fraction.js": "^4.1.2", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "peer": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "peer": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "peer": true, + "requires": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "peer": true + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "peer": true + }, + "caniuse-lite": { + "version": "1.0.30001299", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz", + "integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==", + "peer": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "peer": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "peer": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "peer": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-fetch": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", + "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", + "requires": { + "node-fetch": "2.6.1" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "peer": true + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "peer": true + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "peer": true, + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "peer": true + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "peer": true + }, + "electron-to-chromium": { + "version": "1.4.42", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.42.tgz", + "integrity": "sha512-JJLT8bjdswJzk8sNRnQjee0MGtO4zTn1t7eWwYPr8gPTadQgNRR/wFRKLGD6HZVZby39yHERkvuCVKNm10r7Dg==", + "peer": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "peer": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-shim": { + "version": "0.35.6", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", + "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "peer": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "peer": true + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "requires": { + "original": "^1.0.0" + } + }, + "fast-glob": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz", + "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==", + "peer": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "peer": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "peer": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "peer": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fraction.js": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", + "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "peer": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true, + "peer": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "peer": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "peer": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "peer": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "peer": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "peer": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "peer": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "peer": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "peer": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "peer": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "peer": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "peer": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "peer": true + }, + "lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "peer": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "peer": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "peer": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "peer": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mini-svg-data-uri": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.3.tgz", + "integrity": "sha512-gSfqpMRC8IxghvMcxzzmMnWpXAChSA+vy4cia33RgerMS8Fex95akUyQZPbxJJmeBGiGmK7n/1OpUX8ksRjIdA==" + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "peer": true + }, + "nanoid": { + "version": "3.1.31", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.31.tgz", + "integrity": "sha512-ZivnJm0o9bb13p2Ot5CpgC2rQdzB9Uxm/mFZweqm5eMViqOJe3PV6LU2E30SiLgheesmcPrjquqraoolONSA0A==", + "peer": true + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "peer": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "peer": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "peer": true + }, + "object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "peer": true + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "requires": { + "url-parse": "^1.4.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "peer": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "peer": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "peer": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "peer": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "peer": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "peer": true + }, + "postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "peer": true, + "requires": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + } + }, + "postcss-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", + "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "peer": true, + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-load-config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", + "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", + "peer": true, + "requires": { + "lilconfig": "^2.0.4", + "yaml": "^1.10.2" + } + }, + "postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "peer": true, + "requires": { + "postcss-selector-parser": "^6.0.6" + } + }, + "postcss-selector-parser": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", + "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "peer": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "peer": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "peer": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "peer": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "peer": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resolve": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", + "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "peer": true, + "requires": { + "is-core-module": "^2.8.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "peer": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "peer": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "peer": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "source-map-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", + "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "peer": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "peer": true + }, + "tailwindcss": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.13.tgz", + "integrity": "sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==", + "peer": true, + "requires": { + "arg": "^5.0.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color-name": "^1.1.4", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.8", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.21.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "peer": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "url-parse": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz", + "integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "peer": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "peer": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "peer": true + } + } +} diff --git a/tests/NorthwindAuto/package.json b/tests/NorthwindAuto/package.json new file mode 100644 index 00000000000..a4c14e4492a --- /dev/null +++ b/tests/NorthwindAuto/package.json @@ -0,0 +1,12 @@ +{ + "name": "my-app", + "version": "1.0.0", + "scripts": { + "ui:dev": "npx tailwindcss -c tailwind.config.js -i index.css -o shared/css/ui.css --watch", + "ui:build": "npx tailwindcss -c tailwind.config.js -i index.css -o shared/css/ui.css --minify" + }, + "dependencies": { + "@servicestack/client": "^1.1.17", + "@tailwindcss/forms": "^0.4.0" + } +} diff --git a/tests/NorthwindAuto/shared/Alert.html b/tests/NorthwindAuto/shared/Alert.html new file mode 100644 index 00000000000..b8e8ff163c5 --- /dev/null +++ b/tests/NorthwindAuto/shared/Alert.html @@ -0,0 +1,16 @@ + + diff --git a/tests/NorthwindAuto/shared/AlertSuccess.html b/tests/NorthwindAuto/shared/AlertSuccess.html new file mode 100644 index 00000000000..35c2b3fda8d --- /dev/null +++ b/tests/NorthwindAuto/shared/AlertSuccess.html @@ -0,0 +1,18 @@ + + diff --git a/tests/NorthwindAuto/shared/AuthNav.html b/tests/NorthwindAuto/shared/AuthNav.html new file mode 100644 index 00000000000..fa7582f78a6 --- /dev/null +++ b/tests/NorthwindAuto/shared/AuthNav.html @@ -0,0 +1,58 @@ + + + + diff --git a/tests/NorthwindAuto/shared/Brand.html b/tests/NorthwindAuto/shared/Brand.html new file mode 100644 index 00000000000..5e05bf340dd --- /dev/null +++ b/tests/NorthwindAuto/shared/Brand.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/tests/NorthwindAuto/shared/CloseButton.html b/tests/NorthwindAuto/shared/CloseButton.html new file mode 100644 index 00000000000..79541f61da3 --- /dev/null +++ b/tests/NorthwindAuto/shared/CloseButton.html @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/tests/NorthwindAuto/shared/CopyIcon.html b/tests/NorthwindAuto/shared/CopyIcon.html new file mode 100644 index 00000000000..6bfb2d11481 --- /dev/null +++ b/tests/NorthwindAuto/shared/CopyIcon.html @@ -0,0 +1,29 @@ + + diff --git a/tests/NorthwindAuto/shared/CopyLine.html b/tests/NorthwindAuto/shared/CopyLine.html new file mode 100644 index 00000000000..e23035f272d --- /dev/null +++ b/tests/NorthwindAuto/shared/CopyLine.html @@ -0,0 +1,34 @@ + + \ No newline at end of file diff --git a/tests/NorthwindAuto/shared/ErrorSummary.html b/tests/NorthwindAuto/shared/ErrorSummary.html new file mode 100644 index 00000000000..9045b3f1a74 --- /dev/null +++ b/tests/NorthwindAuto/shared/ErrorSummary.html @@ -0,0 +1,18 @@ + + diff --git a/tests/NorthwindAuto/shared/Image.html b/tests/NorthwindAuto/shared/Image.html new file mode 100644 index 00000000000..5980cdd36cf --- /dev/null +++ b/tests/NorthwindAuto/shared/Image.html @@ -0,0 +1,22 @@ + + diff --git a/tests/NorthwindAuto/shared/Input.html b/tests/NorthwindAuto/shared/Input.html new file mode 100644 index 00000000000..100c3de36ab --- /dev/null +++ b/tests/NorthwindAuto/shared/Input.html @@ -0,0 +1,81 @@ + + + + diff --git a/tests/NorthwindAuto/shared/Loading.html b/tests/NorthwindAuto/shared/Loading.html new file mode 100644 index 00000000000..748533a8b39 --- /dev/null +++ b/tests/NorthwindAuto/shared/Loading.html @@ -0,0 +1,20 @@ + + + + diff --git a/tests/NorthwindAuto/shared/Meta.html b/tests/NorthwindAuto/shared/Meta.html new file mode 100644 index 00000000000..ccc9b50d89e --- /dev/null +++ b/tests/NorthwindAuto/shared/Meta.html @@ -0,0 +1,2 @@ + + diff --git a/tests/NorthwindAuto/shared/PreviewObject.html b/tests/NorthwindAuto/shared/PreviewObject.html new file mode 100644 index 00000000000..2d2b690985a --- /dev/null +++ b/tests/NorthwindAuto/shared/PreviewObject.html @@ -0,0 +1,107 @@ + + + + + + + + + diff --git a/tests/NorthwindAuto/shared/SignIn.html b/tests/NorthwindAuto/shared/SignIn.html new file mode 100644 index 00000000000..6af92657930 --- /dev/null +++ b/tests/NorthwindAuto/shared/SignIn.html @@ -0,0 +1,128 @@ + + + + + + + diff --git a/tests/NorthwindAuto/shared/css/ui.css b/tests/NorthwindAuto/shared/css/ui.css new file mode 100644 index 00000000000..ce68acc189b --- /dev/null +++ b/tests/NorthwindAuto/shared/css/ui.css @@ -0,0 +1 @@ +/*! tailwindcss v3.0.13 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input:-ms-input-placeholder,textarea:-ms-input-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid #0000;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:#0000;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{border-color:#0000;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:#0000;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px auto -webkit-focus-ring-color}*,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }b{font-weight:500}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background-color:#ccc}em{color:#3b82f6;font-weight:400;background-color:#eff6ff;border-radius:.25rem;padding:.125em .5rem;margin-left:.125em;margin-right:.125em;font-style:normal}.svg-lock{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 512 512'%3E%3Cpath fill='%23B1B4B5' d='M376.749 349.097c-13.531 0-24.5-10.969-24.5-24.5V181.932c0-48.083-39.119-87.203-87.203-87.203-48.083 0-87.203 39.119-87.203 87.203v82.977c0 13.531-10.969 24.5-24.5 24.5s-24.5-10.969-24.5-24.5v-82.977c0-75.103 61.1-136.203 136.203-136.203s136.203 61.1 136.203 136.203v142.665c0 13.531-10.969 24.5-24.5 24.5z'/%3E%3Cpath fill='%23FFB636' d='M414.115 497.459H115.977c-27.835 0-50.4-22.565-50.4-50.4V274.691c0-27.835 22.565-50.4 50.4-50.4h298.138c27.835 0 50.4 22.565 50.4 50.4v172.367c0 27.836-22.565 50.401-50.4 50.401z'/%3E%3Cpath fill='%23FFD469' d='M109.311 456.841h-2.525c-7.953 0-14.4-6.447-14.4-14.4V279.309c0-7.953 6.447-14.4 14.4-14.4h2.525c7.953 0 14.4 6.447 14.4 14.4v163.132c0 7.953-6.447 14.4-14.4 14.4z'/%3E%3C/svg%3E") no-repeat;background-size:cover}.svg-external{background:url("data:image/svg+xml;charset=utf-8,%3Csvg width='1.25rem' height='1.25rem' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-4M14 4h6m0 0v6m0-6L10 14' stroke='%231E40AF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E") no-repeat 100% 100%;padding-right:1.35rem}.loading .app,.when-loading{display:none}.loading .when-loading,.sm\:noauth-nopage\:hidden{display:block}.sm\:noauth-nopage\:block{display:none}.auth .sm\:auth\:hidden,.noauth .sm\:noauth\:hidden,.nopage .sm\:nopage\:hidden,.page .sm\:page\:hidden{display:block}.auth .sm\:auth\:block,.noauth .sm\:noauth\:block,.nopage .sm\:nopage\:block,.page .sm\:page\:block{display:none}@media (max-width:640px){.auth .sm\:auth\:hidden,.noauth .sm\:noauth\:hidden,.nopage .sm\:nopage\:hidden,.page .sm\:page\:hidden{display:none}.auth .sm\:auth\:block,.noauth .sm\:noauth\:block,.nopage .sm\:nopage\:block,.page .sm\:page\:block{display:block}.noauth.nopage .sm\:noauth-nopage\:hidden{display:none}.noauth.nopage .sm\:noauth-nopage\:block{display:block}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:-webkit-sticky;position:sticky}.inset-0{right:0;left:0}.inset-0,.inset-y-0{top:0;bottom:0}.top-0{top:0}.top-1{top:.25rem}.right-2{right:.5rem}.right-0{right:0}.z-10{z-index:10}.z-\[1\]{z-index:1}.z-0{z-index:0}.z-40{z-index:40}.z-20{z-index:20}.col-span-6{grid-column:span 6/span 6}.my-3{margin-top:.75rem;margin-bottom:.75rem}.mx-auto{margin-left:auto;margin-right:auto}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.-ml-0\.5{margin-left:-.125rem}.-mt-0\.5{margin-top:-.125rem}.-ml-0{margin-left:0}.-mt-0{margin-top:0}.mr-2{margin-right:.5rem}.ml-3{margin-left:.75rem}.mb-3{margin-bottom:.75rem}.mr-1{margin-right:.25rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.ml-1{margin-left:.25rem}.mt-4{margin-top:1rem}.mb-8{margin-bottom:2rem}.mt-2{margin-top:.5rem}.-mb-px{margin-bottom:-1px}.-ml-px{margin-left:-1px}.ml-2\.5{margin-left:.625rem}.mt-2\.5{margin-top:.625rem}.ml-2{margin-left:.5rem}.-mr-12{margin-right:-3rem}.-ml-\[1px\]{margin-left:-1px}.mb-5{margin-bottom:1.25rem}.mt-0\.5{margin-top:.125rem}.mt-0{margin-top:0}.mb-2{margin-bottom:.5rem}.mt-5{margin-top:1.25rem}.mr-3{margin-right:.75rem}.-ml-1{margin-left:-.25rem}.mb-1{margin-bottom:.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-12{height:3rem}.h-6{height:1.5rem}.h-5{height:1.25rem}.h-4{height:1rem}.h-10{height:2.5rem}.h-\[315px\]{height:315px}.h-screen{height:100vh}.h-8{height:2rem}.h-0{height:0}.max-h-24{max-height:6rem}.min-h-0{min-height:0}.min-h-full{min-height:100%}.w-12{width:3rem}.w-6{width:1.5rem}.w-full{width:100%}.w-1\/3{width:33.333333%}.w-5{width:1.25rem}.w-4{width:1rem}.w-10{width:2.5rem}.w-14{width:3.5rem}.w-60{width:15rem}.w-8{width:2rem}.w-48{width:12rem}.min-w-full{min-width:100%}.max-w-screen-sm{max-width:640px}.max-w-screen-md{max-width:768px}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow{flex-grow:1}.origin-top-right{transform-origin:top right}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.rotate-90{--tw-rotate:90deg}.rotate-90,.rotate-180{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-95,.scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x:.95;--tw-scale-y:.95}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.select-none{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-6{gap:1.5rem}.gap-3{gap:.75rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-1px*var(--tw-space-x-reverse));margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.rounded-md{border-radius:.375rem}.rounded-full{border-radius:9999px}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.border{border-width:1px}.border-0{border-width:0}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-t{border-top-width:1px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.border-transparent{border-color:#0000}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165/var(--tw-border-opacity))}.border-indigo-600{--tw-border-opacity:1;border-color:rgb(79 70 229/var(--tw-border-opacity))}.border-pink-400{--tw-border-opacity:1;border-color:rgb(244 114 182/var(--tw-border-opacity))}.border-yellow-400{--tw-border-opacity:1;border-color:rgb(250 204 21/var(--tw-border-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity))}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity))}.bg-indigo-400{--tw-bg-opacity:1;background-color:rgb(129 140 248/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-pink-50{--tw-bg-opacity:1;background-color:rgb(253 242 248/var(--tw-bg-opacity))}.bg-red-600{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.bg-red-400{--tw-bg-opacity:1;background-color:rgb(248 113 113/var(--tw-bg-opacity))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-sky-500{--tw-bg-opacity:1;background-color:rgb(14 165 233/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.p-2{padding:.5rem}.p-1{padding:.25rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-0{padding:0}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-0{padding-top:0;padding-bottom:0}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pl-1{padding-left:.25rem}.pt-1{padding-top:.25rem}.pt-2\.5{padding-top:.625rem}.pb-6{padding-bottom:1.5rem}.pt-2{padding-top:.5rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pb-3{padding-bottom:.75rem}.pt-4{padding-top:1rem}.pt-20{padding-top:5rem}.pb-8{padding-bottom:2rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.pl-8{padding-left:2rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pl-10{padding-left:2.5rem}.pt-5{padding-top:1.25rem}.pr-6{padding-right:1.5rem}.pt-3{padding-top:.75rem}.pr-4{padding-right:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.text-sm{font-size:.875rem;line-height:1.25rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem}.text-lg,.text-xl{line-height:1.75rem}.text-xl{font-size:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.font-medium{font-weight:500}.font-bold{font-weight:700}.font-semibold{font-weight:600}.font-normal{font-weight:400}.font-extrabold{font-weight:800}.uppercase{text-transform:uppercase}.leading-4{line-height:1rem}.leading-6{line-height:1.5rem}.tracking-wider{letter-spacing:.05em}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-blue-800{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(133 77 14/var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-900{--tw-text-opacity:1;color:rgb(127 29 29/var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.text-pink-700{--tw-text-opacity:1;color:rgb(190 24 93/var(--tw-text-opacity))}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21/var(--tw-text-opacity))}.text-yellow-700{--tw-text-opacity:1;color:rgb(161 98 7/var(--tw-text-opacity))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity))}.underline{-webkit-text-decoration-line:underline;text-decoration-line:underline}.placeholder-red-300::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(252 165 165/var(--tw-placeholder-opacity))}.placeholder-red-300:-ms-input-placeholder{--tw-placeholder-opacity:1;color:rgb(252 165 165/var(--tw-placeholder-opacity))}.placeholder-red-300::placeholder{--tw-placeholder-opacity:1;color:rgb(252 165 165/var(--tw-placeholder-opacity))}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid #0000;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-indigo-500{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,fill,stroke,-webkit-text-decoration-color;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,-webkit-text-decoration-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-opacity{transition-duration:.15s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-linear{transition-timing-function:linear}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.hover\:bg-indigo-700:hover{--tw-bg-opacity:1;background-color:rgb(67 56 202/var(--tw-bg-opacity))}.hover\:bg-red-700:hover{--tw-bg-opacity:1;background-color:rgb(185 28 28/var(--tw-bg-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-inset:focus{--tw-ring-inset:inset}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(239 68 68/var(--tw-ring-opacity))}.focus\:ring-white:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}@media (min-width:640px){.sm\:col-span-3{grid-column:span 3/span 3}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mx-auto{margin-left:auto;margin-right:auto}.sm\:mt-0{margin-top:0}.sm\:mb-3{margin-bottom:.75rem}.sm\:mb-0{margin-bottom:0}.sm\:ml-6{margin-left:1.5rem}.sm\:block{display:block}.sm\:flex{display:flex}.sm\:hidden{display:none}.sm\:h-\[315px\]{height:315px}.sm\:w-\[560px\]{width:560px}.sm\:w-full{width:100%}.sm\:max-w-md{max-width:28rem}.sm\:flex-shrink{flex-shrink:1}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1.25rem*var(--tw-space-x-reverse));margin-left:calc(1.25rem*(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:.5rem}.sm\:rounded-md{border-radius:.375rem}.sm\:p-4{padding:1rem}.sm\:p-6{padding:1.5rem}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-2{padding-left:.5rem;padding-right:.5rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:px-10{padding-left:2.5rem;padding-right:2.5rem}.sm\:pl-3{padding-left:.75rem}.sm\:pt-3{padding-top:.75rem}.sm\:pt-1{padding-top:.25rem}.sm\:text-left{text-align:left}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}}@media (min-width:768px){.md\:fixed{position:fixed}.md\:inset-y-0{top:0;bottom:0}.md\:ml-1{margin-left:.25rem}.md\:block{display:block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:h-6{height:1.5rem}.md\:h-\[526px\]{height:526px}.md\:w-6{width:1.5rem}.md\:w-\[896px\]{width:896px}.md\:w-64{width:16rem}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-col{flex-direction:column}.md\:divide-y-0>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(0px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(0px*var(--tw-divide-y-reverse))}.md\:divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;border-right-width:calc(1px*var(--tw-divide-x-reverse));border-left-width:calc(1px*(1 - var(--tw-divide-x-reverse)))}.md\:rounded-lg{border-radius:.5rem}.md\:p-4{padding:1rem}.md\:py-8{padding-top:2rem;padding-bottom:2rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:pl-64{padding-left:16rem}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}.md\:shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}}@media (min-width:1024px){.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:ml-1{margin-left:.25rem}.lg\:block{display:block}.lg\:inline{display:inline}.lg\:flex{display:flex}.lg\:w-1\/2{width:50%}.lg\:max-w-screen-md{max-width:768px}.lg\:rounded-md{border-radius:.375rem}.lg\:bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.lg\:p-2{padding:.5rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.lg\:hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}}@media (min-width:1280px){.xl\:block{display:block}} \ No newline at end of file diff --git a/tests/NorthwindAuto/shared/js/PetiteVueApp.js b/tests/NorthwindAuto/shared/js/PetiteVueApp.js new file mode 100644 index 00000000000..8bf82b887ef --- /dev/null +++ b/tests/NorthwindAuto/shared/js/PetiteVueApp.js @@ -0,0 +1,112 @@ +import { EventBus, each } from '@servicestack/client' +/*minify:*/ +/** + * App to register and build a PetiteVue App + * @class + */ +function PetiteVueApp() { + let Components = {} + let Directives = {} + let Props = {} + let OnStart = [] + this.petite = null + this.events = new EventBus() + + let assertNotBuilt = (name) => { + if (this.petite) + throw new Error(`Cannot call App.${name}() after App is built`) + } + function template (name, $template) { + if (typeof $template != 'string') + throw new Error(`Template ${name} must be a template selector not ${$template}`) + return create(name, function(args, apply) { + let to = { + $template, + ...args + } + if (apply) apply(to,name) + return to + }) + } + function create (name, x) { + if (typeof x == "string") + return template(name, x) + else if (typeof x == "function") + return x + throw new Error(`${name} is not a Component or $template`) + } + function register (name, component) { + window[name] = Components[name] = create(name, component) + } + this.components = function (components) { + assertNotBuilt('components') + Object.keys(components).forEach(name => register(name, components[name])) + } + this.component = function(name, component) { + assertNotBuilt('component') + register(name, component) + } + this.template = function (name, $template) { + assertNotBuilt('template') + register(name, template(name, $template)) + } + this.templates = function (templates) { + assertNotBuilt('template') + Object.keys(templates).forEach(name => register(name, template(name, templates[name]))) + } + + this.directive = function(name, fn) { + assertNotBuilt('directive') + Directives[name] = fn + } + + this.prop = function (name, val) { + assertNotBuilt('prop') + Props[name] = val + } + this.props = function (props) { + assertNotBuilt('props') + Object.assign(Props, props) + } + + this.build = function(args) { + if (!window.PetiteVue) + throw new ReferenceError('PetiteVue is not defined') + Object.assign(this, window.PetiteVue) + + this.petite = PetiteVue.createApp({ + ...Props, + ...Components, + ...args, + }) + Object.keys(Directives).forEach(name => this.petite.directive(name, Directives[name])) + return this.petite + } + + this.plugin = function (plugins) { + Object.keys(plugins).forEach(name => { + let f = plugins[name] + this[name] = typeof f == 'function' ? f.bind(this) : f + }) + } + + this.import = function (src) { + return new Promise((resolve, reject) => { + let s = document.createElement('script') + s.setAttribute('src', src) + s.addEventListener('load', resolve) + s.addEventListener('error', reject) + document.body.appendChild(s) + }) + } + + this.onStart = function (f) { + OnStart.push(f) + } + this.start = function () { + OnStart.forEach(f => f(this)) + } + + Object.assign(this, window.PetiteVue||{}) +} +/*:minify*/ diff --git a/tests/NorthwindAuto/shared/js/core.js b/tests/NorthwindAuto/shared/js/core.js new file mode 100644 index 00000000000..b7dac77d84b --- /dev/null +++ b/tests/NorthwindAuto/shared/js/core.js @@ -0,0 +1,65 @@ +import { apiValue, isDate, mapGet, padInt, $1 } from "@servicestack/client" +/*minify:*/ + +export function setBodyClass(obj) { + let bodyCls = document.body.classList + Object.keys(obj).forEach(name => { + if (obj[name]) { + bodyCls.add(name) + bodyCls.remove(`no${name}`) + } else { + bodyCls.remove(name) + bodyCls.add(`no${name}`) + } + }) +} + +export function styleProperty(name) { + return document.documentElement.style.getPropertyValue(name) +} +export function setStyleProperty(props) { + let style = document.documentElement.style + Object.keys(props).forEach(name => style.setProperty(name, props[name])) +} + +function mapGetForInput(o, id) { + let ret = apiValue(mapGet(o,id)) + return isDate(ret) + ? `${ret.getFullYear()}-${padInt(ret.getMonth() + 1)}-${padInt(ret.getDate())}` + : ret +} + +function gridClass() { return `grid grid-cols-6 gap-6` } +function gridInputs(formLayout) { + let to = [] + formLayout.forEach(group => { + group.forEach(input => { + to.push({ input, rowClass: colClass(group.length) }) + }) + }) + return to +} +function colClass(fields) { + return `col-span-6` + (fields === 2 ? ' sm:col-span-3' : fields === 3 ? ' sm:col-span-2' : '') +} + +export function setFavIcon(icon, defaultSrc) { + setFavIconSrc(icon.uri || defaultSrc) +} + +export function setFavIconSrc(src) { + let link = $1("link[rel~='icon']") + if (!link) { + link = document.createElement('link') + link.rel = 'icon' + $1('head').appendChild(link) + } + link.href = src +} + +export function highlight(src, language) { + if (!language) language = 'csharp' + return hljs.highlight(src, { language }).value +} + +/*:minify*/ \ No newline at end of file diff --git a/tests/NorthwindAuto/shared/plugins/useBreakpoints.js b/tests/NorthwindAuto/shared/plugins/useBreakpoints.js new file mode 100644 index 00000000000..2d27911259e --- /dev/null +++ b/tests/NorthwindAuto/shared/plugins/useBreakpoints.js @@ -0,0 +1,54 @@ +import {each, on} from "@servicestack/client" + +/*minify:*/ +/** + * Returns a reactive store that maintains different resolution states: + * Defaults: 2xl:1536, xl:1280, lg:1024, md:768, sm:640 + * E.g. at 1200px: { 2xl:false, xl:false, lg:true, md:true, sm:true } + * Events: + * breakpoint:change - the browser width changed breakpoints + */ +App.plugin({ + useBreakpoints(options) { + if (!options) options = {} + let { resolutions, handlers } = options + if (!resolutions) resolutions = { '2xl':1536, xl:1280, lg:1024, md:768, sm:640 } + let sizes = Object.keys(resolutions) + + let previous = {} + let events = this.events + + let store = App.reactive({ + get previous() { return previous }, + get current() { return each(sizes, (o,res) => o[res] = this[res]) }, + snap() { + let w = document.body.clientWidth + let current = each(sizes, (o,res) => o[res] = w > resolutions[res]) + let changed = false + sizes.forEach(res => { + if (current[res] !== this[res]) { + this[res] = current[res] + changed = true + } + }) + + if (changed) { + previous = current + events.publish('breakpoint:change', this) + } + }, + }) + + on(window, { + resize: () => store.snap() + }) + + if (handlers && handlers.change) + events.subscribe('breakpoint:change', args => handlers.change(args)) + + this.onStart(app => store.snap()) + + return store + } +}) +/*:minify*/ diff --git a/tests/NorthwindAuto/shared/plugins/usePageRoutes.js b/tests/NorthwindAuto/shared/plugins/usePageRoutes.js new file mode 100644 index 00000000000..a203a6198a6 --- /dev/null +++ b/tests/NorthwindAuto/shared/plugins/usePageRoutes.js @@ -0,0 +1,90 @@ +import { queryString, leftPart, each } from "@servicestack/client" +/*minify:*/ +/** + * Maintain page route state: + * - /{pageKey}?{queryKeys} + * Events: + * route:init - loaded from URL + * route:to - navigated by to() + * route:nav - fired for both + */ +App.plugin({ + usePageRoutes({ page, queryKeys, handlers }) { + if (typeof page != 'string' || page === '') + throw new Error('page is required') + if (typeof queryKeys == 'undefined' || !queryKeys.length) + throw new Error('Array of queryKeys is required') + + let allKeys = [page,...queryKeys] + let getPage = () => leftPart(location.href.substring(document.baseURI.length),'?') + let state = store => each(allKeys, (o, key) => store[key] ? o[key] = store[key] : null) + + let publish = (name,args) => { + events.publish('route:' + name, args) + events.publish('route:nav',args) + } + + let events = this.events + let store = App.reactive({ + page, + queryKeys, + ...each(allKeys, (o,x) => o[x] = ''), + start() { + window.addEventListener('popstate', (event) => { + this.set({ [page]:getPage(), ...event.state}) + publish('init', state(this)) + }) + + this.set({ [page]:getPage(), ...(location.search ? queryString(location.search) : {}) }) + publish('init', state(this)) + }, + set(args) { + if (typeof args['$page'] != 'undefined') args[page] = args['$page'] + Object.keys(args).forEach(k => { + if (allKeys.indexOf(k) >= 0) { + this[k] = args[k] + } + }) + }, + get state() { return state(this) }, + to(args) { + this.set(args) + let cleanArgs = state(this) + if (typeof args.$on == 'function') args.$on(cleanArgs) + history.pushState(cleanArgs, this[page], this.href()) + publish('to', cleanArgs) + }, + href(args) { + /**: can't mutate reactive stores before createApp() */ + if (args && typeof args['$page'] != 'undefined') args[page] = args['$page'] + let s = args ? Object.assign({}, state(this), args) : state(this) + let path = s[page] || '' + let qs = queryKeys.filter(k => s[k]).map(k => + `${encodeURIComponent(k)}=${encodeURIComponent(s[k])}`).join('&') + return path + (qs ? '?' + qs : '') + } + }) + + this.directive('href', ({ effect, get, el }) => { + el.href = store.href(get()) + el.onclick = e => { + e.preventDefault() + store.to(get()) + } + }) + + if (handlers) { + if (handlers.init) + this.events.subscribe('route:init', args => handlers.init(args)) + if (handlers.to) + this.events.subscribe('route:to', args => handlers.to(args)) + if (handlers.nav) + this.events.subscribe('route:nav', args => handlers.nav(args)) + } + + this.onStart(app => store.start()) + + return store + } +}) +/*:minify*/ diff --git a/tests/NorthwindAuto/shared/plugins/useTransitions.js b/tests/NorthwindAuto/shared/plugins/useTransitions.js new file mode 100644 index 00000000000..943c6fab6c6 --- /dev/null +++ b/tests/NorthwindAuto/shared/plugins/useTransitions.js @@ -0,0 +1,59 @@ +import { $$ } from "@servicestack/client" +/*minify:*/ +App.plugin({ + useTransitions(transitions) { + function transition(prop, enter) { + let transitionEls = $$(`[data-transition-for=${prop}]`) + transitionEls.forEach(el => { + let duration = 300 + let attr = el.getAttribute('data-transition') + el.style.display = null + + if (attr) { + let rule = new Function("return " + attr)() + let prevTransition = rule[enter ? 'leaving' : 'entering'] + let nextTransition = rule[enter ? 'entering' : 'leaving'] + if (rule.cls) { + if (el.className.indexOf(rule.cls) < 0) el.className += ` ${rule.cls}` + ;let clsDuration = rule.cls.split(' ').find(x => x.startsWith('duration-')) + if (clsDuration) { + duration = parseInt(clsDuration.split('-')[1]) + } + } + + el.className = el.className.replace(` ${prevTransition.to}`, '') + el.className += ` ${nextTransition.from}` + ;setTimeout(() => { + el.className = el.className.replace(nextTransition.from, nextTransition.to) + }, duration) + } + + setTimeout(() => { + el.style.display = enter ? null : 'none' + }, duration * 2) + }) + return enter + } + this.transition = transition + + let PropValues = {} + if (transitions) { + Object.keys(transitions).forEach(prop => { + let transProp = transitions[prop] + if (typeof transProp != 'boolean') + throw new Error(`useTransitions({ ${prop} }) must be a boolean not '${transProp}'`) + PropValues[prop] = transProp + }) + } + + this.props({ + transition(name, val) { + let enter = typeof val == 'boolean' + ? val + : PropValues[name] = !PropValues[name] + return transition(name, enter) + }, + }) + } +}) +/*:minify*/ diff --git a/tests/NorthwindAuto/tailwind.config.js b/tests/NorthwindAuto/tailwind.config.js new file mode 100644 index 00000000000..7e56dabed76 --- /dev/null +++ b/tests/NorthwindAuto/tailwind.config.js @@ -0,0 +1,9 @@ +module.exports = { + content: ['./ui/**/*.html', './admin-ui/**/*.html', './shared/**/*.html'], + theme: { + extend: {}, + }, + plugins: [ + require('@tailwindcss/forms') + ], +} diff --git a/tests/NorthwindAuto/ui/components/ApiCode.html b/tests/NorthwindAuto/ui/components/ApiCode.html new file mode 100644 index 00000000000..7b0dcecceb9 --- /dev/null +++ b/tests/NorthwindAuto/ui/components/ApiCode.html @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/NorthwindAuto/ui/components/ApiDetails.html b/tests/NorthwindAuto/ui/components/ApiDetails.html new file mode 100644 index 00000000000..be9b8727b84 --- /dev/null +++ b/tests/NorthwindAuto/ui/components/ApiDetails.html @@ -0,0 +1,260 @@ + + + + diff --git a/tests/NorthwindAuto/ui/components/ApiForm.html b/tests/NorthwindAuto/ui/components/ApiForm.html new file mode 100644 index 00000000000..f081e5d4768 --- /dev/null +++ b/tests/NorthwindAuto/ui/components/ApiForm.html @@ -0,0 +1,447 @@ + + + + + + + + + diff --git a/tests/NorthwindAuto/ui/components/AutoForm.html b/tests/NorthwindAuto/ui/components/AutoForm.html new file mode 100644 index 00000000000..f678d98e5a1 --- /dev/null +++ b/tests/NorthwindAuto/ui/components/AutoForm.html @@ -0,0 +1,124 @@ + + + + diff --git a/tests/NorthwindAuto/ui/components/Sidebar.html b/tests/NorthwindAuto/ui/components/Sidebar.html new file mode 100644 index 00000000000..ab280e2dd4a --- /dev/null +++ b/tests/NorthwindAuto/ui/components/Sidebar.html @@ -0,0 +1,97 @@ + + + + + + diff --git a/tests/NorthwindAuto/ui/components/Welcome.html b/tests/NorthwindAuto/ui/components/Welcome.html new file mode 100644 index 00000000000..d2863d5e3d9 --- /dev/null +++ b/tests/NorthwindAuto/ui/components/Welcome.html @@ -0,0 +1,68 @@ + + + + diff --git a/tests/NorthwindAuto/ui/css/app.css b/tests/NorthwindAuto/ui/css/app.css new file mode 100644 index 00000000000..fc2cc6608da --- /dev/null +++ b/tests/NorthwindAuto/ui/css/app.css @@ -0,0 +1,45 @@ +:root { + --sidebar-width: 20rem; + --sm-nav-height: 0px; + --top-nav-height: 65px; + --sub-nav-height: 45px; + --scroll-width: 8px; + --body-width: calc(100vw - var(--sidebar-width)); + --pb-scroll: 0; +} +@media (max-width: 768px) { + :root { + --pb-scroll: 8rem; /* fix scrolling to bottom */ + --sm-nav-height: 45px; + } + .md\:pb-scroll { padding-bottom: var(--pb-scroll) !important } +} + +.top-sm-nav { top: calc(var(--sm-nav-height)) } +.top-top-nav { top: calc(var(--sm-nav-height) + var(--top-nav-height)) } +.top-sub-nav { top: calc(var(--sm-nav-height) + var(--top-nav-height) + var(--sub-nav-height)) } +.w-sidebar { width: var(--sidebar-width); } +.max-w-sidebar { max-width: var(--sidebar-width); } +.h-top-nav { height: calc(100vh - var(--sm-nav-height) - var(--top-nav-height)) } +.h-sub-nav { height: calc(100vh - var(--sm-nav-height) - var(--top-nav-height) - var(--sub-nav-height)) } +.w-body { width: 100vw } + +@media (min-width: 768px) { + .md\:w-sidebar { width: var(--sidebar-width) } + .md\:pl-sidebar { padding-left: var(--sidebar-width) } + .md\:w-sidebar { width: calc(100vw - var(--sidebar-width)) !important } + .md\:w-body { width: calc(100vw - var(--sidebar-width)) } +} + +.icon-right .icon { + right: 1em; +} +.notes a { + color: rgb(30 64 175); /*text-blue-800*/ +} +.bg-gray-50 .hljs, .lg\:bg-gray-50 .hljs { + background-color: transparent; +} +[lang=json] .hljs-attr { color: rgb(17 24 39) } +[lang=json] .hljs-string { color: rgb(21 128 61) } +.language-typescript .hljs-attr { color: rgb(17 24 39) } diff --git a/tests/NorthwindAuto/ui/docs/AuthenticateDocs.html b/tests/NorthwindAuto/ui/docs/AuthenticateDocs.html new file mode 100644 index 00000000000..87637f360f8 --- /dev/null +++ b/tests/NorthwindAuto/ui/docs/AuthenticateDocs.html @@ -0,0 +1,57 @@ + + diff --git a/tests/NorthwindAuto/ui/docs/RegisterDocs.html b/tests/NorthwindAuto/ui/docs/RegisterDocs.html new file mode 100644 index 00000000000..51eb7ed28b5 --- /dev/null +++ b/tests/NorthwindAuto/ui/docs/RegisterDocs.html @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/tests/NorthwindAuto/ui/index.html b/tests/NorthwindAuto/ui/index.html new file mode 100644 index 00000000000..e1fada3bf2e --- /dev/null +++ b/tests/NorthwindAuto/ui/index.html @@ -0,0 +1,171 @@ + + + + + + + + + + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/NorthwindAuto/ui/js/appInit.js b/tests/NorthwindAuto/ui/js/appInit.js new file mode 100644 index 00000000000..447326b4b68 --- /dev/null +++ b/tests/NorthwindAuto/ui/js/appInit.js @@ -0,0 +1,84 @@ +import { JsonServiceClient, lastLeftPart, leftPart, trimEnd } from "@servicestack/client" +import { APP } from "../../lib/types" +/*minify:*/ +//APP.config.debugMode = false +let BASE_URL = lastLeftPart(trimEnd(document.baseURI,'/'),'/') +let bearerToken = null +let authsecret = null + +function createClient(fn) { + return new JsonServiceClient(BASE_URL).apply(c => { + c.bearerToken = bearerToken + c.enableAutoRefreshToken = false + if (authsecret) c.headers.set('authsecret', authsecret) + let apiFmt = APP.httpHandlers['ApiHandlers.Json'] + if (apiFmt) + c.basePath = apiFmt.replace('/{Request}', '') + if (fn) fn(c) + }) +} +let client = createClient() + +APP.api.operations.forEach(op => { + if (!op.tags) op.tags = [] +}) + +let appOps = APP.api.operations.filter(op => !op.request.namespace.startsWith('ServiceStack')) +let appTags = Array.from(new Set(appOps.flatMap(op => op.tags))).sort() +let sideNav = appTags.map(tag => ({ + tag, + expanded: true, + operations: appOps.filter(op => op.tags.indexOf(tag) >= 0) +})) + +let ssOps = APP.api.operations.filter(op => op.request.namespace.startsWith('ServiceStack')) +let ssTags = Array.from(new Set(ssOps.flatMap(op => op.tags))).sort() +ssTags.map(tag => ({ + tag, + expanded: true, + operations: ssOps.filter(op => op.tags.indexOf(tag) >= 0) +})).forEach(nav => sideNav.push(nav)) + +let other = { + tag: appTags.length > 0 ? 'other' : 'APIs', + expanded: true, + operations: [...appOps, ...ssOps].filter(op => op.tags.length === 0) +} +if (other.operations.length > 0) sideNav.push(other) + +let alwaysHideTags = APP.ui.alwaysHideTags || !DEBUG && APP.ui.hideTags +if (alwaysHideTags) { + sideNav = sideNav.filter(group => alwaysHideTags.indexOf(group.tag) < 0) +} + +let CACHE = {} +let OpsMap = {} +let TypesMap = {} +let HttpErrors = { 401:'Unauthorized', 403:'Forbidden' } +APP.api.operations.forEach(op => { + OpsMap[op.request.name] = op + TypesMap[op.request.name] = op.request + if (op.response) TypesMap[op.response.name] = op.response +}) +APP.api.types.forEach(type => TypesMap[type.name] = type) + +let cleanSrc = src => src.trim(); + +function invalidAccessMessage(op, authRoles, authPerms) { + if (authRoles.indexOf('Admin') >= 0) return null + + let missingRoles = op.requiredRoles.filter(x => authRoles.indexOf(x) < 0) + if (missingRoles.length > 0) + return `Requires ${missingRoles.map(x => '' + x + '').join(', ')} Role` + (missingRoles.length > 1 ? 's' : '') + let missingPerms = op.requiredPermissions.filter(x => authPerms.indexOf(x) < 0) + if (missingPerms.length > 0) + return `Requires ${missingPerms.map(x => '' + x + '').join(', ')} Permission` + (missingPerms.length > 1 ? 's' : '') + + if (missingRoles.length > 0) + return `Requires any ${missingRoles.map(x => '' + x + '').join(', ')} Role` + (missingRoles.length > 1 ? 's' : '') + missingPerms = op.requiresAnyPermission.filter(x => authPerms.indexOf(x) < 0) + if (missingPerms.length > 0) + return `Requires any ${missingPerms.map(x => '' + x + '').join(', ')} Permission` + (missingPerms.length > 1 ? 's' : '') + return null +} +/*:minify*/ diff --git a/tests/NorthwindAuto/ui/js/stores.js b/tests/NorthwindAuto/ui/js/stores.js new file mode 100644 index 00000000000..694113d3fa1 --- /dev/null +++ b/tests/NorthwindAuto/ui/js/stores.js @@ -0,0 +1,310 @@ +import { leftPart } from "@servicestack/client" +import { APP, Authenticate } from "../../lib/types" +import { setBodyClass } from "../../shared/js/core" + +/*minify:*/ +App.useTransitions({ sidebar: true }) +let breakpoints = App.useBreakpoints({ + handlers: { + change({ previous, current }) { console.log('breakpoints.change', previous, current) } /*debug*/ + } +}) + +let routes = App.usePageRoutes({ + page:'op', + queryKeys:'tab,lang,preview,detailSrc,form,response,body,provider,doc'.split(','), + handlers: { + nav(state) { console.log('nav', state) } /*debug*/ + } +}) + +let store = PetiteVue.reactive({ + previewResult: null, + copied: false, + filter: '', + sideNav, + detailSrcResult: {}, + debug: APP.config.debugMode, + api: null, + auth: window.AUTH, + baseUrl: BASE_URL, + + get useLang() { return routes.lang || 'csharp' }, + + init() { + this.loadDetailSrc() + this.loadLang() + this.loadPreview() + setBodyClass({ page: routes.op }) + }, + + get filteredSideNav() { + let filter = op => { + let lowerFilter = this.filter.toLowerCase() + if (op.requiresAuth && !this.debug) + { + if (!this.auth) + return false + if (invalidAccessMessage(op, this.auth.roles, this.auth.permissions)) + return false + } + return !lowerFilter || op.request.name.toLowerCase().indexOf(lowerFilter) >= 0 + } + let ret = this.sideNav.filter(nav => nav.operations.some(filter)) + .map(nav => ({ + ...nav, + operations: nav.operations.filter(filter) + })) + + /**:return [...ret, ...ret, ...ret, ...ret, ...ret]*/ + return ret + }, + + toggle(tag) { + let nav = this.sideNav.find(x => x.tag === tag) + nav.expanded = !nav.expanded + }, + + loadLang() { + if (!this.activeLangSrc) { + let cache = this.langCache() + if (CACHE[cache.url]) { + this.langResult = { cache, result: CACHE[cache.url] } + } else { + this.cachedFetch(cache.url) + .then(src => { + this.langResult = { cache, result: CACHE[cache.url] = cleanSrc(src) } + if (!this.activeLangSrc) { + this.loadLang() + } + }) + } + } + }, + + getTypeUrl(types) { return `/types/csharp?IncludeTypes=${types}&WithoutOptions=true&MakeVirtual=false&MakePartial=false&AddServiceStackTypes=true` }, + + get previewCache() { + if (routes.preview.startsWith('types.')) { + let types = routes.preview.substring('types.'.length) + return { preview: routes.preview, url: this.getTypeUrl(types), lang:'csharp' } + } + return null + }, + + loadPreview() { + if (!this.previewSrc) { + let cache = this.previewCache + if (!cache) return + if (CACHE[cache.url]) { + this.previewResult = { type:'src', ...cache, result: CACHE[cache.url] } + } else { + this.cachedFetch(cache.url) + .then(src => { + this.previewResult = { + type:'src', + ...cache, + result: CACHE[cache.url] = cache.lang ? cleanSrc(src) : src + } + }) + } + } + }, + + get previewSrc() { + let r = this.previewResult + if (!r) return '' + return routes.preview === r.preview && r.type === 'src' && r.lang ? r.result : '' + }, + + get activeLangSrc() { + let cache = this.langResult && this.langResult.cache + let ret = cache && routes.op === cache.op && this.useLang === cache.lang ? this.langResult.result : null + return ret + }, + + loadDetailSrc() { + if (!routes.detailSrc) return + let cache = { url: this.getTypeUrl(routes.detailSrc) } + if (CACHE[cache.url]) { + this.detailSrcResult[cache.url] = { ...cache, result: CACHE[cache.url] } + } else { + this.cachedFetch(cache.url).then(src => { + this.detailSrcResult[cache.url] = { ...cache, result: CACHE[cache.url] = cleanSrc(src) } + }) + } + }, + + get activeDetailSrc() { return routes.detailSrc && this.detailSrcResult[this.getTypeUrl(routes.detailSrc)] }, + + get op() { + return routes.op ? APP.api.operations.find(op => op.request.name === routes.op) : null + }, + get opName() { return this.op && this.op.request.name }, + + get opTabs() { + return this.op + ? { ['API']:'', 'Details':'details', ['Code']:'code' } + : {} + }, + + get isServiceStackType() { + return this.op && this.op.request.namespace.startsWith("ServiceStack") + }, + + langCache() { + let op = routes.op, lang = this.useLang + return { op, lang, url: `/types/${lang}?IncludeTypes=${op}.*&WithoutOptions=true&MakeVirtual=false&MakePartial=false` + (this.isServiceStackType ? '&AddServiceStackTypes=true' : '') } + }, + + cachedFetch(url) { + return new Promise((resolve,reject) => { + let src = CACHE[url] + if (src) { + resolve(src) + } else { + fetch(url) + .then(r => { + if (r.ok) return r.text() + else throw r.statusText + }) + .then(src => { + resolve(CACHE[url] = src) + }) + .catch(e => { + console.error(`fetchCache (${url}):`, e) + reject(e) + }) + } + }) + }, + + SignIn() { + return APP.plugins.auth + ? SignIn({ + plugin: APP.plugins.auth, + provider:() => routes.provider, + login:args => this.login(args), + api: () => this.api, + }) + : NoAuth({ message:`${APP.app.serviceName} API Explorer` }) + }, + + login(args) { + let provider = routes.provider || 'credentials' + let authProvider = APP.plugins.auth.authProviders.find(x => x.name === provider) + if (!authProvider) + throw new Error("!authProvider") + let auth = new Authenticate() + bearerToken = authsecret = null + if (authProvider.type === 'Bearer') { + bearerToken = client.bearerToken = (args['BearerToken'] || '').trim() + } else if (authProvider.type === 'authsecret') { + authsecret = (args['authsecret'] || '').trim() + client.headers.set('authsecret',authsecret) + } else { + auth = new Authenticate({ provider, ...args }) + } + client.api(auth, { jsconfig: 'eccn' }) + .then(r => { + this.api = r + if (r.error && !r.error.message) + r.error.message = HttpErrors[r.errorCode] || r.errorCode + if (this.api.succeeded) { + this.auth = this.api.response + setBodyClass({ auth: this.auth }) + } + }) + }, + + logout() { + setBodyClass({ auth: this.auth }) + client.api(new Authenticate({ provider: 'logout' })) + authsecret = bearerToken = client.bearerToken = null + client.headers.delete('authsecret') + this.auth = null + }, + + /**: v-if doesn't protect against nested access so need to guard against deep NRE access */ + get authRoles() { return this.auth && this.auth.roles || [] }, + get authPermissions() { return this.auth && this.auth.permissions || [] }, + get authProfileUrl() { return this.auth && this.auth.profileUrl }, + + get authLinks() { + let to = [] + let roleLinks = this.auth && APP.plugins.auth && APP.plugins.auth.roleLinks || {} + if (Object.keys(roleLinks).length > 0) { + this.authRoles.forEach(role => { + if (!roleLinks[role]) return; + roleLinks[role].forEach(link => to.push(link)) + }) + } + return to + }, + + get displayName() { + let auth = this.auth + return auth + ? auth.displayName || (auth.firstName ? `${auth.firstName} ${auth.lastName}` : null) || auth.userName || auth.email + : null + }, + + invalidAccess() { + let op = this.op + if (!op || !op.requiresAuth) return null + if (!this.auth) return `${op.request.name} requires Authentication` + ;return invalidAccessMessage(op, this.auth.roles, this.auth.permissions) + }, +}) + +App.events.subscribe('route:nav', args => store.init()) + +function typeProperties(type) { + let props = [] + while (type) { + if (type.properties) props.push(...type.properties) + type = type.inherits ? TypesMap[type.inherits.name] : null + } + return props.map(prop => prop.type.endsWith('[]') + ? {...prop, type:'List`1', genericArgs:[prop.type.substring(0,prop.type.length-2)] } + : prop) +} +let NumTypesMap = { + Byte: 'byte', + Int16: 'short', + Int32: 'int', + Int64: 'long', + UInt16: 'ushort', + Unt32: 'uint', + UInt64: 'ulong', + Single: 'float', + Double: 'double', + Decimal: 'decimal', +} +let NumTypes = [ ...Object.keys(NumTypesMap), ...Object.values(NumTypesMap) ] +let TypeAliases = { + String: 'string', + Boolean: 'bool', + ...NumTypesMap, +} +function isNumberType(type) { + return type && NumTypes.indexOf(type) >= 0 +} +function typeAlias(typeName) { + return TypeAliases[typeName] || typeName +} +function unwrap(type) { return type && type.endsWith('?') ? type.substring(0,type.length-1) : type } +function typeName2(name, genericArgs) { + if (!name) return '' + if (!genericArgs) + genericArgs = [] + if (name === 'Nullable`1') + return typeAlias(genericArgs[0]) + '?' + if (name.endsWith('[]')) + return `List<${typeAlias(name.substring(0,name.length-2))}>` + ;if (genericArgs.length === 0) + return typeAlias(name) + return leftPart(typeAlias(name), '`') + '<' + genericArgs.join(',') + '>' +} +function typeName(metaType) { return metaType && typeName2(metaType.name, metaType.genericArgs) } +/*:minify*/ diff --git a/tests/NorthwindAuto/wwwroot/index.html b/tests/NorthwindAuto/wwwroot/index.html new file mode 100644 index 00000000000..9983acbc23a --- /dev/null +++ b/tests/NorthwindAuto/wwwroot/index.html @@ -0,0 +1,138 @@ + + + Northwind CRUD + + + + +
+ +

/ui

+

/admin-ui

+ +

AutoCrud Generation Links

+
+ + + + + + + + + + + + + + + + + + + + + +
RDBMS Schema + /crud/tables +
New Auto Generated Services (C#) + /crud/new/csharp +
All Services (C#) + /crud/all/csharp +
Generate DTOs in alt languages (e.g. TypeScript) + +
+ * requires DebugMode or Admin role + (e.g. ?authsecret=zsecret) +
+ +

Eject into code-first models

+

+ Use dotnet tool to generate Types for Tables where AutoQuery Services don't already exist: +

+ +
x csharp https://localhost:5001 -path /crud/new/csharp
+ +
+ If RDBMS Schema changes, can update dtos as normal: +
+
x csharp
+ + + +

+ Hello API +

+ +
+ +

Example Code

+
+
<script src="/js/servicestack-client.js"></script>
+
Object.assign(window, window['@servicestack/client']) //import
+
+var client = new JsonServiceClient()
+client.get(new Hello({ name: name }))
+    .then(function(r) {
+        console.log(r.result)
+    })
+
+ +

+ Generate Typed DTOs from + Add ServiceStack Reference +

+
+ + + + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/App.config b/tests/RazorRockstars.Console.Files/App.config index 3ce635accc9..5837dd52a8f 100644 --- a/tests/RazorRockstars.Console.Files/App.config +++ b/tests/RazorRockstars.Console.Files/App.config @@ -5,11 +5,15 @@
+ + +
+ @@ -19,14 +23,41 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/AppHost.cs b/tests/RazorRockstars.Console.Files/AppHost.cs index 97ec05047a5..1071046c5fc 100644 --- a/tests/RazorRockstars.Console.Files/AppHost.cs +++ b/tests/RazorRockstars.Console.Files/AppHost.cs @@ -1,59 +1,115 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Data; +using System.Net; using System.Runtime.Serialization; +using System.Security.Cryptography; using Funq; -using ServiceStack.Common; -using ServiceStack.Common.Web; +using ServiceStack; +using ServiceStack.Api.OpenApi; +using ServiceStack.Auth; +using ServiceStack.Data; using ServiceStack.DataAnnotations; +using ServiceStack.Formats; using ServiceStack.OrmLite; using ServiceStack.Razor; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Validation; +using ServiceStack.Web; //The entire C# code for the stand-alone RazorRockstars demo. namespace RazorRockstars.Console.Files { - public class AppHost : AppHostHttpListenerBase + public class AppHost : AppHostHttpListenerBase { public AppHost() : base("Test Razor", typeof(AppHost).Assembly) { } public bool EnableRazor = true; + public bool EnableMarkdown = false; + public RSAParameters? JwtRsaPrivateKey; + public RSAParameters? JwtRsaPublicKey; + public bool JwtEncryptPayload = false; + public List FallbackAuthKeys = new List(); + public List FallbackPublicKeys = new List(); + public Func GetAuthRepositoryFn; + + public Action Use; public override void Configure(Container container) { + Use?.Invoke(container); + if (EnableRazor) Plugins.Add(new RazorFormat()); + if (EnableMarkdown) + Plugins.Add(new MarkdownFormat()); + + Plugins.Add(new OpenApiFeature()); + Plugins.Add(new RequestInfoFeature()); + Plugins.Add(new RequestLogsFeature()); + Plugins.Add(new ServerEventsFeature()); + + Plugins.Add(new ValidationFeature()); + container.RegisterValidators(typeof(AutoValidationValidator).Assembly); - container.Register( - new OrmLiteConnectionFactory(":memory:", false, SqliteDialect.Provider)); + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); - using (var db = container.Resolve().OpenDbConnection()) + dbFactory.RegisterConnection("testdb", "~/App_Data/test.sqlite".MapAbsolutePath(), SqliteDialect.Provider); + + using (var db = dbFactory.OpenDbConnection()) { db.DropAndCreateTable(); //Create table if not exists db.Insert(Rockstar.SeedData); //Populate with seed data } - } + + using (var db = dbFactory.OpenDbConnection("testdb")) + { + db.DropAndCreateTable(); //Create table if not exists + db.Insert(new Rockstar(1, "Test", "Database", 27)); + } + + SetConfig(new HostConfig + { + AdminAuthSecret = "secret", + DebugMode = true, + }); + } + + public override IDbConnection GetDbConnection(IRequest req = null) + { + var apiKey = req.GetApiKey(); + return apiKey != null && apiKey.Environment == "test" + ? TryResolve().OpenDbConnection("testdb") + : base.GetDbConnection(req); + } + + public override IAuthRepository GetAuthRepository(IRequest req = null) + { + return GetAuthRepositoryFn != null + ? GetAuthRepositoryFn(req) + : base.GetAuthRepository(req); + } private static void Main(string[] args) { var appHost = new AppHost(); appHost.Init(); - appHost.Start("http://*:1337/"); - System.Console.WriteLine("Listening on http://localhost:1337/ ..."); + appHost.Start("http://*:3337/"); + System.Console.WriteLine("Listening on http://localhost:3337/ ..."); System.Console.ReadLine(); - System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); - } + System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); + } } public class Rockstar { public static Rockstar[] SeedData = new[] { - new Rockstar(1, "Jimi", "Hendrix", 27), - new Rockstar(2, "Janis", "Joplin", 27), - new Rockstar(3, "Jim", "Morrisson", 27), - new Rockstar(4, "Kurt", "Cobain", 27), - new Rockstar(5, "Elvis", "Presley", 42), - new Rockstar(6, "Michael", "Jackson", 50), + new Rockstar(1, "Jimi", "Hendrix", 27), + new Rockstar(2, "Janis", "Joplin", 27), + new Rockstar(3, "Jim", "Morrisson", 27), + new Rockstar(4, "Kurt", "Cobain", 27), + new Rockstar(5, "Elvis", "Presley", 42), + new Rockstar(6, "Michael", "Jackson", 50), }; [AutoIncrement] @@ -72,12 +128,12 @@ public Rockstar(int id, string firstName, string lastName, int age) Age = age; } } - + [Route("/rockstars")] [Route("/rockstars/aged/{Age}")] [Route("/rockstars/delete/{Delete}")] [Route("/rockstars/{Id}")] - public class Rockstars + public class Rockstars : IReturn { public int Id { get; set; } public string FirstName { get; set; } @@ -92,9 +148,12 @@ public class Rockstars [DataContract] //Attrs for CSV Format to recognize it's a DTO and serialize the Enumerable property public class RockstarsResponse { - [DataMember] public int Total { get; set; } - [DataMember] public int? Aged { get; set; } - [DataMember] public List Results { get; set; } + [DataMember] + public int Total { get; set; } + [DataMember] + public int? Aged { get; set; } + [DataMember] + public List Results { get; set; } } [Route("/ilist1/{View}")] @@ -125,6 +184,17 @@ public class PartialChildModel public string SomeProperty { get; set; } } + public class GetAllRockstars : IReturn { } + + [Authenticate] + public class SecureServices : Service + { + public object Any(GetAllRockstars request) + { + return new RockstarsResponse { Results = Db.Select() }; + } + } + public class RockstarsService : Service { public object Get(Rockstars request) @@ -139,9 +209,10 @@ public object Get(Rockstars request) Db.DeleteById(request.Delete.ToInt()); } - var response = new RockstarsResponse { + var response = new RockstarsResponse + { Aged = request.Age, - Total = Db.GetScalar("select count(*) from Rockstar"), + Total = Db.Scalar("select count(*) from Rockstar"), Results = request.Id != default(int) ? Db.Select(q => q.Id == request.Id) : request.Age.HasValue ? @@ -150,7 +221,8 @@ public object Get(Rockstars request) }; if (request.View != null || request.Template != null) - return new HttpResult(response) { + return new HttpResult(response) + { View = request.View, Template = request.Template, }; @@ -160,10 +232,10 @@ public object Get(Rockstars request) public object Post(Rockstars request) { - Db.Insert(request.TranslateTo()); + Db.Insert(request.ConvertTo()); return Get(new Rockstars()); } - + public IList Get(IList1 request) { base.Request.Items["View"] = request.View; @@ -186,10 +258,137 @@ public PartialModel Any(PartialModel request) { return new PartialModel { - Items = 5.Times(x => new PartialChildModel { + Items = 5.Times(x => new PartialChildModel + { SomeProperty = "value " + x }) }; } + + public void Any(RedirectWithoutQueryString request) { } + } + + public class RedirectWithoutQueryStringFilterAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + if (req.QueryString.Count > 0) + { + res.RedirectToUrl(req.PathInfo); + } + } + } + + [RedirectWithoutQueryStringFilter] + public class RedirectWithoutQueryString + { + public int Id { get; set; } + } + + + [Route("/channels/{Channel}/raw")] + public class PostRawToChannel : IReturnVoid + { + public string From { get; set; } + public string ToUserId { get; set; } + public string Channel { get; set; } + public string Message { get; set; } + public string Selector { get; set; } + } + + public class ServerEventsService : Service + { + public IServerEvents ServerEvents { get; set; } + + public void Any(PostRawToChannel request) + { + var sub = ServerEvents.GetSubscriptionInfo(request.From); + if (sub == null) + throw HttpError.NotFound("Subscription {0} does not exist".Fmt(request.From)); + + if (request.ToUserId != null) + { + ServerEvents.NotifyUserId(request.ToUserId, request.Selector, request.Message); + } + else + { + ServerEvents.NotifyChannel(request.Channel, request.Selector, request.Message); + } + } + } + + [Route("/Content/hello/{Name*}")] + public class TestWildcardRazorPage + { + public string Name { get; set; } + } + + public class IssueServices : Service + { + public object Get(TestWildcardRazorPage request) + { + return request; + } + } + + [Route("/contentpages/{PathInfo*}")] + public class TestRazorContentPage + { + public string PathInfo { get; set; } + } + + public class TestRazorContentPageService : Service + { + public object Any(TestRazorContentPage request) + { + return new HttpResult(request) + { + View = "/" + request.PathInfo + }; + } + } + + [Route("/test/session")] + public class TestSession : IReturn { } + + [Route("/test/session/view")] + public class TestSessionView : IReturn { } + + public class TestSessionResponse + { + public string UserAuthId { get; set; } + public bool IsAuthenticated { get; set; } + } + + public class TestSessionAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var session = req.GetSession(); + if (!session.IsAuthenticated) + { + res.StatusCode = (int)HttpStatusCode.Unauthorized; + res.EndRequestWithNoContent(); + } + } + } + + public class TestSessionService : Service + { + [TestSession] + public object Any(TestSession request) + { + var session = base.Request.GetSession(); + return new TestSessionResponse + { + UserAuthId = session.UserAuthId, + IsAuthenticated = session.IsAuthenticated, + }; + } + + public object Any(TestSessionView request) + { + return new TestSessionResponse(); + } } } diff --git a/tests/RazorRockstars.Console.Files/Benchmarks.cs b/tests/RazorRockstars.Console.Files/Benchmarks.cs deleted file mode 100644 index f50a0ee4734..00000000000 --- a/tests/RazorRockstars.Console.Files/Benchmarks.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using NUnit.Framework; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.Razor; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Formats; - -namespace RazorRockstars.Console.Files -{ - [Explicit("Ignore benchmarks")] - [TestFixture] - public class Benchmarks - { - AppHost appHost; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - LogManager.LogFactory = new ConsoleLogFactory(); - appHost = new AppHost(); - appHost.Init(); - appHost.Start("http://*:1337/"); - } - - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - appHost.Dispose(); - } - - [Test] - public void Benchmark_Razor_vs_Markdown() - { - var iterations = 10000; - var razorFormat = RazorFormat.Instance; - var markdownFmt = MarkdownFormat.Instance; - var dto = new RockstarsResponse { Results = Rockstar.SeedData.ToList() }; - - "Warm up MVC Razor...".Print(); - var mockReq = new MockHttpRequest { OperationName = "RockstarsRazor" }; - var mockRes = new MockHttpResponse(); - razorFormat.ProcessRequest(mockReq, mockRes, dto); - mockRes.ReadAsString().Print(); - - "Warm up Markdown Razor...".Print(); - mockReq = new MockHttpRequest { OperationName = "RockstarsMark" }; - mockRes = new MockHttpResponse(); - markdownFmt.ProcessRequest(mockReq, mockRes, dto); - mockRes.ReadAsString().Print(); - - "\n\nRunning for {0} times...".Fmt(iterations).Print(); - CompareRuns(iterations, - "MVC Razor", () => { - mockReq = new MockHttpRequest { OperationName = "RockstarsRazor" }; - mockRes = new MockHttpResponse(); - razorFormat.ProcessRequest(mockReq, mockRes, dto); - }, - "Markdown Razor", () => { - mockReq = new MockHttpRequest { OperationName = "RockstarsMark" }; - mockRes = new MockHttpResponse(); - markdownFmt.ProcessRequest(mockReq, mockRes, dto); - }); - } - - protected void CompareRuns(int iterations, string run1Name, Action run1Action, string run2Name, Action run2Action) - { - var run1 = RunAction(run1Action, iterations, run1Name); - var run2 = RunAction(run2Action, iterations, run2Name); - - var runDiff = run1 - run2; - var run1IsSlower = runDiff > 0; - var slowerRun = run1IsSlower ? run1Name : run2Name; - var fasterRun = run1IsSlower ? run2Name : run1Name; - var runDiffTime = run1IsSlower ? runDiff : runDiff * -1; - var runDiffAvg = run1IsSlower ? run1 / run2 : run2 / run1; - - "{0} was {1}ms or {2} times slower than {3}".Fmt( - slowerRun, runDiffTime, Math.Round(runDiffAvg, 2), fasterRun).Print(); - } - - protected decimal RunAction(Action action, int iterations, string actionName) - { - actionName = actionName ?? action.GetType().Name; - var ticksTaken = Measure(action, iterations); - var timeSpan = TimeSpan.FromSeconds(ticksTaken * 1d / Stopwatch.Frequency); - - "{0} took {1}ms ({2} ticks), avg: {3} ticks".Fmt( - actionName, timeSpan.TotalMilliseconds, ticksTaken, (ticksTaken / iterations)).Print(); - - return ticksTaken; - } - - protected long Measure(Action action, decimal iterations) - { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var begin = Stopwatch.GetTimestamp(); - - for (var i = 0; i < iterations; i++) - { - action(); - } - - var end = Stopwatch.GetTimestamp(); - - return (end - begin); - } - - protected void WarmUp(params Action[] actions) - { - foreach (var action in actions) - { - action(); - GC.Collect(); - } - } - - } -} diff --git a/tests/RazorRockstars.Console.Files/CompileError.cshtml b/tests/RazorRockstars.Console.Files/CompileError.cshtml new file mode 100644 index 00000000000..05f5a985e75 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/CompileError.cshtml @@ -0,0 +1,8 @@ +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "Page with typed 'Rockstars' model and no C# controller"; +} + +
+ @base.InvalidSymbol +
diff --git a/tests/RazorRockstars.Console.Files/ComplexModelService.cs b/tests/RazorRockstars.Console.Files/ComplexModelService.cs new file mode 100644 index 00000000000..6f152c23db8 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/ComplexModelService.cs @@ -0,0 +1,19 @@ +using ServiceStack; + +namespace RazorRockstars.Console.Files +{ + [Route("/ComplexModel")] + public class ComplexModel + { + public int[] Ids { get; set; } + public string[] Names { get; set; } + } + + public class ComplexModelService : Service + { + public object Any(ComplexModel request) + { + return request; + } + } +} \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Content/content-page.cshtml b/tests/RazorRockstars.Console.Files/Content/content-page.cshtml new file mode 100644 index 00000000000..4981c8350ae --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Content/content-page.cshtml @@ -0,0 +1,7 @@ +@{ + Layout = "SimpleLayout"; +} + +

Content Page

+ + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Content/default.html b/tests/RazorRockstars.Console.Files/Content/default.html new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Content/default.html @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Content/static-sub-embedded.txt b/tests/RazorRockstars.Console.Files/Content/static-sub-embedded.txt new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Content/static-sub-embedded.txt @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Content/static-sub.txt b/tests/RazorRockstars.Console.Files/Content/static-sub.txt new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Content/static-sub.txt @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/ContentPartialModel.cshtml b/tests/RazorRockstars.Console.Files/ContentPartialModel.cshtml new file mode 100644 index 00000000000..50ff104a677 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/ContentPartialModel.cshtml @@ -0,0 +1,10 @@ +@model List + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/DynamicJsonTests.cs b/tests/RazorRockstars.Console.Files/DynamicJsonTests.cs index 48b184dc7f9..211069bb4b0 100644 --- a/tests/RazorRockstars.Console.Files/DynamicJsonTests.cs +++ b/tests/RazorRockstars.Console.Files/DynamicJsonTests.cs @@ -1,5 +1,5 @@ using NUnit.Framework; -using ServiceStack.Razor.Json; +using ServiceStack; using ServiceStack.Text; namespace RazorRockstars.Console.Files diff --git a/tests/RazorRockstars.Console.Files/Login.cshtml b/tests/RazorRockstars.Console.Files/Login.cshtml new file mode 100644 index 00000000000..f2dd56a9645 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Login.cshtml @@ -0,0 +1,3 @@ +

Login Page

+ + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/MsgPackServiceTests.cs b/tests/RazorRockstars.Console.Files/MsgPackServiceTests.cs index f53fa2baf88..8f64c007e46 100644 --- a/tests/RazorRockstars.Console.Files/MsgPackServiceTests.cs +++ b/tests/RazorRockstars.Console.Files/MsgPackServiceTests.cs @@ -1,17 +1,11 @@ -using System; -using System.IO; -using System.Runtime.Serialization; +using System.IO; using System.Text; using MsgPack; using MsgPack.Serialization; using NUnit.Framework; -using ServiceStack.Common; +using ServiceStack; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.Plugins.MsgPack; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.MsgPack; using ServiceStack.Text; namespace RazorRockstars.Console.Files @@ -74,11 +68,11 @@ public object Any(MsgPackEmail request) [TestFixture] public class MsgPackServiceTests { - protected const string ListeningOn = "http://localhost:85/"; + protected const string ListeningOn = "http://localhost:3337/"; AppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { LogManager.LogFactory = new ConsoleLogFactory(); @@ -89,7 +83,7 @@ public void OnTestFixtureSetUp() appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { Dispose(); @@ -99,7 +93,6 @@ public void Dispose() { if (appHost == null) return; appHost.Dispose(); - appHost = null; } MsgPackEmail request = new MsgPackEmail { @@ -119,13 +112,10 @@ public void Can_Send_MsgPack_request() { var response = client.Send(request); - response.PrintDump(); - Assert.That(response.Equals(request)); } catch (WebServiceException webEx) { - webEx.ResponseDto.PrintDump(); Assert.Fail(webEx.Message); } } @@ -135,7 +125,7 @@ public void Can_serialize_email_dto() { using (var ms = new MemoryStream()) { - var serializer = MessagePackSerializer.Create(request.GetType()); + var serializer = MessagePackSerializer.Get(request.GetType()); serializer.PackTo(Packer.Create(ms), request); ms.Position = 0; @@ -153,7 +143,7 @@ public void Can_serialize_email_dto_generic() { using (var ms = new MemoryStream()) { - var serializer = MessagePackSerializer.Create(); + var serializer = MessagePackSerializer.Get(); serializer.Pack(ms, request); ms.Position = 0; @@ -163,6 +153,5 @@ public void Can_serialize_email_dto_generic() Assert.That(response.Equals(request)); } } - } -} \ No newline at end of file +} diff --git a/tests/RazorRockstars.Console.Files/Pages/Page1.cshtml b/tests/RazorRockstars.Console.Files/Pages/Page1.cshtml index 51780c8f4dc..f54b1fa1ed9 100644 --- a/tests/RazorRockstars.Console.Files/Pages/Page1.cshtml +++ b/tests/RazorRockstars.Console.Files/Pages/Page1.cshtml @@ -1,6 +1,5 @@ @inherits ViewPage - -@{ +@{ ViewBag.Title = "Page1"; int age = 0; var hasAge = Request.QueryString["Age"] != null && int.TryParse(Model.Age, out age); diff --git a/tests/RazorRockstars.Console.Files/Pages/PagesPartialModel.cshtml b/tests/RazorRockstars.Console.Files/Pages/PagesPartialModel.cshtml new file mode 100644 index 00000000000..f4e160c3d29 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Pages/PagesPartialModel.cshtml @@ -0,0 +1,10 @@ +@model List + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Pages/PartialExamples.cshtml b/tests/RazorRockstars.Console.Files/Pages/PartialExamples.cshtml new file mode 100644 index 00000000000..20e4611e357 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Pages/PartialExamples.cshtml @@ -0,0 +1,18 @@ +@inherits ViewPage + +

Render Partial Examples

+ +

GetReqstar from Partial

+ +@Html.Partial("GetReqstar", + base.Gateway.Send(new GetReqstar { Id = 1 })) + +

GetReqstar from RenderAction

+ +@Html.RenderAction("/reqstars/1") + +

GetReqstar from RenderAction (View: CustomReqstar)

+ +@Html.RenderAction("/reqstars/1", "CustomReqstar") + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Pages/_Layout.cshtml b/tests/RazorRockstars.Console.Files/Pages/_Layout.cshtml index 921ff7b7420..41f16484961 100644 --- a/tests/RazorRockstars.Console.Files/Pages/_Layout.cshtml +++ b/tests/RazorRockstars.Console.Files/Pages/_Layout.cshtml @@ -1,7 +1,8 @@  - Global _Layout (/Pages) + Global _Layout (/Pages) + @RenderSection("SectionHead", required: false)

Global _Layout

diff --git a/tests/RazorRockstars.Console.Files/Pages/default.cshtml b/tests/RazorRockstars.Console.Files/Pages/default.cshtml index be192c18aa5..9e8e91e5c85 100644 --- a/tests/RazorRockstars.Console.Files/Pages/default.cshtml +++ b/tests/RazorRockstars.Console.Files/Pages/default.cshtml @@ -8,11 +8,17 @@ var title = Model.Age.HasValue ? "{0} year old rockstars".Fmt(Model.Age) : "All Rockstars"; } +@section SectionHead { +

Inside SectionHead

+ @Html.Partial("PartialChildModel", new PartialChildModel { SomeProperty = "Prop" }) +} +
@Html.Partial("RazorPartial") @Html.Partial("MarkdownPartial") @Html.Partial("RazorPartialModel", rockstars) +@Html.Partial("PagesPartialModel", rockstars)
@title
    diff --git a/tests/RazorRockstars.Console.Files/Properties/AssemblyInfo.cs b/tests/RazorRockstars.Console.Files/Properties/AssemblyInfo.cs index f730494e2bb..068d9acfe8f 100644 --- a/tests/RazorRockstars.Console.Files/Properties/AssemblyInfo.cs +++ b/tests/RazorRockstars.Console.Files/Properties/AssemblyInfo.cs @@ -10,8 +10,8 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RazorRockstars.Console")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCopyright("Copyright (c) ServiceStack 2018")] +[assembly: AssemblyTrademark("Service Stack")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("6.0.0.0")] diff --git a/tests/RazorRockstars.Console.Files/RazorRockstars.Console.Files.csproj b/tests/RazorRockstars.Console.Files/RazorRockstars.Console.Files.csproj index 80df616dac8..77fa27caddd 100644 --- a/tests/RazorRockstars.Console.Files/RazorRockstars.Console.Files.csproj +++ b/tests/RazorRockstars.Console.Files/RazorRockstars.Console.Files.csproj @@ -1,5 +1,5 @@  - + Debug x86 @@ -13,6 +13,10 @@ 512 ..\..\src\ true + v4.7.2 + + + x86 @@ -24,6 +28,7 @@ prompt 4 true + false x86 @@ -33,57 +38,111 @@ TRACE prompt 4 + false + + + bin\x86\Signed\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + false - - ..\..\lib\Mono.Data.Sqlite.dll - - - - False - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - + + - - ..\..\src\packages\System.Data.SQLite.x64.1.0.84.0\lib\net40\System.Data.SQLite.dll - - - ..\..\src\packages\System.Data.SQLite.x64.1.0.84.0\lib\net40\System.Data.SQLite.Linq.dll - + + + - - ..\..\lib\ServiceStack.Text.dll - - - ..\..\lib\tests\nunit.framework.dll - - + + + Designer - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -96,13 +155,31 @@ PreserveNewest - - sqlite3.dll + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest @@ -148,7 +225,9 @@ PreserveNewest - + + Designer + PreserveNewest @@ -231,35 +310,84 @@ --> + + + + + {5e258282-86a6-4780-ab25-5e458f2e6f70} + ServiceStack.Api.OpenApi + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + - {982416DB-C143-4028-A0C3-CF41892D18D3} + {982416db-c143-4028-a0c3-cf41892d18d3} ServiceStack.Common - - {672F2DFE-4EE8-498B-B449-23E9E7F6961C} - ServiceStack.FluentValidation.Mvc3 + + {c05de4a1-84c5-481b-8bd4-c837a1303b01} + ServiceStack.HttpClient - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} + {55942102-033a-4da8-a6af-1db7b2f34a2d} ServiceStack.Interfaces - - {6B751A07-75D4-4A9D-B3A0-EEA27808E64C} - ServiceStack.Plugins.MsgPack + + {6b751a07-75d4-4a9d-b3a0-eea27808e64c} + ServiceStack.MsgPack - {D73274AE-006B-4CEE-BA60-0ECF5873048D} + {d73274ae-006b-4cee-ba60-0ecf5873048d} ServiceStack.Razor - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface + + {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} + ServiceStack.Server - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} + {680a1709-25eb-4d52-a87f-ee03ffd94baa} ServiceStack - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/RazorRockstars_FilesTests.cs b/tests/RazorRockstars.Console.Files/RazorRockstars_FilesTests.cs index 1672b43c1d7..306fcb851e2 100644 --- a/tests/RazorRockstars.Console.Files/RazorRockstars_FilesTests.cs +++ b/tests/RazorRockstars.Console.Files/RazorRockstars_FilesTests.cs @@ -5,12 +5,10 @@ using System.Net; using System.Threading; using NUnit.Framework; -using ServiceStack.Common; +using ServiceStack; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; using ServiceStack.Razor; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Testing; using ServiceStack.Text; namespace RazorRockstars.Console.Files @@ -18,11 +16,8 @@ namespace RazorRockstars.Console.Files [TestFixture] public class RazorRockstars_FilesTests { - private const string ListeningOn = "http://*:1337/"; - public const string Host = "http://localhost:1337"; - - //private const string ListeningOn = "http://*:1337/subdir/subdir2/"; - //private const string Host = "http://localhost:1337/subdir/subdir2"; + public const string ListeningOn = "http://*:2337/"; + public const string Host = "http://localhost:2337"; private const string BaseUri = Host + "/"; @@ -30,17 +25,20 @@ public class RazorRockstars_FilesTests Stopwatch startedAt; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { LogManager.LogFactory = new ConsoleLogFactory(); startedAt = Stopwatch.StartNew(); - appHost = new AppHost(); + appHost = new AppHost + { + EnableMarkdown = true, + }; appHost.Init(); appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { "Time Taken {0}ms".Fmt(startedAt.ElapsedMilliseconds).Print(); @@ -51,6 +49,7 @@ public void TestFixtureTearDown() [Test] public void RunFor10Mins() { + Process.Start(BaseUri); Thread.Sleep(TimeSpan.FromMinutes(10)); } @@ -58,17 +57,17 @@ public void RunFor10Mins() public void Does_not_use_same_razor_page_instance() { var html = GetRazorInstanceHtml(); - Assert.That(html, Is.StringContaining("
    Counter: 1
    ")); + Assert.That(html, Does.Contain("
    Counter: 1
    ")); html = GetRazorInstanceHtml(); - Assert.That(html, Is.StringContaining("
    Counter: 1
    ")); + Assert.That(html, Does.Contain("
    Counter: 1
    ")); } private static string GetRazorInstanceHtml() { var razorFormat = RazorFormat.Instance; var mockReq = new MockHttpRequest { OperationName = "RazorInstance" }; - var mockRes = new MockHttpResponse(); + var mockRes = new MockHttpResponse(mockReq); var dto = new RockstarsResponse { Results = Rockstar.SeedData.ToList() }; razorFormat.ProcessRequest(mockReq, mockRes, dto); var html = mockRes.ReadAsString(); @@ -84,6 +83,7 @@ public void Assert200(string url, params string[] containsItems) if (r.StatusCode != HttpStatusCode.OK) Assert.Fail(url + " did not return 200 OK"); }); + //text.Print(); foreach (var item in containsItems) { if (!text.Contains(item)) @@ -93,6 +93,24 @@ public void Assert200(string url, params string[] containsItems) } } + public void Assert200Without(string url, params string[] withoutStrings) + { + url.Print(); + var text = url.GetStringFromUrl(AcceptContentType, responseFilter: r => + { + if (r.StatusCode != HttpStatusCode.OK) + Assert.Fail(url + " did not return 200 OK"); + }); + text.Print(); + foreach (var item in withoutStrings) + { + if (text.Contains(item)) + { + Assert.Fail(item + " was found in " + url); + } + } + } + public void Assert200UrlContentType(string url, string contentType) { url.Print(); @@ -162,11 +180,18 @@ public void AssertStatus(string url, HttpStatusCode statusCode, params string[] static string ViewMarkdownPartial = ""; static string ViewRazorPartialModel = ""; static string ViewPartialChildModel = ""; + static string ViewContentPartialModel = ""; + static string ViewPagesPartialModel = ""; + + static string SectionPartialHeaderSection = ""; static string View_Default = ""; static string View_Pages_Default = ""; static string View_Pages_Dir_Default = ""; static string ViewM_Pages_Dir2_Default = ""; + static string View_RequestFilters = ""; + static string View_RequestFiltersPage = ""; + static string View_Content_ContentPage = ""; static string Template_Layout = ""; static string Template_Pages_Layout = ""; @@ -278,13 +303,30 @@ public void Redirects_when_trying_to_get_markdown_page_with_extension() public void Can_get_default_razor_pages() { Assert200(Host + "/", - View_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); + View_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel, ViewContentPartialModel, ViewPagesPartialModel); Assert200(Host + "/Pages/", - View_Pages_Default, Template_Pages_Layout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); + View_Pages_Default, Template_Pages_Layout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel, ViewPagesPartialModel); Assert200(Host + "/Pages/Dir/", View_Pages_Dir_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel); } + [Test] + public void Can_get_ContentPages_via_HttpResult_View() + { + Assert200(Host + "/contentpages/NoModelNoController.cshtml", + ViewNoModelNoController, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial); + + Assert200(Host + "/contentpages/Content/content-page.cshtml", + View_Content_ContentPage, Template_SimpleLayout); + } + + [Test] + public void Can_get_default_file() + { + Assert200(Host + "/default_file", + View_Default, Template_SimpleLayout, ViewRazorPartial, ViewMarkdownPartial, ViewRazorPartialModel, ViewContentPartialModel, ViewPagesPartialModel); + } + [Test] public void Can_get_default_markdown_pages() { @@ -330,6 +372,12 @@ public void Can_get_RequestPathInfo_in_PartialChildModel() Assert200(Host + "/partialmodel", Template_PartialModel, ViewPartialChildModel, "PathInfo: /partialmodel"); } + [Test] + public void Can_render_PartialHeaderSection_in_PartialChildModel() + { + Assert200(Host + "/partialmodel", Template_PartialModel, ViewPartialChildModel, SectionPartialHeaderSection); + } + [Test] public void Does_return_populated_error_page() { @@ -349,6 +397,109 @@ public void Does_return_populated_error_page_with_custom_status() "

    ResponseStatus: ArgumentException

    ", "

    ResponseStatus: Custom_Error_Message_Only

    "); } + + [Test] + public void Does_render_partials_inside_sections() + { + Assert200(Host + "/Pages/", + View_Pages_Default, + "

    Inside SectionHead

    ", + "

    Inside PartialChildModel

    ", + ""); + } + + [Test] + public void Does_shortcircuit_RequestFilters() + { + Assert200(Host + "/RequestFilters", + View_RequestFilters, + "

    QueryStrings:0

    "); + + Assert200(Host + "/RequestFilters?a=querystring", + View_RequestFilters, + "

    QueryStrings:0

    "); + } + + [Test] + public void Does_shortcircuit_RequestFiltersPage_testing_Layout() + { + Assert200(Host + "/RequestFiltersPage", + View_RequestFiltersPage, + "

    QueryStrings:0

    "); + + Assert200(Host + "/RequestFiltersPage?a=querystring", + View_RequestFiltersPage, + "

    QueryStrings:0

    "); + } + + [Test] + public void Does_not_allow_direct_access_to_ViewPages() + { + AssertStatus(Host + "/Views/SimpleView", HttpStatusCode.NotFound); + } + + [Test] + public void Does_return_AddServiceStackReference_Endpoints() + { + Assert200(Host + "/types/csharp", "/* Options:", + "//GlobalNamespace: ", + "//MakePartial: True", + "//MakeVirtual: True", + "//MakeDataContractsExtensible: False", + "//AddReturnMarker: True", + "//AddDescriptionAsComments: True", + "//AddDataContractAttributes: False", + "//AddIndexesToDataMembers: False", + "//AddGeneratedCodeAttributes: False", + "//AddResponseStatus: False", + "//AddImplicitVersion: ", + "//InitializeCollections: True", + "//IncludeTypes: ", + "//ExcludeTypes: ", + "//AddDefaultXmlNamespace: http://schemas.servicestack.net/types", + "using System;", + "public partial class ACodeGenTest", + "public virtual int FirstField { get; set; }", + "IReturn", + "///Description for ACodeGenTest", + "///Description for FirstField", + "///Description for FirstResult", + "///Description for SecondResult", + "[ApiMember(Description=\"Description for SecondResult\")]", + "[DataContract]{0} public partial class ACodeGenTestResponse".Fmt(Environment.NewLine), + "[DataMember]{0} public virtual int FirstResult".Fmt(Environment.NewLine) + ); + + Assert200(Host + "/types/csharp"); + Assert200(Host + "/types/csharp?MakePartial=false", "MakePartial: False", "public class ACodeGenTest"); + Assert200(Host + "/types/csharp?MakeVirtual=false", "MakeVirtual: False", "public int FirstField"); + Assert200(Host + "/types/csharp?MakeDataContractsExtensible=true", "MakeDataContractsExtensible: True", "ExtensionDataObject ExtensionData"); + Assert200(Host + "/types/csharp?AddDescriptionAsComments=false", "AddDescriptionAsComments: False", "[Description(\"Description for ACodeGenTest\")]", "[Description(\"Description for FirstField\")]"); + Assert200Without(Host + "/types/csharp?AddDescriptionAsComments=false", "AddDescriptionAsComments: True", "///Description for ACodeGenTest", "///Description for FirstField"); + Assert200(Host + "/types/csharp?AddDataContractAttributes=true", "AddDataContractAttributes: True", + "[DataContract]{0} public partial class ACodeGenTest".Fmt(Environment.NewLine), + "[DataMember]{0} public virtual int FirstField".Fmt(Environment.NewLine)); + Assert200(Host + "/types/csharp?AddIndexesToDataMembers=true", "AddIndexesToDataMembers: True", + "[DataMember(Order=1)]{0} public virtual int FirstResult".Fmt(Environment.NewLine)); + Assert200(Host + "/types/csharp?AddResponseStatus=true", "AddResponseStatus: True", + "public virtual int SecondResult {{ get; set; }}{0}{0} public virtual ResponseStatus ResponseStatus".Fmt(Environment.NewLine)); + Assert200(Host + "/types/csharp?AddGeneratedCodeAttributes=true", "AddGeneratedCodeAttributes: True", "[GeneratedCode("); + Assert200(Host + "/types/csharp?AddImplicitVersion=1", "AddImplicitVersion: 1", "Version = 1"); + Assert200(Host + "/types/csharp?InitializeCollections=true", "InitializeCollections: True", "SecondFields = new List"); + Assert200(Host + "/types/csharp?IncludeTypes=ACodeGenTest", "IncludeTypes: ACodeGenTest", "public partial class ACodeGenTest"); + Assert200Without(Host + "/types/csharp?IncludeTypes=ACodeGenTest", "public partial class ACodeGenTestResponse"); + Assert200(Host + "/types/csharp?IncludeTypes=ACodeGenTest.*", "public partial class ACodeGenTestResponse"); + Assert200Without(Host + "/types/csharp?ExcludeTypes=ACodeGenTestResponse", "public partial class ACodeGenTestResponse"); + Assert200(Host + "/types/csharp?AddDefaultXmlNamespace=example.org&AddDataContractAttributes=true", "AddDefaultXmlNamespace: example.org", "[assembly: ContractNamespace(\"example.org\","); + + Assert200(Host + "/types/fsharp", "(* Options:", "open System"); + Assert200(Host + "/types/vbnet", "' Options:", "Imports System"); + Assert200(Host + "/types/swift", "/* Options:", "import Foundation"); + Assert200(Host + "/types/java", "/* Options:", "import java.math.*;"); + Assert200(Host + "/types/kotlin", "/* Options:", "import java.math.*"); + Assert200(Host + "/types/typescript", "/* Options:", "export interface IReturnVoid"); + Assert200(Host + "/types/typescript.d", "/* Options:", "interface IReturnVoid"); + } } } diff --git a/tests/RazorRockstars.Console.Files/ReqStarsService.cs b/tests/RazorRockstars.Console.Files/ReqStarsService.cs index 2c25b43d37c..6b6b71a1800 100644 --- a/tests/RazorRockstars.Console.Files/ReqStarsService.cs +++ b/tests/RazorRockstars.Console.Files/ReqStarsService.cs @@ -6,21 +6,16 @@ using System.Net; using System.Runtime.Serialization; using System.Threading; +using System.Web.ModelBinding; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Web; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.Host; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; +using ServiceStack.MsgPack; using ServiceStack.OrmLite; -using ServiceStack.Plugins.MsgPack; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Cors; -using ServiceStack.ServiceInterface.ServiceModel; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Web; namespace RazorRockstars.Console.Files { @@ -37,6 +32,27 @@ namespace RazorRockstars.Console.Files /// New API are also available in ServiceStack's typed service clients (they're actually even more succinct :) /// Any Views rendered is based on Request or Returned DTO type, see: http://razor.servicestack.net/#unified-stack + [System.ComponentModel.Description("Description for ACodeGenTest")] + public class ACodeGenTest + { + [ServiceStack.DataAnnotations.Description("Description for FirstField")] + public int FirstField { get; set; } + + public List SecondFields { get; set; } + } + + [DataContract] + public class ACodeGenTestResponse + { + [DataMember] + [ServiceStack.DataAnnotations.Description("Description for FirstResult")] + public int FirstResult { get; set; } + + [DataMember] + [ApiMember(Description = "Description for SecondResult")] + public int SecondResult { get; set; } + } + [Route("/reqstars/search", "GET")] [Route("/reqstars/aged/{Age}")] public class SearchReqstars : IReturn @@ -70,6 +86,12 @@ public class GetReqstar : IReturn public int Id { get; set; } } + [Route("/cached/reqstars/{Id}", "GET")] + public class GetCachedReqstar : IReturn + { + public int Id { get; set; } + } + [Route("/reqstars/{Id}/delete")] public class DeleteReqstar : IReturnVoid { @@ -149,6 +171,11 @@ public class ReqstarsService : Service new Reqstar(3, "Foo2", "Bar2", 20), }; + public object Any(ACodeGenTest request) + { + return new ACodeGenTestResponse { FirstResult = request.FirstField }; + } + [EnableCors] public void Options(Reqstar reqstar) { } @@ -166,7 +193,7 @@ public ReqstarsResponse Get(SearchReqstars request) return new ReqstarsResponse //matches ReqstarsResponse.cshtml razor view { Aged = request.Age, - Total = Db.GetScalar("select count(*) from Reqstar"), + Total = Db.Scalar("select count(*) from Reqstar"), Results = request.Age.HasValue ? Db.Select(q => q.Age == request.Age.Value) : Db.Select() @@ -184,10 +211,10 @@ public object Any(CachedAllReqstars request) throw new ArgumentException("Invalid Age"); var cacheKey = typeof(CachedAllReqstars).Name; - return base.RequestContext.ToOptimizedResultUsingCache(base.Cache, cacheKey, () => + return base.Request.ToOptimizedResultUsingCache(base.Cache, cacheKey, () => new ReqstarsResponse { Aged = request.Aged, - Total = Db.GetScalar("select count(*) from Reqstar"), + Total = Db.Scalar("select count(*) from Reqstar"), Results = Db.Select(q => q.Age == request.Aged) }); } @@ -195,7 +222,13 @@ public object Any(CachedAllReqstars request) [ClientCanSwapTemplates] //allow action-level filters public Reqstar Get(GetReqstar request) { - return Db.Id(request.Id); + return Db.SingleById(request.Id); + } + + public object Get(GetCachedReqstar request) + { + return Request.ToOptimizedResultUsingCache(Cache, request.GetType().Name, () => + Db.SingleById(request.Id)); } public object Post(Reqstar request) @@ -203,14 +236,14 @@ public object Post(Reqstar request) if (!request.Age.HasValue) throw new ArgumentException("Age is required"); - Db.Insert(request.TranslateTo()); + Db.Insert(request.ConvertTo()); return Db.Select(); } public Reqstar Patch(UpdateReqstar request) { Db.Update(request, x => x.Id == request.Id); - return Db.Id(request.Id); + return Db.SingleById(request.Id); } public void Any(DeleteReqstar request) @@ -366,17 +399,17 @@ public object Get(RequestDto request) public class MyResponseFilterAttribute : ResponseFilterAttribute { public static int Called = 0; - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) + public override void Execute(IRequest req, IResponse res, object responseDto) { Called++; - var x = requestDto; + var x = responseDto; } } public class MyRequestFilterAttribute : RequestFilterAttribute { public static int Called = 0; - public override void Execute(IHttpRequest req, IHttpResponse res, object responseDto) + public override void Execute(IRequest req, IResponse res, object responseDto) { Called++; var x = responseDto; @@ -386,8 +419,8 @@ public override void Execute(IHttpRequest req, IHttpResponse res, object respons [TestFixture] public class ReqStarsServiceTests { - private const string ListeningOn = "http://*:1337/"; - public const string Host = "http://localhost:1337"; + private const string ListeningOn = "http://*:2337/"; + public const string Host = "http://localhost:2337"; private const string BaseUri = Host + "/"; @@ -395,7 +428,7 @@ public class ReqStarsServiceTests private Stopwatch startedAt; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { LogManager.LogFactory = new ConsoleLogFactory(); @@ -404,9 +437,10 @@ public void TestFixtureSetUp() EnableRazor = true, //Uncomment for faster tests! }; appHost.Plugins.Add(new MsgPackFormat()); + //appHost.Plugins.Add(new NetSerializerFormat()); //Fast appHost.Init(); - EndpointHost.Config.DebugMode = true; + HostContext.Config.DebugMode = true; appHost.Start(ListeningOn); } @@ -426,21 +460,21 @@ public void TearDown() db.Dispose(); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { "Time Taken {0}ms".Fmt(startedAt.ElapsedMilliseconds).Print(); appHost.Dispose(); } - [Explicit("Debug Run")] + [Ignore("Debug Run")] [Test] public void RunFor10Mins() { Thread.Sleep(TimeSpan.FromMinutes(10)); } - [Explicit("Concurrent Run")] + [Ignore("Concurrent Run")] [Test] public void Concurrent_GetReqstar_JSON() { @@ -474,7 +508,7 @@ public void Concurrent_GetReqstar_JSON() } - [Explicit("Concurrent Run")] + [Ignore("Concurrent Run")] [Test] public void Concurrent_GetReqstar_Razor() { @@ -513,6 +547,7 @@ public void Concurrent_GetReqstar_Razor() new XmlServiceClient(BaseUri), new JsvServiceClient(BaseUri), new MsgPackServiceClient(BaseUri), + //new NetSerializerServiceClient(BaseUri), }; protected static IServiceClient[] ServiceClients = @@ -524,7 +559,6 @@ public void Concurrent_GetReqstar_Razor() public void Does_allow_sending_collections(IServiceClient client) { var results = client.Send>(new ReqstarsByNames { "Foo", "Foo2" }); - results.PrintDump(); } [Test, TestCaseSource("RestClients")] @@ -540,15 +574,15 @@ public void Does_execute_request_and_response_filter_attributes(IRestClient clie [Test] public void Can_Process_OPTIONS_request_with_Cors_ActionFilter() { - var webReq = (HttpWebRequest)WebRequest.Create(Host + "/reqstars"); + var webReq = WebRequest.CreateHttp(Host + "/reqstars"); webReq.Method = "OPTIONS"; - using (var webRes = webReq.GetResponse()) + using (var r = webReq.GetResponse()) { - Assert.That(webRes.Headers["Access-Control-Allow-Origin"], Is.EqualTo("*")); - Assert.That(webRes.Headers["Access-Control-Allow-Methods"], Is.EqualTo("GET, POST, PUT, DELETE, OPTIONS")); - Assert.That(webRes.Headers["Access-Control-Allow-Headers"], Is.EqualTo("Content-Type")); + Assert.That(r.Headers[HttpHeaders.AllowOrigin], Is.EqualTo(CorsFeature.DefaultOrigin)); + Assert.That(r.Headers[HttpHeaders.AllowMethods], Is.EqualTo(CorsFeature.DefaultMethods)); + Assert.That(r.Headers[HttpHeaders.AllowHeaders], Is.EqualTo(CorsFeature.DefaultHeaders)); - var response = webRes.GetResponseStream().ReadFully(); + var response = r.GetResponseStream().ReadFully(); Assert.That(response.Length, Is.EqualTo(0)); } } @@ -581,10 +615,10 @@ public void Can_GET_AllReqstars_PrettyRestApi(IRestClient client) [Test] public void Can_GET_AllReqstars_View() { - var html = "{0}/reqstars".Fmt(Host).GetStringFromUrl(acceptContentType: "text/html"); + var html = "{0}/reqstars".Fmt(Host).GetStringFromUrl(accept: "text/html"); html.Print(); - Assert.That(html, Is.StringContaining("")); - Assert.That(html, Is.StringContaining("")); + Assert.That(html, Does.Contain("")); + Assert.That(html, Does.Contain("")); } @@ -713,10 +747,10 @@ public void Disallows_SEND_GetReqstar_PrettyTypedApi(IServiceClient client) [Test] public void Can_GET_GetReqstar_View() { - var html = "{0}/reqstars/1".Fmt(Host).GetStringFromUrl(acceptContentType: "text/html"); + var html = "{0}/reqstars/1".Fmt(Host).GetStringFromUrl(accept: "text/html"); html.Print(); - Assert.That(html, Is.StringContaining("")); - Assert.That(html, Is.StringContaining("")); + Assert.That(html, Does.Contain("")); + Assert.That(html, Does.Contain("")); } @@ -774,8 +808,7 @@ public void Can_PATCH_UpdateReqstar_PrettyRestApi(IRestClient client) [Test, TestCaseSource("RestClients")] public void Can_CREATE_Reqstar(IRestClient client) { - var response = client.Post>("/reqstars", - new Reqstar(4, "Just", "Created", 25)); + var response = client.Post>("/reqstars", new Reqstar(4, "Just", "Created", 25)); Assert.That(response.Count, Is.EqualTo(ReqstarsService.SeedData.Length + 1)); @@ -868,7 +901,7 @@ public void Can_GET_RoutelessReqstar_PrettyRestApi(IRestClient client) var format = ((ServiceClientBase)client).Format; Assert.That(request.ToUrl("GET", format), Is.EqualTo( - "/{0}/syncreply/RoutelessReqstar?id=1&firstName=Foo&lastName=Bar".Fmt(format))); + "/{0}/reply/RoutelessReqstar?id=1&firstName=Foo&lastName=Bar".Fmt(format))); Assert.That(response.Id, Is.EqualTo(request.Id)); Assert.That(response.FirstName, Is.EqualTo(request.FirstName)); Assert.That(response.LastName, Is.EqualTo(request.LastName)); @@ -887,7 +920,7 @@ public void Can_POST_RoutelessReqstar_PrettyRestApi(IRestClient client) var format = ((ServiceClientBase)client).Format; Assert.That(request.ToUrl("POST", format), Is.EqualTo( - "/{0}/syncreply/RoutelessReqstar".Fmt(format))); + "/{0}/reply/RoutelessReqstar".Fmt(format))); Assert.That(response.Id, Is.EqualTo(request.Id)); Assert.That(response.FirstName, Is.EqualTo(request.FirstName)); Assert.That(response.LastName, Is.EqualTo(request.LastName)); @@ -915,9 +948,9 @@ public void Can_GET_RichRequest_PrettyRestApi(IRestClient client) public void Does_Cache_RazorPage() { var html = "{0}/reqstars/cached/10".Fmt(Host).GetStringFromUrl(); - Assert.That(html, Is.StringContaining("

    Counter:10

    ")); + Assert.That(html, Does.Contain("

    Counter:10

    ")); html = "{0}/reqstars/cached/20".Fmt(Host).GetStringFromUrl(); - Assert.That(html, Is.StringContaining("

    Counter:10

    ")); + Assert.That(html, Does.Contain("

    Counter:10

    ")); } [Test] @@ -941,6 +974,48 @@ public void Does_ignore_all_types_of_routes() response4 = "{0}/ignorewildcard/a/b?Name=foo".Fmt(Host).GetJsonFromUrl().FromJson(); Assert.That(response4.Name, Is.EqualTo("foo")); } + + [Test] + public void Does_handle_ignored_routes() + { + var restPath = new RestPath(typeof(IgnoreRoute3), "/ignore/{ignore}/with/{name}"); + var pathComponents = RestPath.GetPathPartsForMatching("/ignore/AnyThing/with/foo"); + var score = restPath.MatchScore("GET", pathComponents); + + Assert.That(score, Is.GreaterThan(0)); + + var request = (IgnoreRoute3) restPath.CreateRequest("/ignore/AnyThing/with/foo"); + Assert.That(request.Name, Is.EqualTo("foo")); + } + + [Test] + public void Does_RenderPartial_and_RenderAction() + { + var html = "{0}/Pages/PartialExamples".Fmt(Host) + .GetStringFromUrl(); + + Assert.That(html, Does.Contain("")); + Assert.That(html, Does.Contain("")); + Assert.That(html, Does.Contain("")); + } + + [Test] + public void Does_render_cached_response() + { + var html1 = "{0}/cached/reqstars/1".Fmt(Host) + .GetStringFromUrl(); + + Assert.That(html1, Does.Contain("")); + + var html2 = "{0}/cached/reqstars/1".Fmt(Host) + .GetStringFromUrl(); + + Assert.That(html2, Does.Contain("")); + + Assert.That(html1, Is.EqualTo(html2)); + + html2.Print(); + } } - + } \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/RequestFilters.cshtml b/tests/RazorRockstars.Console.Files/RequestFilters.cshtml new file mode 100644 index 00000000000..e66ef6fdef3 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/RequestFilters.cshtml @@ -0,0 +1,18 @@ +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "Page testing request filters"; + + base.ApplyRequestFilters(new RedirectWithoutQueryString()); + if (Request.QueryString.Count > 0) + { + throw new System.IO.InvalidDataException(); + } +} + +

    Request Filters

    + +

    QueryStrings:@Request.QueryString.Count

    + +@DateTime.UtcNow.ToLongTimeString() + + diff --git a/tests/RazorRockstars.Console.Files/RequestFiltersPage.cshtml b/tests/RazorRockstars.Console.Files/RequestFiltersPage.cshtml new file mode 100644 index 00000000000..249b657ad69 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/RequestFiltersPage.cshtml @@ -0,0 +1,18 @@ +@{ + Layout = "RequestFiltersLayout"; + ViewBag.Title = "Page testing request filters"; + + base.ApplyRequestFilters(new RedirectWithoutQueryString()); + if (Request.QueryString.Count > 0) + { + throw new System.IO.InvalidDataException(); + } +} + +

    Request Filters

    + +

    QueryStrings:@Request.QueryString.Count

    + +@DateTime.UtcNow.ToLongTimeString() + + diff --git a/tests/RazorRockstars.Console.Files/SecuredPage.cshtml b/tests/RazorRockstars.Console.Files/SecuredPage.cshtml new file mode 100644 index 00000000000..96208d5fb04 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/SecuredPage.cshtml @@ -0,0 +1,7 @@ +@{ + base.RedirectIfNotAuthenticated(); +} + +

    Secured Page

    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/ServerEventsTest.cshtml b/tests/RazorRockstars.Console.Files/ServerEventsTest.cshtml new file mode 100644 index 00000000000..7ead61e126f --- /dev/null +++ b/tests/RazorRockstars.Console.Files/ServerEventsTest.cshtml @@ -0,0 +1,140 @@ +@inherits ViewPage + +@{ + Layout = "Empty"; + ViewBag.Title = "Server Sent Events Test"; +} + + + + + +

    Subscribing to SimpleModel

    + +
    +
    #boxid
    +
    .boxclass
    +
    + +

    Send Message

    + + + + + +
    +
    cmd.showPopup message
    +
    cmd.toggle$h1:first-child
    +
    +
    trigger.animateBox$#boxid {"opacity":".5","marginRight":"+=20px"}
    +
    trigger.animateBox$.boxclass {"marginTop":"+=20px", "padding":"+=20"}
    +
    +
    css.color #0C0
    +
    css.color$h1 yellow
    +
    css.backgroundColor #f1f1f1
    +
    css.backgroundColor$h1 blue
    +
    css.backgroundColor$#boxid purple
    +
    css.backgroundColor$.boxclass red
    +
    css.color$#boxid,.boxclass white
    +
    +
    document.title Hello World
    +
    window.location http://google.com
    +
    + +

    Events

    + +
    + + + diff --git a/tests/RazorRockstars.Console.Files/TestSessionPage.cshtml b/tests/RazorRockstars.Console.Files/TestSessionPage.cshtml new file mode 100644 index 00000000000..d668a6834eb --- /dev/null +++ b/tests/RazorRockstars.Console.Files/TestSessionPage.cshtml @@ -0,0 +1,7 @@ +@{ + var session = base.GetSession(); +} + +IsAuthenticated:@session.IsAuthenticated + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/ValidationService.cs b/tests/RazorRockstars.Console.Files/ValidationService.cs new file mode 100644 index 00000000000..0efaf1a078a --- /dev/null +++ b/tests/RazorRockstars.Console.Files/ValidationService.cs @@ -0,0 +1,112 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +using System; +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.FluentValidation; +using ServiceStack.Logging; +using ServiceStack.Text; + +namespace RazorRockstars.Console.Files +{ + [Route("/validation")] + public class Validation + { + public int Id { get; set; } + public string Name { get; set; } + } + + [Route("/AutoValidation")] + public class AutoValidation + { + public int Id { get; set; } + public string Name { get; set; } + } + + [Route("/ManualValidation")] + public class ManualValidation + { + public int Id { get; set; } + public string Name { get; set; } + } + + [DefaultView("Validation")] + public class ValidationService : Service + { + public object Get(Validation request) + { + return request; + } + + public object Post(AutoValidation request) + { + return request.ConvertTo(); + } + + public object Post(ManualValidation request) + { + if (request.Name == null) + throw new ArgumentNullException("Name"); + + if (request.Id < 0) + throw new ArgumentException("Id must be a positive number", "Id"); + + return request.ConvertTo(); + } + } + + public class AutoValidationValidator : AbstractValidator + { + public AutoValidationValidator() + { + RuleFor(x => x.Name).NotEmpty(); + RuleFor(x => x.Id).GreaterThanOrEqualTo(0); + } + } + + + [TestFixture] + public class ValidationTests + { + public const string ListeningOn = "http://*:1337/"; + public const string Host = "http://localhost:1337"; + + //private const string ListeningOn = "http://*:1337/subdir/subdir2/"; + //private const string Host = "http://localhost:1337/subdir/subdir2"; + + private const string BaseUri = Host + "/"; + + AppHost appHost; + + Stopwatch startedAt; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + startedAt = Stopwatch.StartNew(); + appHost = new AppHost(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + "Time Taken {0}ms".Fmt(startedAt.ElapsedMilliseconds).Print(); + appHost.Dispose(); + } + + [Ignore("Debug Run")] + [Test] + public void RunFor10Mins() + { + Process.Start(BaseUri.CombineWith("/validation")); + Thread.Sleep(TimeSpan.FromMinutes(10)); + } + + } +} \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/ComplexModel.cshtml b/tests/RazorRockstars.Console.Files/Views/ComplexModel.cshtml new file mode 100644 index 00000000000..0ca7e19b209 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/ComplexModel.cshtml @@ -0,0 +1,40 @@ +@inherits ViewPage +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "Complex Model Test"; +} + + + + +

    Complex Model

    +
    +@Model.AsRawJson()
    +
    +
    +
    + + +
    +
    + + +
    + + +
    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/CustomReqstar.cshtml b/tests/RazorRockstars.Console.Files/Views/CustomReqstar.cshtml new file mode 100644 index 00000000000..468f2d0ff52 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/CustomReqstar.cshtml @@ -0,0 +1,23 @@ +@inherits ViewPage + +@{ + ViewBag.Title = "Viewing {0}yo {1} {2} profile".Fmt(Model.Age, Model.FirstName, Model.LastName); + Layout = "HtmlReport"; +} +
    +

    Custom Reqstar View

    + +

    @Model.FirstName Details

    +
    +
    Id
    +
    @Model.Id
    +
    Age
    +
    @Model.Age
    +
    First Name
    +
    @Model.FirstName
    +
    LastName
    +
    @Model.LastName
    +
    +
    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/GetCachedReqstar.cshtml b/tests/RazorRockstars.Console.Files/Views/GetCachedReqstar.cshtml new file mode 100644 index 00000000000..19c1bf3841a --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/GetCachedReqstar.cshtml @@ -0,0 +1,27 @@ +@inherits ViewPage + +@{ + ViewBag.Title = "Viewing {0}yo {1} {2} profile".Fmt(Model.Age, Model.FirstName, Model.LastName); + Layout = "HtmlReport"; +} +
    + View this page in: + json, + xml, + jsv, + csv + +

    @Model.FirstName Details

    +
    +
    Id
    +
    @Model.Id
    +
    Age
    +
    @Model.Age
    +
    First Name
    +
    @Model.FirstName
    +
    LastName
    +
    @Model.LastName
    +
    +
    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml b/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml index b08a81d62a4..907bbe923b9 100644 --- a/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml +++ b/tests/RazorRockstars.Console.Files/Views/ModelError.cshtml @@ -2,8 +2,8 @@ @model ModelErrorResponse
    ModelError: @ModelError.AsRawJson()
    -

    ResponseStatus: @ResponseStatus.AsRawJson()

    -

    ResponseStatus: @ResponseStatus.ErrorCode

    -

    ResponseStatus: @ResponseStatus.Message

    +

    ResponseStatus: @this.GetErrorStatus().AsRawJson()

    +

    ResponseStatus: @this.GetErrorStatus().ErrorCode

    +

    ResponseStatus: @this.GetErrorStatus().Message

    \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/PartialChildModel.cshtml b/tests/RazorRockstars.Console.Files/Views/PartialChildModel.cshtml index db9e143e6fb..6d2cbdf957b 100644 --- a/tests/RazorRockstars.Console.Files/Views/PartialChildModel.cshtml +++ b/tests/RazorRockstars.Console.Files/Views/PartialChildModel.cshtml @@ -1,5 +1,7 @@ @model PartialChildModel +

    Inside PartialChildModel

    + @Html.TextBoxFor(x => x.SomeProperty) PathInfo: @base.Request.PathInfo diff --git a/tests/RazorRockstars.Console.Files/Views/PartialHeader.cshtml b/tests/RazorRockstars.Console.Files/Views/PartialHeader.cshtml new file mode 100644 index 00000000000..74bf5e84abc --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/PartialHeader.cshtml @@ -0,0 +1,7 @@ +

    Partial Header

    + +

    RenderSection: PartialHeaderSection

    + +@RenderSection("PartialHeaderSection", required:false) + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/PartialModel.cshtml b/tests/RazorRockstars.Console.Files/Views/PartialModel.cshtml index ac3e9491f6b..07d03341105 100644 --- a/tests/RazorRockstars.Console.Files/Views/PartialModel.cshtml +++ b/tests/RazorRockstars.Console.Files/Views/PartialModel.cshtml @@ -3,6 +3,11 @@ Layout = "Empty"; } +@section PartialHeaderSection { +

    Partial Header Section in PartialModel

    + +} + @@ -16,6 +21,10 @@ {
    @Html.Partial("PartialChildModel", item)
    } + + @Html.Partial("PartialHeader") + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/Secured.cshtml b/tests/RazorRockstars.Console.Files/Views/Secured.cshtml new file mode 100644 index 00000000000..3f06c4e9165 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/Secured.cshtml @@ -0,0 +1,11 @@ +@inherits ViewPage + +@{ + base.RedirectIfNotAuthenticated(); +} + +

    Secure View

    + +

    @Model.Result

    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/Shared/RequestFiltersLayout.cshtml b/tests/RazorRockstars.Console.Files/Views/Shared/RequestFiltersLayout.cshtml new file mode 100644 index 00000000000..16f9de3e5bd --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/Shared/RequestFiltersLayout.cshtml @@ -0,0 +1,24 @@ +@{ + ViewBag.Title = "Page testing request filters"; + + base.ApplyRequestFilters(new RedirectWithoutQueryString()); + if (Request.QueryString.Count > 0) + { + throw new System.IO.InvalidDataException(); + } +} + + + + RequestFilters Layout + + +

    @ViewBag.Title

    + +
    + @RenderBody() +
    + + + + diff --git a/tests/RazorRockstars.Console.Files/Views/Shared/SimpleLayout.cshtml b/tests/RazorRockstars.Console.Files/Views/Shared/SimpleLayout.cshtml index 37cee4d1baf..ccdc5c736fa 100644 --- a/tests/RazorRockstars.Console.Files/Views/Shared/SimpleLayout.cshtml +++ b/tests/RazorRockstars.Console.Files/Views/Shared/SimpleLayout.cshtml @@ -1,4 +1,4 @@ - + Simple Layout diff --git a/tests/RazorRockstars.Console.Files/Views/SimpleView.cshtml b/tests/RazorRockstars.Console.Files/Views/SimpleView.cshtml new file mode 100644 index 00000000000..3870dc403ad --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/SimpleView.cshtml @@ -0,0 +1,4 @@ + +

    Simple View Page

    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/TestSessionView.cshtml b/tests/RazorRockstars.Console.Files/Views/TestSessionView.cshtml new file mode 100644 index 00000000000..ee2c7e84e05 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/TestSessionView.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage +@{ + var session = base.GetSession(); +} + +IsAuthenticated:@session.IsAuthenticated + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Views/Validation.cshtml b/tests/RazorRockstars.Console.Files/Views/Validation.cshtml new file mode 100644 index 00000000000..5e3179fcc9b --- /dev/null +++ b/tests/RazorRockstars.Console.Files/Views/Validation.cshtml @@ -0,0 +1,155 @@ +@inherits ViewPage +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "Validator Test"; +} + + + + +

    Ajax Form

    +
    +
    +
    + + + +
    +
    + + + +
    + + +
    + +

    Manual Form

    +
    + @Html.ValidationSuccess("Manual Validation Passed!") + @Html.ValidationSummary() +
    + + @Html.TextBoxFor(x => x.Id) + @Html.ValidationMessageFor(x => x.Id) +
    +
    + + @Html.TextBoxFor(x => x.Name) + @Html.ValidationMessageFor(x => x.Name) +
    + + +
    + + + + + +

    Events

    +
    + Target 1 +
    +
    + + +
    + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/VirtualPathTests.cs b/tests/RazorRockstars.Console.Files/VirtualPathTests.cs new file mode 100644 index 00000000000..e1d4f91a5be --- /dev/null +++ b/tests/RazorRockstars.Console.Files/VirtualPathTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Text; + +namespace RazorRockstars.Console.Files +{ + [TestFixture] + public class VirtualPathTests + { + public static string ServiceStackBaseUri = RazorRockstars_FilesTests.Host; + public static string ListeningOn = RazorRockstars_FilesTests.ListeningOn; + + private AppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + + [Test] + public void Can_download_static_file_at_root_directory() + { + var contents = "{0}/static-root.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_static_file_at_sub_directory() + { + var contents = "{0}/Content/static-sub.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_embedded_static_file_at_root_directory() + { + var contents = "{0}/static-root-embedded.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_embedded_static_file_at_sub_directory() + { + var contents = "{0}/Content/static-sub-embedded.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_default_static_file_at_sub_directory() + { + var contents = "{0}/Content/".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_default_document_at_root_directory() + { + var contents = "{0}/".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/Web.config b/tests/RazorRockstars.Console.Files/Web.config index c3a58404f2c..49d8c1f98fd 100644 --- a/tests/RazorRockstars.Console.Files/Web.config +++ b/tests/RazorRockstars.Console.Files/Web.config @@ -1,47 +1,79 @@ - - + - +--> - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/bootstrap.css b/tests/RazorRockstars.Console.Files/bootstrap.css new file mode 100644 index 00000000000..3ef7c4297d2 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/bootstrap.css @@ -0,0 +1,6057 @@ +/*! + * Bootstrap v3.0.2 + * + * Copyright 2014 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} +audio, +canvas, +video { + display: inline-block; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +a { + background: transparent; +} +a:focus { + outline: thin dotted; +} +a:active, +a:hover { + outline: 0; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} +mark { + background: #ff0; + color: #000; +} +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} +pre { + white-space: pre-wrap; +} +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 0; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; + padding: 0; +} +button, +input, +select, +textarea { + font-family: inherit; + font-size: 100%; + margin: 0; +} +button, +input { + line-height: normal; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="search"] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +textarea { + overflow: auto; + vertical-align: top; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +@media print { + * { + text-shadow: none !important; + color: #000 !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 2cm .5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +*, +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 62.5%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.428571429; + color: #333333; + background-color: #ffffff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #428bca; + text-decoration: none; +} +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +img { + vertical-align: middle; +} +.img-responsive { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + padding: 4px; + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eeeeee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 200; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +cite { + font-style: normal; +} +.text-muted { + color: #999999; +} +.text-primary { + color: #428bca; +} +.text-primary:hover { + color: #3071a9; +} +.text-warning { + color: #c09853; +} +.text-warning:hover { + color: #a47e3c; +} +.text-danger { + color: #b94a48; +} +.text-danger:hover { + color: #953b39; +} +.text-success { + color: #468847; +} +.text-success:hover { + color: #356635; +} +.text-info { + color: #3a87ad; +} +.text-info:hover { + color: #2d6987; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #999999; +} +h1, +h2, +h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +h2 small, +h3 small, +h1 .small, +h2 .small, +h3 .small { + font-size: 65%; +} +h4, +h5, +h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +h5 small, +h6 small, +h4 .small, +h5 .small, +h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eeeeee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; +} +.list-inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; +} +.list-inline > li:first-child { + padding-left: 0; +} +dl { + margin-bottom: 20px; +} +dt, +dd { + line-height: 1.428571429; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + + } + .dl-horizontal dd:after { + clear: both; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + + } + .dl-horizontal dd:after { + clear: both; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} +blockquote p { + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} +blockquote p:last-child { + margin-bottom: 0; +} +blockquote small { + display: block; + line-height: 1.428571429; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} +blockquote.pull-right p, +blockquote.pull-right small, +blockquote.pull-right .small { + text-align: right; +} +blockquote.pull-right small:before, +blockquote.pull-right .small:before { + content: ''; +} +blockquote.pull-right small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +blockquote:before, +blockquote:after { + content: ""; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.428571429; +} +code, +kbd, +pre, +samp { + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + white-space: nowrap; + border-radius: 4px; +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.428571429; + word-break: break-all; + word-wrap: break-word; + color: #333333; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.container:before, +.container:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.container:after { + clear: both; +} +.container:before, +.container:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.container:after { + clear: both; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.row:before, +.row:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.row:after { + clear: both; +} +.row:before, +.row:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.row:after { + clear: both; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666666666666%; +} +.col-xs-10 { + width: 83.33333333333334%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666666666666%; +} +.col-xs-7 { + width: 58.333333333333336%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666666666667%; +} +.col-xs-4 { + width: 33.33333333333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.666666666666664%; +} +.col-xs-1 { + width: 8.333333333333332%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666666666666%; +} +.col-xs-pull-10 { + right: 83.33333333333334%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666666666666%; +} +.col-xs-pull-7 { + right: 58.333333333333336%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666666666667%; +} +.col-xs-pull-4 { + right: 33.33333333333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.666666666666664%; +} +.col-xs-pull-1 { + right: 8.333333333333332%; +} +.col-xs-pull-0 { + right: 0%; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666666666666%; +} +.col-xs-push-10 { + left: 83.33333333333334%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666666666666%; +} +.col-xs-push-7 { + left: 58.333333333333336%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666666666667%; +} +.col-xs-push-4 { + left: 33.33333333333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.666666666666664%; +} +.col-xs-push-1 { + left: 8.333333333333332%; +} +.col-xs-push-0 { + left: 0%; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .container { + width: 750px; + } + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: 0%; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: 0%; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: 0%; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: 0%; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: 0%; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: 0%; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +table { + max-width: 100%; + background-color: transparent; +} +th { + text-align: left; +} +.table { + width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid #dddddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #dddddd; +} +.table .table { + background-color: #ffffff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} +table col[class*="col-"] { + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + float: none; + display: table-cell; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +@media (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + overflow-x: scroll; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #dddddd; + -webkit-overflow-scrolling: touch; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + /* IE8-9 */ + + line-height: normal; +} +input[type="file"] { + display: block; +} +select[multiple], +select[size] { + height: auto; +} +select optgroup { + font-size: inherit; + font-style: inherit; + font-family: inherit; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + height: auto; +} +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; +} +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #555555; + vertical-align: middle; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.form-control:-moz-placeholder { + color: #999999; +} +.form-control::-moz-placeholder { + color: #999999; +} +.form-control:-ms-input-placeholder { + color: #999999; +} +.form-control::-webkit-input-placeholder { + color: #999999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eeeeee; +} +textarea.form-control { + height: auto; +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + display: block; + min-height: 20px; + margin-top: 10px; + margin-bottom: 10px; + padding-left: 20px; + vertical-align: middle; +} +.radio label, +.checkbox label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm { + height: 30px; + line-height: 30px; +} +textarea.input-sm { + height: auto; +} +.input-lg { + height: 45px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-lg { + height: 45px; + line-height: 45px; +} +textarea.input-lg { + height: auto; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #c09853; +} +.has-warning .form-control { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} +.has-warning .input-group-addon { + color: #c09853; + border-color: #c09853; + background-color: #fcf8e3; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #b94a48; +} +.has-error .form-control { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} +.has-error .input-group-addon { + color: #b94a48; + border-color: #b94a48; + background-color: #f2dede; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #468847; +} +.has-success .form-control { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} +.has-success .input-group-addon { + color: #468847; + border-color: #468847; + background-color: #dff0d8; +} +.form-control-static { + margin-bottom: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} +.form-horizontal .control-label, +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 7px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.form-horizontal .form-group:after { + clear: both; +} +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.form-horizontal .form-group:after { + clear: both; +} +.form-horizontal .form-control-static { + padding-top: 7px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + pointer-events: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-default { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333333; + background-color: #ebebeb; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #ffffff; + border-color: #cccccc; +} +.btn-primary { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} +.btn-warning { + color: #ffffff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #ed9c28; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-danger { + color: #ffffff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #d2322d; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-success { + color: #ffffff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #47a447; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-info { + color: #ffffff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #39b3d7; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-link { + color: #428bca; + font-weight: normal; + cursor: pointer; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #999999; + text-decoration: none; +} +.btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +.btn-sm, +.btn-xs { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs { + padding: 1px 5px; +} +.btn-block { + display: block; + width: 100%; + padding-left: 0; + padding-right: 0; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + transition: height 0.35s ease; +} +@font-face { + font-family: 'Glyphicons Halflings'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon:empty { + width: 1em; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + border-bottom: 0 dotted; +} +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + color: #333333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + text-decoration: none; + color: #262626; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #428bca; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.428571429; + color: #999999; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0 dotted; + border-bottom: 4px solid #000000; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } +} +.btn-default .caret { + border-top-color: #333333; +} +.btn-primary .caret, +.btn-success .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret { + border-top-color: #fff; +} +.dropup .btn-default .caret { + border-bottom-color: #333333; +} +.dropup .btn-primary .caret, +.dropup .btn-success .caret, +.dropup .btn-warning .caret, +.dropup .btn-danger .caret, +.dropup .btn-info .caret { + border-bottom-color: #fff; +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: none; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar:before, +.btn-toolbar:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.btn-toolbar:after { + clear: both; +} +.btn-toolbar:before, +.btn-toolbar:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.btn-toolbar:after { + clear: both; +} +.btn-toolbar .btn-group { + float: left; +} +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group, +.btn-toolbar > .btn-group + .btn-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group-xs > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; + padding: 1px 5px; +} +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.btn-group-vertical > .btn-group:after { + clear: both; +} +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.btn-group-vertical > .btn-group:after { + clear: both; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-bottom-left-radius: 4px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child > .btn:last-child, +.btn-group-vertical > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified .btn { + float: none; + display: table-cell; + width: 1%; +} +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group.col { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 45px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 45px; + line-height: 45px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #555555; + text-align: center; + background-color: #eeeeee; + border: 1px solid #cccccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + white-space: nowrap; +} +.input-group-btn:first-child > .btn { + margin-right: -1px; +} +.input-group-btn:last-child > .btn { + margin-left: -1px; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -4px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:active { + z-index: 2; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav:before, +.nav:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.nav:after { + clear: both; +} +.nav:before, +.nav:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.nav:after { + clear: both; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.nav > li.disabled > a { + color: #999999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #428bca; +} +.nav .open > a .caret, +.nav .open > a:hover .caret, +.nav .open > a:focus .caret { + border-top-color: #2a6496; + border-bottom-color: #2a6496; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #428bca; +} +.nav-pills > li.active > a .caret, +.nav-pills > li.active > a:hover .caret, +.nav-pills > li.active > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav .caret { + border-top-color: #428bca; + border-bottom-color: #428bca; +} +.nav a:hover .caret { + border-top-color: #2a6496; + border-bottom-color: #2a6496; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} +.navbar:before, +.navbar:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.navbar:after { + clear: both; +} +.navbar:before, +.navbar:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.navbar:after { + clear: both; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +.navbar-header:before, +.navbar-header:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.navbar-header:after { + clear: both; +} +.navbar-header:before, +.navbar-header:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.navbar-header:after { + clear: both; +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + max-height: 340px; + overflow-x: visible; + padding-right: 15px; + padding-left: 15px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse:before, +.navbar-collapse:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.navbar-collapse:after { + clear: both; +} +.navbar-collapse:before, +.navbar-collapse:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.navbar-collapse:after { + clear: both; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: auto; + } + .navbar-collapse .navbar-nav.navbar-left:first-child { + margin-left: -15px; + } + .navbar-collapse .navbar-nav.navbar-right:last-child { + margin-right: -15px; + } + .navbar-collapse .navbar-text:last-child { + margin-right: 0; + } +} +.container > .navbar-header, +.container > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 8px; + margin-bottom: 8px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 7.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 8px; + margin-bottom: 8px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-nav.pull-right > li > .dropdown-menu, +.navbar-nav > li > .dropdown-menu.pull-right { + left: auto; + right: 0; +} +.navbar-btn { + margin-top: 8px; + margin-bottom: 8px; +} +.navbar-text { + float: left; + margin-top: 15px; + margin-bottom: 15px; +} +@media (min-width: 768px) { + .navbar-text { + margin-left: 15px; + margin-right: 15px; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777777; +} +.navbar-default .navbar-nav > li > a { + color: #777777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #dddddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #dddddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #cccccc; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .dropdown > a:hover .caret, +.navbar-default .navbar-nav > .dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #e7e7e7; + color: #555555; +} +.navbar-default .navbar-nav > .open > a .caret, +.navbar-default .navbar-nav > .open > a:hover .caret, +.navbar-default .navbar-nav > .open > a:focus .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} +.navbar-default .navbar-nav > .dropdown > a .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777777; +} +.navbar-default .navbar-link:hover { + color: #333333; +} +.navbar-inverse { + background-color: #222222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #999999; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #999999; +} +.navbar-inverse .navbar-nav > li > a { + color: #999999; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #080808; + color: #ffffff; +} +.navbar-inverse .navbar-nav > .dropdown > a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} +.navbar-inverse .navbar-nav > .dropdown > a .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} +.navbar-inverse .navbar-nav > .open > a .caret, +.navbar-inverse .navbar-nav > .open > a:hover .caret, +.navbar-inverse .navbar-nav > .open > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #999999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #999999; +} +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0 5px; + color: #cccccc; +} +.breadcrumb > .active { + color: #999999; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + line-height: 1.428571429; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + background-color: #ffffff; + border-color: #dddddd; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 6px; + border-top-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 20px 0; + list-style: none; + text-align: center; +} +.pager:before, +.pager:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.pager:after { + clear: both; +} +.pager:before, +.pager:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + background-color: #ffffff; + cursor: not-allowed; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +.label[href]:hover, +.label[href]:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.label-default { + background-color: #999999; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} +.label-primary { + background-color: #428bca; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + color: #ffffff; + line-height: 1; + vertical-align: baseline; + white-space: nowrap; + text-align: center; + background-color: #999999; + border-radius: 10px; +} +.badge:empty { + display: none; +} +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.btn .badge { + position: relative; + top: -1px; +} +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #ffffff; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px; + margin-bottom: 30px; + font-size: 21px; + font-weight: 200; + line-height: 2.1428571435; + color: inherit; + background-color: #eeeeee; +} +.jumbotron h1 { + line-height: 1; + color: inherit; +} +.jumbotron p { + line-height: 1.4; +} +.container .jumbotron { + border-radius: 6px; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron { + padding-left: 60px; + padding-right: 60px; + } + .jumbotron h1 { + font-size: 63px; + } +} +.thumbnail { + padding: 4px; + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; + display: block; + margin-bottom: 20px; +} +.thumbnail > img { + display: block; + max-width: 100%; + height: auto; + margin-left: auto; + margin-right: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} +.thumbnail .caption { + padding: 9px; + color: #333333; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable { + padding-right: 35px; +} +.alert-dismissable .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; + color: #468847; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #356635; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; + color: #3a87ad; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #2d6987; +} +.alert-warning { + background-color: #fcf8e3; + border-color: #faebcc; + color: #c09853; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #a47e3c; +} +.alert-danger { + background-color: #f2dede; + border-color: #ebccd1; + color: #b94a48; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #953b39; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-object { + display: block; +} +.media-heading { + margin: 0 0 5px; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +a.list-group-item { + color: #555555; +} +a.list-group-item .list-group-item-heading { + color: #333333; +} +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} +a.list-group-item.active, +a.list-group-item.active:hover, +a.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} +a.list-group-item.active .list-group-item-heading, +a.list-group-item.active:hover .list-group-item-heading, +a.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} +a.list-group-item.active .list-group-item-text, +a.list-group-item.active:hover .list-group-item-text, +a.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-body:before, +.panel-body:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.panel-body:after { + clear: both; +} +.panel-body:before, +.panel-body:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.panel-body:after { + clear: both; +} +.panel > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item { + border-width: 1px 0; +} +.panel > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel > .list-group .list-group-item:last-child { + border-bottom: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive { + margin-bottom: 0; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #dddddd; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:last-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-bordered > thead > tr:last-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; +} +.panel-title > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; + overflow: hidden; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse .panel-body { + border-top: 1px solid #dddddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} +.panel-default { + border-color: #dddddd; +} +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #dddddd; +} +.panel-default > .panel-heading > .dropdown .caret { + border-color: #333333 transparent; +} +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #dddddd; +} +.panel-primary { + border-color: #428bca; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} +.panel-primary > .panel-heading > .dropdown .caret { + border-color: #ffffff transparent; +} +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #428bca; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading > .dropdown .caret { + border-color: #468847 transparent; +} +.panel-success > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #c09853; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading > .dropdown .caret { + border-color: #c09853 transparent; +} +.panel-warning > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #b94a48; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading > .dropdown .caret { + border-color: #b94a48 transparent; +} +.panel-danger > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #ebccd1; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading > .dropdown .caret { + border-color: #3a87ad transparent; +} +.panel-info > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: auto; + overflow-y: scroll; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-dialog { + position: relative; + margin-left: auto; + margin-right: auto; + width: auto; + padding: 10px; + z-index: 1050; +} +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; + outline: none; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; + min-height: 16.428571429px; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.428571429; +} +.modal-body { + position: relative; + padding: 20px; +} +.modal-footer { + margin-top: 15px; + padding: 19px 20px 20px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer:before, +.modal-footer:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.modal-footer:after { + clear: both; +} +.modal-footer:before, +.modal-footer:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +@media screen and (min-width: 768px) { + .modal-dialog { + width: 600px; + padding-top: 30px; + padding-bottom: 30px; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } +} +.tooltip { + position: absolute; + z-index: 1030; + display: block; + visibility: visible; + font-size: 12px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + right: 5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + background-color: #ffffff; + background-clip: padding-box; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + white-space: normal; +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: 11px; +} +.popover .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + bottom: -11px; +} +.popover.top .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); +} +.popover.right .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + top: -11px; +} +.popover.bottom .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); +} +.popover.left .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; + line-height: 1; +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 15%; + opacity: 0.5; + filter: alpha(opacity=50); + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-control.left { + background-image: -webkit-gradient(linear, 0% top, 100% top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001))); + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0%), color-stop(rgba(0, 0, 0, 0.0001) 100%)); + background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} +.carousel-control.right { + left: auto; + right: 0; + background-image: -webkit-gradient(linear, 0% top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5))); + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0%), color-stop(rgba(0, 0, 0, 0.5) 100%)); + background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid #ffffff; + border-radius: 10px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); +} +.carousel-indicators .active { + margin: 0; + width: 12px; + height: 12px; + background-color: #ffffff; +} +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after { + content: " "; + /* 1 */ + + display: table; + /* 2 */ + +} +.clearfix:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +tr.visible-xs, +th.visible-xs, +td.visible-xs { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-xs.visible-sm { + display: block !important; + } + tr.visible-xs.visible-sm { + display: table-row !important; + } + th.visible-xs.visible-sm, + td.visible-xs.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-xs.visible-md { + display: block !important; + } + tr.visible-xs.visible-md { + display: table-row !important; + } + th.visible-xs.visible-md, + td.visible-xs.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-xs.visible-lg { + display: block !important; + } + tr.visible-xs.visible-lg { + display: table-row !important; + } + th.visible-xs.visible-lg, + td.visible-xs.visible-lg { + display: table-cell !important; + } +} +.visible-sm, +tr.visible-sm, +th.visible-sm, +td.visible-sm { + display: none !important; +} +@media (max-width: 767px) { + .visible-sm.visible-xs { + display: block !important; + } + tr.visible-sm.visible-xs { + display: table-row !important; + } + th.visible-sm.visible-xs, + td.visible-sm.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-sm.visible-md { + display: block !important; + } + tr.visible-sm.visible-md { + display: table-row !important; + } + th.visible-sm.visible-md, + td.visible-sm.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-sm.visible-lg { + display: block !important; + } + tr.visible-sm.visible-lg { + display: table-row !important; + } + th.visible-sm.visible-lg, + td.visible-sm.visible-lg { + display: table-cell !important; + } +} +.visible-md, +tr.visible-md, +th.visible-md, +td.visible-md { + display: none !important; +} +@media (max-width: 767px) { + .visible-md.visible-xs { + display: block !important; + } + tr.visible-md.visible-xs { + display: table-row !important; + } + th.visible-md.visible-xs, + td.visible-md.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-md.visible-sm { + display: block !important; + } + tr.visible-md.visible-sm { + display: table-row !important; + } + th.visible-md.visible-sm, + td.visible-md.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-md.visible-lg { + display: block !important; + } + tr.visible-md.visible-lg { + display: table-row !important; + } + th.visible-md.visible-lg, + td.visible-md.visible-lg { + display: table-cell !important; + } +} +.visible-lg, +tr.visible-lg, +th.visible-lg, +td.visible-lg { + display: none !important; +} +@media (max-width: 767px) { + .visible-lg.visible-xs { + display: block !important; + } + tr.visible-lg.visible-xs { + display: table-row !important; + } + th.visible-lg.visible-xs, + td.visible-lg.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-lg.visible-sm { + display: block !important; + } + tr.visible-lg.visible-sm { + display: table-row !important; + } + th.visible-lg.visible-sm, + td.visible-lg.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-lg.visible-md { + display: block !important; + } + tr.visible-lg.visible-md { + display: table-row !important; + } + th.visible-lg.visible-md, + td.visible-lg.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +.hidden-xs { + display: block !important; +} +tr.hidden-xs { + display: table-row !important; +} +th.hidden-xs, +td.hidden-xs { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-xs, + tr.hidden-xs, + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-xs.hidden-sm, + tr.hidden-xs.hidden-sm, + th.hidden-xs.hidden-sm, + td.hidden-xs.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-xs.hidden-md, + tr.hidden-xs.hidden-md, + th.hidden-xs.hidden-md, + td.hidden-xs.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-xs.hidden-lg, + tr.hidden-xs.hidden-lg, + th.hidden-xs.hidden-lg, + td.hidden-xs.hidden-lg { + display: none !important; + } +} +.hidden-sm { + display: block !important; +} +tr.hidden-sm { + display: table-row !important; +} +th.hidden-sm, +td.hidden-sm { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-sm.hidden-xs, + tr.hidden-sm.hidden-xs, + th.hidden-sm.hidden-xs, + td.hidden-sm.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm, + tr.hidden-sm, + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-sm.hidden-md, + tr.hidden-sm.hidden-md, + th.hidden-sm.hidden-md, + td.hidden-sm.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-sm.hidden-lg, + tr.hidden-sm.hidden-lg, + th.hidden-sm.hidden-lg, + td.hidden-sm.hidden-lg { + display: none !important; + } +} +.hidden-md { + display: block !important; +} +tr.hidden-md { + display: table-row !important; +} +th.hidden-md, +td.hidden-md { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-md.hidden-xs, + tr.hidden-md.hidden-xs, + th.hidden-md.hidden-xs, + td.hidden-md.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-md.hidden-sm, + tr.hidden-md.hidden-sm, + th.hidden-md.hidden-sm, + td.hidden-md.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md, + tr.hidden-md, + th.hidden-md, + td.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-md.hidden-lg, + tr.hidden-md.hidden-lg, + th.hidden-md.hidden-lg, + td.hidden-md.hidden-lg { + display: none !important; + } +} +.hidden-lg { + display: block !important; +} +tr.hidden-lg { + display: table-row !important; +} +th.hidden-lg, +td.hidden-lg { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-lg.hidden-xs, + tr.hidden-lg.hidden-xs, + th.hidden-lg.hidden-xs, + td.hidden-lg.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-lg.hidden-sm, + tr.hidden-lg.hidden-sm, + th.hidden-lg.hidden-sm, + td.hidden-lg.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-lg.hidden-md, + tr.hidden-lg.hidden-md, + th.hidden-lg.hidden-md, + td.hidden-lg.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg, + tr.hidden-lg, + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} +.visible-print, +tr.visible-print, +th.visible-print, +td.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } + .hidden-print, + tr.hidden-print, + th.hidden-print, + td.hidden-print { + display: none !important; + } +} diff --git a/tests/RazorRockstars.Console.Files/default.cshtml b/tests/RazorRockstars.Console.Files/default.cshtml index 5728d058966..3b06d6c642c 100644 --- a/tests/RazorRockstars.Console.Files/default.cshtml +++ b/tests/RazorRockstars.Console.Files/default.cshtml @@ -3,7 +3,7 @@ @{ Layout = "SimpleLayout"; ViewBag.Title = "Page with typed 'Rockstars' model and no C# controller"; - var rockstars = Model.Age.HasValue + var rockstars = Model.Age.HasValue ? Db.Select(q => q.Age == Model.Age.Value) : Db.Select(); var title = Model.Age.HasValue ? "{0} year old rockstars".Fmt(Model.Age) : "All Rockstars"; @@ -14,10 +14,13 @@ @Html.Partial("RazorPartial") @Html.Partial("MarkdownPartial") @Html.Partial("RazorPartialModel", rockstars) +@Html.Partial("ContentPartialModel", rockstars) +@Html.Partial("Pages/PagesPartialModel", rockstars)
    @title
      - @foreach (var rockstar in rockstars) { + @foreach (var rockstar in rockstars) + {
    • @rockstar.FirstName - @rockstar.LastName (@rockstar.Age)
    • }
    diff --git a/tests/RazorRockstars.Console.Files/default_file.cshtml b/tests/RazorRockstars.Console.Files/default_file.cshtml new file mode 100644 index 00000000000..3b06d6c642c --- /dev/null +++ b/tests/RazorRockstars.Console.Files/default_file.cshtml @@ -0,0 +1,35 @@ +@inherits ViewPage + +@{ + Layout = "SimpleLayout"; + ViewBag.Title = "Page with typed 'Rockstars' model and no C# controller"; + var rockstars = Model.Age.HasValue + ? Db.Select(q => q.Age == Model.Age.Value) + : Db.Select(); + var title = Model.Age.HasValue ? "{0} year old rockstars".Fmt(Model.Age) : "All Rockstars"; +} + +
    + +@Html.Partial("RazorPartial") +@Html.Partial("MarkdownPartial") +@Html.Partial("RazorPartialModel", rockstars) +@Html.Partial("ContentPartialModel", rockstars) +@Html.Partial("Pages/PagesPartialModel", rockstars) + +
    @title
    +
      + @foreach (var rockstar in rockstars) + { +
    • @rockstar.FirstName - @rockstar.LastName (@rockstar.Age)
    • + } +
    + +

    Show all Rockstars

    + +

    Razor View

    + + +
    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console.Files/jquery-2.0.2.min.js b/tests/RazorRockstars.Console.Files/jquery-2.0.2.min.js new file mode 100644 index 00000000000..73e5218d210 --- /dev/null +++ b/tests/RazorRockstars.Console.Files/jquery-2.0.2.min.js @@ -0,0 +1,6 @@ +/*! jQuery v2.0.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery-2.0.2.min.map +*/ +(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.2",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=at(),k=at(),N=at(),E=!1,S=function(){return 0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],H=L.pop,q=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){q.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=vt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+xt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return St(e.replace(z,"$1"),t,r,i)}function st(e){return Q.test(e+"")}function at(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function ut(e){return e[v]=!0,e}function lt(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t,n){e=e.split("|");var r,o=e.length,s=n?null:t;while(o--)(r=i.attrHandle[e[o]])&&r!==t||(i.attrHandle[e[o]]=s)}function pt(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function ft(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function ht(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:undefined}function dt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function gt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function mt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function yt(e){return ut(function(t){return t=+t,ut(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.parentWindow;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.frameElement&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=lt(function(e){return e.innerHTML="",ct("type|href|height|width",ft,"#"===e.firstChild.getAttribute("href")),ct(R,pt,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),n.input=lt(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),ct("value",ht,n.attributes&&n.input),n.getElementsByTagName=lt(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=lt(function(e){return e.innerHTML="
    ",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=lt(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=st(t.querySelectorAll))&&(lt(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),lt(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=st(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&<(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=st(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},n.sortDetached=lt(function(e){return 1&e.compareDocumentPosition(t.createElement("div"))}),S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return dt(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?dt(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:ut,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=vt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ut(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ut(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?ut(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ut(function(e){return function(t){return ot(e,t).length>0}}),contains:ut(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ut(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:yt(function(){return[0]}),last:yt(function(e,t){return[t-1]}),eq:yt(function(e,t,n){return[0>n?n+t:n]}),even:yt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:yt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:yt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:yt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=gt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=mt(t);function vt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function xt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function bt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function wt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Tt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function Ct(e,t,n,r,i,o){return r&&!r[v]&&(r=Ct(r)),i&&!i[v]&&(i=Ct(i,o)),ut(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Et(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:Tt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=Tt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=Tt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function kt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=bt(function(e){return e===t},a,!0),p=bt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[bt(wt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return Ct(l>1&&wt(f),l>1&&xt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&kt(e.slice(l,r)),o>r&&kt(e=e.slice(r)),o>r&&xt(e))}f.push(n)}return wt(f)}function Nt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=H.call(f));y=Tt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?ut(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=vt(e)),n=t.length;while(n--)o=kt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Nt(i,r))}return o};function Et(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function St(e,t,r,o){var s,u,l,c,p,f=vt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&xt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}i.pseudos.nth=i.pseudos.eq;function jt(){}jt.prototype=i.filters=i.pseudos,i.setFilters=new jt,n.sortStable=v.split("").sort(S).join("")===v,c(),[0,0].sort(S),n.detectDuplicates=E,x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!a||n&&!u||(r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,H,q=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){return t===undefined||t&&"string"==typeof t&&n===undefined?this.get(e,t):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,H=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||H.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return H.access(e,t,n)},_removeData:function(e,t){H.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!H.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));H.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:q.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=H.get(e,t),n&&(!r||x.isArray(n)?r=H.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire() +},_queueHooks:function(e,t){var n=t+"queueHooks";return H.get(e,n)||H.access(e,n,{empty:x.Callbacks("once memory").add(function(){H.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=H.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,i="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,s=0,a=x(this),u=t,l=e.match(w)||[];while(o=l[s++])u=i?u:!a.hasClass(o),a[u?"addClass":"removeClass"](o)}else(n===r||"boolean"===n)&&(this.className&&H.set(this,"__className__",this.className),this.className=this.className||e===!1?"":H.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=H.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=H.hasData(e)&&H.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,H.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(H.get(a,"events")||{})[t.type]&&H.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(H.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*\s*$/g,ct={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!H.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1>")+a[2],l=a[0];while(l--)o=o.firstChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[H.expando],o&&(t=H.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);H.cache[o]&&delete H.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)H.set(e[r],"globalEval",!t||H.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(H.hasData(e)&&(o=H.access(e),s=H.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function Ht(t){return e.getComputedStyle(t,null)}function qt(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=H.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=H.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&H.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=Ht(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return qt(this,!0)},hide:function(){return qt(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:Lt(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||Ht(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Ht(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("', + generic: '' + }; + + $(document).bindHandlers({ + announce: function (msg) { + $("#announce").html(msg).fadeIn('fast'); + setTimeout(function () { $("#announce").fadeOut('slow'); }, 2000); + }, + toggle: function () { + $(this).toggle(); + }, + sendCommand: function () { + $("#txtMsg").val($(this).html()).focus(); + }, + privateMsg: function () { + $txtMsg.val("@@" + this.innerHTML + " ").focus(); + }, + removeReceiver: function (name) { + delete $.ss.eventReceivers[name]; + }, + addReceiver: function (name) { + $.ss.eventReceivers[name] = window[name]; + } + }).on('customEvent', function (e, msg, msgEvent) { + addEntry({ msg: "[event " + e.type + " message: " + msg + "]", cls: "event" }); + console.log("on.customEvent()", this, arguments); + }); + + function addEntry(o) { + console.log("addEntry", o); + var id = "u_" + o.userId + ""; + var skipUser = $("#log .msg:last-child b").hasClass(id); + var user = o.userId && !skipUser ? "" + $("#users ." + id).html() + "" : " "; + var time = "" + $.ss.tfmt12(new Date()) + ""; + var highlight = o.msg.indexOf(activeSub.displayName.replace(" ", "")) >= 0 ? "highlight " : ""; + $("#log").append("
    " + + user + time + "
    " + o.msg + "
    " + "
    "); + } + function createUser(user) { + return "
    " + user.displayName + "
    "; + } + + var msgHistory = [], historyIndex = -1; + function postMsg() { + var msg = $txtMsg.val(), parts, to = null; + msgHistory.push(msg); + + if (msg[0] == "@@") { + parts = $.ss.splitOnFirst(msg, " "); + var toName = parts[0].substring(1); + if (toName == "me") { + to = activeSub.userId; + } else { + var matches = $.grep($("#users .user span"), + function (x) { return x.innerHTML.replace(" ", "").toLowerCase() === toName.toLowerCase(); }); + to = matches.length > 0 ? matches[0].getAttribute("data-id") : null; + } + msg = parts[1]; + } + if (!msg || !activeSub) return; + + if (msg[0] == "/") { + parts = $.ss.splitOnFirst(msg, " "); + $.post("/channels/@channel/raw", { from: activeSub.id, toUserId: to, message: parts[1], selector: parts[0].substring(1) }, function (r) { }); + } else { + $.post("/channels/@channel/chat", { from: activeSub.id, toUserId: to, message: msg, selector: "cmd.chat" }, function (r) { }); + } + $txtMsg.val(""); + } + $("#btnSend").click(postMsg); + + $txtMsg.keydown(function (e) { + var keycode = (e.keyCode ? e.keyCode : e.which); + if ($.ss.getSelection()) { + if (keycode == '9' || keycode == '13' || keycode == '32' || keycode == '39') { + this.value += " "; + if (this.setSelectionRange) this.setSelectionRange(this.value.length, this.value.length); + return false; + } + } + if (keycode == '13') { //enter + postMsg(); + } else if (keycode == '38') { //up arrow + historyIndex = Math.min(++historyIndex, msgHistory.length); + $txtMsg.val(msgHistory[msgHistory.length - 1 - historyIndex]); + return false; + } + else if (keycode == '40') { //down arrow + historyIndex = Math.max(--historyIndex, -1); + $txtMsg.val(msgHistory[msgHistory.length - 1 - historyIndex]); + } else { + historyIndex = -1; + } + }).keyup(function (e) { + if (!$.ss.getSelection() && this.value[0] == '@@' && this.value.indexOf(' ') < 0) { + var partialVal = this.value.substring(1); + var matchingNames = $.grep($("#users .user span") + .map(function () { return this.innerHTML.replace(" ", ""); }), function (x) { + return x.substring(0, partialVal.length).toLowerCase() === partialVal.toLowerCase() + && x.toLowerCase() != activeSub.displayName.toLowerCase(); + }); + + if (matchingNames.length > 0) { + this.value += matchingNames[0].substring(partialVal.length); + if (this.setSelectionRange) this.setSelectionRange(partialVal.length + 1, this.value.length); + return false; + } + } + }); + + + + + diff --git a/tests/ServiceStack.AuthWeb.Tests/ServiceStack.AuthWeb.Tests.csproj b/tests/ServiceStack.AuthWeb.Tests/ServiceStack.AuthWeb.Tests.csproj new file mode 100644 index 00000000000..7feaaf576bd --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/ServiceStack.AuthWeb.Tests.csproj @@ -0,0 +1,247 @@ + + + + + Debug + AnyCPU + + + 2.0 + {7A7A1415-D116-43B2-B992-0DD41B09F4B0} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + ServiceStack.AuthWeb.Tests + ServiceStack.AuthWeb.Tests + v4.7.2 + false + + + + + ..\..\src\ + true + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\ + TRACE + prompt + 4 + false + + + $(DefineConstants);MONO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + Designer + + + + + + + + Global.asax + + + + + + + + {A30BD5B5-00C9-4B9D-9C9D-514B4A676FF3} + ServiceStack.Authentication.RavenDb + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416db-c143-4028-a0c3-cf41892d18d3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {22f8d050-2c96-4993-b221-da16ebc61f31} + ServiceStack.NetFramework + + + {D73274AE-006B-4CEE-BA60-0ECF5873048D} + ServiceStack.Razor + + + {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} + ServiceStack.Server + + + {680A1709-25EB-4D52-A87F-EE03FFD94BAA} + ServiceStack + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + bin\ + TRACE + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + false + + + + + + + + + False + False + 11001 + / + http://localhost:11001/ + False + False + + + False + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.AuthWeb.Tests/Services.cs b/tests/ServiceStack.AuthWeb.Tests/Services.cs new file mode 100644 index 00000000000..40dea4105aa --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/Services.cs @@ -0,0 +1,226 @@ +//#define HTTP_LISTENER + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +#if HTTP_LISTENER +namespace ServiceStack.Auth.Tests +#else +namespace ServiceStack.AuthWeb.Tests +#endif +{ + [Route("/profile")] + public class GetUserProfile { } + + public class UserProfile + { + public int Id { get; set; } + + public UserAuth UserAuth { get; set; } + public AuthUserSession Session { get; set; } + public List UserAuthDetails { get; set; } + } + + public class UserProfileResponse + { + public UserProfile Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/lockallusers")] + public class LockAllUsers {} + public class LockServices : Service + { + public object Any(LockAllUsers request) + { + Db.UpdateOnly(() => new UserAuth { LockedDate = DateTime.UtcNow }, + where: x => x.LockedDate == null); + + return HttpResult.Redirect("/"); + } + } + + [Authenticate] + public class UserProfileService : Service + { + public UserProfile Get(GetUserProfile request) + { + var session = base.SessionAs(); + + var userAuthId = session.UserAuthId.ToInt(); + var userProfile = new UserProfile + { + Id = userAuthId, + Session = session, + UserAuth = Db.SingleById(userAuthId), + UserAuthDetails = Db.Select(x => x.UserAuthId == userAuthId), + }; + + return userProfile; + } + } + + [Route("/reset-userauth")] + public class ResetUserAuth {} + public class ResetUserAuthService : Service + { + public object Get(ResetUserAuth request) + { + this.Cache.Remove(SessionFeature.GetSessionKey(Request)); + + Db.DeleteAll(); + Db.DeleteAll(); + + var referrer = Request.UrlReferrer != null + ? Request.UrlReferrer.AbsoluteUri + : HostContext.Config.WebHostUrl; + + return HttpResult.Redirect(referrer); + } + } + + + [Route("/rockstars")] + [Route("/rockstars/aged/{Age}")] + [Route("/rockstars/delete/{Delete}")] + [Route("/rockstars/{Id}")] + public class Rockstars + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public string Delete { get; set; } + } + + [DataContract] + public class RockstarsResponse + { + [DataMember] + public int Total { get; set; } + + [DataMember] + public int? Aged { get; set; } + + [DataMember] + public List Results { get; set; } + } + + public class Rockstar + { + public static Rockstar[] SeedData = new[] { + new Rockstar(1, "Jimi", "Hendrix", 27), + new Rockstar(2, "Janis", "Joplin", 27), + new Rockstar(3, "Jim", "Morrisson", 27), + new Rockstar(4, "Kurt", "Cobain", 27), + new Rockstar(5, "Elvis", "Presley", 42), + new Rockstar(6, "Michael", "Jackson", 50), + }; + + [AutoIncrement] + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public bool Alive { get; set; } + + public Rockstar() { } + public Rockstar(int id, string firstName, string lastName, int age) + { + Id = id; + FirstName = firstName; + LastName = lastName; + Age = age; + } + } + + [DefaultRequest(typeof(Rockstars))] + public class RockstarsService : Service + { + public IDbConnectionFactory DbFactory { get; set; } + + public object Get(Rockstars request) + { + if (request.Delete == "reset") + { + Db.DeleteAll(); + Db.Insert(Rockstar.SeedData); + } + else if (request.Delete.IsInt()) + { + Db.DeleteById(request.Delete.ToInt()); + } + + return new RockstarsResponse + { + Aged = request.Age, + Total = Db.Scalar("select count(*) from Rockstar"), + Results = request.Id != default(int) ? + Db.Select(q => q.Id == request.Id) + : request.Age.HasValue ? + Db.Select(q => q.Age == request.Age.Value) + : Db.Select() + }; + } + + public object Post(Rockstars request) + { + Db.Insert(request.ConvertTo()); + return Get(new Rockstars()); + } + } + + [Route("/viewmodel/{Id}")] + public class ViewThatUsesLayoutAndModel + { + public string Id { get; set; } + } + + public class ViewThatUsesLayoutAndModelResponse + { + public string Name { get; set; } + public List Results { get; set; } + } + + public class ViewService : Service + { + public object Any(ViewThatUsesLayoutAndModel request) + { + return new ViewThatUsesLayoutAndModelResponse + { + Name = request.Id ?? "Foo", + Results = new List { "Tom", "Dick", "Harry" } + }; + } + } + + [Route("/has-permission")] + public class HasPermission : IReturn { } + + [RequiredPermission("ThePermission")] + public class RequiresPermissionService : Service + { + public object Any(HasPermission request) + { + return SessionAs(); + } + } + + [Route("/has-role")] + public class HasRole : IReturn { } + + [RequiredRole("TheRole")] + public class RequiresRoleService : Service + { + public object Any(HasRole request) + { + return SessionAs(); + } + } +} diff --git a/tests/ServiceStack.AuthWeb.Tests/Views/Shared/Empty.cshtml b/tests/ServiceStack.AuthWeb.Tests/Views/Shared/Empty.cshtml new file mode 100644 index 00000000000..603b12341f4 --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/Views/Shared/Empty.cshtml @@ -0,0 +1 @@ +@RenderBody() diff --git a/tests/ServiceStack.AuthWeb.Tests/Views/_Layout.cshtml b/tests/ServiceStack.AuthWeb.Tests/Views/_Layout.cshtml new file mode 100644 index 00000000000..15f275e31c9 --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/Views/_Layout.cshtml @@ -0,0 +1,17 @@ + + + + + + Auth Tests + + + + +

    Auth Tests

    +
    + @RenderBody() +
    + + + \ No newline at end of file diff --git a/tests/ServiceStack.AuthWeb.Tests/Web.config b/tests/ServiceStack.AuthWeb.Tests/Web.config new file mode 100644 index 00000000000..44f86a71392 --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/Web.config @@ -0,0 +1,193 @@ + + + + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.AuthWeb.Tests/antiforgerytest.cshtml b/tests/ServiceStack.AuthWeb.Tests/antiforgerytest.cshtml new file mode 100644 index 00000000000..c33f1647cbd --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/antiforgerytest.cshtml @@ -0,0 +1,15 @@ +

    With @@Html.AntiForgeryToken()

    +
    + @Html.AntiForgeryToken() + + + + +
    + +

    Without @@Html.AntiForgeryToken()

    +
    + + + +
    \ No newline at end of file diff --git a/tests/ServiceStack.AuthWeb.Tests/basic.cshtml b/tests/ServiceStack.AuthWeb.Tests/basic.cshtml new file mode 100644 index 00000000000..40a7c88b680 --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/basic.cshtml @@ -0,0 +1,137 @@ +@using ServiceStack +@using ServiceStack.Auth +@using ServiceStack.OrmLite + + + + +

    Auth Data

    +
    + +

    Session

    +
    + +

    User Auth

    +
    + +

    Auth Providers

    +
    + +@{ + var session = base.SessionAs(); + if (session.IsAuthenticated) + { +

    Authenticated!

    + + + } + else + { +

    Not Authenticated

    + } +} +
    + +

    Login with Auth Providers

    +
    + +
    +

    Twitter

    + /auth/twitter +
    + +
    +

    Facebook

    + /auth/facebook +
    + +
    +

    Google OpenId

    + /auth/GoogleOpenId +
    + +
    +

    Yahoo

    + /auth/YahooOpenId +
    + +
    +

    Google OAuth

    + /auth/GoogleOAuth +
    + +
    +

    LinkedIn

    + /auth/LinkedIn +
    + +
    +

    GitHub

    + /auth/github +
    + +
    +

    Yandex

    + /auth/Yandex +
    + +
    +

    VK.com

    + /auth/vkcom +
    + +
    +

    Odnoklassniki.ru

    + /auth/Odnoklassniki +
    + +
    +

    Windows Auth

    + /auth/windowsauth +
    + +

    Custom Credentials Auth

    +
    + + + +
    + +

    Register New User

    +
    + + + + + +
    + +
    +

    Reset UserAuth tables and Session

    + /reset-userauth + +

    Lock all Users

    + /lockallusers + +

    Logout

    + /auth/logout +
    + +

    All AuthProviders

    +
    + +

    All User Auths

    +
    + +

    All Auth Providers

    +
    + +
    \ No newline at end of file diff --git a/tests/ServiceStack.AuthWeb.Tests/default.cshtml b/tests/ServiceStack.AuthWeb.Tests/default.cshtml new file mode 100644 index 00000000000..8192296c312 --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/default.cshtml @@ -0,0 +1,158 @@ +@using ServiceStack +@using ServiceStack.Auth +@using ServiceStack.OrmLite + + + + +

    Auth Data

    +
    + +

    Session

    +
    + +

    User Auth

    +
    + +

    Auth Providers

    +
    + +@{ + var session = base.SessionAs(); + if (session.IsAuthenticated) + { + //requires using OrmLiteAuthRepository + var userAuthId = session.UserAuthId.ToInt(); + var userAuth = Db.SingleById(userAuthId); + var authProviders = Db.Select(x => x.UserAuthId == userAuthId); + +

    Authenticated!

    + + + } + else + { +

    Not Authenticated

    + } +} +
    + +

    Login with Auth Providers

    +
    + +
    +

    Twitter

    + /auth/twitter +
    + +
    +

    Facebook

    + /auth/facebook +
    + +
    +

    GitHub

    + /auth/github +
    + +
    +

    Google

    + /auth/google +
    + +
    +

    Microsoft Graph

    + /auth/microsoftgraph +
    + +
    +

    LinkedIn

    + /auth/linkedin +
    + +
    +

    Yandex

    + /auth/Yandex +
    + +
    +

    VK.com

    + /auth/vkcom +
    + +
    +

    Odnoklassniki.ru

    + /auth/Odnoklassniki +
    + +
    +

    Windows Auth

    + /auth/windowsauth +
    + +

    Custom Credentials Auth

    +
    + + + +
    + +

    Private Auth

    +
    + + +
    + +

    Register New User

    +
    + + + + + +
    + +
    +

    Reset UserAuth tables and Session

    + /reset-userauth + +

    Lock all Users

    + /lockallusers + +

    Convert Session to token

    + /session-to-token + +

    Logout

    + /auth/logout +
    + +

    All AuthProviders

    +
    + +

    All User Auths

    +
    + +

    All Auth Providers

    +
    + +@{ + //requires using OrmLiteAuthRepository + var allUserAuths = Db.Select(); + var allAuthProviders = Db.Select(); + + +} +
    \ No newline at end of file diff --git a/tests/ServiceStack.AuthWeb.Tests/img/facebook_normal.png b/tests/ServiceStack.AuthWeb.Tests/img/facebook_normal.png new file mode 100644 index 00000000000..b32d1948e58 Binary files /dev/null and b/tests/ServiceStack.AuthWeb.Tests/img/facebook_normal.png differ diff --git a/tests/ServiceStack.AuthWeb.Tests/img/github_normal.png b/tests/ServiceStack.AuthWeb.Tests/img/github_normal.png new file mode 100644 index 00000000000..68f69c869c6 Binary files /dev/null and b/tests/ServiceStack.AuthWeb.Tests/img/github_normal.png differ diff --git a/tests/ServiceStack.AuthWeb.Tests/img/twitter_normal.png b/tests/ServiceStack.AuthWeb.Tests/img/twitter_normal.png new file mode 100644 index 00000000000..82d9fbde087 Binary files /dev/null and b/tests/ServiceStack.AuthWeb.Tests/img/twitter_normal.png differ diff --git a/tests/ServiceStack.AuthWeb.Tests/jquery-2.1.1.min.js b/tests/ServiceStack.AuthWeb.Tests/jquery-2.1.1.min.js new file mode 100644 index 00000000000..e5ace116b6f --- /dev/null +++ b/tests/ServiceStack.AuthWeb.Tests/jquery-2.1.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v2.1.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=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,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=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.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},n.extend=n.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||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},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=s(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(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;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=s(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&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=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);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(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&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.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?n.extend(a,d):d}},e={};return d.pipe=d.then,n.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&&n.isFunction(a.promise)?e:0,g=1===f?a:n.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]&&n.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;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;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};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b) +},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.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.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.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 L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!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(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=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=jb(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=jb(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?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(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,n.cleanData(ob(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,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n(" +
+} + + +@code { + bool newBooking { get; set; } + + int? editBookingId { get; set; } + + bool expandAbout { get; set; } + + ApiResult> api = new(); + + async Task refresh() => api = await ApiAsync(new QueryBookings()); + + protected override async Task OnInitializedAsync() => await refresh(); + + void reset(bool newBooking = false, int? editBookingId = null) + { + this.newBooking = newBooking; + this.editBookingId = editBookingId; + } + + async Task onDone(IdResponse result) + { + reset(); + await refresh(); + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/CallHello.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/CallHello.razor new file mode 100644 index 00000000000..06b52de4d82 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/CallHello.razor @@ -0,0 +1,34 @@ +@page "/hello" +@inherits AppComponentBase + +

Call Hello

+ +
+ +
+ +
+ +
+
+ +@if (api.Succeeded) { +

@api.Response!.Result

+} + +
+ +
+ +@code { + Hello request = new() + { + Name = "Blazor WASM" + }; + + ApiResult api = new(); + + protected override async Task OnInitializedAsync() => await submit(); + + async Task submit() => api = await ApiAsync(request); +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/CallHelloSecure.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/CallHelloSecure.razor new file mode 100644 index 00000000000..856ec660afd --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/CallHelloSecure.razor @@ -0,0 +1,38 @@ +@page "/hello-secure" +@attribute [Authorize()] +@inherits AppAuthComponentBase + +

+ Call HelloSecure +

+ +
+ +
+ +
+ +
+
+ +@if (api.Succeeded) { +
@User!.GetDisplayName() says:
+

@api.Response!.Result

+} + +
+ +
+ +@code { + HelloSecure request = new() + { + Name = "Blazor WASM" + }; + + ApiResult api = new(); + + protected override async Task OnInitializedAsync() => await submit(); + + async Task submit() => api = await ApiAsync(request); +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/Counter.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/Counter.razor new file mode 100644 index 00000000000..1f952bc9996 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/Counter.razor @@ -0,0 +1,18 @@ +@page "/counter" +@inherits AppComponentBase + +

Counter

+ +

Current count: @currentCount

+ + + +
+ +
+ +@code { + int currentCount = 0; + + void IncrementCount() => currentCount++; +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/Docs.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/Docs.razor new file mode 100644 index 00000000000..b920f3fa6b7 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/Docs.razor @@ -0,0 +1,42 @@ +@page "/docs/{path?}" +@inherits AppComponentBase +@inject HttpClient Http +@inject IJSRuntime JsRuntime +@using Markdig +@using Markdig.Syntax + +@if (render.Response?.Preview != null) +{ +
+
+ @((MarkupString)render.Response!.Preview) +
+
+ +
+ + +
+} +else if (render.Error == null) +{ + +} + + + +@code { + [Parameter] + public string? Path { get; set; } + + ApiResult render { get; set; } = new(); + + async Task loadDoc() => + render = await MarkdownUtils.LoadDocumentAsync(Path!, doc => Http.GetStringAsync($"/content/{doc.FileName}")); + + protected override Task OnAfterRenderAsync(bool firstRender) => + JsRuntime.InvokeVoidAsync("hljs.highlightAll").AsTask(); + + protected override async Task OnParametersSetAsync() => await loadDoc(); + protected override async Task OnInitializedAsync() => await loadDoc(); +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/FetchData.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/FetchData.razor new file mode 100644 index 00000000000..1f9aeb5d05d --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/FetchData.razor @@ -0,0 +1,48 @@ +@page "/fetchdata" +@inject HttpClient Http + +

Weather forecast

+ +

This component demonstrates fetching data from the server.

+ +@if (forecasts == null) +{ + +} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
+} + +
+ +
+ +@code { + List forecasts = new(); + + protected override async Task OnInitializedAsync() + { + forecasts = await Http.GetFromJsonAsync>("sample-data/weather.json") ?? forecasts; + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/Index.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/Index.razor new file mode 100644 index 00000000000..7dcf3635f83 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/Index.razor @@ -0,0 +1,9 @@ +@page "/" + +

Hello, world!

+ +Welcome to your new Blazor WASM app, if you're new to Blazor +checkout the docs to get started. + + + diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/SignIn.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/SignIn.razor new file mode 100644 index 00000000000..934f1f219db --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/SignIn.razor @@ -0,0 +1,74 @@ +@page "/signin" +@inherits AppAuthComponentBase +@inject ServiceStackStateProvider provider +@inject NavigationManager NavigationManager + +@if (IsAuthenticated) +{ + NavigationManager.NavigateTo(NavigationManager.GetReturnUrl(), true); + return; +} + +

Sign In

+ +
+ + + +
+ +
+
+ +
+ +
+ + Register New User +
+
+
+ +
+ Quick Links: + + + + +
+ +
+ +
+ +@code { + string[] VisibleFields => new[]{ nameof(Authenticate.UserName), nameof(Authenticate.Password) }; + + ApiResult api = new(); + + Authenticate request = new(); + + void SetUser(string email, string password) + { + request.UserName = email; + request.Password = password; + } + + async Task submit() + { + api.ClearErrors(); + + if (request.UserName.IsNullOrEmpty()) + api.AddFieldError(nameof(request.UserName), "Email is required"); + + if (request.Password.IsNullOrEmpty()) + api.AddFieldError(nameof(request.Password), "Password is required"); + + if (api.Failed) return; + + api = await provider.LoginAsync(request.UserName, request.Password); + + if (api.Succeeded) + NavigationManager.NavigateTo(NavigationManager.GetReturnUrl(), true); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/SignUp.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/SignUp.razor new file mode 100644 index 00000000000..fab09729398 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/SignUp.razor @@ -0,0 +1,101 @@ +@page "/signup" +@inherits AppAuthComponentBase +@inject ServiceStackStateProvider authProvider +@inject NavigationManager NavigationManager + +@if (IsAuthenticated) +{ + NavigationManager.NavigateTo(NavigationManager.GetReturnUrl(), true); + return; +} + +

Sign Up

+ +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+
+
+ +
+ Quick Links: + +
+ +
+ +
+ +@code { + string[] VisibleFields => new[]{ + nameof(request.DisplayName), nameof(request.Email), nameof(request.Password), nameof(request.ConfirmPassword) }; + + Register request = new() { AutoLogin = true }; + + ApiResult api = new(); + + void SetUser() + { + request.DisplayName = "New User"; + request.Email = "new@user.com"; + request.Password = request.ConfirmPassword = "p@55wOrd"; + request.AutoLogin = true; + } + + async Task submit() + { + api.ClearErrors(); + + if (request.Email.IsNullOrEmpty()) + api.AddFieldError(nameof(Register.Email), "Email is required"); + + if (request.Password.IsNullOrEmpty()) + api.AddFieldError(nameof(Register.Password), "Password is required"); + else if (request.ConfirmPassword != request.Password) + api.AddFieldError(nameof(Register.ConfirmPassword), "Passwords do not match"); + + if (api.Failed) return; + + api = await ApiAsync(request); + + if (api.Succeeded) + { + if (request.AutoLogin == true) + { + await authProvider.SignInAsync(api.Response!); + NavigationManager.NavigateTo(NavigationManager.GetReturnUrl(), true); + } + else + { + NavigationManager.NavigateTo("/signin?return=" + NavigationManager.GetReturnUrl(), true); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/TodoMvc.razor b/tests/ServiceStack.Blazor.Tests/Client/Pages/TodoMvc.razor new file mode 100644 index 00000000000..d424be35602 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/TodoMvc.razor @@ -0,0 +1,158 @@ +@page "/todomvc" +@inherits AppComponentBase + +
+ + +
+ Todos Application +
+ + + + + +
+
    + @foreach (var todo in filteredTodos()) + { +
  • +
    +
    + @if (todo.IsFinished) + { + check_circle + } + else + { + radio_button_unchecked + } +
    +
    + +
    +
    + @if (todo.IsFinished) + { + delete_outline + } +
    +
    +
  • + } +
+
+ + + +
+ + + +
+ +
+
+ + +@code { + enum Filter + { + All, + Finished, + Unfinished + } + static string[] VisibleFields = new[] { nameof(CreateTodo.Text) }; + + string TabClass(string @class, bool isActive) => + ClassNames("border-gray-200 text-sm font-medium px-4 py-2 hover:bg-gray-100 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700", + (isActive ? "text-blue-700 dark:bg-blue-600" : "text-gray-900 hover:text-blue-700 dark:bg-gray-700"), @class); + + List todos = new(); + Filter filter = Filter.All; + + CreateTodo request = new(); + ResponseStatus? errorStatus; + + IEnumerable filteredTodos() => filter switch + { + Filter.Finished => finishedTodos(), + Filter.Unfinished => unfinishedTodos(), + _ => todos + }; + IEnumerable finishedTodos() => todos.Where(x => x.IsFinished); + IEnumerable unfinishedTodos() => todos.Where(x => !x.IsFinished); + + protected override async Task OnInitializedAsync() => await refreshTodos(); + + // For best UX: apply changes locally then revalidate with real server state + async Task refreshTodos() + { + var api = await ApiAsync(new QueryTodos()); + if (api.Succeeded) + todos = api.Response!.Results; + else + errorStatus = api.Error; + } + + async Task addTodo() + { + errorStatus = null; + todos.Add(new Todo { Text = request.Text }); + var api = await ApiAsync(request); + if (api.Succeeded) + request.Text = ""; + else + errorStatus = api.Error; + await refreshTodos(); + } + + async Task removeTodo(long id) + { + todos.RemoveAll(x => x.Id == id); + var api = await ApiAsync(new DeleteTodo { Id = id }); + errorStatus = api.Error; + await refreshTodos(); + } + + async Task removeFinishedTodos() + { + var ids = todos.Where(x => x.IsFinished).Select(x => x.Id).ToList(); + if (ids.Count == 0) return; + todos.RemoveAll(x => ids.Contains(x.Id)); + var api = await ApiAsync(new DeleteTodos { Ids = ids }); + errorStatus = api.Error; + await refreshTodos(); + } + + async Task toggleTodo(long id) + { + var todo = todos.Find(x => x.Id == id)!; + todo.IsFinished = !todo.IsFinished; + var api = await ApiAsync(new UpdateTodo { Id = todo.Id, Text = todo.Text, IsFinished = todo.IsFinished }); + errorStatus = api.Error; + await refreshTodos(); + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Pages/TodoMvc.razor.css b/tests/ServiceStack.Blazor.Tests/Client/Pages/TodoMvc.razor.css new file mode 100644 index 00000000000..c69ff1ad3cb --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Pages/TodoMvc.razor.css @@ -0,0 +1,273 @@ +/* convert tailwind size into fontsize */ +.material-icons { cursor: pointer } +.material-icons.h-5.w-5 { + font-size: 20px; +} + +/* tailwind styles used in https://vue-ssg.jamstacks.net/todos */ +[type='text'] +{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:0.5rem 0.75rem;font-size:1rem;line-height:1.5rem} +[type='text']:focus{ + outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/); + --tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb; + --tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);border-color:#2563eb} +[type='text'].is-invalid{border-color:#dc3545} +*, ::before, ::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: #e5e7eb; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + --tw-border-opacity: 1; + border-color: rgba(229,231,235,var(--tw-border-opacity)); + --tw-ring-inset: var(--tw-empty, ); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgba(59, 130, 246, .5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-blur: var(--tw-empty, ); + --tw-brightness: var(--tw-empty, ); + --tw-contrast: var(--tw-empty, ); + --tw-grayscale: var(--tw-empty, ); + --tw-hue-rotate: var(--tw-empty, ); + --tw-invert: var(--tw-empty, ); + --tw-saturate: var(--tw-empty, ); + --tw-sepia: var(--tw-empty, ); + --tw-drop-shadow: var(--tw-empty, ); + --tw-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} +a { + cursor: pointer; + color: inherit; + text-decoration: inherit; + text-decoration-line: inherit; + text-decoration-thickness: inherit; + text-decoration-style: inherit; + text-decoration-color: inherit; +} +ol, ul { + list-style: none; + margin: 0; + padding: 0; +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow); +} +.shadow-sm { + box-shadow: 0 .125rem .25rem rgba(0,0,0,.075) !important; +} +.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgba(229,231,235,var(--tw-divide-opacity)); +} +.divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} +.divide-gray-200 > * + * { + --tw-divide-opacity: 1; + border-color: rgba(229, 231, 235, var(--tw-divide-opacity)); +} +.divide-y > * + * { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} +.w-5 { + width: 1.25rem; +} +.h-5 { + height: 1.25rem; +} +.h-6 { + height: 1.5rem; +} +.-ml-6 { + margin-left: -1.5rem; +} +.ml-1 { + margin-left: 0.25rem; +} +.ml-3 { + margin-left: 0.75rem; +} +.mt-4 { + margin-top: 1rem; +} +.my-8 { + margin-top: 2rem; + margin-bottom: 2rem; +} +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.leading-8 { + line-height: 2rem; +} +.bg-white { + --tw-bg-opacity: 1; + background-color: rgba(255,255,255,var(--tw-bg-opacity)); +} +.border { + border-width: 1px; +} +.border-b { + border-bottom-width: 1px; +} +.border-t { + border-top-width: 1px; +} +.border-gray-200 { + --tw-border-opacity: 1; + border-color: rgba(229,231,235,var(--tw-border-opacity)); +} +.rounded-md { + border-radius: 0.375rem; +} +.rounded-l-lg { + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; +} +.rounded-r-md { + border-top-right-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; +} +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} +.text-gray-400 { + --tw-text-opacity: 1; + color: rgba(156,163,175,var(--tw-text-opacity)); +} +.text-gray-700 { + --tw-text-opacity: 1; + color: rgba(55,65,81,var(--tw-text-opacity)); +} +.text-gray-900 { + --tw-text-opacity: 1; + color: rgba(17,24,39,var(--tw-text-opacity)); +} +.text-green-600 { + --tw-text-opacity: 1; + color: rgba(5,150,105,var(--tw-text-opacity)); +} +.text-blue-700 { + --tw-text-opacity: 1; + color: rgba(29,78,216,var(--tw-text-opacity)); +} +.text-purple-800 { + --tw-text-opacity: 1; + color: rgba(91, 33, 182, var(--tw-text-opacity)); +} +.font-medium { + font-weight: 500; +} +.text-center { + text-align: center; +} +.text-sm { + font-size: .875rem; + line-height: 1.25rem; +} +.w-full { width:100% } +.rounded-md { + border-radius: 0.375rem; +} +.overflow-hidden { + overflow: hidden; +} +.invisible { + visibility: hidden +} +.inline-flex { + display: inline-flex; +} +.flex { + display: flex; +} +.flex-grow { + flex-grow: 1; +} +.justify-center { + justify-content: center; +} +.justify-between { + justify-content: space-between; +} +.items-start { + align-items: flex-start; +} +.items-center { + align-items: center; +} +.relative { + position: relative; +} +.line-through { + text-decoration: line-through; +} +.hidden { + display: none; +} + +.hover\:bg-gray-100:hover { + --tw-bg-opacity: 1; + background-color: rgba(243,244,246,var(--tw-bg-opacity)); +} +.focus\:ring-blue-700:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgba(29, 78, 216, var(--tw-ring-opacity)); +} +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000); +} +.focus\:text-blue-700:focus { + --tw-text-opacity: 1; + color: rgba(29,78,216,var(--tw-text-opacity)); +} +.focus\:z-10:focus { + z-index: 10; +} + +@media (min-width: 640px) { + .sm\:inline { + display: inline; + } + .sm\:ml-4 { + margin-left: 1rem; + } + .sm\:text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/Program.cs b/tests/ServiceStack.Blazor.Tests/Client/Program.cs new file mode 100644 index 00000000000..4d6aa765987 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Program.cs @@ -0,0 +1,30 @@ +using System; +using System.Net.Http; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Components.Web; +using Blazor.Extensions.Logging; +using ServiceStack.Blazor; +using MyApp.Client; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.Services.AddLogging(c => c + .AddBrowserConsole() + .SetMinimumLevel(LogLevel.Trace) +); +builder.RootComponents.Add("#app"); +builder.RootComponents.Add("head::after"); +builder.Services.AddOptions(); +builder.Services.AddAuthorizationCore(); + +// Use / for local or CDN resources +builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); +builder.Services.AddScoped(s => s.GetRequiredService()); + +builder.Services.AddBlazorApiClient(builder.Configuration["ApiBaseUrl"] ?? builder.HostEnvironment.BaseAddress); + +builder.Services.AddScoped(); + +await builder.Build().RunAsync(); \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/Properties/launchSettings.json b/tests/ServiceStack.Blazor.Tests/Client/Properties/launchSettings.json new file mode 100644 index 00000000000..bd6493eb903 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:8345", + "sslPort": 44311 + } + }, + "profiles": { + "MyApp": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/AdminPage.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/AdminPage.razor new file mode 100644 index 00000000000..7010b373a45 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/AdminPage.razor @@ -0,0 +1,105 @@ +@inherits AppAuthComponentBase +@inject ServiceStackStateProvider AuthStateProvider; +@inject NavigationManager NavigationManager; + +@if (HasInit) +{ +
+ + + + + @if (!User.HasRole(AppRoles.Admin)) + { +

Sorry

+ +

+ + This area is only accessible to users with the Admin role +

+ +
+

+ Please + Login + as a user with the Admin role. +

+
+ } + else + { + + @ChildContent + + } + +
+} +else +{ + +} + + + + +@code { + [Parameter] public string? Title { get; set; } + + [Parameter] + public string? @class { get; set; } + + [Parameter] + public string? IconClass { get; set; } + + [Parameter] + public string? IconSrc { get; set; } + + [Parameter] public RenderFragment? ChildContent { get; set; } + + ApiResult appMetadataApi = new(); + AppMetadata? AppMetadata => appMetadataApi.Response; + + protected PluginInfo? Plugins => AppMetadata?.Plugins; + + protected AdminUsersInfo? AdminUsers => Plugins?.AdminUsers; + + protected override async Task OnInitializedAsync() + { + appMetadataApi = await this.ApiAppMetadataAsync(); + if (appMetadataApi.Succeeded) + { + if (AdminUsers == null) + appMetadataApi.SetError("AdminUsersFeature not registered, see: https://docs.servicestack.net/admin-users"); + } + } + + async Task SignInAsAnotherUser() + { + await AuthStateProvider.LogoutAsync(); + NavigationManager.NavigateTo(NavigationManager.GetLoginUrl(), true); + } + +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/Components/README.ss b/tests/ServiceStack.Blazor.Tests/Client/Shared/Components/README.ss new file mode 100644 index 00000000000..2a1799c6424 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/Components/README.ss @@ -0,0 +1,33 @@ +{{* + +ServiceStack.Blazor Components are easily customizable by modifying a local copy their *.razor UI markup that can be copied from: +https://github.com/ServiceStack/ServiceStack/tree/master/src/ServiceStack.Blazor/Components/Bootstrap + +This README is executable, to copy all ServiceStack.Blazor Bootstrap components into this folder, run: + + $ x run README.ss + +Then to use your local version, in your _Imports.razor replace: + + @using ServiceStack.Blazor.Components.Bootstrap + +with: + + @using MyApp.Client.Shared.Components + +Available themes: Bootstrap, Tailwind + +> PRs welcome! + +*}} + + +```code +var theme = 'Bootstrap' +var fs = vfsFileSystem('.') +#each name in 'AlertSuccess,CheckboxInput,DateTimeInput,DynamicInput,ErrorSummary,SelectInput,TextAreaInput,TextInput'.split(',') + var url = `https://raw.githubusercontent.com/ServiceStack/ServiceStack/master/src/ServiceStack.Blazor/Components/${theme}/${name}.razor` + url |> urlContents |> to => contents + fs.writeFile(`${name}.razor`, contents) +/each +``` diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/FormatValue.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/FormatValue.razor new file mode 100644 index 00000000000..86514cc8fb6 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/FormatValue.razor @@ -0,0 +1,6 @@ +@((MarkupString) HtmlUtils.HtmlDump(value ?? "")) + +@code { + [Parameter, EditorRequired] + public object? value { get; set; } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/GettingStarted.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/GettingStarted.razor new file mode 100644 index 00000000000..486601aed92 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/GettingStarted.razor @@ -0,0 +1,47 @@ +
+

+ Getting Started +

+
+
+
+ +

Create New Project

+ + + + +
+ Open with Visual Studio 2022 +
+
+
+
+
+ +@code { + string project { get; set; } = ""; + + string projectName => string.IsNullOrEmpty(project) ? "MyApp" : project; + + string projectZip => projectName + ".zip"; + + string zipUrl(string template) => + $"https://account.servicestack.net/archive/{template}?Name={projectName}"; +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/Loading.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/Loading.razor new file mode 100644 index 00000000000..1d86c912e0b --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/Loading.razor @@ -0,0 +1,35 @@ +@inject IJSRuntime JsRuntime +@inject NavigationManager NavigationManager + +@if (!string.IsNullOrEmpty(prerenderedHtml)) +{ + @((MarkupString)prerenderedHtml) +} +else +{ +
+ +
+

@Message

+} + +@code { + [Parameter] + public string Message { get; set; } = "Loading..."; + + [Parameter] + public string @class { get; set; } = ""; + + public string prerenderedHtml { get; set; } = ""; + + protected override async Task OnInitializedAsync() + { + var html = await JsRuntime.InvokeAsync("prerenderedPage") ?? ""; + var currentPath = new Uri(NavigationManager.Uri).AbsolutePath; + var prerenderedContentIsForPath = html.IndexOf($"data-prerender=\"{currentPath}\"") >= 0; + if (prerenderedContentIsForPath) + { + prerenderedHtml = html; + } + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/MainLayout.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/MainLayout.razor new file mode 100644 index 00000000000..e4448899cc7 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/MainLayout.razor @@ -0,0 +1,70 @@ +@inherits LayoutComponentBase +@inject ServiceStackStateProvider AuthStateProvider; +@inject NavigationManager NavigationManager; + +
+ + +
+
+ + + + + @context.User.GetDisplayName() + @foreach (var role in context.User.GetRoles()) + { + @role + } + Logout + + + Login + + + Login + + +
+
+ @Body +
+
+
+ +@code { + [CascadingParameter] protected Task? AuthenticationStateTask { get; set; } + + string LoginUrl { get; set; } = "/signin"; + + protected override Task OnParametersSetAsync() + { + LoginUrl = NavigationManager.GetLoginUrl(); + return Task.CompletedTask; + } + + async Task logout() + { + await AuthStateProvider.LogoutAsync(); + NavigationManager.NavigateTo(LoginUrl, true); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/NavMenu.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/NavMenu.razor new file mode 100644 index 00000000000..9a51d1d6619 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/NavMenu.razor @@ -0,0 +1,88 @@ +@inject ServiceStackStateProvider AuthStateProvider; +@inject NavigationManager NavigationManager; + + + +
+ +
+ +@code { + bool collapseNavMenu = true; + + void ToggleNavMenu() => collapseNavMenu = !collapseNavMenu; + + string? LoginUrl { get; set; } + + protected override Task OnParametersSetAsync() + { + LoginUrl = NavigationManager.GetLoginUrl(); + return Task.CompletedTask; + } + + async Task logout() + { + await AuthStateProvider.LogoutAsync(); + NavigationManager.NavigateTo(LoginUrl ?? "/", true); + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/NavPageLink.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/NavPageLink.razor new file mode 100644 index 00000000000..f6dc7998fb6 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/NavPageLink.razor @@ -0,0 +1,33 @@ + +
+
+ @if (IconClass != null) + { + + } + else if (IconSrc != null) + { + + } +
+
@Label
+
+
+
+ +@code { + [Parameter, EditorRequired] + public string? href { get; set; } + + [Parameter, EditorRequired] + public string? Label { get; set; } + + [Parameter] + public string? @class { get; set; } + + [Parameter] + public string? IconClass { get; set; } + + [Parameter] + public string? IconSrc { get; set; } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/ShellCommand.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/ShellCommand.razor new file mode 100644 index 00000000000..cb9113a6f1c --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/ShellCommand.razor @@ -0,0 +1,37 @@ +@inject IJSRuntime JsRuntime + +
+
+ + sh +
+@if (SuccessText != string.Empty) +{ +
+
+ + @SuccessText +
+
+} +
+ +@code { + [Parameter] + public string? @class { get; set; } + + [Parameter] + public RenderFragment? ChildContent { get; set; } + + string SuccessText { get; set; } = string.Empty; + + private ElementReference elCmd; + + async Task copyCommand(MouseEventArgs e) + { + SuccessText = "copied"; + await JsRuntime.InvokeVoidAsync("copy", elCmd); + await Task.Delay(3_000); + SuccessText = string.Empty; + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/ShellCommand.razor.css b/tests/ServiceStack.Blazor.Tests/Client/Shared/ShellCommand.razor.css new file mode 100644 index 00000000000..67956f633cf --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/ShellCommand.razor.css @@ -0,0 +1,90 @@ +.lang:before { + content: "$ "; +} +/* copy tailwind styles used */ +@media (min-width: 640px) { + .sm\:rounded { + border-radius: 0.25rem; + } +} +.text-xs { + font-size: .75rem; + line-height: 1rem; +} +.text-gray-300 { + --tw-text-opacity: 1; + color: rgba(209,213,219,var(--tw-text-opacity)); +} +.text-gray-400 { + --tw-text-opacity: 1; + color: rgba(156,163,175,var(--tw-text-opacity)); +} +.pl-5 { + padding-left: 1.25rem; +} +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} +.bg-gray-700 { + --tw-bg-opacity: 1; + background-color: rgba(55,65,81,var(--tw-bg-opacity)); +} +.flex { + display: flex; +} +.-mt-1 { + margin-top: -0.25rem; +} +.-mr-24 { + margin-right: -6rem; +} +.ml-2 { + margin-left: 0.5rem; +} +.mb-2 { + margin-bottom: 0.5rem; +} +.absolute { + position: absolute; +} +.relative { + position: relative; +} +.justify-between { + justify-content: space-between; +} +.cursor-pointer { + cursor: pointer; +} +.w-full { + width: 100%; +} +small { + font-size: 80%; +} +.text-gray-200 { + --tw-text-opacity: 1; + color: rgba(229,231,235,var(--tw-text-opacity)); +} +.px-1 { + padding-left: 0.25rem; + padding-right: 0.25rem; +} +.pr-1 { + padding-right: 0.25rem; +} +.bg-green-700 { + --tw-bg-opacity: 1; + background-color: rgba(4,120,87,var(--tw-bg-opacity)); +} +.rounded { + border-radius: 0.25rem; +} +.right-0 { + right: 0px; +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/SrcLink.razor b/tests/ServiceStack.Blazor.Tests/Client/Shared/SrcLink.razor new file mode 100644 index 00000000000..a668a673a99 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/SrcLink.razor @@ -0,0 +1,25 @@ +@if (IconClass != null) +{ + + @href.LastRightPart('/') +} +else +{ + + @href.LastRightPart('/') +} + +@code { + // Demonstrates how a parent component can supply parameters + [Parameter, EditorRequired] + public string? href { get; set; } + + [Parameter] + public string? @class { get; set; } + + [Parameter] + public string? IconClass { get; set; } + + [Parameter] + public string? IconSrc { get; set; } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/Shared/SrcLink.razor.css b/tests/ServiceStack.Blazor.Tests/Client/Shared/SrcLink.razor.css new file mode 100644 index 00000000000..a8f4522fcb3 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/Shared/SrcLink.razor.css @@ -0,0 +1,10 @@ +.text-gray-400 { + color: rgb(156,163,175) +} +.hover\:text-gray-400 { + color: rgb(156,163,175) +} + +.text-purple-800 { + color: rgb(91, 33, 182) +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/_Imports.razor b/tests/ServiceStack.Blazor.Tests/Client/_Imports.razor new file mode 100644 index 00000000000..3c4a867d025 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/_Imports.razor @@ -0,0 +1,19 @@ +@using System.Net +@using System.Net.Http +@using System.Net.Http.Json +@using System.Collections.Generic +@using Microsoft.JSInterop +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.WebAssembly.Http +@using Microsoft.AspNetCore.Authorization +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.Extensions.Logging +@using ServiceStack +@using ServiceStack.Blazor +@using ServiceStack.Blazor.Components +@using ServiceStack.Blazor.Components.Bootstrap +@using MyApp.Client +@using MyApp.Client.Shared +@using MyApp.ServiceModel diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/.nojekyll b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/.nojekyll new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/CNAME b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/CNAME new file mode 100644 index 00000000000..ae42ab3d425 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/CNAME @@ -0,0 +1 @@ +{DEPLOY_CDN} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/_headers b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/_headers new file mode 100644 index 00000000000..9079d85b36c --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/_headers @@ -0,0 +1,3 @@ +/assets/* + cache-control: max-age=31536000 + cache-control: immutable diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/_redirects b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/_redirects new file mode 100644 index 00000000000..9529c117cde --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/_redirects @@ -0,0 +1 @@ +/api/* {DEPLOY_API}/api/:splat 200 diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/appsettings.Production.json b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/appsettings.Production.json new file mode 100644 index 00000000000..dde871963b4 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/appsettings.Production.json @@ -0,0 +1,3 @@ +{ + "ApiBaseUrl": "https://{DEPLOY_API}" +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/deploy.md b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/deploy.md new file mode 100644 index 00000000000..506296e5199 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/deploy.md @@ -0,0 +1,169 @@ +--- +title: Deployment with GitHub Actions +summary: Configuring your GitHub repo for SSH and CDN deployments +date: 2021-11-21 +WARN: During development Browser Cache needs to be disabled to refresh .md changes +--- + +# ServiceStack GitHub Action Deployments + +The [release.yml](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/.github/workflows/release.yml) +in this template enables GitHub Actions CI deployment to a dedicated server with SSH access. + +## Overview +`release.yml` is designed to work with a ServiceStack app deploying directly to a single server via SSH. A docker image is built and stored on GitHub's `ghcr.io` docker registry when a GitHub Release is created. + +GitHub Actions specified in `release.yml` then copy files remotely via scp and use `docker-compose` to run the app remotely via SSH. + +## What's the process of `release.yml`? + +![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/mix/release-ghr-vanilla-diagram.png) + +## Deployment server setup +To get this working, a server needs to be setup with the following: + +- SSH access +- docker +- docker-compose +- ports 443 and 80 for web access of your hosted application + +This can be your own server or any cloud hosted server like Digital Ocean, AWS, Azure etc. + +When setting up your server, you'll want to use a dedicated SSH key for access to be used by GitHub Actions. GitHub Actions will need the *private* SSH key within a GitHub Secret to authenticate. This can be done via ssh-keygen and copying the public key to the authorized clients on the server. + +To let your server handle multiple ServiceStack applications and automate the generation and management of TLS certificates, an additional docker-compose file is provided in this template, `nginx-proxy-compose.yml`. This docker-compose file is ready to run and can be copied to the deployment server. + +For example, once copied to remote `~/nginx-proxy-compose.yml`, the following command can be run on the remote server. + +``` +docker-compose -f ~/nginx-proxy-compose.yml up -d +``` + +This will run an nginx reverse proxy along with a companion container that will watch for additional containers in the same docker network and attempt to initialize them with valid TLS certificates. + +## GitHub Repository setup +This template pushes the API server dockerized application to GitHub Container Repository. To do this, you will first need to [create a Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) specifically for use by `release.yml` GitHub Actions. + +This token will need to have access to `write:packages` to the GitHub Package Registry, which includes the GitHub Container Registry. + +The first time the `release.yml` process successfully runs and creates your GitHub Container Repository for your project, you then have the option to [upgrade the workflow to use GITHUB_TOKEN](https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#upgrading-a-workflow-that-accesses-ghcrio) replacing the `CR_PAT`. + +### GitHub Actions secrets + +The `release.yml` assumes 5 secrets have been set: + +| Required Secrets | Description | +| -- | -- | +| `CR_PAT` | GitHub Personal Token with read/write access to packages | +| `DEPLOY_API` | Hostname used to SSH deploy .NET App to, this can either be an IP address or subdomain with A record pointing to the server | +| `DEPLOY_USERNAME` | Username to log in with via SSH e.g, **ubuntu**, **ec2-user**, **root** | +| `DEPLOY_KEY` | SSH private key used to remotely access deploy .NET App | +| `LETSENCRYPT_EMAIL` | Email required for Let's Encrypt automated TLS certificates | + +To also enable deploying static assets to a CDN: + +| Optional Secrets | Description | +| -- | -- | +| `DEPLOY_CDN` | Hostname where static **/wwwroot** assets should be deployed to | + +These secrets can use the [GitHub CLI](https://cli.github.com/manual/gh_secret_set) for ease of creation. Eg, using the GitHub CLI the following can be set. + +```bash +gh secret set CR_PAT -b"" +gh secret set DEPLOY_API -b"" +gh secret set DEPLOY_USERNAME -b"" +gh secret set DEPLOY_KEY < key.pem # DEPLOY_KEY +gh secret set LETSENCRYPT_EMAIL -b"" +gh secret set DEPLOY_CDN -b"" +``` + +These secrets are used to populate variables within GitHub Actions and other configuration files. + +## Client UI Deployment + +The Blazor Client application is built and deployed to GitHub Pages during the `release.yml` workflow process by committing +the result of `vite build` to `gh-pages` branch in the repository. + +### CI .csproj After Build Tasks + +The Host Server `.csproj` includes post build instructions populated by GitHub Actions when publishing **Client** assets to CDN +by first copying the generated `index.html` home page into `404.html` in order to enable full page reloads to use Blazor's App +client routing: + +```xml + + $(MSBuildProjectDirectory)/../MyApp.Client + $(ClientDir)/wwwroot + + + + + + + + + + + + + + + + + + + + + +``` + +Whilst the `_redirects` file is a convention supported by many [popular Jamstack CDNs](https://jamstack.wtf/#deployment) +that sets up a new rule that proxies `/api*` requests to where the production .NET App is deployed to in order +for API requests to not need CORS: + +``` +/api/* {DEPLOY_API}/api/:splat 200 +``` + +By default this template doesn't use the `/api` proxy route & makes CORS API requests so it can be freely hosted +on GitHub pages CDN. + +## Pushing updates and rollbacks + +By default, deployments of both the **Client** and **Server** occur on commit to your main branch. A new Docker image for your +ServiceStack API is produced, pushed to GHCR.io and hosted on your Linux server with Docker Compose. +Your Blazor WASM UI is built and pushed to the repository GitHub Pages. + +The template also will run the release process on the creation of a GitHub Release making it easier to switch to manual production releases. + +Additionally, the `release.yml` workflow can be run manually specifying a version. This enables production rollbacks based on previously tagged releases. +A release must have already been created for the rollback build to work, it doesn't create a new Docker build based on previous code state, only redeploys as existing Docker image. + +## No CORS Hosting Options + +The `CorsFeature` needs to be enabled when adopting our recommended deployment configuration of having static +`/wwwroot` assets hosted from a CDN in order to make cross-domain requests to your .NET APIs. + +### Using a CDN Proxy +Should you want to, our recommended approach to avoid your App making CORS requests is to define an `/api` proxy route +on your CDN to your `$DEPLOY_API` server. + +To better support this use-case, this template includes populating the `_redirects` file used by popular CDNs like +[Cloudflare proxy redirects](https://developers.cloudflare.com/pages/platform/redirects) and +[Netlify proxies](https://docs.netlify.com/routing/redirects/rewrites-proxies/#proxy-to-another-service) to define +redirect and proxy rules. For AWS CloudFront you would need to define a +[Behavior for a custom origin](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html). + +### No CDN + +Of course the easiest solution is to not need CORS in the first place by not deploying to a CDN and serving both **Server** +and Blazor Client **UI** from your .NET App. This would be the preferred approach when deploying within an Intranet where +network speeds are much faster in order for initial load times to be heavily reduced. + +However when deploying to a public site on the Internet we'd highly recommend deploying Blazor WASM's static assets to a CDN +so load times can be reduced as much as possible. diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/hosting.md b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/hosting.md new file mode 100644 index 00000000000..5c1ab1bf73d --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/hosting.md @@ -0,0 +1,81 @@ +--- +title: Hosting Costs +WARN: During development Browser Cache needs to be disabled to refresh .md changes +--- + +# App Hosting Costs + + + + + +The modern [jamstack.org](https://jamstack.org) approach for developing websites is primarily concerned with adopting +the architecture yielding the best performance and superior UX by minimizing the time to first byte from serving +pre-built static assets from CDN edge caches. + +## Cheaper Hosting + + + + + +A consequence of designing your UI decoupled from your back-end server is that it also becomes considerably +cheaper to host as its static files can be hosted by any web server and is a task highly optimized by CDNs +who are able to provide generous free & low cost hosting options. + +## [/MyApp.Client](https://github.com/NetCoreTemplates/blazor-wasm/tree/main/MyApp.Client) + +This template takes advantage of its decoupled architecture and uses [GitHub Actions to deploy](/docs/deploy) +a copy of its static UI generated assets and hosted on: + +### GitHub Pages CDN + +### [blazor-wasm.jamstacks.net](https://blazor-wasm.jamstacks.net) + +This is an optional deployment step which publishes a copy of your .NET App's `/wwwroot` folder to this templates +[gh-pages](https://github.com/NetCoreTemplates/blazor-wasm/tree/gh-pages) branch where it's automatically served from +[GitHub Pages CDN](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages) at **no cost**. + +It's an optional but recommended optimization as it allows the initial download from your website to be served +directly from CDN edge caches. + +## [/MyApp](https://github.com/NetCoreTemplates/blazor-wasm/tree/main/MyApp) + +The .NET 6 `/MyApp` backend server is required for this App's dynamic functions including the Hello API on the home page +and its [built-in Authentication](https://docs.servicestack.net/auth). + +The C# project still contains the complete App and can be hosted independently with the entire App served +directly from its deployed ASP.NET Core server at: + +### Digital Ocean + +### [blazor-wasm-api.jamstacks.net](https://blazor-wasm-api.jamstacks.net) + +But when accessed from the CDN [blazor-wasm.jamstacks.net](https://blazor-wasm.jamstacks.net) that contains a +copy of its static `/wwwroot` UI assets, only its back-end JSON APIs are used to power its dynamic features. + +## Total Cost + + + + + +Since hosting on GitHub Pages CDN is free, the only cost is for hosting this App's .NET Server which is being hosted +from a basic [$10 /mo](https://www.digitalocean.com/pricing) droplet which is currently hosting **25** .NET Docker +Apps and demos of [starting project templates](https://servicestack.net/start) which works out to be just under **$0.40 /mo**! + +## Jamstack Benefits + +Jamstack is quickly becoming the preferred architecture for the development of modern web apps with +[benefits](https://jamstack.org/why-jamstack/) that extend beyond performance to improved: + + - **Security** from a reduced attack surface from hosting read-only static resources and requiring fewer App Servers + - **Scale** with non-essential load removed from App Servers to CDN's architecture capable of incredible scale & load capacity + - **Maintainability** resulting from reduced hosting complexity and the clean decoupling of UI and server logic + - **Portability** with your static UI assets being easily capable from being deployed and generically hosted from any CDN or web server + - **Developer Experience** with the major JavaScript frameworks at the forefront of amazing DX are embracing Jamstack in their dev model, libraries & tooling + +Best of all the Jamstack approach fits perfectly with ServiceStack's recommended +[API First Development](https://docs.servicestack.net/api-first-development) model which encourages development of +reusable message-based APIs where the same System APIs can be reused from all Web, Mobile & Desktop Apps +from multiple HTTP, MQ or gRPC endpoints. diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/prerender.md b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/prerender.md new file mode 100644 index 00000000000..f74b090ab43 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/content/prerender.md @@ -0,0 +1,504 @@ +--- +title: Improving UX with Prerendering +--- + +> Why does this page load so fast? + +### Blazor WASM trade-offs + +Blazor WASM enables reuse of C# skills, tooling & libraries offers a compelling advantage for .NET teams, so much so +it's become our preferred technology for developing internal LOB applications as it's better able to reuse existing +C# investments in an integrated SPA Framework utilizing a single toolchain. + +It does however comes at a cost of a larger initial download size and performance cost resulting in a high Time-To-First-Render (TTFR) +and an overall poor initial User Experience when served over the Internet, that's further exacerbated over low speed Mobile connections. + +This is likely an acceptable trade-off for most LOB applications served over high-speed local networks but may not be a +suitable choice for public Internet sites _(an area our other [jamstacks.net](https://jamstacks.net) templates may serve better)_. + +As an SPA it also suffers from poor SEO as content isn't included in the initial page and needs to be rendered in the browser after +the App has initialized. For some content heavy sites this can be a deal breaker either requiring proxy rules so content pages +are served by a different SEO friendly site or otherwise prohibits using Blazor WASM entirely. + +### Improving Startup Performance + +The solution to both issues is fairly straightforward, by utilizing the mainstay solution behind +[Jamstack Frameworks](https://jamstack.org/generators/) and prerender content at build time. + +We know what needs to be done, but how best to do it in Blazor WASM? Unfortunately the +[official Blazor WASM prerendering guide](https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration?view=aspnetcore-6.0&pivots=webassembly) +isn't actually a prerendering solution, as is typically used to describe +[Static Site Generators (SSG)](https://www.netlify.com/blog/2020/04/14/what-is-a-static-site-generator-and-3-ways-to-find-the-best-one/) +prerendering static content at build-time, whilst Blazor WASM prerendering docs instead describes +a [Server-Side-Rendering (SSR)](https://www.omnisci.com/technical-glossary/server-side-renderings) solution mandating the additional +complexity of maintaining your Apps dependencies in both client and server projects. Unfortunately this approach also wont yield an +optimal result since prerendering is typically used so Apps can host their SSG content on static file hosts, instead SSR does the +opposite whose forced runtime coupling to the .NET Server Host prohibits Blazor WASM Apps from being served from a CDN. + +As this defeats [many of the benefits](hosting) of a Blazor WASM Jamstack App in the first place, we've instead opted for a more optimal +solution that doesn't compromise its CDN hostability. + +### Increasing Perceived Performance + +We've little opportunity over improving the startup time of the real C# Blazor App beyond hosting its static assets on CDN edge caches, +but ultimately what matters is [perceived performance](https://marvelapp.com/blog/a-designers-guide-to-perceived-performance/) which +we do have control over given the screen for a default Blazor WASM project is a glaring white screen flash: + +![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/jamstack/blazor-wasm/loading-default.png) + +The longer users have to wait looking at this black loading screen without signs of progress, the more they'll associate your site +with taking forever to load. + +One technique many popular sites are using to increase perceived performance is to use content placeholders in place of real-content +which gives the impression that the site has almost loaded and only requires a few moments more for the latest live data to be slotted in. + +As an example here's what YouTube content placeholders mimicking the page layout looks like before the real site has loaded: + +![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/jamstack/youtube-placeholder.png) + +But we can do even better than an inert content placeholder, and load a temporary chrome of our App. But as this needs to be done +before Blazor has loaded we need to implement this with a sprinkling of HTML + JS. + +First thing we need to do is move the scoped styles of our Apps +[MainLayout](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/Shared/MainLayout.razor) and +[NavMenu](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/Shared/NavMenu.razor) into an external +[main-layout.css](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/wwwroot/css/main-layout.css) so our temp +App chrome can use it. + +Then in our [/wwwroot/index.html](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/wwwroot/index.html) anything +between `
` is displayed whilst our Blazor App is loading, before it's replaced with the real App. + +So Here we just paste in the **MainLayout** markup: + +```html +
+ +
+ +
+ +
+ +
+ +
+

+ Loading... +

+ +
+
+
+
+``` + +Less our App's navigation menus which we'll dynamically generate with the splash of JS below: + +```js +const SIDEBAR = ` + Home,home,/$ + Counter,plus,/counter + Todos,clipboard,/todomvc + Bookings CRUD,calendar,/bookings-crud + Call Hello,transfer,/hello$ + Call HelloSecure,shield,/hello-secure + Fetch data,list-rich,/fetchdata + Admin,lock-locked,/admin + Login,account-login,/signin +` +const TOP = ` + 0.40 /mo,dollar,/docs/hosting + Prerendering,loop-circular,/docs/prerender + Deployments,cloud-upload,/docs/deploy +` + +const path = location.pathname +const NAV = ({ label, cls, icon, route, exact }) => `` +const renderNav = (csv,f) => csv.trim().split(/\r?\n/g).map(s => NAV(f.apply(null,s.split(',')))).join('') +const $1 = s => document.querySelector(s) + +$1('#app-loading .sidebar .nav').innerHTML = renderNav(SIDEBAR, (label, icon, route) => ({ + label, cls: ` px-3${route == SIDEBAR[0].route ? ' pt-3' : ''}`, + icon, route: route.replace(/\$$/, ''), exact: route.endsWith('$') +})) + +$1('#app-loading .main-top-row .nav').innerHTML = renderNav(TOP, (label, icon, route) => ({ + label, cls: '', icon, route: route.replace(/\$$/, ''), exact: route.endsWith('$') +})) +``` + +Which takes care of both rendering the top and sidebar menus as well as highlighting the active menu for the active +nav item being loaded, and because we're rendering our real App navigation with real links, users will be able to navigate +to the page they want before our App has loaded. + +So you can distinguish a prerendered page from a Blazor rendered page we've added a **subtle box shadow** to prerendered content +which you'll see initially before being reverting to a flat border when the Blazor App takes over and replaces the entire page: + +```html + +``` + +With just this, every page now benefits from an instant App chrome to give the perception that our App has loaded instantly +before any C# in our Blazor App is run. E.g. here's what the [Blazor Counter](/counter) page looks like while it's loading: + +![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/jamstack/blazor-wasm/loading.png) + +If you click refresh the [/counter](/counter) page a few times you'll see the new loading screen prior to the Counter page being available. + +Our App is now in a pretty shippable state with decent UX of a loading page that looks like it loaded instantly instead +of the "under construction" Loading... page from the default Blazor WASM project template. + +It's not quite a zero maintenance solution but still fairly low maintenance as only the `SIDEBAR` and `TOP` csv lists +need updating when add/removing menu items. + +### Improving UX with Prerendering + +We'll now turn our focus to the most important page in our App, the [Home Page](/) which is the page most people will see +when loading the App from the first time. + +With the above temp App chrome already in place, a simple generic pre-rendering solution to be able to load any prerendered +page is to check if any prerendered content exists in the +[/prerender](https://github.com/NetCoreTemplates/blazor-wasm/tree/gh-pages/prerender) +folder for the current path, then if it does replace the default index.html `Loading...` page with it: + +```js +const pagePath = path.endsWith('/') + ? path.substring(0, path.length - 2) + '/index.html' + : path +fetch(`/prerender${pagePath}`) + .then(r => r.text()) + .then(html => { + if (html.indexOf('') >= 0) return // ignore CDN 404.html + const pageBody = $1('#app-loading .content') + if (pageBody) + pageBody.innerHTML = `` + html + }) + .catch(/* no prerendered content found for this path */) +``` + +We also tag which path the prerendered content is for and provide a JS function to fetch the prerendered content +which we'll need to access later in our App: + +```html + +``` + +We now have a solution in place to load pre-rendered content from the `/prerender` folder, but still need some way of generating it. + +The solution is technology independent in that you can you use any solution your most comfortable with, (even manually construct +each prerendered page if preferred), although it's less maintenance if you automate and get your CI to regenerate it when it publishes +your App. + +Which ever tool you choose would also need to be installed in your CI/GitHub Action if that's where it's run, so we've opted for +a dependency-free & least invasive solution by utilizing the existing Tests project, which has both great IDE tooling support and +can easily be run from the command-line and importantly is supported by the [bUnit](https://bunit.dev) testing library which we'll +be using to render component fragments in isolation. + +To distinguish prerendering tasks from our other Tests we've tagged +[PrerenderTasks.cs](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Tests/PrerenderTasks.cs) +with the `prerender` Test category. The only configuration the tasks require is the location of the `ClientDir` WASM Project +defined in [appsettings.json](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Tests/appsettings.json) +that's setup in the constructor. + +The `Render()` method renders the Blazor Page inside a `Bunit.TestContext` which it saves at the location +specified by its `@page` directive. + +```csharp +[TestFixture, Category("prerender")] +public class PrerenderTasks +{ + Bunit.TestContext Context; + string ClientDir; + string WwrootDir => ClientDir.CombineWith("wwwroot"); + string PrerenderDir => WwrootDir.CombineWith("prerender"); + + public PrerenderTasks() + { + Context = new(); + var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); + ClientDir = config[nameof(ClientDir)] + ?? throw new Exception($"{nameof(ClientDir)} not defined in appsettings.json"); + FileSystemVirtualFiles.RecreateDirectory(PrerenderDir); + } + + void Render(params ComponentParameter[] parameters) where T : IComponent + { + WriteLine($"Rendering: {typeof(T).FullName}..."); + var component = Context.RenderComponent(parameters); + var route = typeof(T).GetCustomAttribute()?.Template; + if (string.IsNullOrEmpty(route)) + throw new Exception($"Couldn't infer @page for component {typeof(T).Name}"); + + var fileName = route.EndsWith("/") ? route + "index.html" : $"{route}.html"; + + var writeTo = Path.GetFullPath(PrerenderDir.CombineWith(fileName)); + WriteLine($"Written to {writeTo}"); + File.WriteAllText(writeTo, component.Markup); + } + + [Test] + public void PrerenderPages() + { + Render(); + // Add Pages to prerender... + } +} +``` + +Being a unit test gives it a number of different ways it can be run, using any of the NUnit test runners, from the GUI +integrated in C# IDEs or via command-line test runners like `dotnet test` which can be done with: + +```bash +$ dotnet test --filter TestCategory=prerender +``` + +To have CI automatically run it when it creates a production build of our App we'll add it to our Host `.csproj`: + +```xml + + $(MSBuildProjectDirectory)/../MyApp.Tests + + + + + + + +``` + +Which allows [GitHub Actions to run it](https://github.com/NetCoreTemplates/blazor-wasm/blob/9460ebf57d3e46af1680eb3a2ff5080e59d33a54/.github/workflows/release.yml#L80) +when it publishes the App with: + +```bash +$ dotnet publish -c Release /p:APP_TASKS=prerender +``` + +Now when we next commit code, the GitHub CI Action will run the above task to generate our +[/prerender/index.html](https://github.com/NetCoreTemplates/blazor-wasm/blob/gh-pages/prerender/index.html) page +that now loads our [Home Page](/) instantly! + +[![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/jamstack/blazor-wasm/home-prerendered.png)](/) + +The only issue now is that the default Blazor template behavior will yank our pre-rendered page, once during loading +and another during Authorization. To stop the unwanted yanking we've updated the +[](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/Shared/Loading.razor) component +to instead load the prerendered page content if it's **for the current path**: + +```razor +@inject IJSRuntime JsRuntime +@inject NavigationManager NavigationManager + +@if (!string.IsNullOrEmpty(prerenderedHtml)) +{ + @((MarkupString)prerenderedHtml) +} +else +{ +
+ +
+

+ Loading... +

+} + +@code { + [Parameter] + public string Message { get; set; } = "Loading..."; + + [Parameter] + public string @class { get; set; } = ""; + + public string prerenderedHtml { get; set; } = ""; + + protected override async Task OnInitializedAsync() + { + var html = await JsRuntime.InvokeAsync("prerenderedPage") ?? ""; + var currentPath = new Uri(NavigationManager.Uri).AbsolutePath; + if (html.IndexOf($"data-prerender=\"{currentPath}\"") >= 0) + prerenderedHtml = html; + } +} +``` + +Whilst to prevent yanking by the Authorization component we'll also include the current page when rendering +the alternate layout with an `Authenticating...` text that will appear under the Login/Logout buttons on the top-right: + +```xml + + +

Authenticating...

+ +
+
+``` + +This last change brings us to the optimal UX we have now with the home page loading instantly whilst our Blazor App +is loading in the background that'll eventually replace the home page with its identical looking C# version except +for the **box-shadow under the top navigation** so you can tell when you're looking at the pre-rendered version +instead of the C# Blazor version. + +### Prerendering Markdown Content + +The other pages that would greatly benefit from prerendering are the Markdown `/docs/*` pages (like this one) that's implemented in +[Docs.razor](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/Pages/Docs.razor). + +However to enable SEO friendly content our `fetch(/prerender/*)` solution isn't good enough as the initial page download +needs to contain the prerendered content, i.e. instead of being downloaded in after. + +### PrerenderMarkdown Task + +To do this our `PrerenderMarkdown` Task scans all `*.md` pages in the +[content](https://github.com/NetCoreTemplates/blazor-wasm/tree/main/MyApp.Client/wwwroot/content) +directory and uses the same +[/MyApp.Client/MarkdownUtils.cs](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/MarkdownUtils.cs) +implementation [Docs.razor](https://github.com/NetCoreTemplates/blazor-wasm/blob/main/MyApp.Client/Pages/Docs.razor) +uses to generate the markdown and embeds it into the `index.html` loading page to generate the pre-rendered page: + +```csharp +[Test] +public async Task PrerenderMarkdown() +{ + var srcDir = WwrootDir.CombineWith("content").Replace('\\', '/'); + var dstDir = WwrootDir.CombineWith("docs").Replace('\\', '/'); + + var indexPage = PageTemplate.Create(WwrootDir.CombineWith("index.html")); + if (!Directory.Exists(srcDir)) throw new Exception($"{Path.GetFullPath(srcDir)} does not exist"); + FileSystemVirtualFiles.RecreateDirectory(dstDir); + + foreach (var file in new DirectoryInfo(srcDir).GetFiles("*.md", SearchOption.AllDirectories)) + { + WriteLine($"Converting {file.FullName} ..."); + + var name = file.Name.WithoutExtension(); + var docRender = await Client.MarkdownUtils.LoadDocumentAsync(name, doc => + Task.FromResult(File.ReadAllText(file.FullName))); + + if (docRender.Failed) + { + WriteLine($"Failed: {docRender.ErrorMessage}"); + continue; + } + + var dirName = dstDir.IndexOf("wwwroot") >= 0 + ? dstDir.LastRightPart("wwwroot").Replace('\\', '/') + : new DirectoryInfo(dstDir).Name; + var path = dirName.CombineWith(name == "index" ? "" : name); + + var mdBody = @$" +
+
+ {docRender.Response!.Preview!} +
+
"; + var prerenderedPage = indexPage.Render(mdBody); + string htmlPath = Path.GetFullPath(Path.Combine(dstDir, $"{name}.html")); + File.WriteAllText(htmlPath, prerenderedPage); + WriteLine($"Written to {htmlPath}"); + } +} + +public class PageTemplate +{ + string? Header { get; set; } + string? Footer { get; set; } + + public PageTemplate(string? header, string? footer) + { + Header = header; + Footer = footer; + } + + public static PageTemplate Create(string indexPath) + { + if (!File.Exists(indexPath)) + throw new Exception($"{Path.GetFullPath(indexPath)} does not exist"); + + string? header = null; + string? footer = null; + + var sb = new StringBuilder(); + foreach (var line in File.ReadAllLines(indexPath)) + { + if (header == null) + { + if (line.Contains("")) + { + header = sb.ToString(); // capture up to start page marker + sb.Clear(); + } + else sb.AppendLine(line); + } + else + { + if (sb.Length == 0) + { + if (line.Contains("")) // discard up to end page marker + { + sb.AppendLine(); + continue; + } + } + else sb.AppendLine(line); + } + } + footer = sb.ToString(); + + if (string.IsNullOrEmpty(header) || string.IsNullOrEmpty(footer)) + throw new Exception($"Parsing {indexPath} failed, missing ... markers"); + + return new PageTemplate(header, footer); + } + + public string Render(string body) => Header + body + Footer; +} +``` + +Whilst the `wwwroot/index.html` is parsed with `PageTemplate` above who uses the resulting layout to generate pages +within `` markers. + +After it's also executed by the same MSBuild task run by GitHub Actions it prerenders all `/wwwroot/content/*.md` pages +which are written to the [/wwwroot/docs/*.html](https://github.com/NetCoreTemplates/blazor-wasm/tree/gh-pages/docs) folder. + +This results in the path to the pre-generated markdown docs i.e. [/docs/prerender](/docs/prerender) having the **exact same path** +as its route in the Blazor App, which when exists, CDNs give priority to over the SPA fallback the Blazor App is loaded with. + +It shares similar behavior as the home page where its pre-rendered content is initially loaded before it's replaced with the +C# version once the Blazor App loads. The difference is that it prerenders "complete pages" for better SEO & TTFR. + +> Why does this page load so fast? + +So to answer the initial question, this page loads so fast because a prerendered version is initially loaded from a CDN edge cache, +i.e. the same reason why [Jamstack.org](https://jamstack.org) SSG templates like our modern +[nextjs.jamstacks.net](https://nextjs.jamstacks.net) and [vue-ssg.jamstacks.net](https://vue-ssg.jamstacks.net) +exhibit such great performance and UX out-of-the-box. + +We hope this technique serves useful in greatly improving the initial UX of Blazor Apps, a new Blazor App +with all this integrated can be created on the [Home Page](/) diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/admin.css b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/admin.css new file mode 100644 index 00000000000..9d527bfa8cc --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/admin.css @@ -0,0 +1,116 @@ +.admin-navbar .active { + font-weight: bold +} +.close, .text-close { + user-select: none; +} +.text-close { + cursor: pointer; + font-size: 1.5em; + color: #999; +} +.text-close:hover { + color: #666; +} +.text-close::after { + content: '\00D7'; +} +.results-none { + color: #6c757d; +} +.filters input { + min-width: 50px; + width: 100%; + font-size: 11px; +} +.noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Chrome/Safari/Opera */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE/Edge */ + user-select: none; /* non-prefixed version, currently + not supported by any browser */ +} +.has-auth .auth a { + pointer-events: auto; + color: #4183B8; +} +.svg-btn, .btn-link, .th-link { + cursor: pointer; + user-select: none; +} +.btn-link { + text-decoration: none; +} +::placeholder { + color: #aaa !important; +} +.disabled.md { + font-size: 1rem; +} +.disabled.lg { + font-size: 1.25rem; +} + +.svg-btn,.svg-btn-icon { background-repeat:no-repeat;cursor:pointer;user-select:none; } +.svg-xs, .svg-sm, .svg-md, .svg-lg, .svg-2x, .svg-3x, .svg-4x, .svg-5x, .svg-6x, .svg-7x, .svg-8x, .svg-9x, .svg-10x, .svg-11x, .svg-12x, .svg-13x, .svg-14x, .svg-2\.5x { +background-position:0;background-repeat:no-repeat;display: inline-block;background-size: contain;vertical-align: middle;} +.svg-xs {width:12px;height:12px}.svg-sm {width:14px;height:14px}.svg-md {width:18px;height:18px}.svg-lg {width:24px;height:24px}.svg-2x {width:32px;height:32px} +.svg-3x {width:48px;height:48px}.svg-4x {width:64px;height:64px}.svg-5x {width:80px;height:80px}.svg-6x {width:96px;height:96px}.svg-7x {width:112px;height:112px} +.svg-8x {width:128px;height:128px}.svg-9x {width:144px;height:144px}.svg-10x {width:160px;height:160px}.svg-11x {width:180px;height:180px} +.svg-12x {width:204px;height:204px}.svg-13x {width:232px;height:232px}.svg-14x {width:264px;height:264px} +.svg-2\.5x {width:40px;height:40px} +.svg-admin-home { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' enable-background='new 0 0 24 24' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cg%3E%3Crect fill='none' height='24' width='24'/%3E%3C/g%3E%3Cg%3E%3Cg%3E%3Cpath d='M17,11c0.34,0,0.67,0.04,1,0.09V6.27L10.5,3L3,6.27v4.91c0,4.54,3.2,8.79,7.5,9.82c0.55-0.13,1.08-0.32,1.6-0.55 C11.41,19.47,11,18.28,11,17C11,13.69,13.69,11,17,11z'/%3E%3Cpath d='M17,13c-2.21,0-4,1.79-4,4c0,2.21,1.79,4,4,4s4-1.79,4-4C21,14.79,19.21,13,17,13z M17,14.38c0.62,0,1.12,0.51,1.12,1.12 s-0.51,1.12-1.12,1.12s-1.12-0.51-1.12-1.12S16.38,14.38,17,14.38z M17,19.75c-0.93,0-1.74-0.46-2.24-1.17 c0.05-0.72,1.51-1.08,2.24-1.08s2.19,0.36,2.24,1.08C18.74,19.29,17.93,19.75,17,19.75z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); +} +.svg-admin-users { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z'/%3E%3C/svg%3E"); +} + +@media (max-width: 640px) { + form.shadow { + box-shadow: none !important; + } + form.rounded { + } + .sm\:px-1 { + padding-left: .25rem !important; + padding-right: .25rem !important; + } + form.p-4, .main-container.p-2 { + padding: 0 !important; + } + .sm\:flex-row { + flex-direction: column !important; + } + .sm\:flex-col { + flex-direction: column !important; + } + .sm\:w-full { + width: 100%; + } +} + +.show-xs-tcell { + display: table-cell +} +.show-sm-tcell, .show-md-tcell, .show-lg-tcell, .show-xl-tcell, .show-2xl-tcell { + display: none +} +@media (min-width: 640px) { + .show-sm-tcell { + display: table-cell + } +} +@media (min-width: 768px) { + .show-md-tcell { display: table-cell } +} +@media (min-width: 1024px) { + .show-lg-tcell { display: table-cell } +} +@media (min-width: 1280px) { + .show-xl-tcell { display: table-cell } +} +@media (min-width: 1536px) { + .show-2xl-tcell { display: table-cell } +} diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/app.css b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/app.css new file mode 100644 index 00000000000..4aac77c9252 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/app.css @@ -0,0 +1,101 @@ +@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); + +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +a, .btn-link { + color: #0366d6; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.content { + padding-top: 1.1rem; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + + + +.relative { position: relative } +.absolute { position: absolute } +button.close { + position: absolute; + top: 1rem; + right: 1rem; + padding: 0; + margin: 0; + background: rgba(0,0,0,0); + border: none; +} +button.close i { + display: inline-block; + width: 1.5rem; + height: 1.5rem; + background-image: url("data:image/svg+xml,%3Csvg fill='none' stroke='rgb(156 163 175)' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'%3E%3C/path%3E%3C/svg%3E"); +} +button.close:hover i { + background-image: url("data:image/svg+xml,%3Csvg fill='none' stroke='rgb(107 114 128)' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'%3E%3C/path%3E%3C/svg%3E"); +} + +/* useful tailwind presets */ +.cursor-pointer{cursor:pointer} +.max-w-full{max-width:100%} +.max-w-min{max-width:min-content} +.max-w-max{max-width:max-content} +.max-w-fit{max-width:fit-content} +.max-w-prose{max-width:65ch} +.max-w-screen-xs{max-width:20rem} +.max-w-screen-sm{max-width:640px} +.max-w-screen-md{max-width:768px} +.max-w-screen-lg{max-width:1024px} +.max-w-screen-xl{max-width:1280px} +.max-w-screen-2xl{max-width:1536px} +.max-w-xl{max-width:36rem} +.w-prose{width:65ch} +.w-screen-xs{width:20rem} +.w-screen-sm{width:640px} +.w-screen-md{width:768px} +.w-screen-lg{width:1024px} +.w-screen-xl{width:1280px} +.w-screen-2xl{width:1536px} +.w-xl{width:36rem} +.hover\:shadow-2xl:hover { + --tw-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow) !important; +} + + +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} + diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/bootstrap/bootstrap.min.css b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/bootstrap/bootstrap.min.css new file mode 100644 index 00000000000..0430d8eb7ac --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/bootstrap/bootstrap.min.css @@ -0,0 +1,7 @@ +@charset "UTF-8";/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"� "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:.2rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-bottom,.navbar-expand-sm .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-bottom,.navbar-expand-md .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-bottom,.navbar-expand-lg .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-bottom,.navbar-expand-xl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-bottom,.navbar-expand-xxl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-bottom,.navbar-expand .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{-webkit-animation:placeholder-glow 2s ease-in-out infinite;animation:placeholder-glow 2s ease-in-out infinite}@-webkit-keyframes placeholder-glow{50%{opacity:.2}}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;-webkit-animation:placeholder-wave 2s linear infinite;animation:placeholder-wave 2s linear infinite}@-webkit-keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:#6c757d!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/bootstrap/bootstrap.min.css.map b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/bootstrap/bootstrap.min.css.map new file mode 100644 index 00000000000..1e9cb78a53b --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/css/bootstrap/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","bootstrap.css","../../scss/mixins/_hover.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/mixins/_border-radius.scss","../../scss/_code.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/mixins/_breakpoints.scss","../../scss/mixins/_grid-framework.scss","../../scss/_tables.scss","../../scss/mixins/_table-row.scss","../../scss/_forms.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_forms.scss","../../scss/mixins/_gradients.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/mixins/_nav-divider.scss","../../scss/_button-group.scss","../../scss/_input-group.scss","../../scss/_custom-forms.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/mixins/_badge.scss","../../scss/_jumbotron.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_media.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/utilities/_align.scss","../../scss/mixins/_background-variant.scss","../../scss/utilities/_background.scss","../../scss/utilities/_borders.scss","../../scss/utilities/_display.scss","../../scss/utilities/_embed.scss","../../scss/utilities/_flex.scss","../../scss/utilities/_float.scss","../../scss/utilities/_overflow.scss","../../scss/utilities/_position.scss","../../scss/utilities/_screenreaders.scss","../../scss/mixins/_screen-reader.scss","../../scss/utilities/_shadows.scss","../../scss/utilities/_sizing.scss","../../scss/utilities/_stretched-link.scss","../../scss/utilities/_spacing.scss","../../scss/utilities/_text.scss","../../scss/mixins/_text-truncate.scss","../../scss/mixins/_text-emphasis.scss","../../scss/mixins/_text-hide.scss","../../scss/utilities/_visibility.scss","../../scss/_print.scss"],"names":[],"mappings":"AAAA;;;;;ACAA,MAGI,OAAA,QAAA,SAAA,QAAA,SAAA,QAAA,OAAA,QAAA,MAAA,QAAA,SAAA,QAAA,SAAA,QAAA,QAAA,QAAA,OAAA,QAAA,OAAA,QAAA,QAAA,KAAA,OAAA,QAAA,YAAA,QAIA,UAAA,QAAA,YAAA,QAAA,UAAA,QAAA,OAAA,QAAA,UAAA,QAAA,SAAA,QAAA,QAAA,QAAA,OAAA,QAIA,gBAAA,EAAA,gBAAA,MAAA,gBAAA,MAAA,gBAAA,MAAA,gBAAA,OAKF,yBAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBACA,wBAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UCCF,ECqBA,QADA,SDjBE,WAAA,WAGF,KACE,YAAA,WACA,YAAA,KACA,yBAAA,KACA,4BAAA,YAMF,QAAA,MAAA,WAAA,OAAA,OAAA,OAAA,OAAA,KAAA,IAAA,QACE,QAAA,MAUF,KACE,OAAA,EACA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBEgFI,UAAA,KF9EJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,WAAA,KACA,iBAAA,KGYF,sBHHE,QAAA,YASF,GACE,WAAA,YACA,OAAA,EACA,SAAA,QAaF,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAOF,EACE,WAAA,EACA,cAAA,KCZF,0BDuBA,YAEE,gBAAA,UACA,wBAAA,UAAA,OAAA,gBAAA,UAAA,OACA,OAAA,KACA,cAAA,EACA,iCAAA,KAAA,yBAAA,KAGF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QCjBF,GDoBA,GCrBA,GDwBE,WAAA,EACA,cAAA,KAGF,MCpBA,MACA,MAFA,MDyBE,cAAA,EAGF,GACE,YAAA,IAGF,GACE,cAAA,MACA,YAAA,EAGF,WACE,OAAA,EAAA,EAAA,KAGF,ECrBA,ODuBE,YAAA,OAGF,MEpFI,UAAA,IF6FJ,IC1BA,ID4BE,SAAA,SE/FE,UAAA,IFiGF,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAON,EACE,MAAA,QACA,gBAAA,KACA,iBAAA,YI5KA,QJ+KE,MAAA,QACA,gBAAA,UAUJ,8BACE,MAAA,QACA,gBAAA,KIxLA,oCAAA,oCJ2LE,MAAA,QACA,gBAAA,KANJ,oCAUI,QAAA,EC5BJ,KACA,IDoCA,ICnCA,KDuCE,YAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UErJE,UAAA,IFyJJ,IAEE,WAAA,EAEA,cAAA,KAEA,SAAA,KAQF,OAEE,OAAA,EAAA,EAAA,KAQF,IACE,eAAA,OACA,aAAA,KAGF,IAGE,SAAA,OACA,eAAA,OAQF,MACE,gBAAA,SAGF,QACE,YAAA,OACA,eAAA,OACA,MAAA,QACA,WAAA,KACA,aAAA,OAGF,GAGE,WAAA,QAQF,MAEE,QAAA,aACA,cAAA,MAMF,OAEE,cAAA,EAOF,aACE,QAAA,IAAA,OACA,QAAA,IAAA,KAAA,yBCvEF,OD0EA,MCxEA,SADA,OAEA,SD4EE,OAAA,EACA,YAAA,QEtPE,UAAA,QFwPF,YAAA,QAGF,OC1EA,MD4EE,SAAA,QAGF,OC1EA,OD4EE,eAAA,KAMF,OACE,UAAA,OC1EF,cACA,aACA,cD+EA,OAIE,mBAAA,OC9EF,6BACA,4BACA,6BDiFE,sBAKI,OAAA,QCjFN,gCACA,+BACA,gCDqFA,yBAIE,QAAA,EACA,aAAA,KCpFF,qBDuFA,kBAEE,WAAA,WACA,QAAA,EAIF,iBCvFA,2BACA,kBAFA,iBDiGE,mBAAA,QAGF,SACE,SAAA,KAEA,OAAA,SAGF,SAME,UAAA,EAEA,QAAA,EACA,OAAA,EACA,OAAA,EAKF,OACE,QAAA,MACA,MAAA,KACA,UAAA,KACA,QAAA,EACA,cAAA,MElSI,UAAA,OFoSJ,YAAA,QACA,MAAA,QACA,YAAA,OAGF,SACE,eAAA,SGtGF,yCFGA,yCDyGE,OAAA,KGvGF,cH+GE,eAAA,KACA,mBAAA,KG3GF,yCHmHE,mBAAA,KAQF,6BACE,KAAA,QACA,mBAAA,OAOF,OACE,QAAA,aAGF,QACE,QAAA,UACA,OAAA,QAGF,SACE,QAAA,KGxHF,SH8HE,QAAA,eCvHF,IAAK,IAAK,IAAK,IAAK,IAAK,IIpWzB,GAAA,GAAA,GAAA,GAAA,GAAA,GAEE,cAAA,MAEA,YAAA,IACA,YAAA,IAIF,IAAA,GHgHM,UAAA,OG/GN,IAAA,GH+GM,UAAA,KG9GN,IAAA,GH8GM,UAAA,QG7GN,IAAA,GH6GM,UAAA,OG5GN,IAAA,GH4GM,UAAA,QG3GN,IAAA,GH2GM,UAAA,KGzGN,MHyGM,UAAA,QGvGJ,YAAA,IAIF,WHmGM,UAAA,KGjGJ,YAAA,IACA,YAAA,IAEF,WH8FM,UAAA,OG5FJ,YAAA,IACA,YAAA,IAEF,WHyFM,UAAA,OGvFJ,YAAA,IACA,YAAA,IAEF,WHoFM,UAAA,OGlFJ,YAAA,IACA,YAAA,ILyBF,GKhBE,WAAA,KACA,cAAA,KACA,OAAA,EACA,WAAA,IAAA,MAAA,eJmXF,OI3WA,MHMI,UAAA,IGHF,YAAA,IJ8WF,MI3WA,KAEE,QAAA,KACA,iBAAA,QAQF,eC/EE,aAAA,EACA,WAAA,KDmFF,aCpFE,aAAA,EACA,WAAA,KDsFF,kBACE,QAAA,aADF,mCAII,aAAA,MAUJ,YHjCI,UAAA,IGmCF,eAAA,UAIF,YACE,cAAA,KHeI,UAAA,QGXN,mBACE,QAAA,MH7CE,UAAA,IG+CF,MAAA,QAHF,2BAMI,QAAA,aEnHJ,WCIE,UAAA,KAGA,OAAA,KDDF,eACE,QAAA,OACA,iBAAA,KACA,OAAA,IAAA,MAAA,QEXE,cAAA,ODMF,UAAA,KAGA,OAAA,KDcF,QAEE,QAAA,aAGF,YACE,cAAA,MACA,YAAA,EAGF,gBLkCI,UAAA,IKhCF,MAAA,QGvCF,KRuEI,UAAA,MQrEF,MAAA,QACA,WAAA,WAGA,OACE,MAAA,QAKJ,IACE,QAAA,MAAA,MR0DE,UAAA,MQxDF,MAAA,KACA,iBAAA,QDZE,cAAA,MCQJ,QASI,QAAA,ERkDA,UAAA,KQhDA,YAAA,IVyMJ,IUlME,QAAA,MRyCE,UAAA,MQvCF,MAAA,QAHF,SR0CI,UAAA,QQlCA,MAAA,QACA,WAAA,OAKJ,gBACE,WAAA,MACA,WAAA,OCzCA,WCAA,MAAA,KACA,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KCmDE,yBFvDF,WCYI,UAAA,OC2CF,yBFvDF,WCYI,UAAA,OC2CF,yBFvDF,WCYI,UAAA,OC2CF,0BFvDF,WCYI,UAAA,QDAJ,iBCZA,MAAA,KACA,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KDkBA,KCJA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,MACA,YAAA,MDOA,YACE,aAAA,EACA,YAAA,EAFF,iBVyjBF,0BUnjBM,cAAA,EACA,aAAA,EGjCJ,KAAA,OAAA,QAAA,QAAA,QAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OAAA,OAAA,ObylBF,UAEqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aAFqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aAFkJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACnG,aAEqJ,QAAvI,UAAmG,WAAY,WAAY,WAAhH,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UACtG,aa5lBI,SAAA,SACA,MAAA,KACA,cAAA,KACA,aAAA,KAmBE,KACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,UACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,OFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,OFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,QFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,QFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,QFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEGI,aAAwB,eAAA,GAAA,MAAA,GAExB,YAAuB,eAAA,GAAA,MAAA,GAGrB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,SAAwB,eAAA,EAAA,MAAA,EAAxB,UAAwB,eAAA,GAAA,MAAA,GAAxB,UAAwB,eAAA,GAAA,MAAA,GAAxB,UAAwB,eAAA,GAAA,MAAA,GAMtB,UFTR,YAAA,UESQ,UFTR,YAAA,WESQ,UFTR,YAAA,IESQ,UFTR,YAAA,WESQ,UFTR,YAAA,WESQ,UFTR,YAAA,IESQ,UFTR,YAAA,WESQ,UFTR,YAAA,WESQ,UFTR,YAAA,IESQ,WFTR,YAAA,WESQ,WFTR,YAAA,WCWE,yBC9BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEGI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAMtB,aFTR,YAAA,EESQ,aFTR,YAAA,UESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,cFTR,YAAA,WESQ,cFTR,YAAA,YCWE,yBC9BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEGI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAMtB,aFTR,YAAA,EESQ,aFTR,YAAA,UESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,cFTR,YAAA,WESQ,cFTR,YAAA,YCWE,yBC9BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEGI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAMtB,aFTR,YAAA,EESQ,aFTR,YAAA,UESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,cFTR,YAAA,WESQ,cFTR,YAAA,YCWE,0BC9BE,QACE,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,UAAA,KAEF,aACE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,UAAA,KAIA,UFFN,SAAA,EAAA,EAAA,UAAA,KAAA,EAAA,EAAA,UAIA,UAAA,UEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,UFFN,SAAA,EAAA,EAAA,IAAA,KAAA,EAAA,EAAA,IAIA,UAAA,IEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,WAAA,KAAA,EAAA,EAAA,WAIA,UAAA,WEFM,WFFN,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAIA,UAAA,KEGI,gBAAwB,eAAA,GAAA,MAAA,GAExB,eAAuB,eAAA,GAAA,MAAA,GAGrB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,YAAwB,eAAA,EAAA,MAAA,EAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAAxB,aAAwB,eAAA,GAAA,MAAA,GAMtB,aFTR,YAAA,EESQ,aFTR,YAAA,UESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,aFTR,YAAA,WESQ,aFTR,YAAA,WESQ,aFTR,YAAA,IESQ,cFTR,YAAA,WESQ,cFTR,YAAA,YG7CF,OACE,MAAA,KACA,cAAA,KACA,MAAA,Qdy+CF,Uc5+CA,UAQI,QAAA,OACA,eAAA,IACA,WAAA,IAAA,MAAA,QAVJ,gBAcI,eAAA,OACA,cAAA,IAAA,MAAA,QAfJ,mBAmBI,WAAA,IAAA,MAAA,Qdy+CJ,ach+CA,aAGI,QAAA,MASJ,gBACE,OAAA,IAAA,MAAA,Qd49CF,mBc79CA,mBAKI,OAAA,IAAA,MAAA,Qd69CJ,yBcl+CA,yBAWM,oBAAA,Id89CN,8BAFA,qBcv9CA,qBdw9CA,2Bcn9CI,OAAA,EAQJ,yCAEI,iBAAA,gBX/DF,4BW2EI,MAAA,QACA,iBAAA,iBCnFJ,ef+hDF,kBADA,kBe1hDM,iBAAA,QfkiDN,2BAFA,kBepiDE,kBfqiDF,wBezhDQ,aAAA,QZLN,kCYiBM,iBAAA,QALN,qCf4hDF,qCenhDU,iBAAA,QA5BR,iBfqjDF,oBADA,oBehjDM,iBAAA,QfwjDN,6BAFA,oBe1jDE,oBf2jDF,0Be/iDQ,aAAA,QZLN,oCYiBM,iBAAA,QALN,uCfkjDF,uCeziDU,iBAAA,QA5BR,ef2kDF,kBADA,kBetkDM,iBAAA,Qf8kDN,2BAFA,kBehlDE,kBfilDF,wBerkDQ,aAAA,QZLN,kCYiBM,iBAAA,QALN,qCfwkDF,qCe/jDU,iBAAA,QA5BR,YfimDF,eADA,ee5lDM,iBAAA,QfomDN,wBAFA,eetmDE,efumDF,qBe3lDQ,aAAA,QZLN,+BYiBM,iBAAA,QALN,kCf8lDF,kCerlDU,iBAAA,QA5BR,efunDF,kBADA,kBelnDM,iBAAA,Qf0nDN,2BAFA,kBe5nDE,kBf6nDF,wBejnDQ,aAAA,QZLN,kCYiBM,iBAAA,QALN,qCfonDF,qCe3mDU,iBAAA,QA5BR,cf6oDF,iBADA,iBexoDM,iBAAA,QfgpDN,0BAFA,iBelpDE,iBfmpDF,uBevoDQ,aAAA,QZLN,iCYiBM,iBAAA,QALN,oCf0oDF,oCejoDU,iBAAA,QA5BR,afmqDF,gBADA,gBe9pDM,iBAAA,QfsqDN,yBAFA,gBexqDE,gBfyqDF,sBe7pDQ,aAAA,QZLN,gCYiBM,iBAAA,QALN,mCfgqDF,mCevpDU,iBAAA,QA5BR,YfyrDF,eADA,eeprDM,iBAAA,Qf4rDN,wBAFA,ee9rDE,ef+rDF,qBenrDQ,aAAA,QZLN,+BYiBM,iBAAA,QALN,kCfsrDF,kCe7qDU,iBAAA,QA5BR,cf+sDF,iBADA,iBe1sDM,iBAAA,iBZGJ,iCYiBM,iBAAA,iBALN,oCfqsDF,oCe5rDU,iBAAA,iBD8EV,sBAGM,MAAA,KACA,iBAAA,QACA,aAAA,QALN,uBAWM,MAAA,QACA,iBAAA,QACA,aAAA,QAKN,YACE,MAAA,KACA,iBAAA,QdgnDF,eclnDA,edmnDA,qBc5mDI,aAAA,QAPJ,2BAWI,OAAA,EAXJ,oDAgBM,iBAAA,sBXrIJ,uCW4IM,MAAA,KACA,iBAAA,uBFhFJ,4BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GF1GN,4BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GF1GN,4BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GF1GN,6BEiGA,qBAEI,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MALH,qCASK,OAAA,GAdV,kBAOQ,QAAA,MACA,MAAA,KACA,WAAA,KACA,2BAAA,MAVR,kCAcU,OAAA,EE7KV,cACE,QAAA,MACA,MAAA,KACA,OAAA,2BACA,QAAA,QAAA,OfqHI,UAAA,KelHJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,QRbE,cAAA,OSCE,WAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAKF,uCDLJ,cCMM,WAAA,MDNN,0BAsBI,iBAAA,YACA,OAAA,EEhBF,oBACE,MAAA,QACA,iBAAA,KACA,aAAA,QACA,QAAA,EAKE,WAAA,EAAA,EAAA,EAAA,MAAA,oBFhBN,yCA+BI,MAAA,QAEA,QAAA,EAjCJ,gCA+BI,MAAA,QAEA,QAAA,EAjCJ,oCA+BI,MAAA,QAEA,QAAA,EAjCJ,qCA+BI,MAAA,QAEA,QAAA,EAjCJ,2BA+BI,MAAA,QAEA,QAAA,EAjCJ,uBAAA,wBA2CI,iBAAA,QAEA,QAAA,EAIJ,qCAOI,MAAA,QACA,iBAAA,KAKJ,mBhBm0DA,oBgBj0DE,QAAA,MACA,MAAA,KAUF,gBACE,YAAA,oBACA,eAAA,oBACA,cAAA,EfZE,UAAA,QecF,YAAA,IAGF,mBACE,YAAA,kBACA,eAAA,kBfoCI,UAAA,QelCJ,YAAA,IAGF,mBACE,YAAA,mBACA,eAAA,mBf6BI,UAAA,Qe3BJ,YAAA,IASF,wBACE,QAAA,MACA,MAAA,KACA,YAAA,QACA,eAAA,QACA,cAAA,EACA,YAAA,IACA,MAAA,QACA,iBAAA,YACA,OAAA,MAAA,YACA,aAAA,IAAA,EAVF,wCAAA,wCAcI,cAAA,EACA,aAAA,EAYJ,iBACE,OAAA,0BACA,QAAA,OAAA,MfXI,UAAA,QeaJ,YAAA,IRvIE,cAAA,MQ2IJ,iBACE,OAAA,yBACA,QAAA,MAAA,KfnBI,UAAA,QeqBJ,YAAA,IR/IE,cAAA,MQoJJ,8BAAA,0BAGI,OAAA,KAIJ,sBACE,OAAA,KAQF,YACE,cAAA,KAGF,WACE,QAAA,MACA,WAAA,OAQF,UACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,KACA,YAAA,KAJF,ehBwyDA,wBgBhyDI,cAAA,IACA,aAAA,IASJ,YACE,SAAA,SACA,QAAA,MACA,aAAA,QAGF,kBACE,SAAA,SACA,WAAA,MACA,YAAA,SAHF,6CAMI,MAAA,QAIJ,kBACE,cAAA,EAGF,mBACE,QAAA,mBAAA,QAAA,YACA,eAAA,OAAA,YAAA,OACA,aAAA,EACA,aAAA,OAJF,qCAQI,SAAA,OACA,WAAA,EACA,aAAA,SACA,YAAA,EE3MF,gBACE,QAAA,KACA,MAAA,KACA,WAAA,OjBwCA,UAAA,IiBtCA,MAAA,QAGF,eACE,SAAA,SACA,IAAA,KACA,QAAA,EACA,QAAA,KACA,UAAA,KACA,QAAA,OAAA,MACA,WAAA,MjBmFE,UAAA,QiBjFF,YAAA,IACA,MAAA,KACA,iBAAA,mBV3CA,cAAA,OUgDA,uBAAA,mCAEE,aAAA,QAGE,cAAA,qBACA,iBAAA,2OACA,kBAAA,UACA,oBAAA,OAAA,MAAA,wBACA,gBAAA,sBAAA,sBATJ,6BAAA,yCAaI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBlB2+D6C,uCACrD,sCkB1/DI,mDlBy/DJ,kDkBt+DQ,QAAA,MAOJ,2CAAA,+BAGI,cAAA,qBACA,oBAAA,IAAA,wBAAA,MAAA,wBAMJ,wBAAA,oCAEE,aAAA,QAGE,cAAA,uCACA,WAAA,0JAAA,UAAA,MAAA,OAAA,MAAA,CAAA,IAAA,IAAA,CAAA,2OAAA,KAAA,UAAA,OAAA,MAAA,OAAA,CAAA,sBAAA,sBANJ,8BAAA,0CAUI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBlBg+D8C,wCACtD,uCkB5+DI,oDlB2+DJ,mDkB39DQ,QAAA,MlBi+DkD,4CAC1D,2CkB39DI,wDlB09DJ,uDkBt9DQ,QAAA,MAMJ,6CAAA,yDAGI,MAAA,QlBu9DiD,2CACzD,0CkB39DI,uDlB09DJ,sDkBl9DQ,QAAA,MAMJ,qDAAA,iEAGI,MAAA,QAHJ,6DAAA,yEAMM,aAAA,QlBo9DmD,+CAC7D,8CkB39DI,2DlB09DJ,0DkB98DQ,QAAA,MAZJ,qEAAA,iFAiBM,aAAA,QCnJN,iBAAA,QDkIA,mEAAA,+EAwBM,WAAA,EAAA,EAAA,EAAA,MAAA,oBAxBN,iFAAA,6FA4BM,aAAA,QAQN,+CAAA,2DAGI,aAAA,QlB08DkD,4CAC1D,2CkB98DI,wDlB68DJ,uDkBr8DQ,QAAA,MARJ,qDAAA,iEAaM,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBA7JR,kBACE,QAAA,KACA,MAAA,KACA,WAAA,OjBwCA,UAAA,IiBtCA,MAAA,QAGF,iBACE,SAAA,SACA,IAAA,KACA,QAAA,EACA,QAAA,KACA,UAAA,KACA,QAAA,OAAA,MACA,WAAA,MjBmFE,UAAA,QiBjFF,YAAA,IACA,MAAA,KACA,iBAAA,mBV3CA,cAAA,OUgDA,yBAAA,qCAEE,aAAA,QAGE,cAAA,qBACA,iBAAA,qRACA,kBAAA,UACA,oBAAA,OAAA,MAAA,wBACA,gBAAA,sBAAA,sBATJ,+BAAA,2CAaI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBlBsmEiD,2CACzD,0CkBrnEI,uDlBonEJ,sDkBjmEQ,QAAA,MAOJ,6CAAA,iCAGI,cAAA,qBACA,oBAAA,IAAA,wBAAA,MAAA,wBAMJ,0BAAA,sCAEE,aAAA,QAGE,cAAA,uCACA,WAAA,0JAAA,UAAA,MAAA,OAAA,MAAA,CAAA,IAAA,IAAA,CAAA,qRAAA,KAAA,UAAA,OAAA,MAAA,OAAA,CAAA,sBAAA,sBANJ,gCAAA,4CAUI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBlB2lEkD,4CAC1D,2CkBvmEI,wDlBsmEJ,uDkBtlEQ,QAAA,MlB4lEsD,gDAC9D,+CkBtlEI,4DlBqlEJ,2DkBjlEQ,QAAA,MAMJ,+CAAA,2DAGI,MAAA,QlBklEqD,+CAC7D,8CkBtlEI,2DlBqlEJ,0DkB7kEQ,QAAA,MAMJ,uDAAA,mEAGI,MAAA,QAHJ,+DAAA,2EAMM,aAAA,QlB+kEuD,mDACjE,kDkBtlEI,+DlBqlEJ,8DkBzkEQ,QAAA,MAZJ,uEAAA,mFAiBM,aAAA,QCnJN,iBAAA,QDkIA,qEAAA,iFAwBM,WAAA,EAAA,EAAA,EAAA,MAAA,oBAxBN,mFAAA,+FA4BM,aAAA,QAQN,iDAAA,6DAGI,aAAA,QlBqkEsD,gDAC9D,+CkBzkEI,4DlBwkEJ,2DkBhkEQ,QAAA,MARJ,uDAAA,mEAaM,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBFuEV,aACE,QAAA,YAAA,QAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,eAAA,OAAA,YAAA,OAHF,yBASI,MAAA,KJ9MA,yBIqMJ,mBAeM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,cAAA,EAlBN,yBAuBM,QAAA,YAAA,QAAA,KACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,EA3BN,2BAgCM,QAAA,aACA,MAAA,KACA,eAAA,OAlCN,qCAuCM,QAAA,ahBigEJ,4BgBxiEF,0BA4CM,MAAA,KA5CN,yBAkDM,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,KACA,aAAA,EAtDN,+BAyDM,SAAA,SACA,kBAAA,EAAA,YAAA,EACA,WAAA,EACA,aAAA,OACA,YAAA,EA7DN,6BAiEM,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OAlEN,mCAqEM,cAAA,GIhUN,KACE,QAAA,aAEA,YAAA,IACA,MAAA,QACA,WAAA,OACA,eAAA,OACA,oBAAA,KAAA,iBAAA,KAAA,gBAAA,KAAA,YAAA,KACA,iBAAA,YACA,OAAA,IAAA,MAAA,YCsFA,QAAA,QAAA,OpB0BI,UAAA,KoBxBJ,YAAA,IblGE,cAAA,OSCE,WAAA,MAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAKF,uCGLJ,KHMM,WAAA,MdAJ,WiBQE,MAAA,QACA,gBAAA,KAfJ,WAAA,WAoBI,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBArBJ,cAAA,cA2BI,QAAA,IAeJ,epBi0EA,wBoB/zEE,eAAA,KASA,aCrDA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,mBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,mBAAA,mBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,oBAKJ,sBAAA,sBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,kDAAA,kDrBq2EF,mCqBl2EI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,wDAAA,wDrBk2EJ,yCqB71EQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDKN,eCrDA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,qBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,qBAAA,qBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,qBAKJ,wBAAA,wBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,oDAAA,oDrBu4EF,qCqBp4EI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,0DAAA,0DrBo4EJ,2CqB/3EQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBDKN,aCrDA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,mBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,mBAAA,mBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,mBAKJ,sBAAA,sBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,kDAAA,kDrBy6EF,mCqBt6EI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,wDAAA,wDrBs6EJ,yCqBj6EQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDKN,UCrDA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,gBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,gBAAA,gBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,oBAKJ,mBAAA,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,+CAAA,+CrB28EF,gCqBx8EI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,qDAAA,qDrBw8EJ,sCqBn8EQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDKN,aCrDA,MAAA,QFAE,iBAAA,QEEF,aAAA,QlBIA,mBkBAE,MAAA,QFNA,iBAAA,QEQA,aAAA,QAGF,mBAAA,mBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,oBAKJ,sBAAA,sBAEE,MAAA,QACA,iBAAA,QACA,aAAA,QAOF,kDAAA,kDrB6+EF,mCqB1+EI,MAAA,QACA,iBAAA,QAIA,aAAA,QAEA,wDAAA,wDrB0+EJ,yCqBr+EQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBDKN,YCrDA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,kBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,kBAAA,kBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,mBAKJ,qBAAA,qBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,iDAAA,iDrB+gFF,kCqB5gFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,uDAAA,uDrB4gFJ,wCqBvgFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBDKN,WCrDA,MAAA,QFAE,iBAAA,QEEF,aAAA,QlBIA,iBkBAE,MAAA,QFNA,iBAAA,QEQA,aAAA,QAGF,iBAAA,iBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,qBAKJ,oBAAA,oBAEE,MAAA,QACA,iBAAA,QACA,aAAA,QAOF,gDAAA,gDrBijFF,iCqB9iFI,MAAA,QACA,iBAAA,QAIA,aAAA,QAEA,sDAAA,sDrB8iFJ,uCqBziFQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBDKN,UCrDA,MAAA,KFAE,iBAAA,QEEF,aAAA,QlBIA,gBkBAE,MAAA,KFNA,iBAAA,QEQA,aAAA,QAGF,gBAAA,gBAMI,WAAA,EAAA,EAAA,EAAA,MAAA,kBAKJ,mBAAA,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAOF,+CAAA,+CrBmlFF,gCqBhlFI,MAAA,KACA,iBAAA,QAIA,aAAA,QAEA,qDAAA,qDrBglFJ,sCqB3kFQ,WAAA,EAAA,EAAA,EAAA,MAAA,kBDWN,qBCJA,MAAA,QACA,aAAA,QlBlDA,2BkBqDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,0DAAA,0DrBykFF,2CqBtkFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,gEAAA,gErBykFJ,iDqBpkFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBD5BN,uBCJA,MAAA,QACA,aAAA,QlBlDA,6BkBqDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,6BAAA,6BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,qBAGF,gCAAA,gCAEE,MAAA,QACA,iBAAA,YAGF,4DAAA,4DrBymFF,6CqBtmFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,kEAAA,kErBymFJ,mDqBpmFQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBD5BN,qBCJA,MAAA,QACA,aAAA,QlBlDA,2BkBqDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,0DAAA,0DrByoFF,2CqBtoFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,gEAAA,gErByoFJ,iDqBpoFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBD5BN,kBCJA,MAAA,QACA,aAAA,QlBlDA,wBkBqDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,wBAAA,wBAEE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAGF,2BAAA,2BAEE,MAAA,QACA,iBAAA,YAGF,uDAAA,uDrByqFF,wCqBtqFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,6DAAA,6DrByqFJ,8CqBpqFQ,WAAA,EAAA,EAAA,EAAA,MAAA,oBD5BN,qBCJA,MAAA,QACA,aAAA,QlBlDA,2BkBqDE,MAAA,QACA,iBAAA,QACA,aAAA,QAGF,2BAAA,2BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,8BAAA,8BAEE,MAAA,QACA,iBAAA,YAGF,0DAAA,0DrBysFF,2CqBtsFI,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,gEAAA,gErBysFJ,iDqBpsFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBD5BN,oBCJA,MAAA,QACA,aAAA,QlBlDA,0BkBqDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,0BAAA,0BAEE,WAAA,EAAA,EAAA,EAAA,MAAA,mBAGF,6BAAA,6BAEE,MAAA,QACA,iBAAA,YAGF,yDAAA,yDrByuFF,0CqBtuFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,+DAAA,+DrByuFJ,gDqBpuFQ,WAAA,EAAA,EAAA,EAAA,MAAA,mBD5BN,mBCJA,MAAA,QACA,aAAA,QlBlDA,yBkBqDE,MAAA,QACA,iBAAA,QACA,aAAA,QAGF,yBAAA,yBAEE,WAAA,EAAA,EAAA,EAAA,MAAA,qBAGF,4BAAA,4BAEE,MAAA,QACA,iBAAA,YAGF,wDAAA,wDrBywFF,yCqBtwFI,MAAA,QACA,iBAAA,QACA,aAAA,QAEA,8DAAA,8DrBywFJ,+CqBpwFQ,WAAA,EAAA,EAAA,EAAA,MAAA,qBD5BN,kBCJA,MAAA,QACA,aAAA,QlBlDA,wBkBqDE,MAAA,KACA,iBAAA,QACA,aAAA,QAGF,wBAAA,wBAEE,WAAA,EAAA,EAAA,EAAA,MAAA,kBAGF,2BAAA,2BAEE,MAAA,QACA,iBAAA,YAGF,uDAAA,uDrByyFF,wCqBtyFI,MAAA,KACA,iBAAA,QACA,aAAA,QAEA,6DAAA,6DrByyFJ,8CqBpyFQ,WAAA,EAAA,EAAA,EAAA,MAAA,kBDjBR,UACE,YAAA,IACA,MAAA,QACA,gBAAA,KjBnEA,gBiBsEE,MAAA,QACA,gBAAA,UAPJ,gBAAA,gBAYI,gBAAA,UACA,WAAA,KAbJ,mBAAA,mBAkBI,MAAA,QACA,eAAA,KAWJ,mBAAA,QCLE,QAAA,MAAA,KpB0BI,UAAA,QoBxBJ,YAAA,IblGE,cAAA,MYyGJ,mBAAA,QCTE,QAAA,OAAA,MpB0BI,UAAA,QoBxBJ,YAAA,IblGE,cAAA,MYkHJ,WACE,QAAA,MACA,MAAA,KAFF,sBAMI,WAAA,MpBszFJ,6BADA,4BoBhzFA,6BAII,MAAA,KEtIJ,MLMM,WAAA,QAAA,KAAA,OAKF,uCKXJ,MLYM,WAAA,MKZN,iBAII,QAAA,EAIJ,qBAEI,QAAA,KAIJ,YACE,SAAA,SACA,OAAA,EACA,SAAA,OLXI,WAAA,OAAA,KAAA,KAKF,uCKGJ,YLFM,WAAA,MjB48FN,UACA,UAFA,WuBt9FA,QAIE,SAAA,SAGF,iBACE,YAAA,OCoBE,wBACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAhCJ,WAAA,KAAA,MACA,aAAA,KAAA,MAAA,YACA,cAAA,EACA,YAAA,KAAA,MAAA,YAqDE,8BACE,YAAA,ED1CN,eACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,UAAA,MACA,QAAA,MAAA,EACA,OAAA,QAAA,EAAA,EtBsGI,UAAA,KsBpGJ,MAAA,QACA,WAAA,KACA,WAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,gBf3BE,cAAA,OeoCA,oBACE,MAAA,KACA,KAAA,EAGF,qBACE,MAAA,EACA,KAAA,KXYF,yBWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MXYF,yBWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MXYF,yBWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MXYF,0BWnBA,uBACE,MAAA,KACA,KAAA,EAGF,wBACE,MAAA,EACA,KAAA,MAON,uBAEI,IAAA,KACA,OAAA,KACA,WAAA,EACA,cAAA,QC/BA,gCACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAzBJ,WAAA,EACA,aAAA,KAAA,MAAA,YACA,cAAA,KAAA,MACA,YAAA,KAAA,MAAA,YA8CE,sCACE,YAAA,EDUN,0BAEI,IAAA,EACA,MAAA,KACA,KAAA,KACA,WAAA,EACA,YAAA,QC7CA,mCACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAlBJ,WAAA,KAAA,MAAA,YACA,aAAA,EACA,cAAA,KAAA,MAAA,YACA,YAAA,KAAA,MAuCE,yCACE,YAAA,EA7BF,mCDmDE,eAAA,EAKN,yBAEI,IAAA,EACA,MAAA,KACA,KAAA,KACA,WAAA,EACA,aAAA,QC9DA,kCACE,QAAA,aACA,YAAA,OACA,eAAA,OACA,QAAA,GAJF,kCAgBI,QAAA,KAGF,mCACE,QAAA,aACA,aAAA,OACA,eAAA,OACA,QAAA,GA9BN,WAAA,KAAA,MAAA,YACA,aAAA,KAAA,MACA,cAAA,KAAA,MAAA,YAiCE,wCACE,YAAA,EAVA,mCDiDA,eAAA,EAON,oCAAA,kCAAA,mCAAA,iCAKI,MAAA,KACA,OAAA,KAKJ,kBE9GE,OAAA,EACA,OAAA,MAAA,EACA,SAAA,OACA,WAAA,IAAA,MAAA,QFkHF,eACE,QAAA,MACA,MAAA,KACA,QAAA,OAAA,OACA,MAAA,KACA,YAAA,IACA,MAAA,QACA,WAAA,QACA,YAAA,OACA,iBAAA,YACA,OAAA,EpBpHA,qBAAA,qBoBmIE,MAAA,QACA,gBAAA,KJ9IA,iBAAA,QIoHJ,sBAAA,sBAgCI,MAAA,KACA,gBAAA,KJrJA,iBAAA,QIoHJ,wBAAA,wBAuCI,MAAA,QACA,eAAA,KACA,iBAAA,YAQJ,oBACE,QAAA,MAIF,iBACE,QAAA,MACA,QAAA,MAAA,OACA,cAAA,EtBpDI,UAAA,QsBsDJ,MAAA,QACA,YAAA,OAIF,oBACE,QAAA,MACA,QAAA,OAAA,OACA,MAAA,QG1LF,W1B4sGA,oB0B1sGE,SAAA,SACA,QAAA,mBAAA,QAAA,YACA,eAAA,O1BgtGF,yB0BptGA,gBAOI,SAAA,SACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,K1BmtGJ,+BGltGE,sBuBII,QAAA,E1BqtGN,gCADA,gCADA,+B0BhuGA,uBAAA,uBAAA,sBAkBM,QAAA,EAMN,aACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,cAAA,MAAA,gBAAA,WAHF,0BAMI,MAAA,K1BstGJ,wC0BltGA,kCAII,YAAA,K1BmtGJ,4C0BvtGA,uDlBhBI,wBAAA,EACA,2BAAA,ER4uGJ,6C0B7tGA,kClBFI,uBAAA,EACA,0BAAA,EkBgCJ,uBACE,cAAA,SACA,aAAA,SAFF,8B1B0sGA,yCADA,sC0BlsGI,YAAA,EAGF,yCACE,aAAA,EAIJ,0CAAA,+BACE,cAAA,QACA,aAAA,QAGF,0CAAA,+BACE,cAAA,OACA,aAAA,OAoBF,oBACE,mBAAA,OAAA,eAAA,OACA,eAAA,MAAA,YAAA,WACA,cAAA,OAAA,gBAAA,OAHF,yB1B4rGA,+B0BrrGI,MAAA,K1B0rGJ,iD0BjsGA,2CAYI,WAAA,K1B0rGJ,qD0BtsGA,gElBlFI,2BAAA,EACA,0BAAA,ER6xGJ,sD0B5sGA,2ClBhGI,uBAAA,EACA,wBAAA,EkBuIJ,uB1B0qGA,kC0BvqGI,cAAA,E1B4qGJ,4C0B/qGA,yC1BirGA,uDADA,oD0BzqGM,SAAA,SACA,KAAA,cACA,eAAA,KCzJN,aACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,QAAA,YAAA,QACA,MAAA,K3Bg1GF,0BADA,4B2Bp1GA,2B3Bm1GA,qC2Bx0GI,SAAA,SACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KAGA,MAAA,GACA,cAAA,E3Bw1GJ,uCADA,yCADA,wCADA,yCADA,2CADA,0CAJA,wCADA,0C2B91GA,yC3Bk2GA,kDADA,oDADA,mD2B30GM,YAAA,K3By1GN,sEADA,kC2B72GA,iCA6BI,QAAA,EA7BJ,mDAkCI,QAAA,E3Bq1GJ,6C2Bv3GA,4CnBeI,wBAAA,EACA,2BAAA,ER62GJ,8C2B73GA,6CnB6BI,uBAAA,EACA,0BAAA,EmB9BJ,0BA8CI,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OA/CJ,8D3B04GA,qEQ33GI,wBAAA,EACA,2BAAA,EmBhBJ,+DnB6BI,uBAAA,EACA,0BAAA,ERu3GJ,oB2Bv1GA,qBAEE,QAAA,YAAA,QAAA,K3B21GF,yB2B71GA,0BAQI,SAAA,SACA,QAAA,E3B01GJ,+B2Bn2GA,gCAYM,QAAA,E3B+1GN,8BACA,2CAEA,2CADA,wD2B72GA,+B3Bw2GA,4CAEA,4CADA,yD2Br1GI,YAAA,KAIJ,qBAAuB,aAAA,KACvB,oBAAsB,YAAA,KAQtB,kBACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,QAAA,QAAA,OACA,cAAA,E1BsBI,UAAA,K0BpBJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,WAAA,OACA,YAAA,OACA,iBAAA,QACA,OAAA,IAAA,MAAA,QnB5GE,cAAA,OR48GJ,uC2B52GA,oCAkBI,WAAA,E3B+1GJ,+B2Br1GA,4CAEE,OAAA,yB3Bw1GF,+B2Br1GA,8B3By1GA,yCAFA,sDACA,0CAFA,uD2Bh1GE,QAAA,MAAA,K1BbI,UAAA,Q0BeJ,YAAA,InBzIE,cAAA,MRk+GJ,+B2Br1GA,4CAEE,OAAA,0B3Bw1GF,+B2Br1GA,8B3By1GA,yCAFA,sDACA,0CAFA,uD2Bh1GE,QAAA,OAAA,M1B9BI,UAAA,Q0BgCJ,YAAA,InB1JE,cAAA,MmB8JJ,+B3Bq1GA,+B2Bn1GE,cAAA,Q3B21GF,wFACA,+EAHA,uDACA,oE2B/0GA,uC3B60GA,oDQx+GI,wBAAA,EACA,2BAAA,EmBmKJ,sC3B80GA,mDAGA,qEACA,kFAHA,yDACA,sEQt+GI,uBAAA,EACA,0BAAA,EoB3BJ,gBACE,SAAA,SACA,QAAA,MACA,WAAA,OACA,aAAA,OAGF,uBACE,QAAA,mBAAA,QAAA,YACA,aAAA,KAGF,sBACE,SAAA,SACA,QAAA,GACA,QAAA,EAHF,4DAMI,MAAA,KACA,aAAA,QTtBA,iBAAA,QSeJ,0DAiBM,WAAA,EAAA,EAAA,EAAA,MAAA,oBAjBN,wEAsBI,aAAA,QAtBJ,0EA0BI,MAAA,KACA,iBAAA,QACA,aAAA,QA5BJ,qDAkCM,MAAA,QAlCN,6DAqCQ,iBAAA,QAUR,sBACE,SAAA,SACA,cAAA,EACA,eAAA,IAHF,8BAOI,SAAA,SACA,IAAA,OACA,KAAA,QACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,eAAA,KACA,QAAA,GACA,iBAAA,KACA,OAAA,QAAA,MAAA,IAhBJ,6BAsBI,SAAA,SACA,IAAA,OACA,KAAA,QACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,QAAA,GACA,WAAA,UAAA,GAAA,CAAA,IAAA,IASJ,+CpBrGI,cAAA,OoBqGJ,4EAOM,iBAAA,4LAPN,mFAaM,aAAA,QTjHF,iBAAA,QSoGJ,kFAkBM,iBAAA,yIAlBN,sFAwBM,iBAAA,mBAxBN,4FA2BM,iBAAA,mBASN,4CAGI,cAAA,IAHJ,yEAQM,iBAAA,sIARN,mFAcM,iBAAA,mBAUN,eACE,aAAA,QADF,6CAKM,KAAA,SACA,MAAA,QACA,eAAA,IAEA,cAAA,MATN,4CAaM,IAAA,mBACA,KAAA,qBACA,MAAA,iBACA,OAAA,iBACA,iBAAA,QAEA,cAAA,MXnLA,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,WAAA,CAAA,kBAAA,KAAA,YAAA,WAAA,UAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAAA,WAAA,UAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,WAAA,CAAA,kBAAA,KAAA,YAKF,uCW2JJ,4CX1JM,WAAA,MW0JN,0EA0BM,iBAAA,KACA,kBAAA,mBAAA,UAAA,mBA3BN,oFAiCM,iBAAA,mBAYN,eACE,QAAA,aACA,MAAA,KACA,OAAA,2BACA,QAAA,QAAA,QAAA,QAAA,O3BxFI,UAAA,K2B2FJ,YAAA,IACA,YAAA,IACA,MAAA,QACA,eAAA,OACA,WAAA,0JAAA,UAAA,MAAA,OAAA,MAAA,CAAA,IAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,QpB3NE,cAAA,OoB8NF,mBAAA,KAAA,gBAAA,KAAA,WAAA,KAhBF,qBAmBI,aAAA,QACA,QAAA,EAIE,WAAA,EAAA,EAAA,EAAA,MAAA,oBAxBN,gCAiCM,MAAA,QACA,iBAAA,KAlCN,yBAAA,qCAwCI,OAAA,KACA,cAAA,OACA,iBAAA,KA1CJ,wBA8CI,MAAA,QACA,iBAAA,QA/CJ,2BAoDI,QAAA,KAIJ,kBACE,OAAA,0BACA,YAAA,OACA,eAAA,OACA,aAAA,M3BhJI,UAAA,Q2BoJN,kBACE,OAAA,yBACA,YAAA,MACA,eAAA,MACA,aAAA,K3BxJI,UAAA,Q2BiKN,aACE,SAAA,SACA,QAAA,aACA,MAAA,KACA,OAAA,2BACA,cAAA,EAGF,mBACE,SAAA,SACA,QAAA,EACA,MAAA,KACA,OAAA,2BACA,OAAA,EACA,QAAA,EANF,4CASI,aAAA,QACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAVJ,+CAcI,iBAAA,QAdJ,sDAmBM,QAAA,SAnBN,0DAwBI,QAAA,kBAIJ,mBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,KAAA,EACA,QAAA,EACA,OAAA,2BACA,QAAA,QAAA,OAEA,YAAA,IACA,YAAA,IACA,MAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,QpB5UE,cAAA,OoB+TJ,0BAkBI,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,QAAA,EACA,QAAA,MACA,OAAA,qBACA,QAAA,QAAA,OACA,YAAA,IACA,MAAA,QACA,QAAA,ST1VA,iBAAA,QS4VA,YAAA,QpB7VA,cAAA,EAAA,OAAA,OAAA,EoBwWJ,cACE,MAAA,KACA,OAAA,mBACA,QAAA,EACA,iBAAA,YACA,mBAAA,KAAA,gBAAA,KAAA,WAAA,KALF,oBAQI,QAAA,EARJ,0CAY8B,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,MAAA,oBAZ9B,sCAa8B,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,MAAA,oBAb9B,+BAc8B,WAAA,EAAA,EAAA,EAAA,IAAA,IAAA,CAAA,EAAA,EAAA,EAAA,MAAA,oBAd9B,gCAkBI,OAAA,EAlBJ,oCAsBI,MAAA,KACA,OAAA,KACA,WAAA,QT/XA,iBAAA,QSiYA,OAAA,EpBlYA,cAAA,KSCE,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YWqYF,mBAAA,KAAA,WAAA,KXhYA,uCWkWJ,oCXjWM,WAAA,MWiWN,2CTvWI,iBAAA,QSuWJ,6CAsCI,MAAA,KACA,OAAA,MACA,MAAA,YACA,OAAA,QACA,iBAAA,QACA,aAAA,YpBnZA,cAAA,KoBwWJ,gCAiDI,MAAA,KACA,OAAA,KTzZA,iBAAA,QS2ZA,OAAA,EpB5ZA,cAAA,KSCE,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YW+ZF,gBAAA,KAAA,WAAA,KX1ZA,uCWkWJ,gCXjWM,WAAA,MWiWN,uCTvWI,iBAAA,QSuWJ,gCAgEI,MAAA,KACA,OAAA,MACA,MAAA,YACA,OAAA,QACA,iBAAA,QACA,aAAA,YpB7aA,cAAA,KoBwWJ,yBA2EI,MAAA,KACA,OAAA,KACA,WAAA,EACA,aAAA,MACA,YAAA,MTtbA,iBAAA,QSwbA,OAAA,EpBzbA,cAAA,KSCE,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YW4bF,WAAA,KXvbA,uCWkWJ,yBXjWM,WAAA,MWiWN,gCTvWI,iBAAA,QSuWJ,yBA6FI,MAAA,KACA,OAAA,MACA,MAAA,YACA,OAAA,QACA,iBAAA,YACA,aAAA,YACA,aAAA,MAnGJ,8BAwGI,iBAAA,QpBhdA,cAAA,KoBwWJ,8BA6GI,aAAA,KACA,iBAAA,QpBtdA,cAAA,KoBwWJ,6CAoHM,iBAAA,QApHN,sDAwHM,OAAA,QAxHN,yCA4HM,iBAAA,QA5HN,yCAgIM,OAAA,QAhIN,kCAoIM,iBAAA,QAKN,8B5Bi9GA,mBACA,eiBl8HM,WAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAKF,uCW2eJ,8B5Bw9GE,mBACA,eiBn8HI,WAAA,MYPN,KACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,aAAA,EACA,cAAA,EACA,WAAA,KAGF,UACE,QAAA,MACA,QAAA,MAAA,K1BCA,gBAAA,gB0BEE,gBAAA,KALJ,mBAUI,MAAA,QACA,eAAA,KACA,OAAA,QAQJ,UACE,cAAA,IAAA,MAAA,QADF,oBAII,cAAA,KAJJ,oBAQI,OAAA,IAAA,MAAA,YrB3BA,uBAAA,OACA,wBAAA,OLCF,0BAAA,0B0B6BI,aAAA,QAAA,QAAA,QAZN,6BAgBM,MAAA,QACA,iBAAA,YACA,aAAA,Y7Bm9HN,mC6Br+HA,2BAwBI,MAAA,QACA,iBAAA,KACA,aAAA,QAAA,QAAA,KA1BJ,yBA+BI,WAAA,KrBlDA,uBAAA,EACA,wBAAA,EqB4DJ,qBrBtEI,cAAA,OqBsEJ,4B7B48HA,2B6Br8HI,MAAA,KACA,iBAAA,QASJ,oBAEI,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,WAAA,OAIJ,yBAEI,wBAAA,EAAA,WAAA,EACA,kBAAA,EAAA,UAAA,EACA,WAAA,OASJ,uBAEI,QAAA,KAFJ,qBAKI,QAAA,MCpGJ,QACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,cACA,QAAA,MAAA,KANF,mB9B+iIA,yB8BniII,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,QAAA,gBAAA,cASJ,cACE,QAAA,aACA,YAAA,SACA,eAAA,SACA,aAAA,K7BkFI,UAAA,Q6BhFJ,YAAA,QACA,YAAA,O3BhCA,oBAAA,oB2BmCE,gBAAA,KASJ,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,aAAA,EACA,cAAA,EACA,WAAA,KALF,sBAQI,cAAA,EACA,aAAA,EATJ,2BAaI,SAAA,OACA,MAAA,KASJ,aACE,QAAA,aACA,YAAA,MACA,eAAA,MAYF,iBACE,wBAAA,KAAA,WAAA,KACA,kBAAA,EAAA,UAAA,EAGA,eAAA,OAAA,YAAA,OAIF,gBACE,QAAA,OAAA,O7BmBI,UAAA,Q6BjBJ,YAAA,EACA,iBAAA,YACA,OAAA,IAAA,MAAA,YtB3GE,cAAA,OLWF,sBAAA,sB2BoGE,gBAAA,KAMJ,qBACE,QAAA,aACA,MAAA,MACA,OAAA,MACA,eAAA,OACA,QAAA,GACA,WAAA,UAAA,OAAA,OACA,gBAAA,KAAA,KlBxDE,4BkBkEC,6B9B0gIH,mC8BtgIQ,cAAA,EACA,aAAA,GlBpFN,yBkB+EA,kBAUI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WAXH,8BAcK,mBAAA,IAAA,eAAA,IAdL,6CAiBO,SAAA,SAjBP,wCAqBO,cAAA,MACA,aAAA,MAtBP,6B9BmiIH,mC8BtgIQ,cAAA,OAAA,UAAA,OA7BL,mCAiCK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KApCL,kCAwCK,QAAA,MlB1GN,4BkBkEC,6B9BojIH,mC8BhjIQ,cAAA,EACA,aAAA,GlBpFN,yBkB+EA,kBAUI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WAXH,8BAcK,mBAAA,IAAA,eAAA,IAdL,6CAiBO,SAAA,SAjBP,wCAqBO,cAAA,MACA,aAAA,MAtBP,6B9B6kIH,mC8BhjIQ,cAAA,OAAA,UAAA,OA7BL,mCAiCK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KApCL,kCAwCK,QAAA,MlB1GN,4BkBkEC,6B9B8lIH,mC8B1lIQ,cAAA,EACA,aAAA,GlBpFN,yBkB+EA,kBAUI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WAXH,8BAcK,mBAAA,IAAA,eAAA,IAdL,6CAiBO,SAAA,SAjBP,wCAqBO,cAAA,MACA,aAAA,MAtBP,6B9BunIH,mC8B1lIQ,cAAA,OAAA,UAAA,OA7BL,mCAiCK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KApCL,kCAwCK,QAAA,MlB1GN,6BkBkEC,6B9BwoIH,mC8BpoIQ,cAAA,EACA,aAAA,GlBpFN,0BkB+EA,kBAUI,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WAXH,8BAcK,mBAAA,IAAA,eAAA,IAdL,6CAiBO,SAAA,SAjBP,wCAqBO,cAAA,MACA,aAAA,MAtBP,6B9BiqIH,mC8BpoIQ,cAAA,OAAA,UAAA,OA7BL,mCAiCK,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KApCL,kCAwCK,QAAA,MA7CV,eAeQ,cAAA,IAAA,OAAA,UAAA,IAAA,OACA,cAAA,MAAA,gBAAA,WAhBR,0B9B6rIA,gC8BprIU,cAAA,EACA,aAAA,EAVV,2BAmBU,mBAAA,IAAA,eAAA,IAnBV,0CAsBY,SAAA,SAtBZ,qCA0BY,cAAA,MACA,aAAA,MA3BZ,0B9BitIA,gC8B/qIU,cAAA,OAAA,UAAA,OAlCV,gCAsCU,QAAA,sBAAA,QAAA,eAGA,wBAAA,KAAA,WAAA,KAzCV,+BA6CU,QAAA,KAaV,4BAEI,MAAA,e3BlLF,kCAAA,kC2BqLI,MAAA,eALN,oCAWM,MAAA,e3B3LJ,0CAAA,0C2B8LM,MAAA,eAdR,6CAkBQ,MAAA,e9B0qIR,4CAEA,2CADA,yC8B7rIA,0CA0BM,MAAA,eA1BN,8BA+BI,MAAA,eACA,aAAA,eAhCJ,mCAoCI,iBAAA,uOApCJ,2BAwCI,MAAA,eAxCJ,6BA0CM,MAAA,e3B1NJ,mCAAA,mC2B6NM,MAAA,eAOR,2BAEI,MAAA,K3BtOF,iCAAA,iC2ByOI,MAAA,KALN,mCAWM,MAAA,qB3B/OJ,yCAAA,yC2BkPM,MAAA,sBAdR,4CAkBQ,MAAA,sB9BsqIR,2CAEA,0CADA,wC8BzrIA,yCA0BM,MAAA,KA1BN,6BA+BI,MAAA,qBACA,aAAA,qBAhCJ,kCAoCI,iBAAA,6OApCJ,0BAwCI,MAAA,qBAxCJ,4BA0CM,MAAA,K3B9QJ,kCAAA,kC2BiRM,MAAA,KC7RR,MACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,UAAA,EACA,UAAA,WACA,iBAAA,KACA,gBAAA,WACA,OAAA,IAAA,MAAA,iBvBPE,cAAA,OuBDJ,SAYI,aAAA,EACA,YAAA,EAbJ,2DvBUI,uBAAA,OACA,wBAAA,OuBXJ,yDvBwBI,2BAAA,OACA,0BAAA,OuBIJ,WAGE,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,QAAA,QAIF,YACE,cAAA,OAGF,eACE,WAAA,SACA,cAAA,EAGF,sBACE,cAAA,E5BvCA,iB4B4CE,gBAAA,KAFJ,sBAMI,YAAA,QAQJ,aACE,QAAA,OAAA,QACA,cAAA,EAEA,iBAAA,gBACA,cAAA,IAAA,MAAA,iBALF,yBvB/DI,cAAA,mBAAA,mBAAA,EAAA,EuB+DJ,sDAaM,WAAA,EAKN,aACE,QAAA,OAAA,QACA,iBAAA,gBACA,WAAA,IAAA,MAAA,iBAHF,wBvBjFI,cAAA,EAAA,EAAA,mBAAA,mBuBgGJ,kBACE,aAAA,SACA,cAAA,QACA,YAAA,SACA,cAAA,EAGF,mBACE,aAAA,SACA,YAAA,SAIF,kBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,QAGF,UACE,MAAA,KvBvHE,cAAA,mBuB4HJ,cACE,MAAA,KvBpHE,uBAAA,mBACA,wBAAA,mBuBuHJ,iBACE,MAAA,KvB3GE,2BAAA,mBACA,0BAAA,mBuBiHJ,WACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OAFF,iBAKI,cAAA,KnBvFA,yBmBkFJ,WASI,cAAA,IAAA,KAAA,UAAA,IAAA,KACA,aAAA,MACA,YAAA,MAXJ,iBAcM,QAAA,YAAA,QAAA,KAEA,SAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA,GACA,mBAAA,OAAA,eAAA,OACA,aAAA,KACA,cAAA,EACA,YAAA,MAUN,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OAFF,kBAOI,cAAA,KnBvHA,yBmBgHJ,YAWI,cAAA,IAAA,KAAA,UAAA,IAAA,KAXJ,kBAgBM,SAAA,EAAA,EAAA,GAAA,KAAA,EAAA,EAAA,GACA,cAAA,EAjBN,wBAoBQ,YAAA,EACA,YAAA,EArBR,mCvBvJI,wBAAA,EACA,2BAAA,ERqmJF,gD+B/8IF,iDAgCY,wBAAA,E/Bm7IV,gD+Bn9IF,oDAqCY,2BAAA,EArCZ,oCvBzII,uBAAA,EACA,0BAAA,ERmmJF,iD+B39IF,kDA+CY,uBAAA,E/Bg7IV,iD+B/9IF,qDAoDY,0BAAA,GAaZ,oBAEI,cAAA,OnBnLA,yBmBiLJ,cAMI,qBAAA,EAAA,kBAAA,EAAA,aAAA,EACA,mBAAA,QAAA,gBAAA,QAAA,WAAA,QACA,QAAA,EACA,OAAA,EATJ,oBAYM,QAAA,aACA,MAAA,MAUN,iBAEI,SAAA,OAFJ,8DvB/PI,cAAA,EuB+PJ,wDAUQ,cAAA,EvBzQJ,cAAA,EuB+PJ,+BAgBM,cAAA,EvBxPF,2BAAA,EACA,0BAAA,EuBuOJ,8BvBtPI,uBAAA,EACA,wBAAA,EuBqPJ,8BAyBM,cAAA,KC7RN,YACE,QAAA,YAAA,QAAA,KACA,cAAA,KAAA,UAAA,KACA,QAAA,OAAA,KACA,cAAA,KACA,WAAA,KACA,iBAAA,QxBDE,cAAA,OwBKJ,kCAGI,aAAA,MAHJ,0CAMM,QAAA,aACA,cAAA,MACA,MAAA,QACA,QAAA,IATN,gDAoBI,gBAAA,UApBJ,gDAwBI,gBAAA,KAxBJ,wBA4BI,MAAA,QCtCJ,YACE,QAAA,YAAA,QAAA,K5BGA,aAAA,EACA,WAAA,KGAE,cAAA,OyBCJ,WACE,SAAA,SACA,QAAA,MACA,QAAA,MAAA,OACA,YAAA,KACA,YAAA,KACA,MAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,QARF,iBAWI,QAAA,EACA,MAAA,QACA,gBAAA,KACA,iBAAA,QACA,aAAA,QAfJ,iBAmBI,QAAA,EACA,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBAIJ,kCAGM,YAAA,EzBCF,uBAAA,OACA,0BAAA,OyBLJ,iCzBVI,wBAAA,OACA,2BAAA,OyBSJ,6BAcI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QAjBJ,+BAqBI,MAAA,QACA,eAAA,KAEA,OAAA,KACA,iBAAA,KACA,aAAA,QCtDF,0BACE,QAAA,OAAA,OjC2HE,UAAA,QiCzHF,YAAA,IAKE,iD1BwBF,uBAAA,MACA,0BAAA,M0BpBE,gD1BKF,wBAAA,MACA,2BAAA,M0BnBF,0BACE,QAAA,OAAA,MjC2HE,UAAA,QiCzHF,YAAA,IAKE,iD1BwBF,uBAAA,MACA,0BAAA,M0BpBE,gD1BKF,wBAAA,MACA,2BAAA,M2BjBJ,OACE,QAAA,aACA,QAAA,MAAA,KlCiEE,UAAA,IkC/DF,YAAA,IACA,YAAA,EACA,WAAA,OACA,YAAA,OACA,eAAA,S3BRE,cAAA,OSCE,WAAA,MAAA,KAAA,WAAA,CAAA,iBAAA,KAAA,WAAA,CAAA,aAAA,KAAA,WAAA,CAAA,WAAA,KAAA,YAKF,uCkBNJ,OlBOM,WAAA,MdIJ,cAAA,cgCGI,gBAAA,KAdN,aAoBI,QAAA,KAKJ,YACE,SAAA,SACA,IAAA,KAOF,YACE,cAAA,KACA,aAAA,K3BpCE,cAAA,M2B6CF,eCjDA,MAAA,KACA,iBAAA,QjCcA,sBAAA,sBiCVI,MAAA,KACA,iBAAA,QAHI,sBAAA,sBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,iBCjDA,MAAA,KACA,iBAAA,QjCcA,wBAAA,wBiCVI,MAAA,KACA,iBAAA,QAHI,wBAAA,wBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,qBDqCJ,eCjDA,MAAA,KACA,iBAAA,QjCcA,sBAAA,sBiCVI,MAAA,KACA,iBAAA,QAHI,sBAAA,sBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,YCjDA,MAAA,KACA,iBAAA,QjCcA,mBAAA,mBiCVI,MAAA,KACA,iBAAA,QAHI,mBAAA,mBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,oBDqCJ,eCjDA,MAAA,QACA,iBAAA,QjCcA,sBAAA,sBiCVI,MAAA,QACA,iBAAA,QAHI,sBAAA,sBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,cCjDA,MAAA,KACA,iBAAA,QjCcA,qBAAA,qBiCVI,MAAA,KACA,iBAAA,QAHI,qBAAA,qBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,mBDqCJ,aCjDA,MAAA,QACA,iBAAA,QjCcA,oBAAA,oBiCVI,MAAA,QACA,iBAAA,QAHI,oBAAA,oBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,qBDqCJ,YCjDA,MAAA,KACA,iBAAA,QjCcA,mBAAA,mBiCVI,MAAA,KACA,iBAAA,QAHI,mBAAA,mBAQJ,QAAA,EACA,WAAA,EAAA,EAAA,EAAA,MAAA,kBCbN,WACE,QAAA,KAAA,KACA,cAAA,KAEA,iBAAA,Q7BCE,cAAA,MIuDA,yByB5DJ,WAQI,QAAA,KAAA,MAIJ,iBACE,cAAA,EACA,aAAA,E7BTE,cAAA,E8BDJ,OACE,SAAA,SACA,QAAA,OAAA,QACA,cAAA,KACA,OAAA,IAAA,MAAA,Y9BHE,cAAA,O8BQJ,eAEE,MAAA,QAIF,YACE,YAAA,IAQF,mBACE,cAAA,KADF,0BAKI,SAAA,SACA,IAAA,EACA,MAAA,EACA,QAAA,OAAA,QACA,MAAA,QAUF,eC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDqCF,iBC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,oBACE,iBAAA,QAGF,6BACE,MAAA,QDqCF,eC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDqCF,YC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,eACE,iBAAA,QAGF,wBACE,MAAA,QDqCF,eC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,kBACE,iBAAA,QAGF,2BACE,MAAA,QDqCF,cC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,iBACE,iBAAA,QAGF,0BACE,MAAA,QDqCF,aC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,gBACE,iBAAA,QAGF,yBACE,MAAA,QDqCF,YC9CA,MAAA,QpBKE,iBAAA,QoBHF,aAAA,QAEA,eACE,iBAAA,QAGF,wBACE,MAAA,QCRF,wCACE,KAAO,oBAAA,KAAA,EACP,GAAK,oBAAA,EAAA,GAFP,gCACE,KAAO,oBAAA,KAAA,EACP,GAAK,oBAAA,EAAA,GAIT,UACE,QAAA,YAAA,QAAA,KACA,OAAA,KACA,SAAA,OvCoHI,UAAA,OuClHJ,iBAAA,QhCRE,cAAA,OgCaJ,cACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,iBAAA,QvBnBI,WAAA,MAAA,IAAA,KAKF,uCuBOJ,cvBNM,WAAA,MuBiBN,sBrBcE,iBAAA,iKqBZA,gBAAA,KAAA,KAIA,uBACE,kBAAA,qBAAA,GAAA,OAAA,SAAA,UAAA,qBAAA,GAAA,OAAA,SAEA,uCAHF,uBAII,kBAAA,KAAA,UAAA,MCvCN,OACE,QAAA,YAAA,QAAA,KACA,eAAA,MAAA,YAAA,WAGF,YACE,SAAA,EAAA,KAAA,ECFF,YACE,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OAGA,aAAA,EACA,cAAA,EASF,wBACE,MAAA,KACA,MAAA,QACA,WAAA,QvCNA,8BAAA,8BuCUE,QAAA,EACA,MAAA,QACA,gBAAA,KACA,iBAAA,QAVJ,+BAcI,MAAA,QACA,iBAAA,QASJ,iBACE,SAAA,SACA,QAAA,MACA,QAAA,OAAA,QAEA,cAAA,KAEA,iBAAA,KACA,OAAA,IAAA,MAAA,iBARF,6BlC7BI,uBAAA,OACA,wBAAA,OkC4BJ,4BAeI,cAAA,ElC9BA,2BAAA,OACA,0BAAA,OkCcJ,0BAAA,0BAqBI,MAAA,QACA,eAAA,KACA,iBAAA,KAvBJ,wBA4BI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QAaA,uBACE,mBAAA,IAAA,eAAA,IADF,wCAII,aAAA,KACA,cAAA,EALJ,oDlCpDA,uBAAA,OACA,0BAAA,OAYA,wBAAA,EkCuCA,mDAaM,aAAA,ElC/EN,wBAAA,OACA,2BAAA,OAsCA,0BAAA,EIAA,yB8B2BA,0BACE,mBAAA,IAAA,eAAA,IADF,2CAII,aAAA,KACA,cAAA,EALJ,uDlCpDA,uBAAA,OACA,0BAAA,OAYA,wBAAA,EkCuCA,sDAaM,aAAA,ElC/EN,wBAAA,OACA,2BAAA,OAsCA,0BAAA,GIAA,yB8B2BA,0BACE,mBAAA,IAAA,eAAA,IADF,2CAII,aAAA,KACA,cAAA,EALJ,uDlCpDA,uBAAA,OACA,0BAAA,OAYA,wBAAA,EkCuCA,sDAaM,aAAA,ElC/EN,wBAAA,OACA,2BAAA,OAsCA,0BAAA,GIAA,yB8B2BA,0BACE,mBAAA,IAAA,eAAA,IADF,2CAII,aAAA,KACA,cAAA,EALJ,uDlCpDA,uBAAA,OACA,0BAAA,OAYA,wBAAA,EkCuCA,sDAaM,aAAA,ElC/EN,wBAAA,OACA,2BAAA,OAsCA,0BAAA,GIAA,0B8B2BA,0BACE,mBAAA,IAAA,eAAA,IADF,2CAII,aAAA,KACA,cAAA,EALJ,uDlCpDA,uBAAA,OACA,0BAAA,OAYA,wBAAA,EkCuCA,sDAaM,aAAA,ElC/EN,wBAAA,OACA,2BAAA,OAsCA,0BAAA,GkCuDJ,mCAEI,aAAA,EACA,YAAA,ElCjHA,cAAA,EkC8GJ,8CAOM,cAAA,KAPN,2DAaM,WAAA,EAbN,yDAmBM,cAAA,EACA,cAAA,ECpIJ,yBACE,MAAA,QACA,iBAAA,QxCWF,sDAAA,sDwCPM,MAAA,QACA,iBAAA,QAPN,uDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,2BACE,MAAA,QACA,iBAAA,QxCWF,wDAAA,wDwCPM,MAAA,QACA,iBAAA,QAPN,yDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,yBACE,MAAA,QACA,iBAAA,QxCWF,sDAAA,sDwCPM,MAAA,QACA,iBAAA,QAPN,uDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,sBACE,MAAA,QACA,iBAAA,QxCWF,mDAAA,mDwCPM,MAAA,QACA,iBAAA,QAPN,oDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,yBACE,MAAA,QACA,iBAAA,QxCWF,sDAAA,sDwCPM,MAAA,QACA,iBAAA,QAPN,uDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,wBACE,MAAA,QACA,iBAAA,QxCWF,qDAAA,qDwCPM,MAAA,QACA,iBAAA,QAPN,sDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,uBACE,MAAA,QACA,iBAAA,QxCWF,oDAAA,oDwCPM,MAAA,QACA,iBAAA,QAPN,qDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QAbN,sBACE,MAAA,QACA,iBAAA,QxCWF,mDAAA,mDwCPM,MAAA,QACA,iBAAA,QAPN,oDAWM,MAAA,KACA,iBAAA,QACA,aAAA,QChBR,OACE,MAAA,M3C8HI,UAAA,O2C5HJ,YAAA,IACA,YAAA,EACA,MAAA,KACA,YAAA,EAAA,IAAA,EAAA,KACA,QAAA,GzCKA,ayCDE,MAAA,KACA,gBAAA,KzCIF,2CAAA,2CyCCI,QAAA,IAWN,aACE,QAAA,EACA,iBAAA,YACA,OAAA,EACA,mBAAA,KAAA,gBAAA,KAAA,WAAA,KAMF,iBACE,eAAA,KCvCF,OACE,UAAA,MACA,SAAA,O5C6HI,UAAA,Q4C1HJ,iBAAA,sBACA,gBAAA,YACA,OAAA,IAAA,MAAA,eACA,WAAA,EAAA,OAAA,OAAA,eACA,wBAAA,WAAA,gBAAA,WACA,QAAA,ErCLE,cAAA,OqCLJ,wBAcI,cAAA,OAdJ,eAkBI,QAAA,EAlBJ,YAsBI,QAAA,MACA,QAAA,EAvBJ,YA2BI,QAAA,KAIJ,cACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,QAAA,OAAA,OACA,MAAA,QACA,iBAAA,sBACA,gBAAA,YACA,cAAA,IAAA,MAAA,gBAGF,YACE,QAAA,OCpCF,YAEE,SAAA,OAFF,mBAKI,WAAA,OACA,WAAA,KAKJ,OACE,SAAA,MACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,OAAA,KACA,SAAA,OAGA,QAAA,EAOF,cACE,SAAA,SACA,MAAA,KACA,OAAA,MAEA,eAAA,KAGA,0B7BrCI,WAAA,kBAAA,IAAA,SAAA,WAAA,UAAA,IAAA,SAAA,WAAA,UAAA,IAAA,QAAA,CAAA,kBAAA,IAAA,S6BuCF,kBAAA,mBAAA,UAAA,mB7BlCA,uC6BgCF,0B7B/BI,WAAA,M6BmCJ,0BACE,kBAAA,KAAA,UAAA,KAIJ,yBACE,QAAA,YAAA,QAAA,KACA,WAAA,kBAFF,wCAKI,WAAA,mBACA,SAAA,O9CulLJ,uC8C7lLA,uCAWI,kBAAA,EAAA,YAAA,EAXJ,qCAeI,WAAA,KAIJ,uBACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,WAAA,kBAHF,+BAOI,QAAA,MACA,OAAA,mBACA,QAAA,GATJ,+CAcI,mBAAA,OAAA,eAAA,OACA,cAAA,OAAA,gBAAA,OACA,OAAA,KAhBJ,8DAmBM,WAAA,KAnBN,uDAuBM,QAAA,KAMN,eACE,SAAA,SACA,QAAA,YAAA,QAAA,KACA,mBAAA,OAAA,eAAA,OACA,MAAA,KAGA,eAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,etCzGE,cAAA,MsC6GF,QAAA,EAIF,gBACE,SAAA,MACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,MAAA,MACA,OAAA,MACA,iBAAA,KAPF,qBAUW,QAAA,EAVX,qBAWW,QAAA,GAKX,cACE,QAAA,YAAA,QAAA,KACA,eAAA,MAAA,YAAA,WACA,cAAA,QAAA,gBAAA,cACA,QAAA,KAAA,KACA,cAAA,IAAA,MAAA,QtC7HE,uBAAA,MACA,wBAAA,MsCuHJ,qBASI,QAAA,KAAA,KAEA,OAAA,MAAA,MAAA,MAAA,KAKJ,aACE,cAAA,EACA,YAAA,IAKF,YACE,SAAA,SAGA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,QAAA,KAIF,cACE,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,IAAA,gBAAA,SACA,QAAA,KACA,WAAA,IAAA,MAAA,QtC/IE,2BAAA,MACA,0BAAA,MsCyIJ,iCASyB,YAAA,OATzB,gCAUwB,aAAA,OAIxB,yBACE,SAAA,SACA,IAAA,QACA,MAAA,KACA,OAAA,KACA,SAAA,OlC7HE,yBkCzBJ,cA6JI,UAAA,MACA,OAAA,QAAA,KA7IJ,yBAiJI,WAAA,oBAjJJ,wCAoJM,WAAA,qBAjIN,uBAsII,WAAA,oBAtIJ,+BAyIM,OAAA,qBAQJ,UAAY,UAAA,OlC5JV,yBkCgKF,U9CglLA,U8C9kLE,UAAA,OlClKA,0BkCuKF,UAAY,UAAA,QClOd,SACE,SAAA,SACA,QAAA,KACA,QAAA,MACA,OAAA,ECJA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBAEA,WAAA,OACA,YAAA,IACA,YAAA,IACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,YAAA,OACA,WAAA,K/CgHI,UAAA,Q8CpHJ,UAAA,WACA,QAAA,EAXF,cAaW,QAAA,GAbX,gBAgBI,SAAA,SACA,QAAA,MACA,MAAA,MACA,OAAA,MAnBJ,wBAsBM,SAAA,SACA,QAAA,GACA,aAAA,YACA,aAAA,MAKN,mCAAA,gBACE,QAAA,MAAA,EADF,0CAAA,uBAII,OAAA,EAJJ,kDAAA,+BAOM,IAAA,EACA,aAAA,MAAA,MAAA,EACA,iBAAA,KAKN,qCAAA,kBACE,QAAA,EAAA,MADF,4CAAA,yBAII,KAAA,EACA,MAAA,MACA,OAAA,MANJ,oDAAA,iCASM,MAAA,EACA,aAAA,MAAA,MAAA,MAAA,EACA,mBAAA,KAKN,sCAAA,mBACE,QAAA,MAAA,EADF,6CAAA,0BAII,IAAA,EAJJ,qDAAA,kCAOM,OAAA,EACA,aAAA,EAAA,MAAA,MACA,oBAAA,KAKN,oCAAA,iBACE,QAAA,EAAA,MADF,2CAAA,wBAII,MAAA,EACA,MAAA,MACA,OAAA,MANJ,mDAAA,gCASM,KAAA,EACA,aAAA,MAAA,EAAA,MAAA,MACA,kBAAA,KAqBN,eACE,UAAA,MACA,QAAA,OAAA,MACA,MAAA,KACA,WAAA,OACA,iBAAA,KvC3GE,cAAA,OyCLJ,SACE,SAAA,SACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,MACA,UAAA,MDLA,YAAA,aAAA,CAAA,kBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBAEA,WAAA,OACA,YAAA,IACA,YAAA,IACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,YAAA,OACA,WAAA,K/CgHI,UAAA,QgDnHJ,UAAA,WACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,ezCVE,cAAA,MyCLJ,gBAoBI,SAAA,SACA,QAAA,MACA,MAAA,KACA,OAAA,MACA,OAAA,EAAA,MAxBJ,uBAAA,wBA4BM,SAAA,SACA,QAAA,MACA,QAAA,GACA,aAAA,YACA,aAAA,MAKN,mCAAA,gBACE,cAAA,MADF,0CAAA,uBAII,OAAA,yBAJJ,kDAAA,+BAOM,OAAA,EACA,aAAA,MAAA,MAAA,EACA,iBAAA,gBATN,iDAAA,8BAaM,OAAA,IACA,aAAA,MAAA,MAAA,EACA,iBAAA,KAKN,qCAAA,kBACE,YAAA,MADF,4CAAA,yBAII,KAAA,yBACA,MAAA,MACA,OAAA,KACA,OAAA,MAAA,EAPJ,oDAAA,iCAUM,KAAA,EACA,aAAA,MAAA,MAAA,MAAA,EACA,mBAAA,gBAZN,mDAAA,gCAgBM,KAAA,IACA,aAAA,MAAA,MAAA,MAAA,EACA,mBAAA,KAKN,sCAAA,mBACE,WAAA,MADF,6CAAA,0BAII,IAAA,yBAJJ,qDAAA,kCAOM,IAAA,EACA,aAAA,EAAA,MAAA,MAAA,MACA,oBAAA,gBATN,oDAAA,iCAaM,IAAA,IACA,aAAA,EAAA,MAAA,MAAA,MACA,oBAAA,KAfN,8DAAA,2CAqBI,SAAA,SACA,IAAA,EACA,KAAA,IACA,QAAA,MACA,MAAA,KACA,YAAA,OACA,QAAA,GACA,cAAA,IAAA,MAAA,QAIJ,oCAAA,iBACE,aAAA,MADF,2CAAA,wBAII,MAAA,yBACA,MAAA,MACA,OAAA,KACA,OAAA,MAAA,EAPJ,mDAAA,gCAUM,MAAA,EACA,aAAA,MAAA,EAAA,MAAA,MACA,kBAAA,gBAZN,kDAAA,+BAgBM,MAAA,IACA,aAAA,MAAA,EAAA,MAAA,MACA,kBAAA,KAsBN,gBACE,QAAA,MAAA,OACA,cAAA,EhD3BI,UAAA,KgD8BJ,iBAAA,QACA,cAAA,IAAA,MAAA,QzChJE,uBAAA,kBACA,wBAAA,kByCyIJ,sBAWI,QAAA,KAIJ,cACE,QAAA,MAAA,OACA,MAAA,QC5JF,UACE,SAAA,SAGF,wBACE,iBAAA,MAAA,aAAA,MAGF,gBACE,SAAA,SACA,MAAA,KACA,SAAA,OCvBA,uBACE,QAAA,MACA,MAAA,KACA,QAAA,GDwBJ,eACE,SAAA,SACA,QAAA,KACA,MAAA,KACA,MAAA,KACA,aAAA,MACA,4BAAA,OAAA,oBAAA,OjC5BI,WAAA,kBAAA,IAAA,YAAA,WAAA,UAAA,IAAA,YAAA,WAAA,UAAA,IAAA,WAAA,CAAA,kBAAA,IAAA,YAKF,uCiCiBJ,ejChBM,WAAA,MjBomMN,oBACA,oBkD3kMA,sBAGE,QAAA,MlD6kMF,4BkD1kMA,6CAEE,kBAAA,iBAAA,UAAA,iBlD8kMF,2BkD3kMA,8CAEE,kBAAA,kBAAA,UAAA,kBAQF,8BAEI,QAAA,EACA,oBAAA,QACA,kBAAA,KAAA,UAAA,KlD0kMJ,sDACA,uDkD/kMA,qCAUI,QAAA,EACA,QAAA,EAXJ,0ClDqlMA,2CkDrkMI,QAAA,EACA,QAAA,EjCtEE,WAAA,GAAA,IAAA,QAKF,uCiCgDJ,0ClD6lME,2CiB5oMI,WAAA,MjBkpMN,uBkDxkMA,uBAEE,SAAA,SACA,IAAA,EACA,OAAA,EACA,QAAA,EAEA,QAAA,YAAA,QAAA,KACA,eAAA,OAAA,YAAA,OACA,cAAA,OAAA,gBAAA,OACA,MAAA,IACA,MAAA,KACA,WAAA,OACA,QAAA,GjC7FI,WAAA,QAAA,KAAA,KAKF,uCjBuqMF,uBkD5lMF,uBjC1EM,WAAA,MjB6qMN,6BADA,6BGxqME,6BAAA,6B+CwFE,MAAA,KACA,gBAAA,KACA,QAAA,EACA,QAAA,GAGJ,uBACE,KAAA,EAKF,uBACE,MAAA,ElDolMF,4BkD7kMA,4BAEE,QAAA,aACA,MAAA,KACA,OAAA,KACA,WAAA,UAAA,GAAA,CAAA,KAAA,KAEF,4BACE,iBAAA,kLAEF,4BACE,iBAAA,kLASF,qBACE,SAAA,SACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,GACA,QAAA,YAAA,QAAA,KACA,cAAA,OAAA,gBAAA,OACA,aAAA,EAEA,aAAA,IACA,YAAA,IACA,WAAA,KAZF,wBAeI,WAAA,YACA,SAAA,EAAA,EAAA,KAAA,KAAA,EAAA,EAAA,KACA,MAAA,KACA,OAAA,IACA,aAAA,IACA,YAAA,IACA,YAAA,OACA,OAAA,QACA,iBAAA,KACA,gBAAA,YAEA,WAAA,KAAA,MAAA,YACA,cAAA,KAAA,MAAA,YACA,QAAA,GjCtKE,WAAA,QAAA,IAAA,KAKF,uCiCqIJ,wBjCpIM,WAAA,MiCoIN,6BAiCI,QAAA,EASJ,kBACE,SAAA,SACA,MAAA,IACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,YAAA,KACA,eAAA,KACA,MAAA,KACA,WAAA,OE/LF,kCACE,GAAK,kBAAA,eAAA,UAAA,gBADP,0BACE,GAAK,kBAAA,eAAA,UAAA,gBAGP,gBACE,QAAA,aACA,MAAA,KACA,OAAA,KACA,eAAA,YACA,OAAA,MAAA,MAAA,aACA,mBAAA,YAEA,cAAA,IACA,kBAAA,eAAA,KAAA,OAAA,SAAA,UAAA,eAAA,KAAA,OAAA,SAGF,mBACE,MAAA,KACA,OAAA,KACA,aAAA,KAOF,gCACE,GACE,kBAAA,SAAA,UAAA,SAEF,IACE,QAAA,GALJ,wBACE,GACE,kBAAA,SAAA,UAAA,SAEF,IACE,QAAA,GAIJ,cACE,QAAA,aACA,MAAA,KACA,OAAA,KACA,eAAA,YACA,iBAAA,aAEA,cAAA,IACA,QAAA,EACA,kBAAA,aAAA,KAAA,OAAA,SAAA,UAAA,aAAA,KAAA,OAAA,SAGF,iBACE,MAAA,KACA,OAAA,KCnDF,gBAAqB,eAAA,mBACrB,WAAqB,eAAA,cACrB,cAAqB,eAAA,iBACrB,cAAqB,eAAA,iBACrB,mBAAqB,eAAA,sBACrB,gBAAqB,eAAA,mBCFnB,YACE,iBAAA,kBnDUF,mBAAA,mBHm2MF,wBADA,wBsDv2MM,iBAAA,kBANJ,cACE,iBAAA,kBnDUF,qBAAA,qBH62MF,0BADA,0BsDj3MM,iBAAA,kBANJ,YACE,iBAAA,kBnDUF,mBAAA,mBHu3MF,wBADA,wBsD33MM,iBAAA,kBANJ,SACE,iBAAA,kBnDUF,gBAAA,gBHi4MF,qBADA,qBsDr4MM,iBAAA,kBANJ,YACE,iBAAA,kBnDUF,mBAAA,mBH24MF,wBADA,wBsD/4MM,iBAAA,kBANJ,WACE,iBAAA,kBnDUF,kBAAA,kBHq5MF,uBADA,uBsDz5MM,iBAAA,kBANJ,UACE,iBAAA,kBnDUF,iBAAA,iBH+5MF,sBADA,sBsDn6MM,iBAAA,kBANJ,SACE,iBAAA,kBnDUF,gBAAA,gBHy6MF,qBADA,qBsD76MM,iBAAA,kBCCN,UACE,iBAAA,eAGF,gBACE,iBAAA,sBCXF,QAAkB,OAAA,IAAA,MAAA,kBAClB,YAAkB,WAAA,IAAA,MAAA,kBAClB,cAAkB,aAAA,IAAA,MAAA,kBAClB,eAAkB,cAAA,IAAA,MAAA,kBAClB,aAAkB,YAAA,IAAA,MAAA,kBAElB,UAAmB,OAAA,YACnB,cAAmB,WAAA,YACnB,gBAAmB,aAAA,YACnB,iBAAmB,cAAA,YACnB,eAAmB,YAAA,YAGjB,gBACE,aAAA,kBADF,kBACE,aAAA,kBADF,gBACE,aAAA,kBADF,aACE,aAAA,kBADF,gBACE,aAAA,kBADF,eACE,aAAA,kBADF,cACE,aAAA,kBADF,aACE,aAAA,kBAIJ,cACE,aAAA,eAOF,YACE,cAAA,gBAGF,SACE,cAAA,iBAGF,aACE,uBAAA,iBACA,wBAAA,iBAGF,eACE,wBAAA,iBACA,2BAAA,iBAGF,gBACE,2BAAA,iBACA,0BAAA,iBAGF,cACE,uBAAA,iBACA,0BAAA,iBAGF,YACE,cAAA,gBAGF,gBACE,cAAA,cAGF,cACE,cAAA,gBAGF,WACE,cAAA,YLxEA,iBACE,QAAA,MACA,MAAA,KACA,QAAA,GMOE,QAAwB,QAAA,eAAxB,UAAwB,QAAA,iBAAxB,gBAAwB,QAAA,uBAAxB,SAAwB,QAAA,gBAAxB,SAAwB,QAAA,gBAAxB,aAAwB,QAAA,oBAAxB,cAAwB,QAAA,qBAAxB,QAAwB,QAAA,sBAAA,QAAA,eAAxB,eAAwB,QAAA,6BAAA,QAAA,sB7CiD1B,yB6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uB7CiD1B,yB6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uB7CiD1B,yB6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uB7CiD1B,0B6CjDE,WAAwB,QAAA,eAAxB,aAAwB,QAAA,iBAAxB,mBAAwB,QAAA,uBAAxB,YAAwB,QAAA,gBAAxB,YAAwB,QAAA,gBAAxB,gBAAwB,QAAA,oBAAxB,iBAAwB,QAAA,qBAAxB,WAAwB,QAAA,sBAAA,QAAA,eAAxB,kBAAwB,QAAA,6BAAA,QAAA,uBAU9B,aAEI,cAAqB,QAAA,eAArB,gBAAqB,QAAA,iBAArB,sBAAqB,QAAA,uBAArB,eAAqB,QAAA,gBAArB,eAAqB,QAAA,gBAArB,mBAAqB,QAAA,oBAArB,oBAAqB,QAAA,qBAArB,cAAqB,QAAA,sBAAA,QAAA,eAArB,qBAAqB,QAAA,6BAAA,QAAA,uBCrBzB,kBACE,SAAA,SACA,QAAA,MACA,MAAA,KACA,QAAA,EACA,SAAA,OALF,0BAQI,QAAA,MACA,QAAA,GATJ,yC1DsxNA,wBADA,yBAEA,yBACA,wB0DvwNI,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,KACA,OAAA,KACA,OAAA,EAQF,gCAEI,YAAA,WAFJ,gCAEI,YAAA,OAFJ,+BAEI,YAAA,IAFJ,+BAEI,YAAA,KCzBF,UAAgC,mBAAA,cAAA,eAAA,cAChC,aAAgC,mBAAA,iBAAA,eAAA,iBAChC,kBAAgC,mBAAA,sBAAA,eAAA,sBAChC,qBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,WAA8B,cAAA,eAAA,UAAA,eAC9B,aAA8B,cAAA,iBAAA,UAAA,iBAC9B,mBAA8B,cAAA,uBAAA,UAAA,uBAC9B,WAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,aAA8B,kBAAA,YAAA,UAAA,YAC9B,aAA8B,kBAAA,YAAA,UAAA,YAC9B,eAA8B,kBAAA,YAAA,YAAA,YAC9B,eAA8B,kBAAA,YAAA,YAAA,YAE9B,uBAAoC,cAAA,gBAAA,gBAAA,qBACpC,qBAAoC,cAAA,cAAA,gBAAA,mBACpC,wBAAoC,cAAA,iBAAA,gBAAA,iBACpC,yBAAoC,cAAA,kBAAA,gBAAA,wBACpC,wBAAoC,cAAA,qBAAA,gBAAA,uBAEpC,mBAAiC,eAAA,gBAAA,YAAA,qBACjC,iBAAiC,eAAA,cAAA,YAAA,mBACjC,oBAAiC,eAAA,iBAAA,YAAA,iBACjC,sBAAiC,eAAA,mBAAA,YAAA,mBACjC,qBAAiC,eAAA,kBAAA,YAAA,kBAEjC,qBAAkC,mBAAA,gBAAA,cAAA,qBAClC,mBAAkC,mBAAA,cAAA,cAAA,mBAClC,sBAAkC,mBAAA,iBAAA,cAAA,iBAClC,uBAAkC,mBAAA,kBAAA,cAAA,wBAClC,sBAAkC,mBAAA,qBAAA,cAAA,uBAClC,uBAAkC,mBAAA,kBAAA,cAAA,kBAElC,iBAAgC,oBAAA,eAAA,WAAA,eAChC,kBAAgC,oBAAA,gBAAA,WAAA,qBAChC,gBAAgC,oBAAA,cAAA,WAAA,mBAChC,mBAAgC,oBAAA,iBAAA,WAAA,iBAChC,qBAAgC,oBAAA,mBAAA,WAAA,mBAChC,oBAAgC,oBAAA,kBAAA,WAAA,kB/CYhC,yB+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB/CYhC,yB+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB/CYhC,yB+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mB/CYhC,0B+ClDA,aAAgC,mBAAA,cAAA,eAAA,cAChC,gBAAgC,mBAAA,iBAAA,eAAA,iBAChC,qBAAgC,mBAAA,sBAAA,eAAA,sBAChC,wBAAgC,mBAAA,yBAAA,eAAA,yBAEhC,cAA8B,cAAA,eAAA,UAAA,eAC9B,gBAA8B,cAAA,iBAAA,UAAA,iBAC9B,sBAA8B,cAAA,uBAAA,UAAA,uBAC9B,cAA8B,SAAA,EAAA,EAAA,eAAA,KAAA,EAAA,EAAA,eAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,gBAA8B,kBAAA,YAAA,UAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAC9B,kBAA8B,kBAAA,YAAA,YAAA,YAE9B,0BAAoC,cAAA,gBAAA,gBAAA,qBACpC,wBAAoC,cAAA,cAAA,gBAAA,mBACpC,2BAAoC,cAAA,iBAAA,gBAAA,iBACpC,4BAAoC,cAAA,kBAAA,gBAAA,wBACpC,2BAAoC,cAAA,qBAAA,gBAAA,uBAEpC,sBAAiC,eAAA,gBAAA,YAAA,qBACjC,oBAAiC,eAAA,cAAA,YAAA,mBACjC,uBAAiC,eAAA,iBAAA,YAAA,iBACjC,yBAAiC,eAAA,mBAAA,YAAA,mBACjC,wBAAiC,eAAA,kBAAA,YAAA,kBAEjC,wBAAkC,mBAAA,gBAAA,cAAA,qBAClC,sBAAkC,mBAAA,cAAA,cAAA,mBAClC,yBAAkC,mBAAA,iBAAA,cAAA,iBAClC,0BAAkC,mBAAA,kBAAA,cAAA,wBAClC,yBAAkC,mBAAA,qBAAA,cAAA,uBAClC,0BAAkC,mBAAA,kBAAA,cAAA,kBAElC,oBAAgC,oBAAA,eAAA,WAAA,eAChC,qBAAgC,oBAAA,gBAAA,WAAA,qBAChC,mBAAgC,oBAAA,cAAA,WAAA,mBAChC,sBAAgC,oBAAA,iBAAA,WAAA,iBAChC,wBAAgC,oBAAA,mBAAA,WAAA,mBAChC,uBAAgC,oBAAA,kBAAA,WAAA,mBC1ChC,YAAwB,MAAA,eACxB,aAAwB,MAAA,gBACxB,YAAwB,MAAA,ehDoDxB,yBgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBhDoDxB,yBgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBhDoDxB,yBgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBhDoDxB,0BgDtDA,eAAwB,MAAA,eACxB,gBAAwB,MAAA,gBACxB,eAAwB,MAAA,gBCL1B,eAAsB,SAAA,eAAtB,iBAAsB,SAAA,iBCCtB,iBAAyB,SAAA,iBAAzB,mBAAyB,SAAA,mBAAzB,mBAAyB,SAAA,mBAAzB,gBAAyB,SAAA,gBAAzB,iBAAyB,SAAA,yBAAA,SAAA,iBAK3B,WACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,KAAA,EACA,QAAA,KAGF,cACE,SAAA,MACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KAI4B,2DAD9B,YAEI,SAAA,eAAA,SAAA,OACA,IAAA,EACA,QAAA,MCzBJ,SCEE,SAAA,SACA,MAAA,IACA,OAAA,IACA,QAAA,EACA,SAAA,OACA,KAAA,cACA,YAAA,OACA,OAAA,EAUA,0BAAA,yBAEE,SAAA,OACA,MAAA,KACA,OAAA,KACA,SAAA,QACA,KAAA,KACA,YAAA,OC5BJ,WAAa,WAAA,EAAA,QAAA,OAAA,2BACb,QAAU,WAAA,EAAA,MAAA,KAAA,0BACV,WAAa,WAAA,EAAA,KAAA,KAAA,2BACb,aAAe,WAAA,eCCX,MAAuB,MAAA,cAAvB,MAAuB,MAAA,cAAvB,MAAuB,MAAA,cAAvB,OAAuB,MAAA,eAAvB,QAAuB,MAAA,eAAvB,MAAuB,OAAA,cAAvB,MAAuB,OAAA,cAAvB,MAAuB,OAAA,cAAvB,OAAuB,OAAA,eAAvB,QAAuB,OAAA,eAI3B,QAAU,UAAA,eACV,QAAU,WAAA,eAIV,YAAc,UAAA,gBACd,YAAc,WAAA,gBAEd,QAAU,MAAA,gBACV,QAAU,OAAA,gBCfV,uBAEI,SAAA,SACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,EAEA,eAAA,KACA,QAAA,GAEA,iBAAA,cCNI,KAAgC,OAAA,YAChC,MpEsuPR,MoEpuPU,WAAA,YAEF,MpEuuPR,MoEruPU,aAAA,YAEF,MpEwuPR,MoEtuPU,cAAA,YAEF,MpEyuPR,MoEvuPU,YAAA,YAfF,KAAgC,OAAA,iBAChC,MpE8vPR,MoE5vPU,WAAA,iBAEF,MpE+vPR,MoE7vPU,aAAA,iBAEF,MpEgwPR,MoE9vPU,cAAA,iBAEF,MpEiwPR,MoE/vPU,YAAA,iBAfF,KAAgC,OAAA,gBAChC,MpEsxPR,MoEpxPU,WAAA,gBAEF,MpEuxPR,MoErxPU,aAAA,gBAEF,MpEwxPR,MoEtxPU,cAAA,gBAEF,MpEyxPR,MoEvxPU,YAAA,gBAfF,KAAgC,OAAA,eAChC,MpE8yPR,MoE5yPU,WAAA,eAEF,MpE+yPR,MoE7yPU,aAAA,eAEF,MpEgzPR,MoE9yPU,cAAA,eAEF,MpEizPR,MoE/yPU,YAAA,eAfF,KAAgC,OAAA,iBAChC,MpEs0PR,MoEp0PU,WAAA,iBAEF,MpEu0PR,MoEr0PU,aAAA,iBAEF,MpEw0PR,MoEt0PU,cAAA,iBAEF,MpEy0PR,MoEv0PU,YAAA,iBAfF,KAAgC,OAAA,eAChC,MpE81PR,MoE51PU,WAAA,eAEF,MpE+1PR,MoE71PU,aAAA,eAEF,MpEg2PR,MoE91PU,cAAA,eAEF,MpEi2PR,MoE/1PU,YAAA,eAfF,KAAgC,QAAA,YAChC,MpEs3PR,MoEp3PU,YAAA,YAEF,MpEu3PR,MoEr3PU,cAAA,YAEF,MpEw3PR,MoEt3PU,eAAA,YAEF,MpEy3PR,MoEv3PU,aAAA,YAfF,KAAgC,QAAA,iBAChC,MpE84PR,MoE54PU,YAAA,iBAEF,MpE+4PR,MoE74PU,cAAA,iBAEF,MpEg5PR,MoE94PU,eAAA,iBAEF,MpEi5PR,MoE/4PU,aAAA,iBAfF,KAAgC,QAAA,gBAChC,MpEs6PR,MoEp6PU,YAAA,gBAEF,MpEu6PR,MoEr6PU,cAAA,gBAEF,MpEw6PR,MoEt6PU,eAAA,gBAEF,MpEy6PR,MoEv6PU,aAAA,gBAfF,KAAgC,QAAA,eAChC,MpE87PR,MoE57PU,YAAA,eAEF,MpE+7PR,MoE77PU,cAAA,eAEF,MpEg8PR,MoE97PU,eAAA,eAEF,MpEi8PR,MoE/7PU,aAAA,eAfF,KAAgC,QAAA,iBAChC,MpEs9PR,MoEp9PU,YAAA,iBAEF,MpEu9PR,MoEr9PU,cAAA,iBAEF,MpEw9PR,MoEt9PU,eAAA,iBAEF,MpEy9PR,MoEv9PU,aAAA,iBAfF,KAAgC,QAAA,eAChC,MpE8+PR,MoE5+PU,YAAA,eAEF,MpE++PR,MoE7+PU,cAAA,eAEF,MpEg/PR,MoE9+PU,eAAA,eAEF,MpEi/PR,MoE/+PU,aAAA,eAQF,MAAwB,OAAA,kBACxB,OpE++PR,OoE7+PU,WAAA,kBAEF,OpEg/PR,OoE9+PU,aAAA,kBAEF,OpEi/PR,OoE/+PU,cAAA,kBAEF,OpEk/PR,OoEh/PU,YAAA,kBAfF,MAAwB,OAAA,iBACxB,OpEugQR,OoErgQU,WAAA,iBAEF,OpEwgQR,OoEtgQU,aAAA,iBAEF,OpEygQR,OoEvgQU,cAAA,iBAEF,OpE0gQR,OoExgQU,YAAA,iBAfF,MAAwB,OAAA,gBACxB,OpE+hQR,OoE7hQU,WAAA,gBAEF,OpEgiQR,OoE9hQU,aAAA,gBAEF,OpEiiQR,OoE/hQU,cAAA,gBAEF,OpEkiQR,OoEhiQU,YAAA,gBAfF,MAAwB,OAAA,kBACxB,OpEujQR,OoErjQU,WAAA,kBAEF,OpEwjQR,OoEtjQU,aAAA,kBAEF,OpEyjQR,OoEvjQU,cAAA,kBAEF,OpE0jQR,OoExjQU,YAAA,kBAfF,MAAwB,OAAA,gBACxB,OpE+kQR,OoE7kQU,WAAA,gBAEF,OpEglQR,OoE9kQU,aAAA,gBAEF,OpEilQR,OoE/kQU,cAAA,gBAEF,OpEklQR,OoEhlQU,YAAA,gBAMN,QAAmB,OAAA,eACnB,SpEklQJ,SoEhlQM,WAAA,eAEF,SpEmlQJ,SoEjlQM,aAAA,eAEF,SpEolQJ,SoEllQM,cAAA,eAEF,SpEqlQJ,SoEnlQM,YAAA,exDTF,yBwDlDI,QAAgC,OAAA,YAChC,SpEspQN,SoEppQQ,WAAA,YAEF,SpEspQN,SoEppQQ,aAAA,YAEF,SpEspQN,SoEppQQ,cAAA,YAEF,SpEspQN,SoEppQQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpEyqQN,SoEvqQQ,WAAA,iBAEF,SpEyqQN,SoEvqQQ,aAAA,iBAEF,SpEyqQN,SoEvqQQ,cAAA,iBAEF,SpEyqQN,SoEvqQQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpE4rQN,SoE1rQQ,WAAA,gBAEF,SpE4rQN,SoE1rQQ,aAAA,gBAEF,SpE4rQN,SoE1rQQ,cAAA,gBAEF,SpE4rQN,SoE1rQQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpE+sQN,SoE7sQQ,WAAA,eAEF,SpE+sQN,SoE7sQQ,aAAA,eAEF,SpE+sQN,SoE7sQQ,cAAA,eAEF,SpE+sQN,SoE7sQQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpEkuQN,SoEhuQQ,WAAA,iBAEF,SpEkuQN,SoEhuQQ,aAAA,iBAEF,SpEkuQN,SoEhuQQ,cAAA,iBAEF,SpEkuQN,SoEhuQQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpEqvQN,SoEnvQQ,WAAA,eAEF,SpEqvQN,SoEnvQQ,aAAA,eAEF,SpEqvQN,SoEnvQQ,cAAA,eAEF,SpEqvQN,SoEnvQQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpEwwQN,SoEtwQQ,YAAA,YAEF,SpEwwQN,SoEtwQQ,cAAA,YAEF,SpEwwQN,SoEtwQQ,eAAA,YAEF,SpEwwQN,SoEtwQQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpE2xQN,SoEzxQQ,YAAA,iBAEF,SpE2xQN,SoEzxQQ,cAAA,iBAEF,SpE2xQN,SoEzxQQ,eAAA,iBAEF,SpE2xQN,SoEzxQQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpE8yQN,SoE5yQQ,YAAA,gBAEF,SpE8yQN,SoE5yQQ,cAAA,gBAEF,SpE8yQN,SoE5yQQ,eAAA,gBAEF,SpE8yQN,SoE5yQQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpEi0QN,SoE/zQQ,YAAA,eAEF,SpEi0QN,SoE/zQQ,cAAA,eAEF,SpEi0QN,SoE/zQQ,eAAA,eAEF,SpEi0QN,SoE/zQQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpEo1QN,SoEl1QQ,YAAA,iBAEF,SpEo1QN,SoEl1QQ,cAAA,iBAEF,SpEo1QN,SoEl1QQ,eAAA,iBAEF,SpEo1QN,SoEl1QQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpEu2QN,SoEr2QQ,YAAA,eAEF,SpEu2QN,SoEr2QQ,cAAA,eAEF,SpEu2QN,SoEr2QQ,eAAA,eAEF,SpEu2QN,SoEr2QQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpEm2QN,UoEj2QQ,WAAA,kBAEF,UpEm2QN,UoEj2QQ,aAAA,kBAEF,UpEm2QN,UoEj2QQ,cAAA,kBAEF,UpEm2QN,UoEj2QQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpEs3QN,UoEp3QQ,WAAA,iBAEF,UpEs3QN,UoEp3QQ,aAAA,iBAEF,UpEs3QN,UoEp3QQ,cAAA,iBAEF,UpEs3QN,UoEp3QQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpEy4QN,UoEv4QQ,WAAA,gBAEF,UpEy4QN,UoEv4QQ,aAAA,gBAEF,UpEy4QN,UoEv4QQ,cAAA,gBAEF,UpEy4QN,UoEv4QQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpE45QN,UoE15QQ,WAAA,kBAEF,UpE45QN,UoE15QQ,aAAA,kBAEF,UpE45QN,UoE15QQ,cAAA,kBAEF,UpE45QN,UoE15QQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpE+6QN,UoE76QQ,WAAA,gBAEF,UpE+6QN,UoE76QQ,aAAA,gBAEF,UpE+6QN,UoE76QQ,cAAA,gBAEF,UpE+6QN,UoE76QQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpE66QF,YoE36QI,WAAA,eAEF,YpE66QF,YoE36QI,aAAA,eAEF,YpE66QF,YoE36QI,cAAA,eAEF,YpE66QF,YoE36QI,YAAA,gBxDTF,yBwDlDI,QAAgC,OAAA,YAChC,SpE++QN,SoE7+QQ,WAAA,YAEF,SpE++QN,SoE7+QQ,aAAA,YAEF,SpE++QN,SoE7+QQ,cAAA,YAEF,SpE++QN,SoE7+QQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpEkgRN,SoEhgRQ,WAAA,iBAEF,SpEkgRN,SoEhgRQ,aAAA,iBAEF,SpEkgRN,SoEhgRQ,cAAA,iBAEF,SpEkgRN,SoEhgRQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpEqhRN,SoEnhRQ,WAAA,gBAEF,SpEqhRN,SoEnhRQ,aAAA,gBAEF,SpEqhRN,SoEnhRQ,cAAA,gBAEF,SpEqhRN,SoEnhRQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpEwiRN,SoEtiRQ,WAAA,eAEF,SpEwiRN,SoEtiRQ,aAAA,eAEF,SpEwiRN,SoEtiRQ,cAAA,eAEF,SpEwiRN,SoEtiRQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpE2jRN,SoEzjRQ,WAAA,iBAEF,SpE2jRN,SoEzjRQ,aAAA,iBAEF,SpE2jRN,SoEzjRQ,cAAA,iBAEF,SpE2jRN,SoEzjRQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpE8kRN,SoE5kRQ,WAAA,eAEF,SpE8kRN,SoE5kRQ,aAAA,eAEF,SpE8kRN,SoE5kRQ,cAAA,eAEF,SpE8kRN,SoE5kRQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpEimRN,SoE/lRQ,YAAA,YAEF,SpEimRN,SoE/lRQ,cAAA,YAEF,SpEimRN,SoE/lRQ,eAAA,YAEF,SpEimRN,SoE/lRQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpEonRN,SoElnRQ,YAAA,iBAEF,SpEonRN,SoElnRQ,cAAA,iBAEF,SpEonRN,SoElnRQ,eAAA,iBAEF,SpEonRN,SoElnRQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpEuoRN,SoEroRQ,YAAA,gBAEF,SpEuoRN,SoEroRQ,cAAA,gBAEF,SpEuoRN,SoEroRQ,eAAA,gBAEF,SpEuoRN,SoEroRQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpE0pRN,SoExpRQ,YAAA,eAEF,SpE0pRN,SoExpRQ,cAAA,eAEF,SpE0pRN,SoExpRQ,eAAA,eAEF,SpE0pRN,SoExpRQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpE6qRN,SoE3qRQ,YAAA,iBAEF,SpE6qRN,SoE3qRQ,cAAA,iBAEF,SpE6qRN,SoE3qRQ,eAAA,iBAEF,SpE6qRN,SoE3qRQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpEgsRN,SoE9rRQ,YAAA,eAEF,SpEgsRN,SoE9rRQ,cAAA,eAEF,SpEgsRN,SoE9rRQ,eAAA,eAEF,SpEgsRN,SoE9rRQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpE4rRN,UoE1rRQ,WAAA,kBAEF,UpE4rRN,UoE1rRQ,aAAA,kBAEF,UpE4rRN,UoE1rRQ,cAAA,kBAEF,UpE4rRN,UoE1rRQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpE+sRN,UoE7sRQ,WAAA,iBAEF,UpE+sRN,UoE7sRQ,aAAA,iBAEF,UpE+sRN,UoE7sRQ,cAAA,iBAEF,UpE+sRN,UoE7sRQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpEkuRN,UoEhuRQ,WAAA,gBAEF,UpEkuRN,UoEhuRQ,aAAA,gBAEF,UpEkuRN,UoEhuRQ,cAAA,gBAEF,UpEkuRN,UoEhuRQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpEqvRN,UoEnvRQ,WAAA,kBAEF,UpEqvRN,UoEnvRQ,aAAA,kBAEF,UpEqvRN,UoEnvRQ,cAAA,kBAEF,UpEqvRN,UoEnvRQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpEwwRN,UoEtwRQ,WAAA,gBAEF,UpEwwRN,UoEtwRQ,aAAA,gBAEF,UpEwwRN,UoEtwRQ,cAAA,gBAEF,UpEwwRN,UoEtwRQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpEswRF,YoEpwRI,WAAA,eAEF,YpEswRF,YoEpwRI,aAAA,eAEF,YpEswRF,YoEpwRI,cAAA,eAEF,YpEswRF,YoEpwRI,YAAA,gBxDTF,yBwDlDI,QAAgC,OAAA,YAChC,SpEw0RN,SoEt0RQ,WAAA,YAEF,SpEw0RN,SoEt0RQ,aAAA,YAEF,SpEw0RN,SoEt0RQ,cAAA,YAEF,SpEw0RN,SoEt0RQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpE21RN,SoEz1RQ,WAAA,iBAEF,SpE21RN,SoEz1RQ,aAAA,iBAEF,SpE21RN,SoEz1RQ,cAAA,iBAEF,SpE21RN,SoEz1RQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpE82RN,SoE52RQ,WAAA,gBAEF,SpE82RN,SoE52RQ,aAAA,gBAEF,SpE82RN,SoE52RQ,cAAA,gBAEF,SpE82RN,SoE52RQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpEi4RN,SoE/3RQ,WAAA,eAEF,SpEi4RN,SoE/3RQ,aAAA,eAEF,SpEi4RN,SoE/3RQ,cAAA,eAEF,SpEi4RN,SoE/3RQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpEo5RN,SoEl5RQ,WAAA,iBAEF,SpEo5RN,SoEl5RQ,aAAA,iBAEF,SpEo5RN,SoEl5RQ,cAAA,iBAEF,SpEo5RN,SoEl5RQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpEu6RN,SoEr6RQ,WAAA,eAEF,SpEu6RN,SoEr6RQ,aAAA,eAEF,SpEu6RN,SoEr6RQ,cAAA,eAEF,SpEu6RN,SoEr6RQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpE07RN,SoEx7RQ,YAAA,YAEF,SpE07RN,SoEx7RQ,cAAA,YAEF,SpE07RN,SoEx7RQ,eAAA,YAEF,SpE07RN,SoEx7RQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpE68RN,SoE38RQ,YAAA,iBAEF,SpE68RN,SoE38RQ,cAAA,iBAEF,SpE68RN,SoE38RQ,eAAA,iBAEF,SpE68RN,SoE38RQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpEg+RN,SoE99RQ,YAAA,gBAEF,SpEg+RN,SoE99RQ,cAAA,gBAEF,SpEg+RN,SoE99RQ,eAAA,gBAEF,SpEg+RN,SoE99RQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpEm/RN,SoEj/RQ,YAAA,eAEF,SpEm/RN,SoEj/RQ,cAAA,eAEF,SpEm/RN,SoEj/RQ,eAAA,eAEF,SpEm/RN,SoEj/RQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpEsgSN,SoEpgSQ,YAAA,iBAEF,SpEsgSN,SoEpgSQ,cAAA,iBAEF,SpEsgSN,SoEpgSQ,eAAA,iBAEF,SpEsgSN,SoEpgSQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpEyhSN,SoEvhSQ,YAAA,eAEF,SpEyhSN,SoEvhSQ,cAAA,eAEF,SpEyhSN,SoEvhSQ,eAAA,eAEF,SpEyhSN,SoEvhSQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpEqhSN,UoEnhSQ,WAAA,kBAEF,UpEqhSN,UoEnhSQ,aAAA,kBAEF,UpEqhSN,UoEnhSQ,cAAA,kBAEF,UpEqhSN,UoEnhSQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpEwiSN,UoEtiSQ,WAAA,iBAEF,UpEwiSN,UoEtiSQ,aAAA,iBAEF,UpEwiSN,UoEtiSQ,cAAA,iBAEF,UpEwiSN,UoEtiSQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpE2jSN,UoEzjSQ,WAAA,gBAEF,UpE2jSN,UoEzjSQ,aAAA,gBAEF,UpE2jSN,UoEzjSQ,cAAA,gBAEF,UpE2jSN,UoEzjSQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpE8kSN,UoE5kSQ,WAAA,kBAEF,UpE8kSN,UoE5kSQ,aAAA,kBAEF,UpE8kSN,UoE5kSQ,cAAA,kBAEF,UpE8kSN,UoE5kSQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpEimSN,UoE/lSQ,WAAA,gBAEF,UpEimSN,UoE/lSQ,aAAA,gBAEF,UpEimSN,UoE/lSQ,cAAA,gBAEF,UpEimSN,UoE/lSQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpE+lSF,YoE7lSI,WAAA,eAEF,YpE+lSF,YoE7lSI,aAAA,eAEF,YpE+lSF,YoE7lSI,cAAA,eAEF,YpE+lSF,YoE7lSI,YAAA,gBxDTF,0BwDlDI,QAAgC,OAAA,YAChC,SpEiqSN,SoE/pSQ,WAAA,YAEF,SpEiqSN,SoE/pSQ,aAAA,YAEF,SpEiqSN,SoE/pSQ,cAAA,YAEF,SpEiqSN,SoE/pSQ,YAAA,YAfF,QAAgC,OAAA,iBAChC,SpEorSN,SoElrSQ,WAAA,iBAEF,SpEorSN,SoElrSQ,aAAA,iBAEF,SpEorSN,SoElrSQ,cAAA,iBAEF,SpEorSN,SoElrSQ,YAAA,iBAfF,QAAgC,OAAA,gBAChC,SpEusSN,SoErsSQ,WAAA,gBAEF,SpEusSN,SoErsSQ,aAAA,gBAEF,SpEusSN,SoErsSQ,cAAA,gBAEF,SpEusSN,SoErsSQ,YAAA,gBAfF,QAAgC,OAAA,eAChC,SpE0tSN,SoExtSQ,WAAA,eAEF,SpE0tSN,SoExtSQ,aAAA,eAEF,SpE0tSN,SoExtSQ,cAAA,eAEF,SpE0tSN,SoExtSQ,YAAA,eAfF,QAAgC,OAAA,iBAChC,SpE6uSN,SoE3uSQ,WAAA,iBAEF,SpE6uSN,SoE3uSQ,aAAA,iBAEF,SpE6uSN,SoE3uSQ,cAAA,iBAEF,SpE6uSN,SoE3uSQ,YAAA,iBAfF,QAAgC,OAAA,eAChC,SpEgwSN,SoE9vSQ,WAAA,eAEF,SpEgwSN,SoE9vSQ,aAAA,eAEF,SpEgwSN,SoE9vSQ,cAAA,eAEF,SpEgwSN,SoE9vSQ,YAAA,eAfF,QAAgC,QAAA,YAChC,SpEmxSN,SoEjxSQ,YAAA,YAEF,SpEmxSN,SoEjxSQ,cAAA,YAEF,SpEmxSN,SoEjxSQ,eAAA,YAEF,SpEmxSN,SoEjxSQ,aAAA,YAfF,QAAgC,QAAA,iBAChC,SpEsySN,SoEpySQ,YAAA,iBAEF,SpEsySN,SoEpySQ,cAAA,iBAEF,SpEsySN,SoEpySQ,eAAA,iBAEF,SpEsySN,SoEpySQ,aAAA,iBAfF,QAAgC,QAAA,gBAChC,SpEyzSN,SoEvzSQ,YAAA,gBAEF,SpEyzSN,SoEvzSQ,cAAA,gBAEF,SpEyzSN,SoEvzSQ,eAAA,gBAEF,SpEyzSN,SoEvzSQ,aAAA,gBAfF,QAAgC,QAAA,eAChC,SpE40SN,SoE10SQ,YAAA,eAEF,SpE40SN,SoE10SQ,cAAA,eAEF,SpE40SN,SoE10SQ,eAAA,eAEF,SpE40SN,SoE10SQ,aAAA,eAfF,QAAgC,QAAA,iBAChC,SpE+1SN,SoE71SQ,YAAA,iBAEF,SpE+1SN,SoE71SQ,cAAA,iBAEF,SpE+1SN,SoE71SQ,eAAA,iBAEF,SpE+1SN,SoE71SQ,aAAA,iBAfF,QAAgC,QAAA,eAChC,SpEk3SN,SoEh3SQ,YAAA,eAEF,SpEk3SN,SoEh3SQ,cAAA,eAEF,SpEk3SN,SoEh3SQ,eAAA,eAEF,SpEk3SN,SoEh3SQ,aAAA,eAQF,SAAwB,OAAA,kBACxB,UpE82SN,UoE52SQ,WAAA,kBAEF,UpE82SN,UoE52SQ,aAAA,kBAEF,UpE82SN,UoE52SQ,cAAA,kBAEF,UpE82SN,UoE52SQ,YAAA,kBAfF,SAAwB,OAAA,iBACxB,UpEi4SN,UoE/3SQ,WAAA,iBAEF,UpEi4SN,UoE/3SQ,aAAA,iBAEF,UpEi4SN,UoE/3SQ,cAAA,iBAEF,UpEi4SN,UoE/3SQ,YAAA,iBAfF,SAAwB,OAAA,gBACxB,UpEo5SN,UoEl5SQ,WAAA,gBAEF,UpEo5SN,UoEl5SQ,aAAA,gBAEF,UpEo5SN,UoEl5SQ,cAAA,gBAEF,UpEo5SN,UoEl5SQ,YAAA,gBAfF,SAAwB,OAAA,kBACxB,UpEu6SN,UoEr6SQ,WAAA,kBAEF,UpEu6SN,UoEr6SQ,aAAA,kBAEF,UpEu6SN,UoEr6SQ,cAAA,kBAEF,UpEu6SN,UoEr6SQ,YAAA,kBAfF,SAAwB,OAAA,gBACxB,UpE07SN,UoEx7SQ,WAAA,gBAEF,UpE07SN,UoEx7SQ,aAAA,gBAEF,UpE07SN,UoEx7SQ,cAAA,gBAEF,UpE07SN,UoEx7SQ,YAAA,gBAMN,WAAmB,OAAA,eACnB,YpEw7SF,YoEt7SI,WAAA,eAEF,YpEw7SF,YoEt7SI,aAAA,eAEF,YpEw7SF,YoEt7SI,cAAA,eAEF,YpEw7SF,YoEt7SI,YAAA,gBC/DN,gBAAkB,YAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,oBAIlB,cAAiB,WAAA,kBACjB,WAAiB,YAAA,iBACjB,aAAiB,YAAA,iBACjB,eCTE,SAAA,OACA,cAAA,SACA,YAAA,ODeE,WAAwB,WAAA,eACxB,YAAwB,WAAA,gBACxB,aAAwB,WAAA,iBzDqCxB,yByDvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBzDqCxB,yByDvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBzDqCxB,yByDvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBzDqCxB,0ByDvCA,cAAwB,WAAA,eACxB,eAAwB,WAAA,gBACxB,gBAAwB,WAAA,kBAM5B,gBAAmB,eAAA,oBACnB,gBAAmB,eAAA,oBACnB,iBAAmB,eAAA,qBAInB,mBAAuB,YAAA,cACvB,qBAAuB,YAAA,kBACvB,oBAAuB,YAAA,cACvB,kBAAuB,YAAA,cACvB,oBAAuB,YAAA,iBACvB,aAAuB,WAAA,iBAIvB,YAAc,MAAA,eEvCZ,cACE,MAAA,kBpEUF,qBAAA,qBoELM,MAAA,kBANN,gBACE,MAAA,kBpEUF,uBAAA,uBoELM,MAAA,kBANN,cACE,MAAA,kBpEUF,qBAAA,qBoELM,MAAA,kBANN,WACE,MAAA,kBpEUF,kBAAA,kBoELM,MAAA,kBANN,cACE,MAAA,kBpEUF,qBAAA,qBoELM,MAAA,kBANN,aACE,MAAA,kBpEUF,oBAAA,oBoELM,MAAA,kBANN,YACE,MAAA,kBpEUF,mBAAA,mBoELM,MAAA,kBANN,WACE,MAAA,kBpEUF,kBAAA,kBoELM,MAAA,kBFuCR,WAAa,MAAA,kBACb,YAAc,MAAA,kBAEd,eAAiB,MAAA,yBACjB,eAAiB,MAAA,+BAIjB,WGvDE,KAAA,CAAA,CAAA,EAAA,EACA,MAAA,YACA,YAAA,KACA,iBAAA,YACA,OAAA,EHuDF,sBAAwB,gBAAA,eAExB,YACE,WAAA,qBACA,cAAA,qBAKF,YAAc,MAAA,kBIjEd,SACE,WAAA,kBAGF,WACE,WAAA,iBCAA,a3EOF,ECwtTE,QADA,S0ExtTI,YAAA,eAEA,WAAA,eAGF,YAEI,gBAAA,UASJ,mBACE,QAAA,KAAA,YAAA,I3E+LN,I2EhLM,YAAA,mB1EusTJ,W0ErsTE,IAEE,OAAA,IAAA,MAAA,QACA,kBAAA,MAQF,MACE,QAAA,mB1EisTJ,I0E9rTE,GAEE,kBAAA,M1EgsTJ,GACA,G0E9rTE,EAGE,QAAA,EACA,OAAA,EAGF,G1E4rTF,G0E1rTI,iBAAA,MAQF,MACE,KAAA,G3E5CN,K2E+CM,UAAA,gBhEvFJ,WgE0FI,UAAA,gB5C9EN,Q4CmFM,QAAA,KvC/FN,OuCkGM,OAAA,IAAA,MAAA,K5DnGN,O4DuGM,gBAAA,mBADF,U1EsrTF,U0EjrTM,iBAAA,e1EqrTN,mBcxvTF,mB4D0EQ,OAAA,IAAA,MAAA,kB5DWR,Y4DNM,MAAA,Q1EkrTJ,wBAFA,eetyTA,efuyTA,qB0E3qTM,aAAA,Q5DlBR,sB4DuBM,MAAA,QACA,aAAA","sourcesContent":["/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"root\";\n@import \"reboot\";\n@import \"type\";\n@import \"images\";\n@import \"code\";\n@import \"grid\";\n@import \"tables\";\n@import \"forms\";\n@import \"buttons\";\n@import \"transitions\";\n@import \"dropdown\";\n@import \"button-group\";\n@import \"input-group\";\n@import \"custom-forms\";\n@import \"nav\";\n@import \"navbar\";\n@import \"card\";\n@import \"breadcrumb\";\n@import \"pagination\";\n@import \"badge\";\n@import \"jumbotron\";\n@import \"alert\";\n@import \"progress\";\n@import \"media\";\n@import \"list-group\";\n@import \"close\";\n@import \"toasts\";\n@import \"modal\";\n@import \"tooltip\";\n@import \"popover\";\n@import \"carousel\";\n@import \"spinners\";\n@import \"utilities\";\n@import \"print\";\n",":root {\n // Custom variable values only support SassScript inside `#{}`.\n @each $color, $value in $colors {\n --#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$color}: #{$value};\n }\n\n @each $bp, $value in $grid-breakpoints {\n --breakpoint-#{$bp}: #{$value};\n }\n\n // Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --font-family-sans-serif: #{inspect($font-family-sans-serif)};\n --font-family-monospace: #{inspect($font-family-monospace)};\n}\n","// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box; // 1\n}\n\nhtml {\n font-family: sans-serif; // 2\n line-height: 1.15; // 3\n -webkit-text-size-adjust: 100%; // 4\n -webkit-tap-highlight-color: rgba($black, 0); // 5\n}\n\n// Shim for \"new\" HTML5 structural elements to display correctly (IE10, older browsers)\n// TODO: remove in v5\n// stylelint-disable-next-line selector-list-comma-newline-after\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Set an explicit initial text-align value so that we can later use\n// the `inherit` value on things like `` elements.\n\nbody {\n margin: 0; // 1\n font-family: $font-family-base;\n @include font-size($font-size-base);\n font-weight: $font-weight-base;\n line-height: $line-height-base;\n color: $body-color;\n text-align: left; // 3\n background-color: $body-bg; // 2\n}\n\n// Suppress the focus outline on elements that cannot be accessed via keyboard.\n// This prevents an unwanted focus outline from appearing around elements that\n// might still respond to pointer events.\n//\n// Credit: https://github.com/suitcss/base\n[tabindex=\"-1\"]:focus {\n outline: 0 !important;\n}\n\n\n// Content grouping\n//\n// 1. Add the correct box sizing in Firefox.\n// 2. Show the overflow in Edge and IE.\n\nhr {\n box-sizing: content-box; // 1\n height: 0; // 1\n overflow: visible; // 2\n}\n\n\n//\n// Typography\n//\n\n// Remove top margins from headings\n//\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n// stylelint-disable-next-line selector-list-comma-newline-after\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: $headings-margin-bottom;\n}\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Remove the bottom border in Firefox 39-.\n// 5. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-original-title] { // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n border-bottom: 0; // 4\n text-decoration-skip-ink: none; // 5\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // Undo browser default\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: $font-weight-bolder; // Add the correct font weight in Chrome, Edge, and Safari\n}\n\nsmall {\n @include font-size(80%); // Add the correct font size in all browsers\n}\n\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n//\n\nsub,\nsup {\n position: relative;\n @include font-size(75%);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n//\n// Links\n//\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n background-color: transparent; // Remove the gray background on active links in IE 10.\n\n @include hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href)\n// which have not been made explicitly keyboard-focusable (without tabindex).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n\n @include hover-focus {\n color: inherit;\n text-decoration: none;\n }\n\n &:focus {\n outline: 0;\n }\n}\n\n\n//\n// Code\n//\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-monospace;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\npre {\n // Remove browser default top margin\n margin-top: 0;\n // Reset browser default of `1em` to use `rem`s\n margin-bottom: 1rem;\n // Don't allow content to break outside\n overflow: auto;\n}\n\n\n//\n// Figures\n//\n\nfigure {\n // Apply a consistent margin strategy (matches our type styles).\n margin: 0 0 1rem;\n}\n\n\n//\n// Images and content\n//\n\nimg {\n vertical-align: middle;\n border-style: none; // Remove the border on images inside links in IE 10-.\n}\n\nsvg {\n // Workaround for the SVG overflow bug in IE10/11 is still required.\n // See https://github.com/twbs/bootstrap/issues/26878\n overflow: hidden;\n vertical-align: middle;\n}\n\n\n//\n// Tables\n//\n\ntable {\n border-collapse: collapse; // Prevent double borders\n}\n\ncaption {\n padding-top: $table-cell-padding;\n padding-bottom: $table-cell-padding;\n color: $table-caption-color;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n // Matches default `` alignment by inheriting from the ``, or the\n // closest parent with a set `text-align`.\n text-align: inherit;\n}\n\n\n//\n// Forms\n//\n\nlabel {\n // Allow labels to use `margin` for spacing.\n display: inline-block;\n margin-bottom: $label-margin-bottom;\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n//\n// Details at https://github.com/twbs/bootstrap/issues/24093\nbutton {\n // stylelint-disable-next-line property-blacklist\n border-radius: 0;\n}\n\n// Work around a Firefox/IE bug where the transparent `button` background\n// results in a loss of the default `button` focus styles.\n//\n// Credit: https://github.com/suitcss/base/\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // Remove the margin in Firefox and Safari\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible; // Show the overflow in Edge\n}\n\nbutton,\nselect {\n text-transform: none; // Remove the inheritance of text transform in Firefox\n}\n\n// Remove the inheritance of word-wrap in Safari.\n//\n// Details at https://github.com/twbs/bootstrap/issues/24990\nselect {\n word-wrap: normal;\n}\n\n\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`\n// controls in Android 4.\n// 2. Correct the inability to style clickable types in iOS and Safari.\nbutton,\n[type=\"button\"], // 1\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button; // 2\n}\n\n// Opinionated: add \"hand\" cursor to non-disabled button elements.\n@if $enable-pointer-cursor-for-buttons {\n button,\n [type=\"button\"],\n [type=\"reset\"],\n [type=\"submit\"] {\n &:not(:disabled) {\n cursor: pointer;\n }\n }\n}\n\n// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box; // 1. Add the correct box sizing in IE 10-\n padding: 0; // 2. Remove the padding in IE 10-\n}\n\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n // Remove the default appearance of temporal inputs to avoid a Mobile Safari\n // bug where setting a custom line-height prevents text from being vertically\n // centered within the input.\n // See https://bugs.webkit.org/show_bug.cgi?id=139848\n // and https://github.com/twbs/bootstrap/issues/11266\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto; // Remove the default vertical scrollbar in IE.\n // Textareas should really only resize vertically so they don't break their (horizontal) containers.\n resize: vertical;\n}\n\nfieldset {\n // Browsers set a default `min-width: min-content;` on fieldsets,\n // unlike e.g. `

`s, which have `min-width: 0;` by default.\n // So we reset that to ensure fieldsets behave more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359\n // and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements\n min-width: 0;\n // Reset the default outline behavior of fieldsets so they don't affect page layout.\n padding: 0;\n margin: 0;\n border: 0;\n}\n\n// 1. Correct the text wrapping in Edge and IE.\n// 2. Correct the color inheritance from `fieldset` elements in IE.\nlegend {\n display: block;\n width: 100%;\n max-width: 100%; // 1\n padding: 0;\n margin-bottom: .5rem;\n @include font-size(1.5rem);\n line-height: inherit;\n color: inherit; // 2\n white-space: normal; // 1\n}\n\nprogress {\n vertical-align: baseline; // Add the correct vertical alignment in Chrome, Firefox, and Opera.\n}\n\n// Correct the cursor style of increment and decrement buttons in Chrome.\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n // This overrides the extra rounded corners on search inputs in iOS so that our\n // `.form-control` class can properly style them. Note that this cannot simply\n // be added to `.form-control` as it's not specific enough. For details, see\n // https://github.com/twbs/bootstrap/issues/11586.\n outline-offset: -2px; // 2. Correct the outline style in Safari.\n -webkit-appearance: none;\n}\n\n//\n// Remove the inner padding in Chrome and Safari on macOS.\n//\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// 1. Correct the inability to style clickable types in iOS and Safari.\n// 2. Change font properties to `inherit` in Safari.\n//\n\n::-webkit-file-upload-button {\n font: inherit; // 2\n -webkit-appearance: button; // 1\n}\n\n//\n// Correct element displays\n//\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item; // Add the correct display in all browsers\n cursor: pointer;\n}\n\ntemplate {\n display: none; // Add the correct display in IE\n}\n\n// Always hide an element with the `hidden` HTML attribute (from PureCSS).\n// Needed for proper display in IE 10-.\n[hidden] {\n display: none !important;\n}\n","/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n:root {\n --blue: #007bff;\n --indigo: #6610f2;\n --purple: #6f42c1;\n --pink: #e83e8c;\n --red: #dc3545;\n --orange: #fd7e14;\n --yellow: #ffc107;\n --green: #28a745;\n --teal: #20c997;\n --cyan: #17a2b8;\n --white: #fff;\n --gray: #6c757d;\n --gray-dark: #343a40;\n --primary: #007bff;\n --secondary: #6c757d;\n --success: #28a745;\n --info: #17a2b8;\n --warning: #ffc107;\n --danger: #dc3545;\n --light: #f8f9fa;\n --dark: #343a40;\n --breakpoint-xs: 0;\n --breakpoint-sm: 576px;\n --breakpoint-md: 768px;\n --breakpoint-lg: 992px;\n --breakpoint-xl: 1200px;\n --font-family-sans-serif: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n text-align: left;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: 0 !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n -webkit-text-decoration-skip-ink: none;\n text-decoration-skip-ink: none;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg {\n overflow: hidden;\n vertical-align: middle;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #6c757d;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: inherit;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: 0.5rem;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nselect {\n word-wrap: normal;\n}\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton:not(:disabled),\n[type=\"button\"]:not(:disabled),\n[type=\"reset\"]:not(:disabled),\n[type=\"submit\"]:not(:disabled) {\n cursor: pointer;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n cursor: pointer;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n margin-bottom: 0.5rem;\n font-weight: 500;\n line-height: 1.2;\n}\n\nh1, .h1 {\n font-size: 2.5rem;\n}\n\nh2, .h2 {\n font-size: 2rem;\n}\n\nh3, .h3 {\n font-size: 1.75rem;\n}\n\nh4, .h4 {\n font-size: 1.5rem;\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: 6rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\n.display-2 {\n font-size: 5.5rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\n.display-3 {\n font-size: 4.5rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\n.display-4 {\n font-size: 3.5rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\nhr {\n margin-top: 1rem;\n margin-bottom: 1rem;\n border: 0;\n border-top: 1px solid rgba(0, 0, 0, 0.1);\n}\n\nsmall,\n.small {\n font-size: 80%;\n font-weight: 400;\n}\n\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n\n.list-inline-item:not(:last-child) {\n margin-right: 0.5rem;\n}\n\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n\n.blockquote-footer {\n display: block;\n font-size: 80%;\n color: #6c757d;\n}\n\n.blockquote-footer::before {\n content: \"\\2014\\00A0\";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: #fff;\n border: 1px solid #dee2e6;\n border-radius: 0.25rem;\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 90%;\n color: #6c757d;\n}\n\ncode {\n font-size: 87.5%;\n color: #e83e8c;\n word-break: break-word;\n}\n\na > code {\n color: inherit;\n}\n\nkbd {\n padding: 0.2rem 0.4rem;\n font-size: 87.5%;\n color: #fff;\n background-color: #212529;\n border-radius: 0.2rem;\n}\n\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n}\n\npre {\n display: block;\n font-size: 87.5%;\n color: #212529;\n}\n\npre code {\n font-size: inherit;\n color: inherit;\n word-break: normal;\n}\n\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n\n.container {\n width: 100%;\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container {\n max-width: 540px;\n }\n}\n\n@media (min-width: 768px) {\n .container {\n max-width: 720px;\n }\n}\n\n@media (min-width: 992px) {\n .container {\n max-width: 960px;\n }\n}\n\n@media (min-width: 1200px) {\n .container {\n max-width: 1140px;\n }\n}\n\n.container-fluid {\n width: 100%;\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n\n.row {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n margin-right: -15px;\n margin-left: -15px;\n}\n\n.no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n\n.no-gutters > .col,\n.no-gutters > [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n\n.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,\n.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,\n.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,\n.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,\n.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,\n.col-xl-auto {\n position: relative;\n width: 100%;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n.col {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n -ms-flex-positive: 1;\n flex-grow: 1;\n max-width: 100%;\n}\n\n.col-auto {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n}\n\n.col-1 {\n -ms-flex: 0 0 8.333333%;\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n}\n\n.col-2 {\n -ms-flex: 0 0 16.666667%;\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n}\n\n.col-3 {\n -ms-flex: 0 0 25%;\n flex: 0 0 25%;\n max-width: 25%;\n}\n\n.col-4 {\n -ms-flex: 0 0 33.333333%;\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n}\n\n.col-5 {\n -ms-flex: 0 0 41.666667%;\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n}\n\n.col-6 {\n -ms-flex: 0 0 50%;\n flex: 0 0 50%;\n max-width: 50%;\n}\n\n.col-7 {\n -ms-flex: 0 0 58.333333%;\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n}\n\n.col-8 {\n -ms-flex: 0 0 66.666667%;\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n}\n\n.col-9 {\n -ms-flex: 0 0 75%;\n flex: 0 0 75%;\n max-width: 75%;\n}\n\n.col-10 {\n -ms-flex: 0 0 83.333333%;\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n}\n\n.col-11 {\n -ms-flex: 0 0 91.666667%;\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n}\n\n.col-12 {\n -ms-flex: 0 0 100%;\n flex: 0 0 100%;\n max-width: 100%;\n}\n\n.order-first {\n -ms-flex-order: -1;\n order: -1;\n}\n\n.order-last {\n -ms-flex-order: 13;\n order: 13;\n}\n\n.order-0 {\n -ms-flex-order: 0;\n order: 0;\n}\n\n.order-1 {\n -ms-flex-order: 1;\n order: 1;\n}\n\n.order-2 {\n -ms-flex-order: 2;\n order: 2;\n}\n\n.order-3 {\n -ms-flex-order: 3;\n order: 3;\n}\n\n.order-4 {\n -ms-flex-order: 4;\n order: 4;\n}\n\n.order-5 {\n -ms-flex-order: 5;\n order: 5;\n}\n\n.order-6 {\n -ms-flex-order: 6;\n order: 6;\n}\n\n.order-7 {\n -ms-flex-order: 7;\n order: 7;\n}\n\n.order-8 {\n -ms-flex-order: 8;\n order: 8;\n}\n\n.order-9 {\n -ms-flex-order: 9;\n order: 9;\n}\n\n.order-10 {\n -ms-flex-order: 10;\n order: 10;\n}\n\n.order-11 {\n -ms-flex-order: 11;\n order: 11;\n}\n\n.order-12 {\n -ms-flex-order: 12;\n order: 12;\n}\n\n.offset-1 {\n margin-left: 8.333333%;\n}\n\n.offset-2 {\n margin-left: 16.666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.333333%;\n}\n\n.offset-5 {\n margin-left: 41.666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.333333%;\n}\n\n.offset-8 {\n margin-left: 66.666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.333333%;\n}\n\n.offset-11 {\n margin-left: 91.666667%;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n -ms-flex-positive: 1;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-sm-auto {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-sm-1 {\n -ms-flex: 0 0 8.333333%;\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-sm-2 {\n -ms-flex: 0 0 16.666667%;\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-sm-3 {\n -ms-flex: 0 0 25%;\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-sm-4 {\n -ms-flex: 0 0 33.333333%;\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-sm-5 {\n -ms-flex: 0 0 41.666667%;\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-sm-6 {\n -ms-flex: 0 0 50%;\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-sm-7 {\n -ms-flex: 0 0 58.333333%;\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-sm-8 {\n -ms-flex: 0 0 66.666667%;\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-sm-9 {\n -ms-flex: 0 0 75%;\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-sm-10 {\n -ms-flex: 0 0 83.333333%;\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-sm-11 {\n -ms-flex: 0 0 91.666667%;\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-sm-12 {\n -ms-flex: 0 0 100%;\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-sm-first {\n -ms-flex-order: -1;\n order: -1;\n }\n .order-sm-last {\n -ms-flex-order: 13;\n order: 13;\n }\n .order-sm-0 {\n -ms-flex-order: 0;\n order: 0;\n }\n .order-sm-1 {\n -ms-flex-order: 1;\n order: 1;\n }\n .order-sm-2 {\n -ms-flex-order: 2;\n order: 2;\n }\n .order-sm-3 {\n -ms-flex-order: 3;\n order: 3;\n }\n .order-sm-4 {\n -ms-flex-order: 4;\n order: 4;\n }\n .order-sm-5 {\n -ms-flex-order: 5;\n order: 5;\n }\n .order-sm-6 {\n -ms-flex-order: 6;\n order: 6;\n }\n .order-sm-7 {\n -ms-flex-order: 7;\n order: 7;\n }\n .order-sm-8 {\n -ms-flex-order: 8;\n order: 8;\n }\n .order-sm-9 {\n -ms-flex-order: 9;\n order: 9;\n }\n .order-sm-10 {\n -ms-flex-order: 10;\n order: 10;\n }\n .order-sm-11 {\n -ms-flex-order: 11;\n order: 11;\n }\n .order-sm-12 {\n -ms-flex-order: 12;\n order: 12;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.333333%;\n }\n .offset-sm-2 {\n margin-left: 16.666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.333333%;\n }\n .offset-sm-5 {\n margin-left: 41.666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.333333%;\n }\n .offset-sm-8 {\n margin-left: 66.666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.333333%;\n }\n .offset-sm-11 {\n margin-left: 91.666667%;\n }\n}\n\n@media (min-width: 768px) {\n .col-md {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n -ms-flex-positive: 1;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-md-auto {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-md-1 {\n -ms-flex: 0 0 8.333333%;\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-md-2 {\n -ms-flex: 0 0 16.666667%;\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-md-3 {\n -ms-flex: 0 0 25%;\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-md-4 {\n -ms-flex: 0 0 33.333333%;\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-md-5 {\n -ms-flex: 0 0 41.666667%;\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-md-6 {\n -ms-flex: 0 0 50%;\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-md-7 {\n -ms-flex: 0 0 58.333333%;\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-md-8 {\n -ms-flex: 0 0 66.666667%;\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-md-9 {\n -ms-flex: 0 0 75%;\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-md-10 {\n -ms-flex: 0 0 83.333333%;\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-md-11 {\n -ms-flex: 0 0 91.666667%;\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-md-12 {\n -ms-flex: 0 0 100%;\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-md-first {\n -ms-flex-order: -1;\n order: -1;\n }\n .order-md-last {\n -ms-flex-order: 13;\n order: 13;\n }\n .order-md-0 {\n -ms-flex-order: 0;\n order: 0;\n }\n .order-md-1 {\n -ms-flex-order: 1;\n order: 1;\n }\n .order-md-2 {\n -ms-flex-order: 2;\n order: 2;\n }\n .order-md-3 {\n -ms-flex-order: 3;\n order: 3;\n }\n .order-md-4 {\n -ms-flex-order: 4;\n order: 4;\n }\n .order-md-5 {\n -ms-flex-order: 5;\n order: 5;\n }\n .order-md-6 {\n -ms-flex-order: 6;\n order: 6;\n }\n .order-md-7 {\n -ms-flex-order: 7;\n order: 7;\n }\n .order-md-8 {\n -ms-flex-order: 8;\n order: 8;\n }\n .order-md-9 {\n -ms-flex-order: 9;\n order: 9;\n }\n .order-md-10 {\n -ms-flex-order: 10;\n order: 10;\n }\n .order-md-11 {\n -ms-flex-order: 11;\n order: 11;\n }\n .order-md-12 {\n -ms-flex-order: 12;\n order: 12;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.333333%;\n }\n .offset-md-2 {\n margin-left: 16.666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.333333%;\n }\n .offset-md-5 {\n margin-left: 41.666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.333333%;\n }\n .offset-md-8 {\n margin-left: 66.666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.333333%;\n }\n .offset-md-11 {\n margin-left: 91.666667%;\n }\n}\n\n@media (min-width: 992px) {\n .col-lg {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n -ms-flex-positive: 1;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-lg-auto {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-lg-1 {\n -ms-flex: 0 0 8.333333%;\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-lg-2 {\n -ms-flex: 0 0 16.666667%;\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-lg-3 {\n -ms-flex: 0 0 25%;\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-lg-4 {\n -ms-flex: 0 0 33.333333%;\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-lg-5 {\n -ms-flex: 0 0 41.666667%;\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-lg-6 {\n -ms-flex: 0 0 50%;\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-lg-7 {\n -ms-flex: 0 0 58.333333%;\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-lg-8 {\n -ms-flex: 0 0 66.666667%;\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-lg-9 {\n -ms-flex: 0 0 75%;\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-lg-10 {\n -ms-flex: 0 0 83.333333%;\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-lg-11 {\n -ms-flex: 0 0 91.666667%;\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-lg-12 {\n -ms-flex: 0 0 100%;\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-lg-first {\n -ms-flex-order: -1;\n order: -1;\n }\n .order-lg-last {\n -ms-flex-order: 13;\n order: 13;\n }\n .order-lg-0 {\n -ms-flex-order: 0;\n order: 0;\n }\n .order-lg-1 {\n -ms-flex-order: 1;\n order: 1;\n }\n .order-lg-2 {\n -ms-flex-order: 2;\n order: 2;\n }\n .order-lg-3 {\n -ms-flex-order: 3;\n order: 3;\n }\n .order-lg-4 {\n -ms-flex-order: 4;\n order: 4;\n }\n .order-lg-5 {\n -ms-flex-order: 5;\n order: 5;\n }\n .order-lg-6 {\n -ms-flex-order: 6;\n order: 6;\n }\n .order-lg-7 {\n -ms-flex-order: 7;\n order: 7;\n }\n .order-lg-8 {\n -ms-flex-order: 8;\n order: 8;\n }\n .order-lg-9 {\n -ms-flex-order: 9;\n order: 9;\n }\n .order-lg-10 {\n -ms-flex-order: 10;\n order: 10;\n }\n .order-lg-11 {\n -ms-flex-order: 11;\n order: 11;\n }\n .order-lg-12 {\n -ms-flex-order: 12;\n order: 12;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.333333%;\n }\n .offset-lg-2 {\n margin-left: 16.666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.333333%;\n }\n .offset-lg-5 {\n margin-left: 41.666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.333333%;\n }\n .offset-lg-8 {\n margin-left: 66.666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.333333%;\n }\n .offset-lg-11 {\n margin-left: 91.666667%;\n }\n}\n\n@media (min-width: 1200px) {\n .col-xl {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n -ms-flex-positive: 1;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-xl-auto {\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-xl-1 {\n -ms-flex: 0 0 8.333333%;\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-xl-2 {\n -ms-flex: 0 0 16.666667%;\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-xl-3 {\n -ms-flex: 0 0 25%;\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-xl-4 {\n -ms-flex: 0 0 33.333333%;\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-xl-5 {\n -ms-flex: 0 0 41.666667%;\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-xl-6 {\n -ms-flex: 0 0 50%;\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-xl-7 {\n -ms-flex: 0 0 58.333333%;\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-xl-8 {\n -ms-flex: 0 0 66.666667%;\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-xl-9 {\n -ms-flex: 0 0 75%;\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-xl-10 {\n -ms-flex: 0 0 83.333333%;\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-xl-11 {\n -ms-flex: 0 0 91.666667%;\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-xl-12 {\n -ms-flex: 0 0 100%;\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-xl-first {\n -ms-flex-order: -1;\n order: -1;\n }\n .order-xl-last {\n -ms-flex-order: 13;\n order: 13;\n }\n .order-xl-0 {\n -ms-flex-order: 0;\n order: 0;\n }\n .order-xl-1 {\n -ms-flex-order: 1;\n order: 1;\n }\n .order-xl-2 {\n -ms-flex-order: 2;\n order: 2;\n }\n .order-xl-3 {\n -ms-flex-order: 3;\n order: 3;\n }\n .order-xl-4 {\n -ms-flex-order: 4;\n order: 4;\n }\n .order-xl-5 {\n -ms-flex-order: 5;\n order: 5;\n }\n .order-xl-6 {\n -ms-flex-order: 6;\n order: 6;\n }\n .order-xl-7 {\n -ms-flex-order: 7;\n order: 7;\n }\n .order-xl-8 {\n -ms-flex-order: 8;\n order: 8;\n }\n .order-xl-9 {\n -ms-flex-order: 9;\n order: 9;\n }\n .order-xl-10 {\n -ms-flex-order: 10;\n order: 10;\n }\n .order-xl-11 {\n -ms-flex-order: 11;\n order: 11;\n }\n .order-xl-12 {\n -ms-flex-order: 12;\n order: 12;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.333333%;\n }\n .offset-xl-2 {\n margin-left: 16.666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.333333%;\n }\n .offset-xl-5 {\n margin-left: 41.666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.333333%;\n }\n .offset-xl-8 {\n margin-left: 66.666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.333333%;\n }\n .offset-xl-11 {\n margin-left: 91.666667%;\n }\n}\n\n.table {\n width: 100%;\n margin-bottom: 1rem;\n color: #212529;\n}\n\n.table th,\n.table td {\n padding: 0.75rem;\n vertical-align: top;\n border-top: 1px solid #dee2e6;\n}\n\n.table thead th {\n vertical-align: bottom;\n border-bottom: 2px solid #dee2e6;\n}\n\n.table tbody + tbody {\n border-top: 2px solid #dee2e6;\n}\n\n.table-sm th,\n.table-sm td {\n padding: 0.3rem;\n}\n\n.table-bordered {\n border: 1px solid #dee2e6;\n}\n\n.table-bordered th,\n.table-bordered td {\n border: 1px solid #dee2e6;\n}\n\n.table-bordered thead th,\n.table-bordered thead td {\n border-bottom-width: 2px;\n}\n\n.table-borderless th,\n.table-borderless td,\n.table-borderless thead th,\n.table-borderless tbody + tbody {\n border: 0;\n}\n\n.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.table-hover tbody tr:hover {\n color: #212529;\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-primary,\n.table-primary > th,\n.table-primary > td {\n background-color: #b8daff;\n}\n\n.table-primary th,\n.table-primary td,\n.table-primary thead th,\n.table-primary tbody + tbody {\n border-color: #7abaff;\n}\n\n.table-hover .table-primary:hover {\n background-color: #9fcdff;\n}\n\n.table-hover .table-primary:hover > td,\n.table-hover .table-primary:hover > th {\n background-color: #9fcdff;\n}\n\n.table-secondary,\n.table-secondary > th,\n.table-secondary > td {\n background-color: #d6d8db;\n}\n\n.table-secondary th,\n.table-secondary td,\n.table-secondary thead th,\n.table-secondary tbody + tbody {\n border-color: #b3b7bb;\n}\n\n.table-hover .table-secondary:hover {\n background-color: #c8cbcf;\n}\n\n.table-hover .table-secondary:hover > td,\n.table-hover .table-secondary:hover > th {\n background-color: #c8cbcf;\n}\n\n.table-success,\n.table-success > th,\n.table-success > td {\n background-color: #c3e6cb;\n}\n\n.table-success th,\n.table-success td,\n.table-success thead th,\n.table-success tbody + tbody {\n border-color: #8fd19e;\n}\n\n.table-hover .table-success:hover {\n background-color: #b1dfbb;\n}\n\n.table-hover .table-success:hover > td,\n.table-hover .table-success:hover > th {\n background-color: #b1dfbb;\n}\n\n.table-info,\n.table-info > th,\n.table-info > td {\n background-color: #bee5eb;\n}\n\n.table-info th,\n.table-info td,\n.table-info thead th,\n.table-info tbody + tbody {\n border-color: #86cfda;\n}\n\n.table-hover .table-info:hover {\n background-color: #abdde5;\n}\n\n.table-hover .table-info:hover > td,\n.table-hover .table-info:hover > th {\n background-color: #abdde5;\n}\n\n.table-warning,\n.table-warning > th,\n.table-warning > td {\n background-color: #ffeeba;\n}\n\n.table-warning th,\n.table-warning td,\n.table-warning thead th,\n.table-warning tbody + tbody {\n border-color: #ffdf7e;\n}\n\n.table-hover .table-warning:hover {\n background-color: #ffe8a1;\n}\n\n.table-hover .table-warning:hover > td,\n.table-hover .table-warning:hover > th {\n background-color: #ffe8a1;\n}\n\n.table-danger,\n.table-danger > th,\n.table-danger > td {\n background-color: #f5c6cb;\n}\n\n.table-danger th,\n.table-danger td,\n.table-danger thead th,\n.table-danger tbody + tbody {\n border-color: #ed969e;\n}\n\n.table-hover .table-danger:hover {\n background-color: #f1b0b7;\n}\n\n.table-hover .table-danger:hover > td,\n.table-hover .table-danger:hover > th {\n background-color: #f1b0b7;\n}\n\n.table-light,\n.table-light > th,\n.table-light > td {\n background-color: #fdfdfe;\n}\n\n.table-light th,\n.table-light td,\n.table-light thead th,\n.table-light tbody + tbody {\n border-color: #fbfcfc;\n}\n\n.table-hover .table-light:hover {\n background-color: #ececf6;\n}\n\n.table-hover .table-light:hover > td,\n.table-hover .table-light:hover > th {\n background-color: #ececf6;\n}\n\n.table-dark,\n.table-dark > th,\n.table-dark > td {\n background-color: #c6c8ca;\n}\n\n.table-dark th,\n.table-dark td,\n.table-dark thead th,\n.table-dark tbody + tbody {\n border-color: #95999c;\n}\n\n.table-hover .table-dark:hover {\n background-color: #b9bbbe;\n}\n\n.table-hover .table-dark:hover > td,\n.table-hover .table-dark:hover > th {\n background-color: #b9bbbe;\n}\n\n.table-active,\n.table-active > th,\n.table-active > td {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover > td,\n.table-hover .table-active:hover > th {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table .thead-dark th {\n color: #fff;\n background-color: #343a40;\n border-color: #454d55;\n}\n\n.table .thead-light th {\n color: #495057;\n background-color: #e9ecef;\n border-color: #dee2e6;\n}\n\n.table-dark {\n color: #fff;\n background-color: #343a40;\n}\n\n.table-dark th,\n.table-dark td,\n.table-dark thead th {\n border-color: #454d55;\n}\n\n.table-dark.table-bordered {\n border: 0;\n}\n\n.table-dark.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(255, 255, 255, 0.05);\n}\n\n.table-dark.table-hover tbody tr:hover {\n color: #fff;\n background-color: rgba(255, 255, 255, 0.075);\n}\n\n@media (max-width: 575.98px) {\n .table-responsive-sm {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-sm > .table-bordered {\n border: 0;\n }\n}\n\n@media (max-width: 767.98px) {\n .table-responsive-md {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-md > .table-bordered {\n border: 0;\n }\n}\n\n@media (max-width: 991.98px) {\n .table-responsive-lg {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-lg > .table-bordered {\n border: 0;\n }\n}\n\n@media (max-width: 1199.98px) {\n .table-responsive-xl {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-xl > .table-bordered {\n border: 0;\n }\n}\n\n.table-responsive {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.table-responsive > .table-bordered {\n border: 0;\n}\n\n.form-control {\n display: block;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .form-control {\n transition: none;\n }\n}\n\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n\n.form-control:focus {\n color: #495057;\n background-color: #fff;\n border-color: #80bdff;\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.form-control::-webkit-input-placeholder {\n color: #6c757d;\n opacity: 1;\n}\n\n.form-control::-moz-placeholder {\n color: #6c757d;\n opacity: 1;\n}\n\n.form-control:-ms-input-placeholder {\n color: #6c757d;\n opacity: 1;\n}\n\n.form-control::-ms-input-placeholder {\n color: #6c757d;\n opacity: 1;\n}\n\n.form-control::placeholder {\n color: #6c757d;\n opacity: 1;\n}\n\n.form-control:disabled, .form-control[readonly] {\n background-color: #e9ecef;\n opacity: 1;\n}\n\nselect.form-control:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.form-control-file,\n.form-control-range {\n display: block;\n width: 100%;\n}\n\n.col-form-label {\n padding-top: calc(0.375rem + 1px);\n padding-bottom: calc(0.375rem + 1px);\n margin-bottom: 0;\n font-size: inherit;\n line-height: 1.5;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem + 1px);\n padding-bottom: calc(0.5rem + 1px);\n font-size: 1.25rem;\n line-height: 1.5;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem + 1px);\n padding-bottom: calc(0.25rem + 1px);\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.form-control-plaintext {\n display: block;\n width: 100%;\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n margin-bottom: 0;\n line-height: 1.5;\n color: #212529;\n background-color: transparent;\n border: solid transparent;\n border-width: 1px 0;\n}\n\n.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm {\n height: calc(1.5em + 0.5rem + 2px);\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.form-control-lg {\n height: calc(1.5em + 1rem + 2px);\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\nselect.form-control[size], select.form-control[multiple] {\n height: auto;\n}\n\ntextarea.form-control {\n height: auto;\n}\n\n.form-group {\n margin-bottom: 1rem;\n}\n\n.form-text {\n display: block;\n margin-top: 0.25rem;\n}\n\n.form-row {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n margin-right: -5px;\n margin-left: -5px;\n}\n\n.form-row > .col,\n.form-row > [class*=\"col-\"] {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.form-check {\n position: relative;\n display: block;\n padding-left: 1.25rem;\n}\n\n.form-check-input {\n position: absolute;\n margin-top: 0.3rem;\n margin-left: -1.25rem;\n}\n\n.form-check-input:disabled ~ .form-check-label {\n color: #6c757d;\n}\n\n.form-check-label {\n margin-bottom: 0;\n}\n\n.form-check-inline {\n display: -ms-inline-flexbox;\n display: inline-flex;\n -ms-flex-align: center;\n align-items: center;\n padding-left: 0;\n margin-right: 0.75rem;\n}\n\n.form-check-inline .form-check-input {\n position: static;\n margin-top: 0;\n margin-right: 0.3125rem;\n margin-left: 0;\n}\n\n.valid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 80%;\n color: #28a745;\n}\n\n.valid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: .1rem;\n font-size: 0.875rem;\n line-height: 1.5;\n color: #fff;\n background-color: rgba(40, 167, 69, 0.9);\n border-radius: 0.25rem;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid {\n border-color: #28a745;\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: center right calc(0.375em + 0.1875rem);\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus {\n border-color: #28a745;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:valid ~ .valid-feedback,\n.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback,\n.form-control.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated textarea.form-control:valid, textarea.form-control.is-valid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .custom-select:valid, .custom-select.is-valid {\n border-color: #28a745;\n padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem);\n background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px, url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus {\n border-color: #28a745;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-select:valid ~ .valid-feedback,\n.was-validated .custom-select:valid ~ .valid-tooltip, .custom-select.is-valid ~ .valid-feedback,\n.custom-select.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-control-file:valid ~ .valid-feedback,\n.was-validated .form-control-file:valid ~ .valid-tooltip, .form-control-file.is-valid ~ .valid-feedback,\n.form-control-file.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {\n color: #28a745;\n}\n\n.was-validated .form-check-input:valid ~ .valid-feedback,\n.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback,\n.form-check-input.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label {\n color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before {\n border-color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .valid-feedback,\n.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback,\n.custom-control-input.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before {\n border-color: #34ce57;\n background-color: #34ce57;\n}\n\n.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before {\n border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label {\n border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .valid-feedback,\n.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback,\n.custom-file-input.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label {\n border-color: #28a745;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.invalid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 80%;\n color: #dc3545;\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: .1rem;\n font-size: 0.875rem;\n line-height: 1.5;\n color: #fff;\n background-color: rgba(220, 53, 69, 0.9);\n border-radius: 0.25rem;\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid {\n border-color: #dc3545;\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E\");\n background-repeat: no-repeat;\n background-position: center right calc(0.375em + 0.1875rem);\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .form-control:invalid ~ .invalid-feedback,\n.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback,\n.form-control.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .custom-select:invalid, .custom-select.is-invalid {\n border-color: #dc3545;\n padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem);\n background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px, url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E\") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-select:invalid ~ .invalid-feedback,\n.was-validated .custom-select:invalid ~ .invalid-tooltip, .custom-select.is-invalid ~ .invalid-feedback,\n.custom-select.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-control-file:invalid ~ .invalid-feedback,\n.was-validated .form-control-file:invalid ~ .invalid-tooltip, .form-control-file.is-invalid ~ .invalid-feedback,\n.form-control-file.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {\n color: #dc3545;\n}\n\n.was-validated .form-check-input:invalid ~ .invalid-feedback,\n.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback,\n.form-check-input.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label {\n color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before {\n border-color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .invalid-feedback,\n.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback,\n.custom-control-input.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before {\n border-color: #e4606d;\n background-color: #e4606d;\n}\n\n.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before {\n border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label {\n border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .invalid-feedback,\n.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback,\n.custom-file-input.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.form-inline {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-flow: row wrap;\n flex-flow: row wrap;\n -ms-flex-align: center;\n align-items: center;\n}\n\n.form-inline .form-check {\n width: 100%;\n}\n\n@media (min-width: 576px) {\n .form-inline label {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n margin-bottom: 0;\n }\n .form-inline .form-group {\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n -ms-flex-flow: row wrap;\n flex-flow: row wrap;\n -ms-flex-align: center;\n align-items: center;\n margin-bottom: 0;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-plaintext {\n display: inline-block;\n }\n .form-inline .input-group,\n .form-inline .custom-select {\n width: auto;\n }\n .form-inline .form-check {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n width: auto;\n padding-left: 0;\n }\n .form-inline .form-check-input {\n position: relative;\n -ms-flex-negative: 0;\n flex-shrink: 0;\n margin-top: 0;\n margin-right: 0.25rem;\n margin-left: 0;\n }\n .form-inline .custom-control {\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n }\n .form-inline .custom-control-label {\n margin-bottom: 0;\n }\n}\n\n.btn {\n display: inline-block;\n font-weight: 400;\n color: #212529;\n text-align: center;\n vertical-align: middle;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n background-color: transparent;\n border: 1px solid transparent;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n line-height: 1.5;\n border-radius: 0.25rem;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .btn {\n transition: none;\n }\n}\n\n.btn:hover {\n color: #212529;\n text-decoration: none;\n}\n\n.btn:focus, .btn.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.btn.disabled, .btn:disabled {\n opacity: 0.65;\n}\n\na.btn.disabled,\nfieldset:disabled a.btn {\n pointer-events: none;\n}\n\n.btn-primary {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:hover {\n color: #fff;\n background-color: #0069d9;\n border-color: #0062cc;\n}\n\n.btn-primary:focus, .btn-primary.focus {\n box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);\n}\n\n.btn-primary.disabled, .btn-primary:disabled {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,\n.show > .btn-primary.dropdown-toggle {\n color: #fff;\n background-color: #0062cc;\n border-color: #005cbf;\n}\n\n.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-primary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);\n}\n\n.btn-secondary {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-secondary:hover {\n color: #fff;\n background-color: #5a6268;\n border-color: #545b62;\n}\n\n.btn-secondary:focus, .btn-secondary.focus {\n box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);\n}\n\n.btn-secondary.disabled, .btn-secondary:disabled {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,\n.show > .btn-secondary.dropdown-toggle {\n color: #fff;\n background-color: #545b62;\n border-color: #4e555b;\n}\n\n.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-secondary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);\n}\n\n.btn-success {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:hover {\n color: #fff;\n background-color: #218838;\n border-color: #1e7e34;\n}\n\n.btn-success:focus, .btn-success.focus {\n box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);\n}\n\n.btn-success.disabled, .btn-success:disabled {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,\n.show > .btn-success.dropdown-toggle {\n color: #fff;\n background-color: #1e7e34;\n border-color: #1c7430;\n}\n\n.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,\n.show > .btn-success.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);\n}\n\n.btn-info {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:hover {\n color: #fff;\n background-color: #138496;\n border-color: #117a8b;\n}\n\n.btn-info:focus, .btn-info.focus {\n box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);\n}\n\n.btn-info.disabled, .btn-info:disabled {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,\n.show > .btn-info.dropdown-toggle {\n color: #fff;\n background-color: #117a8b;\n border-color: #10707f;\n}\n\n.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,\n.show > .btn-info.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);\n}\n\n.btn-warning {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:hover {\n color: #212529;\n background-color: #e0a800;\n border-color: #d39e00;\n}\n\n.btn-warning:focus, .btn-warning.focus {\n box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);\n}\n\n.btn-warning.disabled, .btn-warning:disabled {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,\n.show > .btn-warning.dropdown-toggle {\n color: #212529;\n background-color: #d39e00;\n border-color: #c69500;\n}\n\n.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,\n.show > .btn-warning.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);\n}\n\n.btn-danger {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:hover {\n color: #fff;\n background-color: #c82333;\n border-color: #bd2130;\n}\n\n.btn-danger:focus, .btn-danger.focus {\n box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);\n}\n\n.btn-danger.disabled, .btn-danger:disabled {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,\n.show > .btn-danger.dropdown-toggle {\n color: #fff;\n background-color: #bd2130;\n border-color: #b21f2d;\n}\n\n.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,\n.show > .btn-danger.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);\n}\n\n.btn-light {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:hover {\n color: #212529;\n background-color: #e2e6ea;\n border-color: #dae0e5;\n}\n\n.btn-light:focus, .btn-light.focus {\n box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);\n}\n\n.btn-light.disabled, .btn-light:disabled {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,\n.show > .btn-light.dropdown-toggle {\n color: #212529;\n background-color: #dae0e5;\n border-color: #d3d9df;\n}\n\n.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,\n.show > .btn-light.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);\n}\n\n.btn-dark {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:hover {\n color: #fff;\n background-color: #23272b;\n border-color: #1d2124;\n}\n\n.btn-dark:focus, .btn-dark.focus {\n box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);\n}\n\n.btn-dark.disabled, .btn-dark:disabled {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,\n.show > .btn-dark.dropdown-toggle {\n color: #fff;\n background-color: #1d2124;\n border-color: #171a1d;\n}\n\n.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,\n.show > .btn-dark.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);\n}\n\n.btn-outline-primary {\n color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:hover {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:focus, .btn-outline-primary.focus {\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-primary.disabled, .btn-outline-primary:disabled {\n color: #007bff;\n background-color: transparent;\n}\n\n.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,\n.show > .btn-outline-primary.dropdown-toggle {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-primary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-secondary {\n color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-outline-secondary:hover {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-outline-secondary:focus, .btn-outline-secondary.focus {\n box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {\n color: #6c757d;\n background-color: transparent;\n}\n\n.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,\n.show > .btn-outline-secondary.dropdown-toggle {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-secondary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.btn-outline-success {\n color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:hover {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:focus, .btn-outline-success.focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-success.disabled, .btn-outline-success:disabled {\n color: #28a745;\n background-color: transparent;\n}\n\n.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,\n.show > .btn-outline-success.dropdown-toggle {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-success.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-info {\n color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:hover {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:focus, .btn-outline-info.focus {\n box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-info.disabled, .btn-outline-info:disabled {\n color: #17a2b8;\n background-color: transparent;\n}\n\n.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,\n.show > .btn-outline-info.dropdown-toggle {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-info.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-warning {\n color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:hover {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:focus, .btn-outline-warning.focus {\n box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-warning.disabled, .btn-outline-warning:disabled {\n color: #ffc107;\n background-color: transparent;\n}\n\n.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,\n.show > .btn-outline-warning.dropdown-toggle {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-warning.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-danger {\n color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:hover {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:focus, .btn-outline-danger.focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-danger.disabled, .btn-outline-danger:disabled {\n color: #dc3545;\n background-color: transparent;\n}\n\n.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,\n.show > .btn-outline-danger.dropdown-toggle {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-danger.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-light {\n color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:hover {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:focus, .btn-outline-light.focus {\n box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-light.disabled, .btn-outline-light:disabled {\n color: #f8f9fa;\n background-color: transparent;\n}\n\n.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,\n.show > .btn-outline-light.dropdown-toggle {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-light.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-dark {\n color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:hover {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:focus, .btn-outline-dark.focus {\n box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.btn-outline-dark.disabled, .btn-outline-dark:disabled {\n color: #343a40;\n background-color: transparent;\n}\n\n.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,\n.show > .btn-outline-dark.dropdown-toggle {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-dark.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.btn-link {\n font-weight: 400;\n color: #007bff;\n text-decoration: none;\n}\n\n.btn-link:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\n.btn-link:focus, .btn-link.focus {\n text-decoration: underline;\n box-shadow: none;\n}\n\n.btn-link:disabled, .btn-link.disabled {\n color: #6c757d;\n pointer-events: none;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n.btn-block + .btn-block {\n margin-top: 0.5rem;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n\n.fade {\n transition: opacity 0.15s linear;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fade {\n transition: none;\n }\n}\n\n.fade:not(.show) {\n opacity: 0;\n}\n\n.collapse:not(.show) {\n display: none;\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .collapsing {\n transition: none;\n }\n}\n\n.dropup,\n.dropright,\n.dropdown,\n.dropleft {\n position: relative;\n}\n\n.dropdown-toggle {\n white-space: nowrap;\n}\n\n.dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-bottom: 0;\n border-left: 0.3em solid transparent;\n}\n\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 10rem;\n padding: 0.5rem 0;\n margin: 0.125rem 0 0;\n font-size: 1rem;\n color: #212529;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n\n@media (min-width: 576px) {\n .dropdown-menu-sm-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-sm-right {\n right: 0;\n left: auto;\n }\n}\n\n@media (min-width: 768px) {\n .dropdown-menu-md-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-md-right {\n right: 0;\n left: auto;\n }\n}\n\n@media (min-width: 992px) {\n .dropdown-menu-lg-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-lg-right {\n right: 0;\n left: auto;\n }\n}\n\n@media (min-width: 1200px) {\n .dropdown-menu-xl-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-xl-right {\n right: 0;\n left: auto;\n }\n}\n\n.dropup .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 0.125rem;\n}\n\n.dropup .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0;\n border-right: 0.3em solid transparent;\n border-bottom: 0.3em solid;\n border-left: 0.3em solid transparent;\n}\n\n.dropup .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropright .dropdown-menu {\n top: 0;\n right: auto;\n left: 100%;\n margin-top: 0;\n margin-left: 0.125rem;\n}\n\n.dropright .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0;\n border-bottom: 0.3em solid transparent;\n border-left: 0.3em solid;\n}\n\n.dropright .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropright .dropdown-toggle::after {\n vertical-align: 0;\n}\n\n.dropleft .dropdown-menu {\n top: 0;\n right: 100%;\n left: auto;\n margin-top: 0;\n margin-right: 0.125rem;\n}\n\n.dropleft .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n}\n\n.dropleft .dropdown-toggle::after {\n display: none;\n}\n\n.dropleft .dropdown-toggle::before {\n display: inline-block;\n margin-right: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0.3em solid;\n border-bottom: 0.3em solid transparent;\n}\n\n.dropleft .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropleft .dropdown-toggle::before {\n vertical-align: 0;\n}\n\n.dropdown-menu[x-placement^=\"top\"], .dropdown-menu[x-placement^=\"right\"], .dropdown-menu[x-placement^=\"bottom\"], .dropdown-menu[x-placement^=\"left\"] {\n right: auto;\n bottom: auto;\n}\n\n.dropdown-divider {\n height: 0;\n margin: 0.5rem 0;\n overflow: hidden;\n border-top: 1px solid #e9ecef;\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: 0.25rem 1.5rem;\n clear: both;\n font-weight: 400;\n color: #212529;\n text-align: inherit;\n white-space: nowrap;\n background-color: transparent;\n border: 0;\n}\n\n.dropdown-item:hover, .dropdown-item:focus {\n color: #16181b;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.dropdown-item.active, .dropdown-item:active {\n color: #fff;\n text-decoration: none;\n background-color: #007bff;\n}\n\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: #6c757d;\n pointer-events: none;\n background-color: transparent;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: 0.5rem 1.5rem;\n margin-bottom: 0;\n font-size: 0.875rem;\n color: #6c757d;\n white-space: nowrap;\n}\n\n.dropdown-item-text {\n display: block;\n padding: 0.25rem 1.5rem;\n color: #212529;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: -ms-inline-flexbox;\n display: inline-flex;\n vertical-align: middle;\n}\n\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n}\n\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover {\n z-index: 1;\n}\n\n.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 1;\n}\n\n.btn-toolbar {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-pack: start;\n justify-content: flex-start;\n}\n\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) {\n margin-left: -1px;\n}\n\n.btn-group > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n\n.dropdown-toggle-split::after,\n.dropup .dropdown-toggle-split::after,\n.dropright .dropdown-toggle-split::after {\n margin-left: 0;\n}\n\n.dropleft .dropdown-toggle-split::before {\n margin-right: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n -ms-flex-direction: column;\n flex-direction: column;\n -ms-flex-align: start;\n align-items: flex-start;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group {\n width: 100%;\n}\n\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) {\n margin-top: -1px;\n}\n\n.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group-vertical > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.btn-group-toggle > .btn,\n.btn-group-toggle > .btn-group > .btn {\n margin-bottom: 0;\n}\n\n.btn-group-toggle > .btn input[type=\"radio\"],\n.btn-group-toggle > .btn input[type=\"checkbox\"],\n.btn-group-toggle > .btn-group > .btn input[type=\"radio\"],\n.btn-group-toggle > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n\n.input-group {\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-align: stretch;\n align-items: stretch;\n width: 100%;\n}\n\n.input-group > .form-control,\n.input-group > .form-control-plaintext,\n.input-group > .custom-select,\n.input-group > .custom-file {\n position: relative;\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n width: 1%;\n margin-bottom: 0;\n}\n\n.input-group > .form-control + .form-control,\n.input-group > .form-control + .custom-select,\n.input-group > .form-control + .custom-file,\n.input-group > .form-control-plaintext + .form-control,\n.input-group > .form-control-plaintext + .custom-select,\n.input-group > .form-control-plaintext + .custom-file,\n.input-group > .custom-select + .form-control,\n.input-group > .custom-select + .custom-select,\n.input-group > .custom-select + .custom-file,\n.input-group > .custom-file + .form-control,\n.input-group > .custom-file + .custom-select,\n.input-group > .custom-file + .custom-file {\n margin-left: -1px;\n}\n\n.input-group > .form-control:focus,\n.input-group > .custom-select:focus,\n.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label {\n z-index: 3;\n}\n\n.input-group > .custom-file .custom-file-input:focus {\n z-index: 4;\n}\n\n.input-group > .form-control:not(:last-child),\n.input-group > .custom-select:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group > .form-control:not(:first-child),\n.input-group > .custom-select:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.input-group > .custom-file {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n}\n\n.input-group > .custom-file:not(:last-child) .custom-file-label,\n.input-group > .custom-file:not(:last-child) .custom-file-label::after {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group > .custom-file:not(:first-child) .custom-file-label {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.input-group-prepend,\n.input-group-append {\n display: -ms-flexbox;\n display: flex;\n}\n\n.input-group-prepend .btn,\n.input-group-append .btn {\n position: relative;\n z-index: 2;\n}\n\n.input-group-prepend .btn:focus,\n.input-group-append .btn:focus {\n z-index: 3;\n}\n\n.input-group-prepend .btn + .btn,\n.input-group-prepend .btn + .input-group-text,\n.input-group-prepend .input-group-text + .input-group-text,\n.input-group-prepend .input-group-text + .btn,\n.input-group-append .btn + .btn,\n.input-group-append .btn + .input-group-text,\n.input-group-append .input-group-text + .input-group-text,\n.input-group-append .input-group-text + .btn {\n margin-left: -1px;\n}\n\n.input-group-prepend {\n margin-right: -1px;\n}\n\n.input-group-append {\n margin-left: -1px;\n}\n\n.input-group-text {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n padding: 0.375rem 0.75rem;\n margin-bottom: 0;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n text-align: center;\n white-space: nowrap;\n background-color: #e9ecef;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n}\n\n.input-group-text input[type=\"radio\"],\n.input-group-text input[type=\"checkbox\"] {\n margin-top: 0;\n}\n\n.input-group-lg > .form-control:not(textarea),\n.input-group-lg > .custom-select {\n height: calc(1.5em + 1rem + 2px);\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .custom-select,\n.input-group-lg > .input-group-prepend > .input-group-text,\n.input-group-lg > .input-group-append > .input-group-text,\n.input-group-lg > .input-group-prepend > .btn,\n.input-group-lg > .input-group-append > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\n.input-group-sm > .form-control:not(textarea),\n.input-group-sm > .custom-select {\n height: calc(1.5em + 0.5rem + 2px);\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .custom-select,\n.input-group-sm > .input-group-prepend > .input-group-text,\n.input-group-sm > .input-group-append > .input-group-text,\n.input-group-sm > .input-group-prepend > .btn,\n.input-group-sm > .input-group-append > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.input-group-lg > .custom-select,\n.input-group-sm > .custom-select {\n padding-right: 1.75rem;\n}\n\n.input-group > .input-group-prepend > .btn,\n.input-group > .input-group-prepend > .input-group-text,\n.input-group > .input-group-append:not(:last-child) > .btn,\n.input-group > .input-group-append:not(:last-child) > .input-group-text,\n.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group > .input-group-append > .btn,\n.input-group > .input-group-append > .input-group-text,\n.input-group > .input-group-prepend:not(:first-child) > .btn,\n.input-group > .input-group-prepend:not(:first-child) > .input-group-text,\n.input-group > .input-group-prepend:first-child > .btn:not(:first-child),\n.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.custom-control {\n position: relative;\n display: block;\n min-height: 1.5rem;\n padding-left: 1.5rem;\n}\n\n.custom-control-inline {\n display: -ms-inline-flexbox;\n display: inline-flex;\n margin-right: 1rem;\n}\n\n.custom-control-input {\n position: absolute;\n z-index: -1;\n opacity: 0;\n}\n\n.custom-control-input:checked ~ .custom-control-label::before {\n color: #fff;\n border-color: #007bff;\n background-color: #007bff;\n}\n\n.custom-control-input:focus ~ .custom-control-label::before {\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-control-input:focus:not(:checked) ~ .custom-control-label::before {\n border-color: #80bdff;\n}\n\n.custom-control-input:not(:disabled):active ~ .custom-control-label::before {\n color: #fff;\n background-color: #b3d7ff;\n border-color: #b3d7ff;\n}\n\n.custom-control-input:disabled ~ .custom-control-label {\n color: #6c757d;\n}\n\n.custom-control-input:disabled ~ .custom-control-label::before {\n background-color: #e9ecef;\n}\n\n.custom-control-label {\n position: relative;\n margin-bottom: 0;\n vertical-align: top;\n}\n\n.custom-control-label::before {\n position: absolute;\n top: 0.25rem;\n left: -1.5rem;\n display: block;\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n content: \"\";\n background-color: #fff;\n border: #adb5bd solid 1px;\n}\n\n.custom-control-label::after {\n position: absolute;\n top: 0.25rem;\n left: -1.5rem;\n display: block;\n width: 1rem;\n height: 1rem;\n content: \"\";\n background: no-repeat 50% / 50% 50%;\n}\n\n.custom-checkbox .custom-control-label::before {\n border-radius: 0.25rem;\n}\n\n.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e\");\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before {\n border-color: #007bff;\n background-color: #007bff;\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e\");\n}\n\n.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-radio .custom-control-label::before {\n border-radius: 50%;\n}\n\n.custom-radio .custom-control-input:checked ~ .custom-control-label::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\");\n}\n\n.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-switch {\n padding-left: 2.25rem;\n}\n\n.custom-switch .custom-control-label::before {\n left: -2.25rem;\n width: 1.75rem;\n pointer-events: all;\n border-radius: 0.5rem;\n}\n\n.custom-switch .custom-control-label::after {\n top: calc(0.25rem + 2px);\n left: calc(-2.25rem + 2px);\n width: calc(1rem - 4px);\n height: calc(1rem - 4px);\n background-color: #adb5bd;\n border-radius: 0.5rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out;\n transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-switch .custom-control-label::after {\n transition: none;\n }\n}\n\n.custom-switch .custom-control-input:checked ~ .custom-control-label::after {\n background-color: #fff;\n -webkit-transform: translateX(0.75rem);\n transform: translateX(0.75rem);\n}\n\n.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-select {\n display: inline-block;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n padding: 0.375rem 1.75rem 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n vertical-align: middle;\n background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px;\n background-color: #fff;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.custom-select:focus {\n border-color: #80bdff;\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-select:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.custom-select[multiple], .custom-select[size]:not([size=\"1\"]) {\n height: auto;\n padding-right: 0.75rem;\n background-image: none;\n}\n\n.custom-select:disabled {\n color: #6c757d;\n background-color: #e9ecef;\n}\n\n.custom-select::-ms-expand {\n display: none;\n}\n\n.custom-select-sm {\n height: calc(1.5em + 0.5rem + 2px);\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n padding-left: 0.5rem;\n font-size: 0.875rem;\n}\n\n.custom-select-lg {\n height: calc(1.5em + 1rem + 2px);\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n padding-left: 1rem;\n font-size: 1.25rem;\n}\n\n.custom-file {\n position: relative;\n display: inline-block;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n margin-bottom: 0;\n}\n\n.custom-file-input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n margin: 0;\n opacity: 0;\n}\n\n.custom-file-input:focus ~ .custom-file-label {\n border-color: #80bdff;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-file-input:disabled ~ .custom-file-label {\n background-color: #e9ecef;\n}\n\n.custom-file-input:lang(en) ~ .custom-file-label::after {\n content: \"Browse\";\n}\n\n.custom-file-input ~ .custom-file-label[data-browse]::after {\n content: attr(data-browse);\n}\n\n.custom-file-label {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n height: calc(1.5em + 0.75rem + 2px);\n padding: 0.375rem 0.75rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n background-color: #fff;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n}\n\n.custom-file-label::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n z-index: 3;\n display: block;\n height: calc(1.5em + 0.75rem);\n padding: 0.375rem 0.75rem;\n line-height: 1.5;\n color: #495057;\n content: \"Browse\";\n background-color: #e9ecef;\n border-left: inherit;\n border-radius: 0 0.25rem 0.25rem 0;\n}\n\n.custom-range {\n width: 100%;\n height: calc(1rem + 0.4rem);\n padding: 0;\n background-color: transparent;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.custom-range:focus {\n outline: none;\n}\n\n.custom-range:focus::-webkit-slider-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range:focus::-moz-range-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range:focus::-ms-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range::-moz-focus-outer {\n border: 0;\n}\n\n.custom-range::-webkit-slider-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: -0.25rem;\n background-color: #007bff;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n -webkit-appearance: none;\n appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-range::-webkit-slider-thumb {\n transition: none;\n }\n}\n\n.custom-range::-webkit-slider-thumb:active {\n background-color: #b3d7ff;\n}\n\n.custom-range::-webkit-slider-runnable-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: #dee2e6;\n border-color: transparent;\n border-radius: 1rem;\n}\n\n.custom-range::-moz-range-thumb {\n width: 1rem;\n height: 1rem;\n background-color: #007bff;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n -moz-appearance: none;\n appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-range::-moz-range-thumb {\n transition: none;\n }\n}\n\n.custom-range::-moz-range-thumb:active {\n background-color: #b3d7ff;\n}\n\n.custom-range::-moz-range-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: #dee2e6;\n border-color: transparent;\n border-radius: 1rem;\n}\n\n.custom-range::-ms-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: 0;\n margin-right: 0.2rem;\n margin-left: 0.2rem;\n background-color: #007bff;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-range::-ms-thumb {\n transition: none;\n }\n}\n\n.custom-range::-ms-thumb:active {\n background-color: #b3d7ff;\n}\n\n.custom-range::-ms-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: transparent;\n border-color: transparent;\n border-width: 0.5rem;\n}\n\n.custom-range::-ms-fill-lower {\n background-color: #dee2e6;\n border-radius: 1rem;\n}\n\n.custom-range::-ms-fill-upper {\n margin-right: 15px;\n background-color: #dee2e6;\n border-radius: 1rem;\n}\n\n.custom-range:disabled::-webkit-slider-thumb {\n background-color: #adb5bd;\n}\n\n.custom-range:disabled::-webkit-slider-runnable-track {\n cursor: default;\n}\n\n.custom-range:disabled::-moz-range-thumb {\n background-color: #adb5bd;\n}\n\n.custom-range:disabled::-moz-range-track {\n cursor: default;\n}\n\n.custom-range:disabled::-ms-thumb {\n background-color: #adb5bd;\n}\n\n.custom-control-label::before,\n.custom-file-label,\n.custom-select {\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-control-label::before,\n .custom-file-label,\n .custom-select {\n transition: none;\n }\n}\n\n.nav {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: 0.5rem 1rem;\n}\n\n.nav-link:hover, .nav-link:focus {\n text-decoration: none;\n}\n\n.nav-link.disabled {\n color: #6c757d;\n pointer-events: none;\n cursor: default;\n}\n\n.nav-tabs {\n border-bottom: 1px solid #dee2e6;\n}\n\n.nav-tabs .nav-item {\n margin-bottom: -1px;\n}\n\n.nav-tabs .nav-link {\n border: 1px solid transparent;\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {\n border-color: #e9ecef #e9ecef #dee2e6;\n}\n\n.nav-tabs .nav-link.disabled {\n color: #6c757d;\n background-color: transparent;\n border-color: transparent;\n}\n\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: #495057;\n background-color: #fff;\n border-color: #dee2e6 #dee2e6 #fff;\n}\n\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills .nav-link {\n border-radius: 0.25rem;\n}\n\n.nav-pills .nav-link.active,\n.nav-pills .show > .nav-link {\n color: #fff;\n background-color: #007bff;\n}\n\n.nav-fill .nav-item {\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified .nav-item {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n -ms-flex-positive: 1;\n flex-grow: 1;\n text-align: center;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: justify;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n}\n\n.navbar > .container,\n.navbar > .container-fluid {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: justify;\n justify-content: space-between;\n}\n\n.navbar-brand {\n display: inline-block;\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: 1rem;\n font-size: 1.25rem;\n line-height: inherit;\n white-space: nowrap;\n}\n\n.navbar-brand:hover, .navbar-brand:focus {\n text-decoration: none;\n}\n\n.navbar-nav {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.navbar-nav .nav-link {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-nav .dropdown-menu {\n position: static;\n float: none;\n}\n\n.navbar-text {\n display: inline-block;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n\n.navbar-collapse {\n -ms-flex-preferred-size: 100%;\n flex-basis: 100%;\n -ms-flex-positive: 1;\n flex-grow: 1;\n -ms-flex-align: center;\n align-items: center;\n}\n\n.navbar-toggler {\n padding: 0.25rem 0.75rem;\n font-size: 1.25rem;\n line-height: 1;\n background-color: transparent;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.navbar-toggler:hover, .navbar-toggler:focus {\n text-decoration: none;\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n content: \"\";\n background: no-repeat center center;\n background-size: 100% 100%;\n}\n\n@media (max-width: 575.98px) {\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n -ms-flex-flow: row nowrap;\n flex-flow: row nowrap;\n -ms-flex-pack: start;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n -ms-flex-wrap: nowrap;\n flex-wrap: nowrap;\n }\n .navbar-expand-sm .navbar-collapse {\n display: -ms-flexbox !important;\n display: flex !important;\n -ms-flex-preferred-size: auto;\n flex-basis: auto;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 767.98px) {\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 768px) {\n .navbar-expand-md {\n -ms-flex-flow: row nowrap;\n flex-flow: row nowrap;\n -ms-flex-pack: start;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n -ms-flex-wrap: nowrap;\n flex-wrap: nowrap;\n }\n .navbar-expand-md .navbar-collapse {\n display: -ms-flexbox !important;\n display: flex !important;\n -ms-flex-preferred-size: auto;\n flex-basis: auto;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 991.98px) {\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 992px) {\n .navbar-expand-lg {\n -ms-flex-flow: row nowrap;\n flex-flow: row nowrap;\n -ms-flex-pack: start;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n -ms-flex-wrap: nowrap;\n flex-wrap: nowrap;\n }\n .navbar-expand-lg .navbar-collapse {\n display: -ms-flexbox !important;\n display: flex !important;\n -ms-flex-preferred-size: auto;\n flex-basis: auto;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 1199.98px) {\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n -ms-flex-flow: row nowrap;\n flex-flow: row nowrap;\n -ms-flex-pack: start;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n -ms-flex-wrap: nowrap;\n flex-wrap: nowrap;\n }\n .navbar-expand-xl .navbar-collapse {\n display: -ms-flexbox !important;\n display: flex !important;\n -ms-flex-preferred-size: auto;\n flex-basis: auto;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n}\n\n.navbar-expand {\n -ms-flex-flow: row nowrap;\n flex-flow: row nowrap;\n -ms-flex-pack: start;\n justify-content: flex-start;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-expand .navbar-nav {\n -ms-flex-direction: row;\n flex-direction: row;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n\n.navbar-expand .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n -ms-flex-wrap: nowrap;\n flex-wrap: nowrap;\n}\n\n.navbar-expand .navbar-collapse {\n display: -ms-flexbox !important;\n display: flex !important;\n -ms-flex-preferred-size: auto;\n flex-basis: auto;\n}\n\n.navbar-expand .navbar-toggler {\n display: none;\n}\n\n.navbar-light .navbar-brand {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-nav .nav-link {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {\n color: rgba(0, 0, 0, 0.7);\n}\n\n.navbar-light .navbar-nav .nav-link.disabled {\n color: rgba(0, 0, 0, 0.3);\n}\n\n.navbar-light .navbar-nav .show > .nav-link,\n.navbar-light .navbar-nav .active > .nav-link,\n.navbar-light .navbar-nav .nav-link.show,\n.navbar-light .navbar-nav .nav-link.active {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-toggler {\n color: rgba(0, 0, 0, 0.5);\n border-color: rgba(0, 0, 0, 0.1);\n}\n\n.navbar-light .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.navbar-light .navbar-text {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-text a {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-dark .navbar-brand {\n color: #fff;\n}\n\n.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {\n color: #fff;\n}\n\n.navbar-dark .navbar-nav .nav-link {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {\n color: rgba(255, 255, 255, 0.75);\n}\n\n.navbar-dark .navbar-nav .nav-link.disabled {\n color: rgba(255, 255, 255, 0.25);\n}\n\n.navbar-dark .navbar-nav .show > .nav-link,\n.navbar-dark .navbar-nav .active > .nav-link,\n.navbar-dark .navbar-nav .nav-link.show,\n.navbar-dark .navbar-nav .nav-link.active {\n color: #fff;\n}\n\n.navbar-dark .navbar-toggler {\n color: rgba(255, 255, 255, 0.5);\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n.navbar-dark .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.navbar-dark .navbar-text {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-text a {\n color: #fff;\n}\n\n.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {\n color: #fff;\n}\n\n.card {\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n min-width: 0;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: border-box;\n border: 1px solid rgba(0, 0, 0, 0.125);\n border-radius: 0.25rem;\n}\n\n.card > hr {\n margin-right: 0;\n margin-left: 0;\n}\n\n.card > .list-group:first-child .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.card > .list-group:last-child .list-group-item:last-child {\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.card-body {\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n padding: 1.25rem;\n}\n\n.card-title {\n margin-bottom: 0.75rem;\n}\n\n.card-subtitle {\n margin-top: -0.375rem;\n margin-bottom: 0;\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link:hover {\n text-decoration: none;\n}\n\n.card-link + .card-link {\n margin-left: 1.25rem;\n}\n\n.card-header {\n padding: 0.75rem 1.25rem;\n margin-bottom: 0;\n background-color: rgba(0, 0, 0, 0.03);\n border-bottom: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-header:first-child {\n border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;\n}\n\n.card-header + .list-group .list-group-item:first-child {\n border-top: 0;\n}\n\n.card-footer {\n padding: 0.75rem 1.25rem;\n background-color: rgba(0, 0, 0, 0.03);\n border-top: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-footer:last-child {\n border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);\n}\n\n.card-header-tabs {\n margin-right: -0.625rem;\n margin-bottom: -0.75rem;\n margin-left: -0.625rem;\n border-bottom: 0;\n}\n\n.card-header-pills {\n margin-right: -0.625rem;\n margin-left: -0.625rem;\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: 1.25rem;\n}\n\n.card-img {\n width: 100%;\n border-radius: calc(0.25rem - 1px);\n}\n\n.card-img-top {\n width: 100%;\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n\n.card-img-bottom {\n width: 100%;\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n\n.card-deck {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n\n.card-deck .card {\n margin-bottom: 15px;\n}\n\n@media (min-width: 576px) {\n .card-deck {\n -ms-flex-flow: row wrap;\n flex-flow: row wrap;\n margin-right: -15px;\n margin-left: -15px;\n }\n .card-deck .card {\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 1 0 0%;\n flex: 1 0 0%;\n -ms-flex-direction: column;\n flex-direction: column;\n margin-right: 15px;\n margin-bottom: 0;\n margin-left: 15px;\n }\n}\n\n.card-group {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n\n.card-group > .card {\n margin-bottom: 15px;\n}\n\n@media (min-width: 576px) {\n .card-group {\n -ms-flex-flow: row wrap;\n flex-flow: row wrap;\n }\n .card-group > .card {\n -ms-flex: 1 0 0%;\n flex: 1 0 0%;\n margin-bottom: 0;\n }\n .card-group > .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group > .card:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-top,\n .card-group > .card:not(:last-child) .card-header {\n border-top-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-bottom,\n .card-group > .card:not(:last-child) .card-footer {\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-top,\n .card-group > .card:not(:first-child) .card-header {\n border-top-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-bottom,\n .card-group > .card:not(:first-child) .card-footer {\n border-bottom-left-radius: 0;\n }\n}\n\n.card-columns .card {\n margin-bottom: 0.75rem;\n}\n\n@media (min-width: 576px) {\n .card-columns {\n -webkit-column-count: 3;\n -moz-column-count: 3;\n column-count: 3;\n -webkit-column-gap: 1.25rem;\n -moz-column-gap: 1.25rem;\n column-gap: 1.25rem;\n orphans: 1;\n widows: 1;\n }\n .card-columns .card {\n display: inline-block;\n width: 100%;\n }\n}\n\n.accordion > .card {\n overflow: hidden;\n}\n\n.accordion > .card:not(:first-of-type) .card-header:first-child {\n border-radius: 0;\n}\n\n.accordion > .card:not(:first-of-type):not(:last-of-type) {\n border-bottom: 0;\n border-radius: 0;\n}\n\n.accordion > .card:first-of-type {\n border-bottom: 0;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.accordion > .card:last-of-type {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.accordion > .card .card-header {\n margin-bottom: -1px;\n}\n\n.breadcrumb {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n padding: 0.75rem 1rem;\n margin-bottom: 1rem;\n list-style: none;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.breadcrumb-item + .breadcrumb-item {\n padding-left: 0.5rem;\n}\n\n.breadcrumb-item + .breadcrumb-item::before {\n display: inline-block;\n padding-right: 0.5rem;\n color: #6c757d;\n content: \"/\";\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: underline;\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: none;\n}\n\n.breadcrumb-item.active {\n color: #6c757d;\n}\n\n.pagination {\n display: -ms-flexbox;\n display: flex;\n padding-left: 0;\n list-style: none;\n border-radius: 0.25rem;\n}\n\n.page-link {\n position: relative;\n display: block;\n padding: 0.5rem 0.75rem;\n margin-left: -1px;\n line-height: 1.25;\n color: #007bff;\n background-color: #fff;\n border: 1px solid #dee2e6;\n}\n\n.page-link:hover {\n z-index: 2;\n color: #0056b3;\n text-decoration: none;\n background-color: #e9ecef;\n border-color: #dee2e6;\n}\n\n.page-link:focus {\n z-index: 2;\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.page-item:first-child .page-link {\n margin-left: 0;\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.page-item:last-child .page-link {\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n}\n\n.page-item.active .page-link {\n z-index: 1;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.page-item.disabled .page-link {\n color: #6c757d;\n pointer-events: none;\n cursor: auto;\n background-color: #fff;\n border-color: #dee2e6;\n}\n\n.pagination-lg .page-link {\n padding: 0.75rem 1.5rem;\n font-size: 1.25rem;\n line-height: 1.5;\n}\n\n.pagination-lg .page-item:first-child .page-link {\n border-top-left-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n\n.pagination-lg .page-item:last-child .page-link {\n border-top-right-radius: 0.3rem;\n border-bottom-right-radius: 0.3rem;\n}\n\n.pagination-sm .page-link {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.pagination-sm .page-item:first-child .page-link {\n border-top-left-radius: 0.2rem;\n border-bottom-left-radius: 0.2rem;\n}\n\n.pagination-sm .page-item:last-child .page-link {\n border-top-right-radius: 0.2rem;\n border-bottom-right-radius: 0.2rem;\n}\n\n.badge {\n display: inline-block;\n padding: 0.25em 0.4em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25rem;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .badge {\n transition: none;\n }\n}\n\na.badge:hover, a.badge:focus {\n text-decoration: none;\n}\n\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.badge-pill {\n padding-right: 0.6em;\n padding-left: 0.6em;\n border-radius: 10rem;\n}\n\n.badge-primary {\n color: #fff;\n background-color: #007bff;\n}\n\na.badge-primary:hover, a.badge-primary:focus {\n color: #fff;\n background-color: #0062cc;\n}\n\na.badge-primary:focus, a.badge-primary.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.badge-secondary {\n color: #fff;\n background-color: #6c757d;\n}\n\na.badge-secondary:hover, a.badge-secondary:focus {\n color: #fff;\n background-color: #545b62;\n}\n\na.badge-secondary:focus, a.badge-secondary.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.badge-success {\n color: #fff;\n background-color: #28a745;\n}\n\na.badge-success:hover, a.badge-success:focus {\n color: #fff;\n background-color: #1e7e34;\n}\n\na.badge-success:focus, a.badge-success.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.badge-info {\n color: #fff;\n background-color: #17a2b8;\n}\n\na.badge-info:hover, a.badge-info:focus {\n color: #fff;\n background-color: #117a8b;\n}\n\na.badge-info:focus, a.badge-info.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.badge-warning {\n color: #212529;\n background-color: #ffc107;\n}\n\na.badge-warning:hover, a.badge-warning:focus {\n color: #212529;\n background-color: #d39e00;\n}\n\na.badge-warning:focus, a.badge-warning.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.badge-danger {\n color: #fff;\n background-color: #dc3545;\n}\n\na.badge-danger:hover, a.badge-danger:focus {\n color: #fff;\n background-color: #bd2130;\n}\n\na.badge-danger:focus, a.badge-danger.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.badge-light {\n color: #212529;\n background-color: #f8f9fa;\n}\n\na.badge-light:hover, a.badge-light:focus {\n color: #212529;\n background-color: #dae0e5;\n}\n\na.badge-light:focus, a.badge-light.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.badge-dark {\n color: #fff;\n background-color: #343a40;\n}\n\na.badge-dark:hover, a.badge-dark:focus {\n color: #fff;\n background-color: #1d2124;\n}\n\na.badge-dark:focus, a.badge-dark.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.jumbotron {\n padding: 2rem 1rem;\n margin-bottom: 2rem;\n background-color: #e9ecef;\n border-radius: 0.3rem;\n}\n\n@media (min-width: 576px) {\n .jumbotron {\n padding: 4rem 2rem;\n }\n}\n\n.jumbotron-fluid {\n padding-right: 0;\n padding-left: 0;\n border-radius: 0;\n}\n\n.alert {\n position: relative;\n padding: 0.75rem 1.25rem;\n margin-bottom: 1rem;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: 700;\n}\n\n.alert-dismissible {\n padding-right: 4rem;\n}\n\n.alert-dismissible .close {\n position: absolute;\n top: 0;\n right: 0;\n padding: 0.75rem 1.25rem;\n color: inherit;\n}\n\n.alert-primary {\n color: #004085;\n background-color: #cce5ff;\n border-color: #b8daff;\n}\n\n.alert-primary hr {\n border-top-color: #9fcdff;\n}\n\n.alert-primary .alert-link {\n color: #002752;\n}\n\n.alert-secondary {\n color: #383d41;\n background-color: #e2e3e5;\n border-color: #d6d8db;\n}\n\n.alert-secondary hr {\n border-top-color: #c8cbcf;\n}\n\n.alert-secondary .alert-link {\n color: #202326;\n}\n\n.alert-success {\n color: #155724;\n background-color: #d4edda;\n border-color: #c3e6cb;\n}\n\n.alert-success hr {\n border-top-color: #b1dfbb;\n}\n\n.alert-success .alert-link {\n color: #0b2e13;\n}\n\n.alert-info {\n color: #0c5460;\n background-color: #d1ecf1;\n border-color: #bee5eb;\n}\n\n.alert-info hr {\n border-top-color: #abdde5;\n}\n\n.alert-info .alert-link {\n color: #062c33;\n}\n\n.alert-warning {\n color: #856404;\n background-color: #fff3cd;\n border-color: #ffeeba;\n}\n\n.alert-warning hr {\n border-top-color: #ffe8a1;\n}\n\n.alert-warning .alert-link {\n color: #533f03;\n}\n\n.alert-danger {\n color: #721c24;\n background-color: #f8d7da;\n border-color: #f5c6cb;\n}\n\n.alert-danger hr {\n border-top-color: #f1b0b7;\n}\n\n.alert-danger .alert-link {\n color: #491217;\n}\n\n.alert-light {\n color: #818182;\n background-color: #fefefe;\n border-color: #fdfdfe;\n}\n\n.alert-light hr {\n border-top-color: #ececf6;\n}\n\n.alert-light .alert-link {\n color: #686868;\n}\n\n.alert-dark {\n color: #1b1e21;\n background-color: #d6d8d9;\n border-color: #c6c8ca;\n}\n\n.alert-dark hr {\n border-top-color: #b9bbbe;\n}\n\n.alert-dark .alert-link {\n color: #040505;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 1rem 0;\n }\n to {\n background-position: 0 0;\n }\n}\n\n@keyframes progress-bar-stripes {\n from {\n background-position: 1rem 0;\n }\n to {\n background-position: 0 0;\n }\n}\n\n.progress {\n display: -ms-flexbox;\n display: flex;\n height: 1rem;\n overflow: hidden;\n font-size: 0.75rem;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.progress-bar {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n -ms-flex-pack: center;\n justify-content: center;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n background-color: #007bff;\n transition: width 0.6s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 1rem 1rem;\n}\n\n.progress-bar-animated {\n -webkit-animation: progress-bar-stripes 1s linear infinite;\n animation: progress-bar-stripes 1s linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .progress-bar-animated {\n -webkit-animation: none;\n animation: none;\n }\n}\n\n.media {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: start;\n align-items: flex-start;\n}\n\n.media-body {\n -ms-flex: 1;\n flex: 1;\n}\n\n.list-group {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n}\n\n.list-group-item-action {\n width: 100%;\n color: #495057;\n text-align: inherit;\n}\n\n.list-group-item-action:hover, .list-group-item-action:focus {\n z-index: 1;\n color: #495057;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.list-group-item-action:active {\n color: #212529;\n background-color: #e9ecef;\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 0.75rem 1.25rem;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.list-group-item.disabled, .list-group-item:disabled {\n color: #6c757d;\n pointer-events: none;\n background-color: #fff;\n}\n\n.list-group-item.active {\n z-index: 2;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.list-group-horizontal {\n -ms-flex-direction: row;\n flex-direction: row;\n}\n\n.list-group-horizontal .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n}\n\n.list-group-horizontal .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n}\n\n.list-group-horizontal .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n}\n\n@media (min-width: 576px) {\n .list-group-horizontal-sm {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .list-group-horizontal-sm .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-sm .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-sm .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n@media (min-width: 768px) {\n .list-group-horizontal-md {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .list-group-horizontal-md .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-md .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-md .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n@media (min-width: 992px) {\n .list-group-horizontal-lg {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .list-group-horizontal-lg .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-lg .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-lg .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n@media (min-width: 1200px) {\n .list-group-horizontal-xl {\n -ms-flex-direction: row;\n flex-direction: row;\n }\n .list-group-horizontal-xl .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-xl .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xl .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n.list-group-flush .list-group-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n\n.list-group-flush .list-group-item:last-child {\n margin-bottom: -1px;\n}\n\n.list-group-flush:first-child .list-group-item:first-child {\n border-top: 0;\n}\n\n.list-group-flush:last-child .list-group-item:last-child {\n margin-bottom: 0;\n border-bottom: 0;\n}\n\n.list-group-item-primary {\n color: #004085;\n background-color: #b8daff;\n}\n\n.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {\n color: #004085;\n background-color: #9fcdff;\n}\n\n.list-group-item-primary.list-group-item-action.active {\n color: #fff;\n background-color: #004085;\n border-color: #004085;\n}\n\n.list-group-item-secondary {\n color: #383d41;\n background-color: #d6d8db;\n}\n\n.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {\n color: #383d41;\n background-color: #c8cbcf;\n}\n\n.list-group-item-secondary.list-group-item-action.active {\n color: #fff;\n background-color: #383d41;\n border-color: #383d41;\n}\n\n.list-group-item-success {\n color: #155724;\n background-color: #c3e6cb;\n}\n\n.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {\n color: #155724;\n background-color: #b1dfbb;\n}\n\n.list-group-item-success.list-group-item-action.active {\n color: #fff;\n background-color: #155724;\n border-color: #155724;\n}\n\n.list-group-item-info {\n color: #0c5460;\n background-color: #bee5eb;\n}\n\n.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {\n color: #0c5460;\n background-color: #abdde5;\n}\n\n.list-group-item-info.list-group-item-action.active {\n color: #fff;\n background-color: #0c5460;\n border-color: #0c5460;\n}\n\n.list-group-item-warning {\n color: #856404;\n background-color: #ffeeba;\n}\n\n.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {\n color: #856404;\n background-color: #ffe8a1;\n}\n\n.list-group-item-warning.list-group-item-action.active {\n color: #fff;\n background-color: #856404;\n border-color: #856404;\n}\n\n.list-group-item-danger {\n color: #721c24;\n background-color: #f5c6cb;\n}\n\n.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {\n color: #721c24;\n background-color: #f1b0b7;\n}\n\n.list-group-item-danger.list-group-item-action.active {\n color: #fff;\n background-color: #721c24;\n border-color: #721c24;\n}\n\n.list-group-item-light {\n color: #818182;\n background-color: #fdfdfe;\n}\n\n.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {\n color: #818182;\n background-color: #ececf6;\n}\n\n.list-group-item-light.list-group-item-action.active {\n color: #fff;\n background-color: #818182;\n border-color: #818182;\n}\n\n.list-group-item-dark {\n color: #1b1e21;\n background-color: #c6c8ca;\n}\n\n.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {\n color: #1b1e21;\n background-color: #b9bbbe;\n}\n\n.list-group-item-dark.list-group-item-action.active {\n color: #fff;\n background-color: #1b1e21;\n border-color: #1b1e21;\n}\n\n.close {\n float: right;\n font-size: 1.5rem;\n font-weight: 700;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n opacity: .5;\n}\n\n.close:hover {\n color: #000;\n text-decoration: none;\n}\n\n.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus {\n opacity: .75;\n}\n\nbutton.close {\n padding: 0;\n background-color: transparent;\n border: 0;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\na.close.disabled {\n pointer-events: none;\n}\n\n.toast {\n max-width: 350px;\n overflow: hidden;\n font-size: 0.875rem;\n background-color: rgba(255, 255, 255, 0.85);\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.1);\n box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);\n -webkit-backdrop-filter: blur(10px);\n backdrop-filter: blur(10px);\n opacity: 0;\n border-radius: 0.25rem;\n}\n\n.toast:not(:last-child) {\n margin-bottom: 0.75rem;\n}\n\n.toast.showing {\n opacity: 1;\n}\n\n.toast.show {\n display: block;\n opacity: 1;\n}\n\n.toast.hide {\n display: none;\n}\n\n.toast-header {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n padding: 0.25rem 0.75rem;\n color: #6c757d;\n background-color: rgba(255, 255, 255, 0.85);\n background-clip: padding-box;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n}\n\n.toast-body {\n padding: 0.75rem;\n}\n\n.modal-open {\n overflow: hidden;\n}\n\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.modal {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1050;\n display: none;\n width: 100%;\n height: 100%;\n overflow: hidden;\n outline: 0;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 0.5rem;\n pointer-events: none;\n}\n\n.modal.fade .modal-dialog {\n transition: -webkit-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out;\n -webkit-transform: translate(0, -50px);\n transform: translate(0, -50px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .modal.fade .modal-dialog {\n transition: none;\n }\n}\n\n.modal.show .modal-dialog {\n -webkit-transform: none;\n transform: none;\n}\n\n.modal-dialog-scrollable {\n display: -ms-flexbox;\n display: flex;\n max-height: calc(100% - 1rem);\n}\n\n.modal-dialog-scrollable .modal-content {\n max-height: calc(100vh - 1rem);\n overflow: hidden;\n}\n\n.modal-dialog-scrollable .modal-header,\n.modal-dialog-scrollable .modal-footer {\n -ms-flex-negative: 0;\n flex-shrink: 0;\n}\n\n.modal-dialog-scrollable .modal-body {\n overflow-y: auto;\n}\n\n.modal-dialog-centered {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n min-height: calc(100% - 1rem);\n}\n\n.modal-dialog-centered::before {\n display: block;\n height: calc(100vh - 1rem);\n content: \"\";\n}\n\n.modal-dialog-centered.modal-dialog-scrollable {\n -ms-flex-direction: column;\n flex-direction: column;\n -ms-flex-pack: center;\n justify-content: center;\n height: 100%;\n}\n\n.modal-dialog-centered.modal-dialog-scrollable .modal-content {\n max-height: none;\n}\n\n.modal-dialog-centered.modal-dialog-scrollable::before {\n content: none;\n}\n\n.modal-content {\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n width: 100%;\n pointer-events: auto;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n outline: 0;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1040;\n width: 100vw;\n height: 100vh;\n background-color: #000;\n}\n\n.modal-backdrop.fade {\n opacity: 0;\n}\n\n.modal-backdrop.show {\n opacity: 0.5;\n}\n\n.modal-header {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: start;\n align-items: flex-start;\n -ms-flex-pack: justify;\n justify-content: space-between;\n padding: 1rem 1rem;\n border-bottom: 1px solid #dee2e6;\n border-top-left-radius: 0.3rem;\n border-top-right-radius: 0.3rem;\n}\n\n.modal-header .close {\n padding: 1rem 1rem;\n margin: -1rem -1rem -1rem auto;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: 1.5;\n}\n\n.modal-body {\n position: relative;\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n padding: 1rem;\n}\n\n.modal-footer {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: end;\n justify-content: flex-end;\n padding: 1rem;\n border-top: 1px solid #dee2e6;\n border-bottom-right-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n\n.modal-footer > :not(:first-child) {\n margin-left: .25rem;\n}\n\n.modal-footer > :not(:last-child) {\n margin-right: .25rem;\n}\n\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n@media (min-width: 576px) {\n .modal-dialog {\n max-width: 500px;\n margin: 1.75rem auto;\n }\n .modal-dialog-scrollable {\n max-height: calc(100% - 3.5rem);\n }\n .modal-dialog-scrollable .modal-content {\n max-height: calc(100vh - 3.5rem);\n }\n .modal-dialog-centered {\n min-height: calc(100% - 3.5rem);\n }\n .modal-dialog-centered::before {\n height: calc(100vh - 3.5rem);\n }\n .modal-sm {\n max-width: 300px;\n }\n}\n\n@media (min-width: 992px) {\n .modal-lg,\n .modal-xl {\n max-width: 800px;\n }\n}\n\n@media (min-width: 1200px) {\n .modal-xl {\n max-width: 1140px;\n }\n}\n\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n opacity: 0;\n}\n\n.tooltip.show {\n opacity: 0.9;\n}\n\n.tooltip .arrow {\n position: absolute;\n display: block;\n width: 0.8rem;\n height: 0.4rem;\n}\n\n.tooltip .arrow::before {\n position: absolute;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-tooltip-top, .bs-tooltip-auto[x-placement^=\"top\"] {\n padding: 0.4rem 0;\n}\n\n.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^=\"top\"] .arrow {\n bottom: 0;\n}\n\n.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^=\"top\"] .arrow::before {\n top: 0;\n border-width: 0.4rem 0.4rem 0;\n border-top-color: #000;\n}\n\n.bs-tooltip-right, .bs-tooltip-auto[x-placement^=\"right\"] {\n padding: 0 0.4rem;\n}\n\n.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^=\"right\"] .arrow {\n left: 0;\n width: 0.4rem;\n height: 0.8rem;\n}\n\n.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^=\"right\"] .arrow::before {\n right: 0;\n border-width: 0.4rem 0.4rem 0.4rem 0;\n border-right-color: #000;\n}\n\n.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^=\"bottom\"] {\n padding: 0.4rem 0;\n}\n\n.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^=\"bottom\"] .arrow {\n top: 0;\n}\n\n.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^=\"bottom\"] .arrow::before {\n bottom: 0;\n border-width: 0 0.4rem 0.4rem;\n border-bottom-color: #000;\n}\n\n.bs-tooltip-left, .bs-tooltip-auto[x-placement^=\"left\"] {\n padding: 0 0.4rem;\n}\n\n.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^=\"left\"] .arrow {\n right: 0;\n width: 0.4rem;\n height: 0.8rem;\n}\n\n.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^=\"left\"] .arrow::before {\n left: 0;\n border-width: 0.4rem 0 0.4rem 0.4rem;\n border-left-color: #000;\n}\n\n.tooltip-inner {\n max-width: 200px;\n padding: 0.25rem 0.5rem;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 0.25rem;\n}\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: block;\n max-width: 276px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n}\n\n.popover .arrow {\n position: absolute;\n display: block;\n width: 1rem;\n height: 0.5rem;\n margin: 0 0.3rem;\n}\n\n.popover .arrow::before, .popover .arrow::after {\n position: absolute;\n display: block;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-popover-top, .bs-popover-auto[x-placement^=\"top\"] {\n margin-bottom: 0.5rem;\n}\n\n.bs-popover-top > .arrow, .bs-popover-auto[x-placement^=\"top\"] > .arrow {\n bottom: calc((0.5rem + 1px) * -1);\n}\n\n.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^=\"top\"] > .arrow::before {\n bottom: 0;\n border-width: 0.5rem 0.5rem 0;\n border-top-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^=\"top\"] > .arrow::after {\n bottom: 1px;\n border-width: 0.5rem 0.5rem 0;\n border-top-color: #fff;\n}\n\n.bs-popover-right, .bs-popover-auto[x-placement^=\"right\"] {\n margin-left: 0.5rem;\n}\n\n.bs-popover-right > .arrow, .bs-popover-auto[x-placement^=\"right\"] > .arrow {\n left: calc((0.5rem + 1px) * -1);\n width: 0.5rem;\n height: 1rem;\n margin: 0.3rem 0;\n}\n\n.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^=\"right\"] > .arrow::before {\n left: 0;\n border-width: 0.5rem 0.5rem 0.5rem 0;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^=\"right\"] > .arrow::after {\n left: 1px;\n border-width: 0.5rem 0.5rem 0.5rem 0;\n border-right-color: #fff;\n}\n\n.bs-popover-bottom, .bs-popover-auto[x-placement^=\"bottom\"] {\n margin-top: 0.5rem;\n}\n\n.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow {\n top: calc((0.5rem + 1px) * -1);\n}\n\n.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow::before {\n top: 0;\n border-width: 0 0.5rem 0.5rem 0.5rem;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow::after {\n top: 1px;\n border-width: 0 0.5rem 0.5rem 0.5rem;\n border-bottom-color: #fff;\n}\n\n.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^=\"bottom\"] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: 1rem;\n margin-left: -0.5rem;\n content: \"\";\n border-bottom: 1px solid #f7f7f7;\n}\n\n.bs-popover-left, .bs-popover-auto[x-placement^=\"left\"] {\n margin-right: 0.5rem;\n}\n\n.bs-popover-left > .arrow, .bs-popover-auto[x-placement^=\"left\"] > .arrow {\n right: calc((0.5rem + 1px) * -1);\n width: 0.5rem;\n height: 1rem;\n margin: 0.3rem 0;\n}\n\n.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^=\"left\"] > .arrow::before {\n right: 0;\n border-width: 0.5rem 0 0.5rem 0.5rem;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^=\"left\"] > .arrow::after {\n right: 1px;\n border-width: 0.5rem 0 0.5rem 0.5rem;\n border-left-color: #fff;\n}\n\n.popover-header {\n padding: 0.5rem 0.75rem;\n margin-bottom: 0;\n font-size: 1rem;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-top-left-radius: calc(0.3rem - 1px);\n border-top-right-radius: calc(0.3rem - 1px);\n}\n\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: 0.5rem 0.75rem;\n color: #212529;\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel.pointer-event {\n -ms-touch-action: pan-y;\n touch-action: pan-y;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n\n.carousel-inner::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.carousel-item {\n position: relative;\n display: none;\n float: left;\n width: 100%;\n margin-right: -100%;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n transition: -webkit-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-item {\n transition: none;\n }\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n.carousel-item-next:not(.carousel-item-left),\n.active.carousel-item-right {\n -webkit-transform: translateX(100%);\n transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-right),\n.active.carousel-item-left {\n -webkit-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n\n.carousel-fade .carousel-item {\n opacity: 0;\n transition-property: opacity;\n -webkit-transform: none;\n transform: none;\n}\n\n.carousel-fade .carousel-item.active,\n.carousel-fade .carousel-item-next.carousel-item-left,\n.carousel-fade .carousel-item-prev.carousel-item-right {\n z-index: 1;\n opacity: 1;\n}\n\n.carousel-fade .active.carousel-item-left,\n.carousel-fade .active.carousel-item-right {\n z-index: 0;\n opacity: 0;\n transition: 0s 0.6s opacity;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-fade .active.carousel-item-left,\n .carousel-fade .active.carousel-item-right {\n transition: none;\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n width: 15%;\n color: #fff;\n text-align: center;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-control-prev,\n .carousel-control-next {\n transition: none;\n }\n}\n\n.carousel-control-prev:hover, .carousel-control-prev:focus,\n.carousel-control-next:hover,\n.carousel-control-next:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: 0.9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n background: no-repeat 50% / 100% 100%;\n}\n\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e\");\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e\");\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 15;\n display: -ms-flexbox;\n display: flex;\n -ms-flex-pack: center;\n justify-content: center;\n padding-left: 0;\n margin-right: 15%;\n margin-left: 15%;\n list-style: none;\n}\n\n.carousel-indicators li {\n box-sizing: content-box;\n -ms-flex: 0 1 auto;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #fff;\n background-clip: padding-box;\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n opacity: .5;\n transition: opacity 0.6s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-indicators li {\n transition: none;\n }\n}\n\n.carousel-indicators .active {\n opacity: 1;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n}\n\n@-webkit-keyframes spinner-border {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n\n@keyframes spinner-border {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n\n.spinner-border {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n vertical-align: text-bottom;\n border: 0.25em solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n -webkit-animation: spinner-border .75s linear infinite;\n animation: spinner-border .75s linear infinite;\n}\n\n.spinner-border-sm {\n width: 1rem;\n height: 1rem;\n border-width: 0.2em;\n}\n\n@-webkit-keyframes spinner-grow {\n 0% {\n -webkit-transform: scale(0);\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n }\n}\n\n@keyframes spinner-grow {\n 0% {\n -webkit-transform: scale(0);\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n }\n}\n\n.spinner-grow {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n vertical-align: text-bottom;\n background-color: currentColor;\n border-radius: 50%;\n opacity: 0;\n -webkit-animation: spinner-grow .75s linear infinite;\n animation: spinner-grow .75s linear infinite;\n}\n\n.spinner-grow-sm {\n width: 1rem;\n height: 1rem;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.bg-primary {\n background-color: #007bff !important;\n}\n\na.bg-primary:hover, a.bg-primary:focus,\nbutton.bg-primary:hover,\nbutton.bg-primary:focus {\n background-color: #0062cc !important;\n}\n\n.bg-secondary {\n background-color: #6c757d !important;\n}\n\na.bg-secondary:hover, a.bg-secondary:focus,\nbutton.bg-secondary:hover,\nbutton.bg-secondary:focus {\n background-color: #545b62 !important;\n}\n\n.bg-success {\n background-color: #28a745 !important;\n}\n\na.bg-success:hover, a.bg-success:focus,\nbutton.bg-success:hover,\nbutton.bg-success:focus {\n background-color: #1e7e34 !important;\n}\n\n.bg-info {\n background-color: #17a2b8 !important;\n}\n\na.bg-info:hover, a.bg-info:focus,\nbutton.bg-info:hover,\nbutton.bg-info:focus {\n background-color: #117a8b !important;\n}\n\n.bg-warning {\n background-color: #ffc107 !important;\n}\n\na.bg-warning:hover, a.bg-warning:focus,\nbutton.bg-warning:hover,\nbutton.bg-warning:focus {\n background-color: #d39e00 !important;\n}\n\n.bg-danger {\n background-color: #dc3545 !important;\n}\n\na.bg-danger:hover, a.bg-danger:focus,\nbutton.bg-danger:hover,\nbutton.bg-danger:focus {\n background-color: #bd2130 !important;\n}\n\n.bg-light {\n background-color: #f8f9fa !important;\n}\n\na.bg-light:hover, a.bg-light:focus,\nbutton.bg-light:hover,\nbutton.bg-light:focus {\n background-color: #dae0e5 !important;\n}\n\n.bg-dark {\n background-color: #343a40 !important;\n}\n\na.bg-dark:hover, a.bg-dark:focus,\nbutton.bg-dark:hover,\nbutton.bg-dark:focus {\n background-color: #1d2124 !important;\n}\n\n.bg-white {\n background-color: #fff !important;\n}\n\n.bg-transparent {\n background-color: transparent !important;\n}\n\n.border {\n border: 1px solid #dee2e6 !important;\n}\n\n.border-top {\n border-top: 1px solid #dee2e6 !important;\n}\n\n.border-right {\n border-right: 1px solid #dee2e6 !important;\n}\n\n.border-bottom {\n border-bottom: 1px solid #dee2e6 !important;\n}\n\n.border-left {\n border-left: 1px solid #dee2e6 !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-right-0 {\n border-right: 0 !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-left-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n border-color: #007bff !important;\n}\n\n.border-secondary {\n border-color: #6c757d !important;\n}\n\n.border-success {\n border-color: #28a745 !important;\n}\n\n.border-info {\n border-color: #17a2b8 !important;\n}\n\n.border-warning {\n border-color: #ffc107 !important;\n}\n\n.border-danger {\n border-color: #dc3545 !important;\n}\n\n.border-light {\n border-color: #f8f9fa !important;\n}\n\n.border-dark {\n border-color: #343a40 !important;\n}\n\n.border-white {\n border-color: #fff !important;\n}\n\n.rounded-sm {\n border-radius: 0.2rem !important;\n}\n\n.rounded {\n border-radius: 0.25rem !important;\n}\n\n.rounded-top {\n border-top-left-radius: 0.25rem !important;\n border-top-right-radius: 0.25rem !important;\n}\n\n.rounded-right {\n border-top-right-radius: 0.25rem !important;\n border-bottom-right-radius: 0.25rem !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-left {\n border-top-left-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-lg {\n border-radius: 0.3rem !important;\n}\n\n.rounded-circle {\n border-radius: 50% !important;\n}\n\n.rounded-pill {\n border-radius: 50rem !important;\n}\n\n.rounded-0 {\n border-radius: 0 !important;\n}\n\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.d-none {\n display: none !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: -ms-flexbox !important;\n display: flex !important;\n}\n\n.d-inline-flex {\n display: -ms-inline-flexbox !important;\n display: inline-flex !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-none {\n display: none !important;\n }\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: -ms-flexbox !important;\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: -ms-inline-flexbox !important;\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 768px) {\n .d-md-none {\n display: none !important;\n }\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: -ms-flexbox !important;\n display: flex !important;\n }\n .d-md-inline-flex {\n display: -ms-inline-flexbox !important;\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 992px) {\n .d-lg-none {\n display: none !important;\n }\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: -ms-flexbox !important;\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: -ms-inline-flexbox !important;\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 1200px) {\n .d-xl-none {\n display: none !important;\n }\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: -ms-flexbox !important;\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: -ms-inline-flexbox !important;\n display: inline-flex !important;\n }\n}\n\n@media print {\n .d-print-none {\n display: none !important;\n }\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: -ms-flexbox !important;\n display: flex !important;\n }\n .d-print-inline-flex {\n display: -ms-inline-flexbox !important;\n display: inline-flex !important;\n }\n}\n\n.embed-responsive {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n}\n\n.embed-responsive::before {\n display: block;\n content: \"\";\n}\n\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n\n.embed-responsive-21by9::before {\n padding-top: 42.857143%;\n}\n\n.embed-responsive-16by9::before {\n padding-top: 56.25%;\n}\n\n.embed-responsive-4by3::before {\n padding-top: 75%;\n}\n\n.embed-responsive-1by1::before {\n padding-top: 100%;\n}\n\n.flex-row {\n -ms-flex-direction: row !important;\n flex-direction: row !important;\n}\n\n.flex-column {\n -ms-flex-direction: column !important;\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n -ms-flex-direction: row-reverse !important;\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n -ms-flex-direction: column-reverse !important;\n flex-direction: column-reverse !important;\n}\n\n.flex-wrap {\n -ms-flex-wrap: wrap !important;\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n -ms-flex-wrap: nowrap !important;\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n -ms-flex-wrap: wrap-reverse !important;\n flex-wrap: wrap-reverse !important;\n}\n\n.flex-fill {\n -ms-flex: 1 1 auto !important;\n flex: 1 1 auto !important;\n}\n\n.flex-grow-0 {\n -ms-flex-positive: 0 !important;\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n -ms-flex-positive: 1 !important;\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n -ms-flex-negative: 0 !important;\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n -ms-flex-negative: 1 !important;\n flex-shrink: 1 !important;\n}\n\n.justify-content-start {\n -ms-flex-pack: start !important;\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n -ms-flex-pack: end !important;\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n -ms-flex-pack: center !important;\n justify-content: center !important;\n}\n\n.justify-content-between {\n -ms-flex-pack: justify !important;\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n -ms-flex-pack: distribute !important;\n justify-content: space-around !important;\n}\n\n.align-items-start {\n -ms-flex-align: start !important;\n align-items: flex-start !important;\n}\n\n.align-items-end {\n -ms-flex-align: end !important;\n align-items: flex-end !important;\n}\n\n.align-items-center {\n -ms-flex-align: center !important;\n align-items: center !important;\n}\n\n.align-items-baseline {\n -ms-flex-align: baseline !important;\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n -ms-flex-align: stretch !important;\n align-items: stretch !important;\n}\n\n.align-content-start {\n -ms-flex-line-pack: start !important;\n align-content: flex-start !important;\n}\n\n.align-content-end {\n -ms-flex-line-pack: end !important;\n align-content: flex-end !important;\n}\n\n.align-content-center {\n -ms-flex-line-pack: center !important;\n align-content: center !important;\n}\n\n.align-content-between {\n -ms-flex-line-pack: justify !important;\n align-content: space-between !important;\n}\n\n.align-content-around {\n -ms-flex-line-pack: distribute !important;\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n -ms-flex-line-pack: stretch !important;\n align-content: stretch !important;\n}\n\n.align-self-auto {\n -ms-flex-item-align: auto !important;\n align-self: auto !important;\n}\n\n.align-self-start {\n -ms-flex-item-align: start !important;\n align-self: flex-start !important;\n}\n\n.align-self-end {\n -ms-flex-item-align: end !important;\n align-self: flex-end !important;\n}\n\n.align-self-center {\n -ms-flex-item-align: center !important;\n align-self: center !important;\n}\n\n.align-self-baseline {\n -ms-flex-item-align: baseline !important;\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n -ms-flex-item-align: stretch !important;\n align-self: stretch !important;\n}\n\n@media (min-width: 576px) {\n .flex-sm-row {\n -ms-flex-direction: row !important;\n flex-direction: row !important;\n }\n .flex-sm-column {\n -ms-flex-direction: column !important;\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n -ms-flex-direction: row-reverse !important;\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n -ms-flex-direction: column-reverse !important;\n flex-direction: column-reverse !important;\n }\n .flex-sm-wrap {\n -ms-flex-wrap: wrap !important;\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n -ms-flex-wrap: nowrap !important;\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n -ms-flex-wrap: wrap-reverse !important;\n flex-wrap: wrap-reverse !important;\n }\n .flex-sm-fill {\n -ms-flex: 1 1 auto !important;\n flex: 1 1 auto !important;\n }\n .flex-sm-grow-0 {\n -ms-flex-positive: 0 !important;\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n -ms-flex-positive: 1 !important;\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n -ms-flex-negative: 0 !important;\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n -ms-flex-negative: 1 !important;\n flex-shrink: 1 !important;\n }\n .justify-content-sm-start {\n -ms-flex-pack: start !important;\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n -ms-flex-pack: end !important;\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n -ms-flex-pack: center !important;\n justify-content: center !important;\n }\n .justify-content-sm-between {\n -ms-flex-pack: justify !important;\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n -ms-flex-pack: distribute !important;\n justify-content: space-around !important;\n }\n .align-items-sm-start {\n -ms-flex-align: start !important;\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n -ms-flex-align: end !important;\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n -ms-flex-align: center !important;\n align-items: center !important;\n }\n .align-items-sm-baseline {\n -ms-flex-align: baseline !important;\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n -ms-flex-align: stretch !important;\n align-items: stretch !important;\n }\n .align-content-sm-start {\n -ms-flex-line-pack: start !important;\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n -ms-flex-line-pack: end !important;\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n -ms-flex-line-pack: center !important;\n align-content: center !important;\n }\n .align-content-sm-between {\n -ms-flex-line-pack: justify !important;\n align-content: space-between !important;\n }\n .align-content-sm-around {\n -ms-flex-line-pack: distribute !important;\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n -ms-flex-line-pack: stretch !important;\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n -ms-flex-item-align: auto !important;\n align-self: auto !important;\n }\n .align-self-sm-start {\n -ms-flex-item-align: start !important;\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n -ms-flex-item-align: end !important;\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n -ms-flex-item-align: center !important;\n align-self: center !important;\n }\n .align-self-sm-baseline {\n -ms-flex-item-align: baseline !important;\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n -ms-flex-item-align: stretch !important;\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 768px) {\n .flex-md-row {\n -ms-flex-direction: row !important;\n flex-direction: row !important;\n }\n .flex-md-column {\n -ms-flex-direction: column !important;\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n -ms-flex-direction: row-reverse !important;\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n -ms-flex-direction: column-reverse !important;\n flex-direction: column-reverse !important;\n }\n .flex-md-wrap {\n -ms-flex-wrap: wrap !important;\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n -ms-flex-wrap: nowrap !important;\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n -ms-flex-wrap: wrap-reverse !important;\n flex-wrap: wrap-reverse !important;\n }\n .flex-md-fill {\n -ms-flex: 1 1 auto !important;\n flex: 1 1 auto !important;\n }\n .flex-md-grow-0 {\n -ms-flex-positive: 0 !important;\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n -ms-flex-positive: 1 !important;\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n -ms-flex-negative: 0 !important;\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n -ms-flex-negative: 1 !important;\n flex-shrink: 1 !important;\n }\n .justify-content-md-start {\n -ms-flex-pack: start !important;\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n -ms-flex-pack: end !important;\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n -ms-flex-pack: center !important;\n justify-content: center !important;\n }\n .justify-content-md-between {\n -ms-flex-pack: justify !important;\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n -ms-flex-pack: distribute !important;\n justify-content: space-around !important;\n }\n .align-items-md-start {\n -ms-flex-align: start !important;\n align-items: flex-start !important;\n }\n .align-items-md-end {\n -ms-flex-align: end !important;\n align-items: flex-end !important;\n }\n .align-items-md-center {\n -ms-flex-align: center !important;\n align-items: center !important;\n }\n .align-items-md-baseline {\n -ms-flex-align: baseline !important;\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n -ms-flex-align: stretch !important;\n align-items: stretch !important;\n }\n .align-content-md-start {\n -ms-flex-line-pack: start !important;\n align-content: flex-start !important;\n }\n .align-content-md-end {\n -ms-flex-line-pack: end !important;\n align-content: flex-end !important;\n }\n .align-content-md-center {\n -ms-flex-line-pack: center !important;\n align-content: center !important;\n }\n .align-content-md-between {\n -ms-flex-line-pack: justify !important;\n align-content: space-between !important;\n }\n .align-content-md-around {\n -ms-flex-line-pack: distribute !important;\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n -ms-flex-line-pack: stretch !important;\n align-content: stretch !important;\n }\n .align-self-md-auto {\n -ms-flex-item-align: auto !important;\n align-self: auto !important;\n }\n .align-self-md-start {\n -ms-flex-item-align: start !important;\n align-self: flex-start !important;\n }\n .align-self-md-end {\n -ms-flex-item-align: end !important;\n align-self: flex-end !important;\n }\n .align-self-md-center {\n -ms-flex-item-align: center !important;\n align-self: center !important;\n }\n .align-self-md-baseline {\n -ms-flex-item-align: baseline !important;\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n -ms-flex-item-align: stretch !important;\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 992px) {\n .flex-lg-row {\n -ms-flex-direction: row !important;\n flex-direction: row !important;\n }\n .flex-lg-column {\n -ms-flex-direction: column !important;\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n -ms-flex-direction: row-reverse !important;\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n -ms-flex-direction: column-reverse !important;\n flex-direction: column-reverse !important;\n }\n .flex-lg-wrap {\n -ms-flex-wrap: wrap !important;\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n -ms-flex-wrap: nowrap !important;\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n -ms-flex-wrap: wrap-reverse !important;\n flex-wrap: wrap-reverse !important;\n }\n .flex-lg-fill {\n -ms-flex: 1 1 auto !important;\n flex: 1 1 auto !important;\n }\n .flex-lg-grow-0 {\n -ms-flex-positive: 0 !important;\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n -ms-flex-positive: 1 !important;\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n -ms-flex-negative: 0 !important;\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n -ms-flex-negative: 1 !important;\n flex-shrink: 1 !important;\n }\n .justify-content-lg-start {\n -ms-flex-pack: start !important;\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n -ms-flex-pack: end !important;\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n -ms-flex-pack: center !important;\n justify-content: center !important;\n }\n .justify-content-lg-between {\n -ms-flex-pack: justify !important;\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n -ms-flex-pack: distribute !important;\n justify-content: space-around !important;\n }\n .align-items-lg-start {\n -ms-flex-align: start !important;\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n -ms-flex-align: end !important;\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n -ms-flex-align: center !important;\n align-items: center !important;\n }\n .align-items-lg-baseline {\n -ms-flex-align: baseline !important;\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n -ms-flex-align: stretch !important;\n align-items: stretch !important;\n }\n .align-content-lg-start {\n -ms-flex-line-pack: start !important;\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n -ms-flex-line-pack: end !important;\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n -ms-flex-line-pack: center !important;\n align-content: center !important;\n }\n .align-content-lg-between {\n -ms-flex-line-pack: justify !important;\n align-content: space-between !important;\n }\n .align-content-lg-around {\n -ms-flex-line-pack: distribute !important;\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n -ms-flex-line-pack: stretch !important;\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n -ms-flex-item-align: auto !important;\n align-self: auto !important;\n }\n .align-self-lg-start {\n -ms-flex-item-align: start !important;\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n -ms-flex-item-align: end !important;\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n -ms-flex-item-align: center !important;\n align-self: center !important;\n }\n .align-self-lg-baseline {\n -ms-flex-item-align: baseline !important;\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n -ms-flex-item-align: stretch !important;\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 1200px) {\n .flex-xl-row {\n -ms-flex-direction: row !important;\n flex-direction: row !important;\n }\n .flex-xl-column {\n -ms-flex-direction: column !important;\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n -ms-flex-direction: row-reverse !important;\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n -ms-flex-direction: column-reverse !important;\n flex-direction: column-reverse !important;\n }\n .flex-xl-wrap {\n -ms-flex-wrap: wrap !important;\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n -ms-flex-wrap: nowrap !important;\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n -ms-flex-wrap: wrap-reverse !important;\n flex-wrap: wrap-reverse !important;\n }\n .flex-xl-fill {\n -ms-flex: 1 1 auto !important;\n flex: 1 1 auto !important;\n }\n .flex-xl-grow-0 {\n -ms-flex-positive: 0 !important;\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n -ms-flex-positive: 1 !important;\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n -ms-flex-negative: 0 !important;\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n -ms-flex-negative: 1 !important;\n flex-shrink: 1 !important;\n }\n .justify-content-xl-start {\n -ms-flex-pack: start !important;\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n -ms-flex-pack: end !important;\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n -ms-flex-pack: center !important;\n justify-content: center !important;\n }\n .justify-content-xl-between {\n -ms-flex-pack: justify !important;\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n -ms-flex-pack: distribute !important;\n justify-content: space-around !important;\n }\n .align-items-xl-start {\n -ms-flex-align: start !important;\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n -ms-flex-align: end !important;\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n -ms-flex-align: center !important;\n align-items: center !important;\n }\n .align-items-xl-baseline {\n -ms-flex-align: baseline !important;\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n -ms-flex-align: stretch !important;\n align-items: stretch !important;\n }\n .align-content-xl-start {\n -ms-flex-line-pack: start !important;\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n -ms-flex-line-pack: end !important;\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n -ms-flex-line-pack: center !important;\n align-content: center !important;\n }\n .align-content-xl-between {\n -ms-flex-line-pack: justify !important;\n align-content: space-between !important;\n }\n .align-content-xl-around {\n -ms-flex-line-pack: distribute !important;\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n -ms-flex-line-pack: stretch !important;\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n -ms-flex-item-align: auto !important;\n align-self: auto !important;\n }\n .align-self-xl-start {\n -ms-flex-item-align: start !important;\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n -ms-flex-item-align: end !important;\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n -ms-flex-item-align: center !important;\n align-self: center !important;\n }\n .align-self-xl-baseline {\n -ms-flex-item-align: baseline !important;\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n -ms-flex-item-align: stretch !important;\n align-self: stretch !important;\n }\n}\n\n.float-left {\n float: left !important;\n}\n\n.float-right {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-left {\n float: left !important;\n }\n .float-sm-right {\n float: right !important;\n }\n .float-sm-none {\n float: none !important;\n }\n}\n\n@media (min-width: 768px) {\n .float-md-left {\n float: left !important;\n }\n .float-md-right {\n float: right !important;\n }\n .float-md-none {\n float: none !important;\n }\n}\n\n@media (min-width: 992px) {\n .float-lg-left {\n float: left !important;\n }\n .float-lg-right {\n float: right !important;\n }\n .float-lg-none {\n float: none !important;\n }\n}\n\n@media (min-width: 1200px) {\n .float-xl-left {\n float: left !important;\n }\n .float-xl-right {\n float: right !important;\n }\n .float-xl-none {\n float: none !important;\n }\n}\n\n.overflow-auto {\n overflow: auto !important;\n}\n\n.overflow-hidden {\n overflow: hidden !important;\n}\n\n.position-static {\n position: static !important;\n}\n\n.position-relative {\n position: relative !important;\n}\n\n.position-absolute {\n position: absolute !important;\n}\n\n.position-fixed {\n position: fixed !important;\n}\n\n.position-sticky {\n position: -webkit-sticky !important;\n position: sticky !important;\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n@supports ((position: -webkit-sticky) or (position: sticky)) {\n .sticky-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip: auto;\n white-space: normal;\n}\n\n.shadow-sm {\n box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;\n}\n\n.shadow {\n box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;\n}\n\n.shadow-lg {\n box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;\n}\n\n.shadow-none {\n box-shadow: none !important;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.w-auto {\n width: auto !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.h-auto {\n height: auto !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.min-vw-100 {\n min-width: 100vw !important;\n}\n\n.min-vh-100 {\n min-height: 100vh !important;\n}\n\n.vw-100 {\n width: 100vw !important;\n}\n\n.vh-100 {\n height: 100vh !important;\n}\n\n.stretched-link::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1;\n pointer-events: auto;\n content: \"\";\n background-color: rgba(0, 0, 0, 0);\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.mt-0,\n.my-0 {\n margin-top: 0 !important;\n}\n\n.mr-0,\n.mx-0 {\n margin-right: 0 !important;\n}\n\n.mb-0,\n.my-0 {\n margin-bottom: 0 !important;\n}\n\n.ml-0,\n.mx-0 {\n margin-left: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.mt-1,\n.my-1 {\n margin-top: 0.25rem !important;\n}\n\n.mr-1,\n.mx-1 {\n margin-right: 0.25rem !important;\n}\n\n.mb-1,\n.my-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.ml-1,\n.mx-1 {\n margin-left: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.mt-2,\n.my-2 {\n margin-top: 0.5rem !important;\n}\n\n.mr-2,\n.mx-2 {\n margin-right: 0.5rem !important;\n}\n\n.mb-2,\n.my-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.ml-2,\n.mx-2 {\n margin-left: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.mt-3,\n.my-3 {\n margin-top: 1rem !important;\n}\n\n.mr-3,\n.mx-3 {\n margin-right: 1rem !important;\n}\n\n.mb-3,\n.my-3 {\n margin-bottom: 1rem !important;\n}\n\n.ml-3,\n.mx-3 {\n margin-left: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.mt-4,\n.my-4 {\n margin-top: 1.5rem !important;\n}\n\n.mr-4,\n.mx-4 {\n margin-right: 1.5rem !important;\n}\n\n.mb-4,\n.my-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.ml-4,\n.mx-4 {\n margin-left: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.mt-5,\n.my-5 {\n margin-top: 3rem !important;\n}\n\n.mr-5,\n.mx-5 {\n margin-right: 3rem !important;\n}\n\n.mb-5,\n.my-5 {\n margin-bottom: 3rem !important;\n}\n\n.ml-5,\n.mx-5 {\n margin-left: 3rem !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.pt-0,\n.py-0 {\n padding-top: 0 !important;\n}\n\n.pr-0,\n.px-0 {\n padding-right: 0 !important;\n}\n\n.pb-0,\n.py-0 {\n padding-bottom: 0 !important;\n}\n\n.pl-0,\n.px-0 {\n padding-left: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.pt-1,\n.py-1 {\n padding-top: 0.25rem !important;\n}\n\n.pr-1,\n.px-1 {\n padding-right: 0.25rem !important;\n}\n\n.pb-1,\n.py-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pl-1,\n.px-1 {\n padding-left: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.pt-2,\n.py-2 {\n padding-top: 0.5rem !important;\n}\n\n.pr-2,\n.px-2 {\n padding-right: 0.5rem !important;\n}\n\n.pb-2,\n.py-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pl-2,\n.px-2 {\n padding-left: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.pt-3,\n.py-3 {\n padding-top: 1rem !important;\n}\n\n.pr-3,\n.px-3 {\n padding-right: 1rem !important;\n}\n\n.pb-3,\n.py-3 {\n padding-bottom: 1rem !important;\n}\n\n.pl-3,\n.px-3 {\n padding-left: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.pt-4,\n.py-4 {\n padding-top: 1.5rem !important;\n}\n\n.pr-4,\n.px-4 {\n padding-right: 1.5rem !important;\n}\n\n.pb-4,\n.py-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pl-4,\n.px-4 {\n padding-left: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.pt-5,\n.py-5 {\n padding-top: 3rem !important;\n}\n\n.pr-5,\n.px-5 {\n padding-right: 3rem !important;\n}\n\n.pb-5,\n.py-5 {\n padding-bottom: 3rem !important;\n}\n\n.pl-5,\n.px-5 {\n padding-left: 3rem !important;\n}\n\n.m-n1 {\n margin: -0.25rem !important;\n}\n\n.mt-n1,\n.my-n1 {\n margin-top: -0.25rem !important;\n}\n\n.mr-n1,\n.mx-n1 {\n margin-right: -0.25rem !important;\n}\n\n.mb-n1,\n.my-n1 {\n margin-bottom: -0.25rem !important;\n}\n\n.ml-n1,\n.mx-n1 {\n margin-left: -0.25rem !important;\n}\n\n.m-n2 {\n margin: -0.5rem !important;\n}\n\n.mt-n2,\n.my-n2 {\n margin-top: -0.5rem !important;\n}\n\n.mr-n2,\n.mx-n2 {\n margin-right: -0.5rem !important;\n}\n\n.mb-n2,\n.my-n2 {\n margin-bottom: -0.5rem !important;\n}\n\n.ml-n2,\n.mx-n2 {\n margin-left: -0.5rem !important;\n}\n\n.m-n3 {\n margin: -1rem !important;\n}\n\n.mt-n3,\n.my-n3 {\n margin-top: -1rem !important;\n}\n\n.mr-n3,\n.mx-n3 {\n margin-right: -1rem !important;\n}\n\n.mb-n3,\n.my-n3 {\n margin-bottom: -1rem !important;\n}\n\n.ml-n3,\n.mx-n3 {\n margin-left: -1rem !important;\n}\n\n.m-n4 {\n margin: -1.5rem !important;\n}\n\n.mt-n4,\n.my-n4 {\n margin-top: -1.5rem !important;\n}\n\n.mr-n4,\n.mx-n4 {\n margin-right: -1.5rem !important;\n}\n\n.mb-n4,\n.my-n4 {\n margin-bottom: -1.5rem !important;\n}\n\n.ml-n4,\n.mx-n4 {\n margin-left: -1.5rem !important;\n}\n\n.m-n5 {\n margin: -3rem !important;\n}\n\n.mt-n5,\n.my-n5 {\n margin-top: -3rem !important;\n}\n\n.mr-n5,\n.mx-n5 {\n margin-right: -3rem !important;\n}\n\n.mb-n5,\n.my-n5 {\n margin-bottom: -3rem !important;\n}\n\n.ml-n5,\n.mx-n5 {\n margin-left: -3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mt-auto,\n.my-auto {\n margin-top: auto !important;\n}\n\n.mr-auto,\n.mx-auto {\n margin-right: auto !important;\n}\n\n.mb-auto,\n.my-auto {\n margin-bottom: auto !important;\n}\n\n.ml-auto,\n.mx-auto {\n margin-left: auto !important;\n}\n\n@media (min-width: 576px) {\n .m-sm-0 {\n margin: 0 !important;\n }\n .mt-sm-0,\n .my-sm-0 {\n margin-top: 0 !important;\n }\n .mr-sm-0,\n .mx-sm-0 {\n margin-right: 0 !important;\n }\n .mb-sm-0,\n .my-sm-0 {\n margin-bottom: 0 !important;\n }\n .ml-sm-0,\n .mx-sm-0 {\n margin-left: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .mt-sm-1,\n .my-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mr-sm-1,\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n }\n .mb-sm-1,\n .my-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-sm-1,\n .mx-sm-1 {\n margin-left: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .mt-sm-2,\n .my-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mr-sm-2,\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n }\n .mb-sm-2,\n .my-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-sm-2,\n .mx-sm-2 {\n margin-left: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .mt-sm-3,\n .my-sm-3 {\n margin-top: 1rem !important;\n }\n .mr-sm-3,\n .mx-sm-3 {\n margin-right: 1rem !important;\n }\n .mb-sm-3,\n .my-sm-3 {\n margin-bottom: 1rem !important;\n }\n .ml-sm-3,\n .mx-sm-3 {\n margin-left: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .mt-sm-4,\n .my-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mr-sm-4,\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n }\n .mb-sm-4,\n .my-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-sm-4,\n .mx-sm-4 {\n margin-left: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .mt-sm-5,\n .my-sm-5 {\n margin-top: 3rem !important;\n }\n .mr-sm-5,\n .mx-sm-5 {\n margin-right: 3rem !important;\n }\n .mb-sm-5,\n .my-sm-5 {\n margin-bottom: 3rem !important;\n }\n .ml-sm-5,\n .mx-sm-5 {\n margin-left: 3rem !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .pt-sm-0,\n .py-sm-0 {\n padding-top: 0 !important;\n }\n .pr-sm-0,\n .px-sm-0 {\n padding-right: 0 !important;\n }\n .pb-sm-0,\n .py-sm-0 {\n padding-bottom: 0 !important;\n }\n .pl-sm-0,\n .px-sm-0 {\n padding-left: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .pt-sm-1,\n .py-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pr-sm-1,\n .px-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pb-sm-1,\n .py-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-sm-1,\n .px-sm-1 {\n padding-left: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .pt-sm-2,\n .py-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pr-sm-2,\n .px-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pb-sm-2,\n .py-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-sm-2,\n .px-sm-2 {\n padding-left: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .pt-sm-3,\n .py-sm-3 {\n padding-top: 1rem !important;\n }\n .pr-sm-3,\n .px-sm-3 {\n padding-right: 1rem !important;\n }\n .pb-sm-3,\n .py-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pl-sm-3,\n .px-sm-3 {\n padding-left: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .pt-sm-4,\n .py-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pr-sm-4,\n .px-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pb-sm-4,\n .py-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-sm-4,\n .px-sm-4 {\n padding-left: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .pt-sm-5,\n .py-sm-5 {\n padding-top: 3rem !important;\n }\n .pr-sm-5,\n .px-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-5,\n .py-sm-5 {\n padding-bottom: 3rem !important;\n }\n .pl-sm-5,\n .px-sm-5 {\n padding-left: 3rem !important;\n }\n .m-sm-n1 {\n margin: -0.25rem !important;\n }\n .mt-sm-n1,\n .my-sm-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-sm-n1,\n .mx-sm-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-sm-n1,\n .my-sm-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-sm-n1,\n .mx-sm-n1 {\n margin-left: -0.25rem !important;\n }\n .m-sm-n2 {\n margin: -0.5rem !important;\n }\n .mt-sm-n2,\n .my-sm-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-sm-n2,\n .mx-sm-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-sm-n2,\n .my-sm-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-sm-n2,\n .mx-sm-n2 {\n margin-left: -0.5rem !important;\n }\n .m-sm-n3 {\n margin: -1rem !important;\n }\n .mt-sm-n3,\n .my-sm-n3 {\n margin-top: -1rem !important;\n }\n .mr-sm-n3,\n .mx-sm-n3 {\n margin-right: -1rem !important;\n }\n .mb-sm-n3,\n .my-sm-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-sm-n3,\n .mx-sm-n3 {\n margin-left: -1rem !important;\n }\n .m-sm-n4 {\n margin: -1.5rem !important;\n }\n .mt-sm-n4,\n .my-sm-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-sm-n4,\n .mx-sm-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-sm-n4,\n .my-sm-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-sm-n4,\n .mx-sm-n4 {\n margin-left: -1.5rem !important;\n }\n .m-sm-n5 {\n margin: -3rem !important;\n }\n .mt-sm-n5,\n .my-sm-n5 {\n margin-top: -3rem !important;\n }\n .mr-sm-n5,\n .mx-sm-n5 {\n margin-right: -3rem !important;\n }\n .mb-sm-n5,\n .my-sm-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-sm-n5,\n .mx-sm-n5 {\n margin-left: -3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mt-sm-auto,\n .my-sm-auto {\n margin-top: auto !important;\n }\n .mr-sm-auto,\n .mx-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-auto,\n .my-sm-auto {\n margin-bottom: auto !important;\n }\n .ml-sm-auto,\n .mx-sm-auto {\n margin-left: auto !important;\n }\n}\n\n@media (min-width: 768px) {\n .m-md-0 {\n margin: 0 !important;\n }\n .mt-md-0,\n .my-md-0 {\n margin-top: 0 !important;\n }\n .mr-md-0,\n .mx-md-0 {\n margin-right: 0 !important;\n }\n .mb-md-0,\n .my-md-0 {\n margin-bottom: 0 !important;\n }\n .ml-md-0,\n .mx-md-0 {\n margin-left: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .mt-md-1,\n .my-md-1 {\n margin-top: 0.25rem !important;\n }\n .mr-md-1,\n .mx-md-1 {\n margin-right: 0.25rem !important;\n }\n .mb-md-1,\n .my-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-md-1,\n .mx-md-1 {\n margin-left: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .mt-md-2,\n .my-md-2 {\n margin-top: 0.5rem !important;\n }\n .mr-md-2,\n .mx-md-2 {\n margin-right: 0.5rem !important;\n }\n .mb-md-2,\n .my-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-md-2,\n .mx-md-2 {\n margin-left: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .mt-md-3,\n .my-md-3 {\n margin-top: 1rem !important;\n }\n .mr-md-3,\n .mx-md-3 {\n margin-right: 1rem !important;\n }\n .mb-md-3,\n .my-md-3 {\n margin-bottom: 1rem !important;\n }\n .ml-md-3,\n .mx-md-3 {\n margin-left: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .mt-md-4,\n .my-md-4 {\n margin-top: 1.5rem !important;\n }\n .mr-md-4,\n .mx-md-4 {\n margin-right: 1.5rem !important;\n }\n .mb-md-4,\n .my-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-md-4,\n .mx-md-4 {\n margin-left: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .mt-md-5,\n .my-md-5 {\n margin-top: 3rem !important;\n }\n .mr-md-5,\n .mx-md-5 {\n margin-right: 3rem !important;\n }\n .mb-md-5,\n .my-md-5 {\n margin-bottom: 3rem !important;\n }\n .ml-md-5,\n .mx-md-5 {\n margin-left: 3rem !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .pt-md-0,\n .py-md-0 {\n padding-top: 0 !important;\n }\n .pr-md-0,\n .px-md-0 {\n padding-right: 0 !important;\n }\n .pb-md-0,\n .py-md-0 {\n padding-bottom: 0 !important;\n }\n .pl-md-0,\n .px-md-0 {\n padding-left: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .pt-md-1,\n .py-md-1 {\n padding-top: 0.25rem !important;\n }\n .pr-md-1,\n .px-md-1 {\n padding-right: 0.25rem !important;\n }\n .pb-md-1,\n .py-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-md-1,\n .px-md-1 {\n padding-left: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .pt-md-2,\n .py-md-2 {\n padding-top: 0.5rem !important;\n }\n .pr-md-2,\n .px-md-2 {\n padding-right: 0.5rem !important;\n }\n .pb-md-2,\n .py-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-md-2,\n .px-md-2 {\n padding-left: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .pt-md-3,\n .py-md-3 {\n padding-top: 1rem !important;\n }\n .pr-md-3,\n .px-md-3 {\n padding-right: 1rem !important;\n }\n .pb-md-3,\n .py-md-3 {\n padding-bottom: 1rem !important;\n }\n .pl-md-3,\n .px-md-3 {\n padding-left: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .pt-md-4,\n .py-md-4 {\n padding-top: 1.5rem !important;\n }\n .pr-md-4,\n .px-md-4 {\n padding-right: 1.5rem !important;\n }\n .pb-md-4,\n .py-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-md-4,\n .px-md-4 {\n padding-left: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .pt-md-5,\n .py-md-5 {\n padding-top: 3rem !important;\n }\n .pr-md-5,\n .px-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-5,\n .py-md-5 {\n padding-bottom: 3rem !important;\n }\n .pl-md-5,\n .px-md-5 {\n padding-left: 3rem !important;\n }\n .m-md-n1 {\n margin: -0.25rem !important;\n }\n .mt-md-n1,\n .my-md-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-md-n1,\n .mx-md-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-md-n1,\n .my-md-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-md-n1,\n .mx-md-n1 {\n margin-left: -0.25rem !important;\n }\n .m-md-n2 {\n margin: -0.5rem !important;\n }\n .mt-md-n2,\n .my-md-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-md-n2,\n .mx-md-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-md-n2,\n .my-md-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-md-n2,\n .mx-md-n2 {\n margin-left: -0.5rem !important;\n }\n .m-md-n3 {\n margin: -1rem !important;\n }\n .mt-md-n3,\n .my-md-n3 {\n margin-top: -1rem !important;\n }\n .mr-md-n3,\n .mx-md-n3 {\n margin-right: -1rem !important;\n }\n .mb-md-n3,\n .my-md-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-md-n3,\n .mx-md-n3 {\n margin-left: -1rem !important;\n }\n .m-md-n4 {\n margin: -1.5rem !important;\n }\n .mt-md-n4,\n .my-md-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-md-n4,\n .mx-md-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-md-n4,\n .my-md-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-md-n4,\n .mx-md-n4 {\n margin-left: -1.5rem !important;\n }\n .m-md-n5 {\n margin: -3rem !important;\n }\n .mt-md-n5,\n .my-md-n5 {\n margin-top: -3rem !important;\n }\n .mr-md-n5,\n .mx-md-n5 {\n margin-right: -3rem !important;\n }\n .mb-md-n5,\n .my-md-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-md-n5,\n .mx-md-n5 {\n margin-left: -3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mt-md-auto,\n .my-md-auto {\n margin-top: auto !important;\n }\n .mr-md-auto,\n .mx-md-auto {\n margin-right: auto !important;\n }\n .mb-md-auto,\n .my-md-auto {\n margin-bottom: auto !important;\n }\n .ml-md-auto,\n .mx-md-auto {\n margin-left: auto !important;\n }\n}\n\n@media (min-width: 992px) {\n .m-lg-0 {\n margin: 0 !important;\n }\n .mt-lg-0,\n .my-lg-0 {\n margin-top: 0 !important;\n }\n .mr-lg-0,\n .mx-lg-0 {\n margin-right: 0 !important;\n }\n .mb-lg-0,\n .my-lg-0 {\n margin-bottom: 0 !important;\n }\n .ml-lg-0,\n .mx-lg-0 {\n margin-left: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .mt-lg-1,\n .my-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mr-lg-1,\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n }\n .mb-lg-1,\n .my-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-lg-1,\n .mx-lg-1 {\n margin-left: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .mt-lg-2,\n .my-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mr-lg-2,\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n }\n .mb-lg-2,\n .my-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-lg-2,\n .mx-lg-2 {\n margin-left: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .mt-lg-3,\n .my-lg-3 {\n margin-top: 1rem !important;\n }\n .mr-lg-3,\n .mx-lg-3 {\n margin-right: 1rem !important;\n }\n .mb-lg-3,\n .my-lg-3 {\n margin-bottom: 1rem !important;\n }\n .ml-lg-3,\n .mx-lg-3 {\n margin-left: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .mt-lg-4,\n .my-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mr-lg-4,\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n }\n .mb-lg-4,\n .my-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-lg-4,\n .mx-lg-4 {\n margin-left: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .mt-lg-5,\n .my-lg-5 {\n margin-top: 3rem !important;\n }\n .mr-lg-5,\n .mx-lg-5 {\n margin-right: 3rem !important;\n }\n .mb-lg-5,\n .my-lg-5 {\n margin-bottom: 3rem !important;\n }\n .ml-lg-5,\n .mx-lg-5 {\n margin-left: 3rem !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .pt-lg-0,\n .py-lg-0 {\n padding-top: 0 !important;\n }\n .pr-lg-0,\n .px-lg-0 {\n padding-right: 0 !important;\n }\n .pb-lg-0,\n .py-lg-0 {\n padding-bottom: 0 !important;\n }\n .pl-lg-0,\n .px-lg-0 {\n padding-left: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .pt-lg-1,\n .py-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pr-lg-1,\n .px-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pb-lg-1,\n .py-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-lg-1,\n .px-lg-1 {\n padding-left: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .pt-lg-2,\n .py-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pr-lg-2,\n .px-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pb-lg-2,\n .py-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-lg-2,\n .px-lg-2 {\n padding-left: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .pt-lg-3,\n .py-lg-3 {\n padding-top: 1rem !important;\n }\n .pr-lg-3,\n .px-lg-3 {\n padding-right: 1rem !important;\n }\n .pb-lg-3,\n .py-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pl-lg-3,\n .px-lg-3 {\n padding-left: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .pt-lg-4,\n .py-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pr-lg-4,\n .px-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pb-lg-4,\n .py-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-lg-4,\n .px-lg-4 {\n padding-left: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .pt-lg-5,\n .py-lg-5 {\n padding-top: 3rem !important;\n }\n .pr-lg-5,\n .px-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-5,\n .py-lg-5 {\n padding-bottom: 3rem !important;\n }\n .pl-lg-5,\n .px-lg-5 {\n padding-left: 3rem !important;\n }\n .m-lg-n1 {\n margin: -0.25rem !important;\n }\n .mt-lg-n1,\n .my-lg-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-lg-n1,\n .mx-lg-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-lg-n1,\n .my-lg-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-lg-n1,\n .mx-lg-n1 {\n margin-left: -0.25rem !important;\n }\n .m-lg-n2 {\n margin: -0.5rem !important;\n }\n .mt-lg-n2,\n .my-lg-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-lg-n2,\n .mx-lg-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-lg-n2,\n .my-lg-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-lg-n2,\n .mx-lg-n2 {\n margin-left: -0.5rem !important;\n }\n .m-lg-n3 {\n margin: -1rem !important;\n }\n .mt-lg-n3,\n .my-lg-n3 {\n margin-top: -1rem !important;\n }\n .mr-lg-n3,\n .mx-lg-n3 {\n margin-right: -1rem !important;\n }\n .mb-lg-n3,\n .my-lg-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-lg-n3,\n .mx-lg-n3 {\n margin-left: -1rem !important;\n }\n .m-lg-n4 {\n margin: -1.5rem !important;\n }\n .mt-lg-n4,\n .my-lg-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-lg-n4,\n .mx-lg-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-lg-n4,\n .my-lg-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-lg-n4,\n .mx-lg-n4 {\n margin-left: -1.5rem !important;\n }\n .m-lg-n5 {\n margin: -3rem !important;\n }\n .mt-lg-n5,\n .my-lg-n5 {\n margin-top: -3rem !important;\n }\n .mr-lg-n5,\n .mx-lg-n5 {\n margin-right: -3rem !important;\n }\n .mb-lg-n5,\n .my-lg-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-lg-n5,\n .mx-lg-n5 {\n margin-left: -3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mt-lg-auto,\n .my-lg-auto {\n margin-top: auto !important;\n }\n .mr-lg-auto,\n .mx-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-auto,\n .my-lg-auto {\n margin-bottom: auto !important;\n }\n .ml-lg-auto,\n .mx-lg-auto {\n margin-left: auto !important;\n }\n}\n\n@media (min-width: 1200px) {\n .m-xl-0 {\n margin: 0 !important;\n }\n .mt-xl-0,\n .my-xl-0 {\n margin-top: 0 !important;\n }\n .mr-xl-0,\n .mx-xl-0 {\n margin-right: 0 !important;\n }\n .mb-xl-0,\n .my-xl-0 {\n margin-bottom: 0 !important;\n }\n .ml-xl-0,\n .mx-xl-0 {\n margin-left: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .mt-xl-1,\n .my-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mr-xl-1,\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n }\n .mb-xl-1,\n .my-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-xl-1,\n .mx-xl-1 {\n margin-left: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .mt-xl-2,\n .my-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mr-xl-2,\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n }\n .mb-xl-2,\n .my-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-xl-2,\n .mx-xl-2 {\n margin-left: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .mt-xl-3,\n .my-xl-3 {\n margin-top: 1rem !important;\n }\n .mr-xl-3,\n .mx-xl-3 {\n margin-right: 1rem !important;\n }\n .mb-xl-3,\n .my-xl-3 {\n margin-bottom: 1rem !important;\n }\n .ml-xl-3,\n .mx-xl-3 {\n margin-left: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .mt-xl-4,\n .my-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mr-xl-4,\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n }\n .mb-xl-4,\n .my-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-xl-4,\n .mx-xl-4 {\n margin-left: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .mt-xl-5,\n .my-xl-5 {\n margin-top: 3rem !important;\n }\n .mr-xl-5,\n .mx-xl-5 {\n margin-right: 3rem !important;\n }\n .mb-xl-5,\n .my-xl-5 {\n margin-bottom: 3rem !important;\n }\n .ml-xl-5,\n .mx-xl-5 {\n margin-left: 3rem !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .pt-xl-0,\n .py-xl-0 {\n padding-top: 0 !important;\n }\n .pr-xl-0,\n .px-xl-0 {\n padding-right: 0 !important;\n }\n .pb-xl-0,\n .py-xl-0 {\n padding-bottom: 0 !important;\n }\n .pl-xl-0,\n .px-xl-0 {\n padding-left: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .pt-xl-1,\n .py-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pr-xl-1,\n .px-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pb-xl-1,\n .py-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-xl-1,\n .px-xl-1 {\n padding-left: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .pt-xl-2,\n .py-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pr-xl-2,\n .px-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pb-xl-2,\n .py-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-xl-2,\n .px-xl-2 {\n padding-left: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .pt-xl-3,\n .py-xl-3 {\n padding-top: 1rem !important;\n }\n .pr-xl-3,\n .px-xl-3 {\n padding-right: 1rem !important;\n }\n .pb-xl-3,\n .py-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pl-xl-3,\n .px-xl-3 {\n padding-left: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .pt-xl-4,\n .py-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pr-xl-4,\n .px-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pb-xl-4,\n .py-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-xl-4,\n .px-xl-4 {\n padding-left: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .pt-xl-5,\n .py-xl-5 {\n padding-top: 3rem !important;\n }\n .pr-xl-5,\n .px-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-5,\n .py-xl-5 {\n padding-bottom: 3rem !important;\n }\n .pl-xl-5,\n .px-xl-5 {\n padding-left: 3rem !important;\n }\n .m-xl-n1 {\n margin: -0.25rem !important;\n }\n .mt-xl-n1,\n .my-xl-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-xl-n1,\n .mx-xl-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-xl-n1,\n .my-xl-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-xl-n1,\n .mx-xl-n1 {\n margin-left: -0.25rem !important;\n }\n .m-xl-n2 {\n margin: -0.5rem !important;\n }\n .mt-xl-n2,\n .my-xl-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-xl-n2,\n .mx-xl-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-xl-n2,\n .my-xl-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-xl-n2,\n .mx-xl-n2 {\n margin-left: -0.5rem !important;\n }\n .m-xl-n3 {\n margin: -1rem !important;\n }\n .mt-xl-n3,\n .my-xl-n3 {\n margin-top: -1rem !important;\n }\n .mr-xl-n3,\n .mx-xl-n3 {\n margin-right: -1rem !important;\n }\n .mb-xl-n3,\n .my-xl-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-xl-n3,\n .mx-xl-n3 {\n margin-left: -1rem !important;\n }\n .m-xl-n4 {\n margin: -1.5rem !important;\n }\n .mt-xl-n4,\n .my-xl-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-xl-n4,\n .mx-xl-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-xl-n4,\n .my-xl-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-xl-n4,\n .mx-xl-n4 {\n margin-left: -1.5rem !important;\n }\n .m-xl-n5 {\n margin: -3rem !important;\n }\n .mt-xl-n5,\n .my-xl-n5 {\n margin-top: -3rem !important;\n }\n .mr-xl-n5,\n .mx-xl-n5 {\n margin-right: -3rem !important;\n }\n .mb-xl-n5,\n .my-xl-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-xl-n5,\n .mx-xl-n5 {\n margin-left: -3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mt-xl-auto,\n .my-xl-auto {\n margin-top: auto !important;\n }\n .mr-xl-auto,\n .mx-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-auto,\n .my-xl-auto {\n margin-bottom: auto !important;\n }\n .ml-xl-auto,\n .mx-xl-auto {\n margin-left: auto !important;\n }\n}\n\n.text-monospace {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !important;\n}\n\n.text-justify {\n text-align: justify !important;\n}\n\n.text-wrap {\n white-space: normal !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.text-left {\n text-align: left !important;\n}\n\n.text-right {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n@media (min-width: 576px) {\n .text-sm-left {\n text-align: left !important;\n }\n .text-sm-right {\n text-align: right !important;\n }\n .text-sm-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 768px) {\n .text-md-left {\n text-align: left !important;\n }\n .text-md-right {\n text-align: right !important;\n }\n .text-md-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 992px) {\n .text-lg-left {\n text-align: left !important;\n }\n .text-lg-right {\n text-align: right !important;\n }\n .text-lg-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 1200px) {\n .text-xl-left {\n text-align: left !important;\n }\n .text-xl-right {\n text-align: right !important;\n }\n .text-xl-center {\n text-align: center !important;\n }\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.font-weight-light {\n font-weight: 300 !important;\n}\n\n.font-weight-lighter {\n font-weight: lighter !important;\n}\n\n.font-weight-normal {\n font-weight: 400 !important;\n}\n\n.font-weight-bold {\n font-weight: 700 !important;\n}\n\n.font-weight-bolder {\n font-weight: bolder !important;\n}\n\n.font-italic {\n font-style: italic !important;\n}\n\n.text-white {\n color: #fff !important;\n}\n\n.text-primary {\n color: #007bff !important;\n}\n\na.text-primary:hover, a.text-primary:focus {\n color: #0056b3 !important;\n}\n\n.text-secondary {\n color: #6c757d !important;\n}\n\na.text-secondary:hover, a.text-secondary:focus {\n color: #494f54 !important;\n}\n\n.text-success {\n color: #28a745 !important;\n}\n\na.text-success:hover, a.text-success:focus {\n color: #19692c !important;\n}\n\n.text-info {\n color: #17a2b8 !important;\n}\n\na.text-info:hover, a.text-info:focus {\n color: #0f6674 !important;\n}\n\n.text-warning {\n color: #ffc107 !important;\n}\n\na.text-warning:hover, a.text-warning:focus {\n color: #ba8b00 !important;\n}\n\n.text-danger {\n color: #dc3545 !important;\n}\n\na.text-danger:hover, a.text-danger:focus {\n color: #a71d2a !important;\n}\n\n.text-light {\n color: #f8f9fa !important;\n}\n\na.text-light:hover, a.text-light:focus {\n color: #cbd3da !important;\n}\n\n.text-dark {\n color: #343a40 !important;\n}\n\na.text-dark:hover, a.text-dark:focus {\n color: #121416 !important;\n}\n\n.text-body {\n color: #212529 !important;\n}\n\n.text-muted {\n color: #6c757d !important;\n}\n\n.text-black-50 {\n color: rgba(0, 0, 0, 0.5) !important;\n}\n\n.text-white-50 {\n color: rgba(255, 255, 255, 0.5) !important;\n}\n\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n.text-decoration-none {\n text-decoration: none !important;\n}\n\n.text-break {\n word-break: break-word !important;\n overflow-wrap: break-word !important;\n}\n\n.text-reset {\n color: inherit !important;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n@media print {\n *,\n *::before,\n *::after {\n text-shadow: none !important;\n box-shadow: none !important;\n }\n a:not(.btn) {\n text-decoration: underline;\n }\n abbr[title]::after {\n content: \" (\" attr(title) \")\";\n }\n pre {\n white-space: pre-wrap !important;\n }\n pre,\n blockquote {\n border: 1px solid #adb5bd;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n @page {\n size: a3;\n }\n body {\n min-width: 992px !important;\n }\n .container {\n min-width: 992px !important;\n }\n .navbar {\n display: none;\n }\n .badge {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #dee2e6 !important;\n }\n .table-dark {\n color: inherit;\n }\n .table-dark th,\n .table-dark td,\n .table-dark thead th,\n .table-dark tbody + tbody {\n border-color: #dee2e6;\n }\n .table .thead-dark th {\n color: inherit;\n border-color: #dee2e6;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","// stylelint-disable property-blacklist, scss/dollar-variable-default\n\n// SCSS RFS mixin\n//\n// Automated font-resizing\n//\n// See https://github.com/twbs/rfs\n\n// Configuration\n\n// Base font size\n$rfs-base-font-size: 1.25rem !default;\n$rfs-font-size-unit: rem !default;\n\n// Breakpoint at where font-size starts decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n// Resize font-size based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != \"number\" or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-responsive-font-sizes to false\n$enable-responsive-font-sizes: true !default;\n\n// Cache $rfs-base-font-size unit\n$rfs-base-font-size-unit: unit($rfs-base-font-size);\n\n// Remove px-unit from $rfs-base-font-size for calculations\n@if $rfs-base-font-size-unit == \"px\" {\n $rfs-base-font-size: $rfs-base-font-size / ($rfs-base-font-size * 0 + 1);\n}\n@else if $rfs-base-font-size-unit == \"rem\" {\n $rfs-base-font-size: $rfs-base-font-size / ($rfs-base-font-size * 0 + 1 / $rfs-rem-value);\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == \"px\" {\n $rfs-breakpoint: $rfs-breakpoint / ($rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == \"rem\" or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: $rfs-breakpoint / ($rfs-breakpoint * 0 + 1 / $rfs-rem-value);\n}\n\n// Responsive font-size mixin\n@mixin rfs($fs, $important: false) {\n // Cache $fs unit\n $fs-unit: if(type-of($fs) == \"number\", unit($fs), false);\n\n // Add !important suffix if needed\n $rfs-suffix: if($important, \" !important\", \"\");\n\n // If $fs isn't a number (like inherit) or $fs has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $fs-unit or $fs-unit != \"\" and $fs-unit != \"px\" and $fs-unit != \"rem\" or $fs == 0 {\n font-size: #{$fs}#{$rfs-suffix};\n }\n @else {\n // Variables for storing static and fluid rescaling\n $rfs-static: null;\n $rfs-fluid: null;\n\n // Remove px-unit from $fs for calculations\n @if $fs-unit == \"px\" {\n $fs: $fs / ($fs * 0 + 1);\n }\n @else if $fs-unit == \"rem\" {\n $fs: $fs / ($fs * 0 + 1 / $rfs-rem-value);\n }\n\n // Set default font-size\n @if $rfs-font-size-unit == rem {\n $rfs-static: #{$fs / $rfs-rem-value}rem#{$rfs-suffix};\n }\n @else if $rfs-font-size-unit == px {\n $rfs-static: #{$fs}px#{$rfs-suffix};\n }\n @else {\n @error \"`#{$rfs-font-size-unit}` is not a valid unit for $rfs-font-size-unit. Use `px` or `rem`.\";\n }\n\n // Only add media query if font-size is bigger as the minimum font-size\n // If $rfs-factor == 1, no rescaling will take place\n @if $fs > $rfs-base-font-size and $enable-responsive-font-sizes {\n $min-width: null;\n $variable-unit: null;\n\n // Calculate minimum font-size for given font-size\n $fs-min: $rfs-base-font-size + ($fs - $rfs-base-font-size) / $rfs-factor;\n\n // Calculate difference between given font-size and minimum font-size for given font-size\n $fs-diff: $fs - $fs-min;\n\n // Base font-size formatting\n // No need to check if the unit is valid, because we did that before\n $min-width: if($rfs-font-size-unit == rem, #{$fs-min / $rfs-rem-value}rem, #{$fs-min}px);\n\n // If two-dimensional, use smallest of screen width and height\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{$fs-diff * 100 / $rfs-breakpoint}#{$variable-unit};\n\n // Set the calculated font-size.\n $rfs-fluid: calc(#{$min-width} + #{$variable-width}) #{$rfs-suffix};\n }\n\n // Rendering\n @if $rfs-fluid == null {\n // Only render static font-size if no fluid font-size is available\n font-size: $rfs-static;\n }\n @else {\n $mq-value: null;\n\n // RFS breakpoint formatting\n @if $rfs-breakpoint-unit == em or $rfs-breakpoint-unit == rem {\n $mq-value: #{$rfs-breakpoint / $rfs-rem-value}#{$rfs-breakpoint-unit};\n }\n @else if $rfs-breakpoint-unit == px {\n $mq-value: #{$rfs-breakpoint}px;\n }\n @else {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n }\n\n @if $rfs-class == \"disable\" {\n // Adding an extra class increases specificity,\n // which prevents the media query to override the font size\n &,\n .disable-responsive-font-size &,\n &.disable-responsive-font-size {\n font-size: $rfs-static;\n }\n }\n @else {\n font-size: $rfs-static;\n }\n\n @if $rfs-two-dimensional {\n @media (max-width: #{$mq-value}), (max-height: #{$mq-value}) {\n @if $rfs-class == \"enable\" {\n .enable-responsive-font-size &,\n &.enable-responsive-font-size {\n font-size: $rfs-fluid;\n }\n }\n @else {\n font-size: $rfs-fluid;\n }\n\n @if $rfs-safari-iframe-resize-bug-fix {\n // stylelint-disable-next-line length-zero-no-unit\n min-width: 0vw;\n }\n }\n }\n @else {\n @media (max-width: #{$mq-value}) {\n @if $rfs-class == \"enable\" {\n .enable-responsive-font-size &,\n &.enable-responsive-font-size {\n font-size: $rfs-fluid;\n }\n }\n @else {\n font-size: $rfs-fluid;\n }\n\n @if $rfs-safari-iframe-resize-bug-fix {\n // stylelint-disable-next-line length-zero-no-unit\n min-width: 0vw;\n }\n }\n }\n }\n }\n}\n\n// The font-size & responsive-font-size mixin uses RFS to rescale font sizes\n@mixin font-size($fs, $important: false) {\n @include rfs($fs, $important);\n}\n\n@mixin responsive-font-size($fs, $important: false) {\n @include rfs($fs, $important);\n}\n","/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n:root {\n --blue: #007bff;\n --indigo: #6610f2;\n --purple: #6f42c1;\n --pink: #e83e8c;\n --red: #dc3545;\n --orange: #fd7e14;\n --yellow: #ffc107;\n --green: #28a745;\n --teal: #20c997;\n --cyan: #17a2b8;\n --white: #fff;\n --gray: #6c757d;\n --gray-dark: #343a40;\n --primary: #007bff;\n --secondary: #6c757d;\n --success: #28a745;\n --info: #17a2b8;\n --warning: #ffc107;\n --danger: #dc3545;\n --light: #f8f9fa;\n --dark: #343a40;\n --breakpoint-xs: 0;\n --breakpoint-sm: 576px;\n --breakpoint-md: 768px;\n --breakpoint-lg: 992px;\n --breakpoint-xl: 1200px;\n --font-family-sans-serif: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n display: block;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n text-align: left;\n background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n outline: 0 !important;\n}\n\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n text-decoration: underline;\n text-decoration: underline dotted;\n cursor: help;\n border-bottom: 0;\n text-decoration-skip-ink: none;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -.25em;\n}\n\nsup {\n top: -.5em;\n}\n\na {\n color: #007bff;\n text-decoration: none;\n background-color: transparent;\n}\n\na:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {\n color: inherit;\n text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n font-size: 1em;\n}\n\npre {\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg {\n vertical-align: middle;\n border-style: none;\n}\n\nsvg {\n overflow: hidden;\n vertical-align: middle;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.75rem;\n padding-bottom: 0.75rem;\n color: #6c757d;\n text-align: left;\n caption-side: bottom;\n}\n\nth {\n text-align: inherit;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: 0.5rem;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\ninput {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nselect {\n word-wrap: normal;\n}\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\nbutton:not(:disabled),\n[type=\"button\"]:not(:disabled),\n[type=\"reset\"]:not(:disabled),\n[type=\"submit\"]:not(:disabled) {\n cursor: pointer;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n box-sizing: border-box;\n padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n -webkit-appearance: listbox;\n}\n\ntextarea {\n overflow: auto;\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n padding: 0;\n margin-bottom: .5rem;\n font-size: 1.5rem;\n line-height: inherit;\n color: inherit;\n white-space: normal;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n[type=\"search\"] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\nsummary {\n display: list-item;\n cursor: pointer;\n}\n\ntemplate {\n display: none;\n}\n\n[hidden] {\n display: none !important;\n}\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n margin-bottom: 0.5rem;\n font-weight: 500;\n line-height: 1.2;\n}\n\nh1, .h1 {\n font-size: 2.5rem;\n}\n\nh2, .h2 {\n font-size: 2rem;\n}\n\nh3, .h3 {\n font-size: 1.75rem;\n}\n\nh4, .h4 {\n font-size: 1.5rem;\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: 6rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\n.display-2 {\n font-size: 5.5rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\n.display-3 {\n font-size: 4.5rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\n.display-4 {\n font-size: 3.5rem;\n font-weight: 300;\n line-height: 1.2;\n}\n\nhr {\n margin-top: 1rem;\n margin-bottom: 1rem;\n border: 0;\n border-top: 1px solid rgba(0, 0, 0, 0.1);\n}\n\nsmall,\n.small {\n font-size: 80%;\n font-weight: 400;\n}\n\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n\n.list-inline-item:not(:last-child) {\n margin-right: 0.5rem;\n}\n\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n\n.blockquote-footer {\n display: block;\n font-size: 80%;\n color: #6c757d;\n}\n\n.blockquote-footer::before {\n content: \"\\2014\\00A0\";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: #fff;\n border: 1px solid #dee2e6;\n border-radius: 0.25rem;\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 90%;\n color: #6c757d;\n}\n\ncode {\n font-size: 87.5%;\n color: #e83e8c;\n word-break: break-word;\n}\n\na > code {\n color: inherit;\n}\n\nkbd {\n padding: 0.2rem 0.4rem;\n font-size: 87.5%;\n color: #fff;\n background-color: #212529;\n border-radius: 0.2rem;\n}\n\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n}\n\npre {\n display: block;\n font-size: 87.5%;\n color: #212529;\n}\n\npre code {\n font-size: inherit;\n color: inherit;\n word-break: normal;\n}\n\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n\n.container {\n width: 100%;\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container {\n max-width: 540px;\n }\n}\n\n@media (min-width: 768px) {\n .container {\n max-width: 720px;\n }\n}\n\n@media (min-width: 992px) {\n .container {\n max-width: 960px;\n }\n}\n\n@media (min-width: 1200px) {\n .container {\n max-width: 1140px;\n }\n}\n\n.container-fluid {\n width: 100%;\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n\n.row {\n display: flex;\n flex-wrap: wrap;\n margin-right: -15px;\n margin-left: -15px;\n}\n\n.no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n\n.no-gutters > .col,\n.no-gutters > [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n\n.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,\n.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,\n.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,\n.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,\n.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,\n.col-xl-auto {\n position: relative;\n width: 100%;\n padding-right: 15px;\n padding-left: 15px;\n}\n\n.col {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n}\n\n.col-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n}\n\n.col-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n}\n\n.col-3 {\n flex: 0 0 25%;\n max-width: 25%;\n}\n\n.col-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n}\n\n.col-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n}\n\n.col-6 {\n flex: 0 0 50%;\n max-width: 50%;\n}\n\n.col-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n}\n\n.col-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n}\n\n.col-9 {\n flex: 0 0 75%;\n max-width: 75%;\n}\n\n.col-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n}\n\n.col-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n}\n\n.col-12 {\n flex: 0 0 100%;\n max-width: 100%;\n}\n\n.order-first {\n order: -1;\n}\n\n.order-last {\n order: 13;\n}\n\n.order-0 {\n order: 0;\n}\n\n.order-1 {\n order: 1;\n}\n\n.order-2 {\n order: 2;\n}\n\n.order-3 {\n order: 3;\n}\n\n.order-4 {\n order: 4;\n}\n\n.order-5 {\n order: 5;\n}\n\n.order-6 {\n order: 6;\n}\n\n.order-7 {\n order: 7;\n}\n\n.order-8 {\n order: 8;\n}\n\n.order-9 {\n order: 9;\n}\n\n.order-10 {\n order: 10;\n}\n\n.order-11 {\n order: 11;\n}\n\n.order-12 {\n order: 12;\n}\n\n.offset-1 {\n margin-left: 8.333333%;\n}\n\n.offset-2 {\n margin-left: 16.666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.333333%;\n}\n\n.offset-5 {\n margin-left: 41.666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.333333%;\n}\n\n.offset-8 {\n margin-left: 66.666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.333333%;\n}\n\n.offset-11 {\n margin-left: 91.666667%;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-sm-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-sm-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-sm-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-sm-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-sm-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-sm-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-sm-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-sm-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-sm-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-sm-first {\n order: -1;\n }\n .order-sm-last {\n order: 13;\n }\n .order-sm-0 {\n order: 0;\n }\n .order-sm-1 {\n order: 1;\n }\n .order-sm-2 {\n order: 2;\n }\n .order-sm-3 {\n order: 3;\n }\n .order-sm-4 {\n order: 4;\n }\n .order-sm-5 {\n order: 5;\n }\n .order-sm-6 {\n order: 6;\n }\n .order-sm-7 {\n order: 7;\n }\n .order-sm-8 {\n order: 8;\n }\n .order-sm-9 {\n order: 9;\n }\n .order-sm-10 {\n order: 10;\n }\n .order-sm-11 {\n order: 11;\n }\n .order-sm-12 {\n order: 12;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.333333%;\n }\n .offset-sm-2 {\n margin-left: 16.666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.333333%;\n }\n .offset-sm-5 {\n margin-left: 41.666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.333333%;\n }\n .offset-sm-8 {\n margin-left: 66.666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.333333%;\n }\n .offset-sm-11 {\n margin-left: 91.666667%;\n }\n}\n\n@media (min-width: 768px) {\n .col-md {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-md-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-md-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-md-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-md-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-md-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-md-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-md-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-md-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-md-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-md-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-md-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-md-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-md-first {\n order: -1;\n }\n .order-md-last {\n order: 13;\n }\n .order-md-0 {\n order: 0;\n }\n .order-md-1 {\n order: 1;\n }\n .order-md-2 {\n order: 2;\n }\n .order-md-3 {\n order: 3;\n }\n .order-md-4 {\n order: 4;\n }\n .order-md-5 {\n order: 5;\n }\n .order-md-6 {\n order: 6;\n }\n .order-md-7 {\n order: 7;\n }\n .order-md-8 {\n order: 8;\n }\n .order-md-9 {\n order: 9;\n }\n .order-md-10 {\n order: 10;\n }\n .order-md-11 {\n order: 11;\n }\n .order-md-12 {\n order: 12;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.333333%;\n }\n .offset-md-2 {\n margin-left: 16.666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.333333%;\n }\n .offset-md-5 {\n margin-left: 41.666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.333333%;\n }\n .offset-md-8 {\n margin-left: 66.666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.333333%;\n }\n .offset-md-11 {\n margin-left: 91.666667%;\n }\n}\n\n@media (min-width: 992px) {\n .col-lg {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-lg-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-lg-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-lg-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-lg-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-lg-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-lg-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-lg-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-lg-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-lg-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-lg-first {\n order: -1;\n }\n .order-lg-last {\n order: 13;\n }\n .order-lg-0 {\n order: 0;\n }\n .order-lg-1 {\n order: 1;\n }\n .order-lg-2 {\n order: 2;\n }\n .order-lg-3 {\n order: 3;\n }\n .order-lg-4 {\n order: 4;\n }\n .order-lg-5 {\n order: 5;\n }\n .order-lg-6 {\n order: 6;\n }\n .order-lg-7 {\n order: 7;\n }\n .order-lg-8 {\n order: 8;\n }\n .order-lg-9 {\n order: 9;\n }\n .order-lg-10 {\n order: 10;\n }\n .order-lg-11 {\n order: 11;\n }\n .order-lg-12 {\n order: 12;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.333333%;\n }\n .offset-lg-2 {\n margin-left: 16.666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.333333%;\n }\n .offset-lg-5 {\n margin-left: 41.666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.333333%;\n }\n .offset-lg-8 {\n margin-left: 66.666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.333333%;\n }\n .offset-lg-11 {\n margin-left: 91.666667%;\n }\n}\n\n@media (min-width: 1200px) {\n .col-xl {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: 100%;\n }\n .col-xl-1 {\n flex: 0 0 8.333333%;\n max-width: 8.333333%;\n }\n .col-xl-2 {\n flex: 0 0 16.666667%;\n max-width: 16.666667%;\n }\n .col-xl-3 {\n flex: 0 0 25%;\n max-width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 33.333333%;\n max-width: 33.333333%;\n }\n .col-xl-5 {\n flex: 0 0 41.666667%;\n max-width: 41.666667%;\n }\n .col-xl-6 {\n flex: 0 0 50%;\n max-width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 58.333333%;\n max-width: 58.333333%;\n }\n .col-xl-8 {\n flex: 0 0 66.666667%;\n max-width: 66.666667%;\n }\n .col-xl-9 {\n flex: 0 0 75%;\n max-width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 83.333333%;\n max-width: 83.333333%;\n }\n .col-xl-11 {\n flex: 0 0 91.666667%;\n max-width: 91.666667%;\n }\n .col-xl-12 {\n flex: 0 0 100%;\n max-width: 100%;\n }\n .order-xl-first {\n order: -1;\n }\n .order-xl-last {\n order: 13;\n }\n .order-xl-0 {\n order: 0;\n }\n .order-xl-1 {\n order: 1;\n }\n .order-xl-2 {\n order: 2;\n }\n .order-xl-3 {\n order: 3;\n }\n .order-xl-4 {\n order: 4;\n }\n .order-xl-5 {\n order: 5;\n }\n .order-xl-6 {\n order: 6;\n }\n .order-xl-7 {\n order: 7;\n }\n .order-xl-8 {\n order: 8;\n }\n .order-xl-9 {\n order: 9;\n }\n .order-xl-10 {\n order: 10;\n }\n .order-xl-11 {\n order: 11;\n }\n .order-xl-12 {\n order: 12;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.333333%;\n }\n .offset-xl-2 {\n margin-left: 16.666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.333333%;\n }\n .offset-xl-5 {\n margin-left: 41.666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.333333%;\n }\n .offset-xl-8 {\n margin-left: 66.666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.333333%;\n }\n .offset-xl-11 {\n margin-left: 91.666667%;\n }\n}\n\n.table {\n width: 100%;\n margin-bottom: 1rem;\n color: #212529;\n}\n\n.table th,\n.table td {\n padding: 0.75rem;\n vertical-align: top;\n border-top: 1px solid #dee2e6;\n}\n\n.table thead th {\n vertical-align: bottom;\n border-bottom: 2px solid #dee2e6;\n}\n\n.table tbody + tbody {\n border-top: 2px solid #dee2e6;\n}\n\n.table-sm th,\n.table-sm td {\n padding: 0.3rem;\n}\n\n.table-bordered {\n border: 1px solid #dee2e6;\n}\n\n.table-bordered th,\n.table-bordered td {\n border: 1px solid #dee2e6;\n}\n\n.table-bordered thead th,\n.table-bordered thead td {\n border-bottom-width: 2px;\n}\n\n.table-borderless th,\n.table-borderless td,\n.table-borderless thead th,\n.table-borderless tbody + tbody {\n border: 0;\n}\n\n.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.table-hover tbody tr:hover {\n color: #212529;\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-primary,\n.table-primary > th,\n.table-primary > td {\n background-color: #b8daff;\n}\n\n.table-primary th,\n.table-primary td,\n.table-primary thead th,\n.table-primary tbody + tbody {\n border-color: #7abaff;\n}\n\n.table-hover .table-primary:hover {\n background-color: #9fcdff;\n}\n\n.table-hover .table-primary:hover > td,\n.table-hover .table-primary:hover > th {\n background-color: #9fcdff;\n}\n\n.table-secondary,\n.table-secondary > th,\n.table-secondary > td {\n background-color: #d6d8db;\n}\n\n.table-secondary th,\n.table-secondary td,\n.table-secondary thead th,\n.table-secondary tbody + tbody {\n border-color: #b3b7bb;\n}\n\n.table-hover .table-secondary:hover {\n background-color: #c8cbcf;\n}\n\n.table-hover .table-secondary:hover > td,\n.table-hover .table-secondary:hover > th {\n background-color: #c8cbcf;\n}\n\n.table-success,\n.table-success > th,\n.table-success > td {\n background-color: #c3e6cb;\n}\n\n.table-success th,\n.table-success td,\n.table-success thead th,\n.table-success tbody + tbody {\n border-color: #8fd19e;\n}\n\n.table-hover .table-success:hover {\n background-color: #b1dfbb;\n}\n\n.table-hover .table-success:hover > td,\n.table-hover .table-success:hover > th {\n background-color: #b1dfbb;\n}\n\n.table-info,\n.table-info > th,\n.table-info > td {\n background-color: #bee5eb;\n}\n\n.table-info th,\n.table-info td,\n.table-info thead th,\n.table-info tbody + tbody {\n border-color: #86cfda;\n}\n\n.table-hover .table-info:hover {\n background-color: #abdde5;\n}\n\n.table-hover .table-info:hover > td,\n.table-hover .table-info:hover > th {\n background-color: #abdde5;\n}\n\n.table-warning,\n.table-warning > th,\n.table-warning > td {\n background-color: #ffeeba;\n}\n\n.table-warning th,\n.table-warning td,\n.table-warning thead th,\n.table-warning tbody + tbody {\n border-color: #ffdf7e;\n}\n\n.table-hover .table-warning:hover {\n background-color: #ffe8a1;\n}\n\n.table-hover .table-warning:hover > td,\n.table-hover .table-warning:hover > th {\n background-color: #ffe8a1;\n}\n\n.table-danger,\n.table-danger > th,\n.table-danger > td {\n background-color: #f5c6cb;\n}\n\n.table-danger th,\n.table-danger td,\n.table-danger thead th,\n.table-danger tbody + tbody {\n border-color: #ed969e;\n}\n\n.table-hover .table-danger:hover {\n background-color: #f1b0b7;\n}\n\n.table-hover .table-danger:hover > td,\n.table-hover .table-danger:hover > th {\n background-color: #f1b0b7;\n}\n\n.table-light,\n.table-light > th,\n.table-light > td {\n background-color: #fdfdfe;\n}\n\n.table-light th,\n.table-light td,\n.table-light thead th,\n.table-light tbody + tbody {\n border-color: #fbfcfc;\n}\n\n.table-hover .table-light:hover {\n background-color: #ececf6;\n}\n\n.table-hover .table-light:hover > td,\n.table-hover .table-light:hover > th {\n background-color: #ececf6;\n}\n\n.table-dark,\n.table-dark > th,\n.table-dark > td {\n background-color: #c6c8ca;\n}\n\n.table-dark th,\n.table-dark td,\n.table-dark thead th,\n.table-dark tbody + tbody {\n border-color: #95999c;\n}\n\n.table-hover .table-dark:hover {\n background-color: #b9bbbe;\n}\n\n.table-hover .table-dark:hover > td,\n.table-hover .table-dark:hover > th {\n background-color: #b9bbbe;\n}\n\n.table-active,\n.table-active > th,\n.table-active > td {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover > td,\n.table-hover .table-active:hover > th {\n background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table .thead-dark th {\n color: #fff;\n background-color: #343a40;\n border-color: #454d55;\n}\n\n.table .thead-light th {\n color: #495057;\n background-color: #e9ecef;\n border-color: #dee2e6;\n}\n\n.table-dark {\n color: #fff;\n background-color: #343a40;\n}\n\n.table-dark th,\n.table-dark td,\n.table-dark thead th {\n border-color: #454d55;\n}\n\n.table-dark.table-bordered {\n border: 0;\n}\n\n.table-dark.table-striped tbody tr:nth-of-type(odd) {\n background-color: rgba(255, 255, 255, 0.05);\n}\n\n.table-dark.table-hover tbody tr:hover {\n color: #fff;\n background-color: rgba(255, 255, 255, 0.075);\n}\n\n@media (max-width: 575.98px) {\n .table-responsive-sm {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-sm > .table-bordered {\n border: 0;\n }\n}\n\n@media (max-width: 767.98px) {\n .table-responsive-md {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-md > .table-bordered {\n border: 0;\n }\n}\n\n@media (max-width: 991.98px) {\n .table-responsive-lg {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-lg > .table-bordered {\n border: 0;\n }\n}\n\n@media (max-width: 1199.98px) {\n .table-responsive-xl {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n .table-responsive-xl > .table-bordered {\n border: 0;\n }\n}\n\n.table-responsive {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.table-responsive > .table-bordered {\n border: 0;\n}\n\n.form-control {\n display: block;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .form-control {\n transition: none;\n }\n}\n\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n\n.form-control:focus {\n color: #495057;\n background-color: #fff;\n border-color: #80bdff;\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.form-control::placeholder {\n color: #6c757d;\n opacity: 1;\n}\n\n.form-control:disabled, .form-control[readonly] {\n background-color: #e9ecef;\n opacity: 1;\n}\n\nselect.form-control:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.form-control-file,\n.form-control-range {\n display: block;\n width: 100%;\n}\n\n.col-form-label {\n padding-top: calc(0.375rem + 1px);\n padding-bottom: calc(0.375rem + 1px);\n margin-bottom: 0;\n font-size: inherit;\n line-height: 1.5;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem + 1px);\n padding-bottom: calc(0.5rem + 1px);\n font-size: 1.25rem;\n line-height: 1.5;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem + 1px);\n padding-bottom: calc(0.25rem + 1px);\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.form-control-plaintext {\n display: block;\n width: 100%;\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n margin-bottom: 0;\n line-height: 1.5;\n color: #212529;\n background-color: transparent;\n border: solid transparent;\n border-width: 1px 0;\n}\n\n.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm {\n height: calc(1.5em + 0.5rem + 2px);\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.form-control-lg {\n height: calc(1.5em + 1rem + 2px);\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\nselect.form-control[size], select.form-control[multiple] {\n height: auto;\n}\n\ntextarea.form-control {\n height: auto;\n}\n\n.form-group {\n margin-bottom: 1rem;\n}\n\n.form-text {\n display: block;\n margin-top: 0.25rem;\n}\n\n.form-row {\n display: flex;\n flex-wrap: wrap;\n margin-right: -5px;\n margin-left: -5px;\n}\n\n.form-row > .col,\n.form-row > [class*=\"col-\"] {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.form-check {\n position: relative;\n display: block;\n padding-left: 1.25rem;\n}\n\n.form-check-input {\n position: absolute;\n margin-top: 0.3rem;\n margin-left: -1.25rem;\n}\n\n.form-check-input:disabled ~ .form-check-label {\n color: #6c757d;\n}\n\n.form-check-label {\n margin-bottom: 0;\n}\n\n.form-check-inline {\n display: inline-flex;\n align-items: center;\n padding-left: 0;\n margin-right: 0.75rem;\n}\n\n.form-check-inline .form-check-input {\n position: static;\n margin-top: 0;\n margin-right: 0.3125rem;\n margin-left: 0;\n}\n\n.valid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 80%;\n color: #28a745;\n}\n\n.valid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: .1rem;\n font-size: 0.875rem;\n line-height: 1.5;\n color: #fff;\n background-color: rgba(40, 167, 69, 0.9);\n border-radius: 0.25rem;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid {\n border-color: #28a745;\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: center right calc(0.375em + 0.1875rem);\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus {\n border-color: #28a745;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:valid ~ .valid-feedback,\n.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback,\n.form-control.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated textarea.form-control:valid, textarea.form-control.is-valid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .custom-select:valid, .custom-select.is-valid {\n border-color: #28a745;\n padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem);\n background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px, url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus {\n border-color: #28a745;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-select:valid ~ .valid-feedback,\n.was-validated .custom-select:valid ~ .valid-tooltip, .custom-select.is-valid ~ .valid-feedback,\n.custom-select.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-control-file:valid ~ .valid-feedback,\n.was-validated .form-control-file:valid ~ .valid-tooltip, .form-control-file.is-valid ~ .valid-feedback,\n.form-control-file.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {\n color: #28a745;\n}\n\n.was-validated .form-check-input:valid ~ .valid-feedback,\n.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback,\n.form-check-input.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label {\n color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before {\n border-color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .valid-feedback,\n.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback,\n.custom-control-input.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before {\n border-color: #34ce57;\n background-color: #34ce57;\n}\n\n.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before {\n border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label {\n border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .valid-feedback,\n.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback,\n.custom-file-input.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label {\n border-color: #28a745;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.invalid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 80%;\n color: #dc3545;\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: .1rem;\n font-size: 0.875rem;\n line-height: 1.5;\n color: #fff;\n background-color: rgba(220, 53, 69, 0.9);\n border-radius: 0.25rem;\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid {\n border-color: #dc3545;\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E\");\n background-repeat: no-repeat;\n background-position: center right calc(0.375em + 0.1875rem);\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .form-control:invalid ~ .invalid-feedback,\n.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback,\n.form-control.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .custom-select:invalid, .custom-select.is-invalid {\n border-color: #dc3545;\n padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem);\n background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px, url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E\") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-select:invalid ~ .invalid-feedback,\n.was-validated .custom-select:invalid ~ .invalid-tooltip, .custom-select.is-invalid ~ .invalid-feedback,\n.custom-select.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-control-file:invalid ~ .invalid-feedback,\n.was-validated .form-control-file:invalid ~ .invalid-tooltip, .form-control-file.is-invalid ~ .invalid-feedback,\n.form-control-file.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {\n color: #dc3545;\n}\n\n.was-validated .form-check-input:invalid ~ .invalid-feedback,\n.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback,\n.form-check-input.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label {\n color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before {\n border-color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .invalid-feedback,\n.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback,\n.custom-control-input.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before {\n border-color: #e4606d;\n background-color: #e4606d;\n}\n\n.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before {\n border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label {\n border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .invalid-feedback,\n.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback,\n.custom-file-input.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.form-inline {\n display: flex;\n flex-flow: row wrap;\n align-items: center;\n}\n\n.form-inline .form-check {\n width: 100%;\n}\n\n@media (min-width: 576px) {\n .form-inline label {\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 0;\n }\n .form-inline .form-group {\n display: flex;\n flex: 0 0 auto;\n flex-flow: row wrap;\n align-items: center;\n margin-bottom: 0;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-plaintext {\n display: inline-block;\n }\n .form-inline .input-group,\n .form-inline .custom-select {\n width: auto;\n }\n .form-inline .form-check {\n display: flex;\n align-items: center;\n justify-content: center;\n width: auto;\n padding-left: 0;\n }\n .form-inline .form-check-input {\n position: relative;\n flex-shrink: 0;\n margin-top: 0;\n margin-right: 0.25rem;\n margin-left: 0;\n }\n .form-inline .custom-control {\n align-items: center;\n justify-content: center;\n }\n .form-inline .custom-control-label {\n margin-bottom: 0;\n }\n}\n\n.btn {\n display: inline-block;\n font-weight: 400;\n color: #212529;\n text-align: center;\n vertical-align: middle;\n user-select: none;\n background-color: transparent;\n border: 1px solid transparent;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n line-height: 1.5;\n border-radius: 0.25rem;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .btn {\n transition: none;\n }\n}\n\n.btn:hover {\n color: #212529;\n text-decoration: none;\n}\n\n.btn:focus, .btn.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.btn.disabled, .btn:disabled {\n opacity: 0.65;\n}\n\na.btn.disabled,\nfieldset:disabled a.btn {\n pointer-events: none;\n}\n\n.btn-primary {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:hover {\n color: #fff;\n background-color: #0069d9;\n border-color: #0062cc;\n}\n\n.btn-primary:focus, .btn-primary.focus {\n box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);\n}\n\n.btn-primary.disabled, .btn-primary:disabled {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,\n.show > .btn-primary.dropdown-toggle {\n color: #fff;\n background-color: #0062cc;\n border-color: #005cbf;\n}\n\n.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-primary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);\n}\n\n.btn-secondary {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-secondary:hover {\n color: #fff;\n background-color: #5a6268;\n border-color: #545b62;\n}\n\n.btn-secondary:focus, .btn-secondary.focus {\n box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);\n}\n\n.btn-secondary.disabled, .btn-secondary:disabled {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,\n.show > .btn-secondary.dropdown-toggle {\n color: #fff;\n background-color: #545b62;\n border-color: #4e555b;\n}\n\n.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-secondary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);\n}\n\n.btn-success {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:hover {\n color: #fff;\n background-color: #218838;\n border-color: #1e7e34;\n}\n\n.btn-success:focus, .btn-success.focus {\n box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);\n}\n\n.btn-success.disabled, .btn-success:disabled {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,\n.show > .btn-success.dropdown-toggle {\n color: #fff;\n background-color: #1e7e34;\n border-color: #1c7430;\n}\n\n.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,\n.show > .btn-success.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);\n}\n\n.btn-info {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:hover {\n color: #fff;\n background-color: #138496;\n border-color: #117a8b;\n}\n\n.btn-info:focus, .btn-info.focus {\n box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);\n}\n\n.btn-info.disabled, .btn-info:disabled {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,\n.show > .btn-info.dropdown-toggle {\n color: #fff;\n background-color: #117a8b;\n border-color: #10707f;\n}\n\n.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,\n.show > .btn-info.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);\n}\n\n.btn-warning {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:hover {\n color: #212529;\n background-color: #e0a800;\n border-color: #d39e00;\n}\n\n.btn-warning:focus, .btn-warning.focus {\n box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);\n}\n\n.btn-warning.disabled, .btn-warning:disabled {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,\n.show > .btn-warning.dropdown-toggle {\n color: #212529;\n background-color: #d39e00;\n border-color: #c69500;\n}\n\n.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,\n.show > .btn-warning.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);\n}\n\n.btn-danger {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:hover {\n color: #fff;\n background-color: #c82333;\n border-color: #bd2130;\n}\n\n.btn-danger:focus, .btn-danger.focus {\n box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);\n}\n\n.btn-danger.disabled, .btn-danger:disabled {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,\n.show > .btn-danger.dropdown-toggle {\n color: #fff;\n background-color: #bd2130;\n border-color: #b21f2d;\n}\n\n.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,\n.show > .btn-danger.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);\n}\n\n.btn-light {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:hover {\n color: #212529;\n background-color: #e2e6ea;\n border-color: #dae0e5;\n}\n\n.btn-light:focus, .btn-light.focus {\n box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);\n}\n\n.btn-light.disabled, .btn-light:disabled {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,\n.show > .btn-light.dropdown-toggle {\n color: #212529;\n background-color: #dae0e5;\n border-color: #d3d9df;\n}\n\n.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,\n.show > .btn-light.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);\n}\n\n.btn-dark {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:hover {\n color: #fff;\n background-color: #23272b;\n border-color: #1d2124;\n}\n\n.btn-dark:focus, .btn-dark.focus {\n box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);\n}\n\n.btn-dark.disabled, .btn-dark:disabled {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,\n.show > .btn-dark.dropdown-toggle {\n color: #fff;\n background-color: #1d2124;\n border-color: #171a1d;\n}\n\n.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,\n.show > .btn-dark.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);\n}\n\n.btn-outline-primary {\n color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:hover {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:focus, .btn-outline-primary.focus {\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-primary.disabled, .btn-outline-primary:disabled {\n color: #007bff;\n background-color: transparent;\n}\n\n.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,\n.show > .btn-outline-primary.dropdown-toggle {\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-primary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-secondary {\n color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-outline-secondary:hover {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-outline-secondary:focus, .btn-outline-secondary.focus {\n box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {\n color: #6c757d;\n background-color: transparent;\n}\n\n.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,\n.show > .btn-outline-secondary.dropdown-toggle {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-secondary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.btn-outline-success {\n color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:hover {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:focus, .btn-outline-success.focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-success.disabled, .btn-outline-success:disabled {\n color: #28a745;\n background-color: transparent;\n}\n\n.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,\n.show > .btn-outline-success.dropdown-toggle {\n color: #fff;\n background-color: #28a745;\n border-color: #28a745;\n}\n\n.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-success.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-info {\n color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:hover {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:focus, .btn-outline-info.focus {\n box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-info.disabled, .btn-outline-info:disabled {\n color: #17a2b8;\n background-color: transparent;\n}\n\n.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,\n.show > .btn-outline-info.dropdown-toggle {\n color: #fff;\n background-color: #17a2b8;\n border-color: #17a2b8;\n}\n\n.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-info.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-warning {\n color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:hover {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:focus, .btn-outline-warning.focus {\n box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-warning.disabled, .btn-outline-warning:disabled {\n color: #ffc107;\n background-color: transparent;\n}\n\n.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,\n.show > .btn-outline-warning.dropdown-toggle {\n color: #212529;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-warning.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-danger {\n color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:hover {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:focus, .btn-outline-danger.focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-danger.disabled, .btn-outline-danger:disabled {\n color: #dc3545;\n background-color: transparent;\n}\n\n.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,\n.show > .btn-outline-danger.dropdown-toggle {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-danger.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-light {\n color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:hover {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:focus, .btn-outline-light.focus {\n box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-light.disabled, .btn-outline-light:disabled {\n color: #f8f9fa;\n background-color: transparent;\n}\n\n.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,\n.show > .btn-outline-light.dropdown-toggle {\n color: #212529;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-light.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-dark {\n color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:hover {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:focus, .btn-outline-dark.focus {\n box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.btn-outline-dark.disabled, .btn-outline-dark:disabled {\n color: #343a40;\n background-color: transparent;\n}\n\n.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,\n.show > .btn-outline-dark.dropdown-toggle {\n color: #fff;\n background-color: #343a40;\n border-color: #343a40;\n}\n\n.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-dark.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.btn-link {\n font-weight: 400;\n color: #007bff;\n text-decoration: none;\n}\n\n.btn-link:hover {\n color: #0056b3;\n text-decoration: underline;\n}\n\n.btn-link:focus, .btn-link.focus {\n text-decoration: underline;\n box-shadow: none;\n}\n\n.btn-link:disabled, .btn-link.disabled {\n color: #6c757d;\n pointer-events: none;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n.btn-block + .btn-block {\n margin-top: 0.5rem;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n\n.fade {\n transition: opacity 0.15s linear;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fade {\n transition: none;\n }\n}\n\n.fade:not(.show) {\n opacity: 0;\n}\n\n.collapse:not(.show) {\n display: none;\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .collapsing {\n transition: none;\n }\n}\n\n.dropup,\n.dropright,\n.dropdown,\n.dropleft {\n position: relative;\n}\n\n.dropdown-toggle {\n white-space: nowrap;\n}\n\n.dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-bottom: 0;\n border-left: 0.3em solid transparent;\n}\n\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 10rem;\n padding: 0.5rem 0;\n margin: 0.125rem 0 0;\n font-size: 1rem;\n color: #212529;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n\n@media (min-width: 576px) {\n .dropdown-menu-sm-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-sm-right {\n right: 0;\n left: auto;\n }\n}\n\n@media (min-width: 768px) {\n .dropdown-menu-md-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-md-right {\n right: 0;\n left: auto;\n }\n}\n\n@media (min-width: 992px) {\n .dropdown-menu-lg-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-lg-right {\n right: 0;\n left: auto;\n }\n}\n\n@media (min-width: 1200px) {\n .dropdown-menu-xl-left {\n right: auto;\n left: 0;\n }\n .dropdown-menu-xl-right {\n right: 0;\n left: auto;\n }\n}\n\n.dropup .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 0.125rem;\n}\n\n.dropup .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0;\n border-right: 0.3em solid transparent;\n border-bottom: 0.3em solid;\n border-left: 0.3em solid transparent;\n}\n\n.dropup .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropright .dropdown-menu {\n top: 0;\n right: auto;\n left: 100%;\n margin-top: 0;\n margin-left: 0.125rem;\n}\n\n.dropright .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0;\n border-bottom: 0.3em solid transparent;\n border-left: 0.3em solid;\n}\n\n.dropright .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropright .dropdown-toggle::after {\n vertical-align: 0;\n}\n\n.dropleft .dropdown-menu {\n top: 0;\n right: 100%;\n left: auto;\n margin-top: 0;\n margin-right: 0.125rem;\n}\n\n.dropleft .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n}\n\n.dropleft .dropdown-toggle::after {\n display: none;\n}\n\n.dropleft .dropdown-toggle::before {\n display: inline-block;\n margin-right: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0.3em solid;\n border-bottom: 0.3em solid transparent;\n}\n\n.dropleft .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropleft .dropdown-toggle::before {\n vertical-align: 0;\n}\n\n.dropdown-menu[x-placement^=\"top\"], .dropdown-menu[x-placement^=\"right\"], .dropdown-menu[x-placement^=\"bottom\"], .dropdown-menu[x-placement^=\"left\"] {\n right: auto;\n bottom: auto;\n}\n\n.dropdown-divider {\n height: 0;\n margin: 0.5rem 0;\n overflow: hidden;\n border-top: 1px solid #e9ecef;\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: 0.25rem 1.5rem;\n clear: both;\n font-weight: 400;\n color: #212529;\n text-align: inherit;\n white-space: nowrap;\n background-color: transparent;\n border: 0;\n}\n\n.dropdown-item:hover, .dropdown-item:focus {\n color: #16181b;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.dropdown-item.active, .dropdown-item:active {\n color: #fff;\n text-decoration: none;\n background-color: #007bff;\n}\n\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: #6c757d;\n pointer-events: none;\n background-color: transparent;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: 0.5rem 1.5rem;\n margin-bottom: 0;\n font-size: 0.875rem;\n color: #6c757d;\n white-space: nowrap;\n}\n\n.dropdown-item-text {\n display: block;\n padding: 0.25rem 1.5rem;\n color: #212529;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n}\n\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n flex: 1 1 auto;\n}\n\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover {\n z-index: 1;\n}\n\n.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 1;\n}\n\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) {\n margin-left: -1px;\n}\n\n.btn-group > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n\n.dropdown-toggle-split::after,\n.dropup .dropdown-toggle-split::after,\n.dropright .dropdown-toggle-split::after {\n margin-left: 0;\n}\n\n.dropleft .dropdown-toggle-split::before {\n margin-right: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n}\n\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group {\n width: 100%;\n}\n\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) {\n margin-top: -1px;\n}\n\n.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group-vertical > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.btn-group-toggle > .btn,\n.btn-group-toggle > .btn-group > .btn {\n margin-bottom: 0;\n}\n\n.btn-group-toggle > .btn input[type=\"radio\"],\n.btn-group-toggle > .btn input[type=\"checkbox\"],\n.btn-group-toggle > .btn-group > .btn input[type=\"radio\"],\n.btn-group-toggle > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n\n.input-group {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n width: 100%;\n}\n\n.input-group > .form-control,\n.input-group > .form-control-plaintext,\n.input-group > .custom-select,\n.input-group > .custom-file {\n position: relative;\n flex: 1 1 auto;\n width: 1%;\n margin-bottom: 0;\n}\n\n.input-group > .form-control + .form-control,\n.input-group > .form-control + .custom-select,\n.input-group > .form-control + .custom-file,\n.input-group > .form-control-plaintext + .form-control,\n.input-group > .form-control-plaintext + .custom-select,\n.input-group > .form-control-plaintext + .custom-file,\n.input-group > .custom-select + .form-control,\n.input-group > .custom-select + .custom-select,\n.input-group > .custom-select + .custom-file,\n.input-group > .custom-file + .form-control,\n.input-group > .custom-file + .custom-select,\n.input-group > .custom-file + .custom-file {\n margin-left: -1px;\n}\n\n.input-group > .form-control:focus,\n.input-group > .custom-select:focus,\n.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label {\n z-index: 3;\n}\n\n.input-group > .custom-file .custom-file-input:focus {\n z-index: 4;\n}\n\n.input-group > .form-control:not(:last-child),\n.input-group > .custom-select:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group > .form-control:not(:first-child),\n.input-group > .custom-select:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.input-group > .custom-file {\n display: flex;\n align-items: center;\n}\n\n.input-group > .custom-file:not(:last-child) .custom-file-label,\n.input-group > .custom-file:not(:last-child) .custom-file-label::after {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group > .custom-file:not(:first-child) .custom-file-label {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.input-group-prepend,\n.input-group-append {\n display: flex;\n}\n\n.input-group-prepend .btn,\n.input-group-append .btn {\n position: relative;\n z-index: 2;\n}\n\n.input-group-prepend .btn:focus,\n.input-group-append .btn:focus {\n z-index: 3;\n}\n\n.input-group-prepend .btn + .btn,\n.input-group-prepend .btn + .input-group-text,\n.input-group-prepend .input-group-text + .input-group-text,\n.input-group-prepend .input-group-text + .btn,\n.input-group-append .btn + .btn,\n.input-group-append .btn + .input-group-text,\n.input-group-append .input-group-text + .input-group-text,\n.input-group-append .input-group-text + .btn {\n margin-left: -1px;\n}\n\n.input-group-prepend {\n margin-right: -1px;\n}\n\n.input-group-append {\n margin-left: -1px;\n}\n\n.input-group-text {\n display: flex;\n align-items: center;\n padding: 0.375rem 0.75rem;\n margin-bottom: 0;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n text-align: center;\n white-space: nowrap;\n background-color: #e9ecef;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n}\n\n.input-group-text input[type=\"radio\"],\n.input-group-text input[type=\"checkbox\"] {\n margin-top: 0;\n}\n\n.input-group-lg > .form-control:not(textarea),\n.input-group-lg > .custom-select {\n height: calc(1.5em + 1rem + 2px);\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .custom-select,\n.input-group-lg > .input-group-prepend > .input-group-text,\n.input-group-lg > .input-group-append > .input-group-text,\n.input-group-lg > .input-group-prepend > .btn,\n.input-group-lg > .input-group-append > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n line-height: 1.5;\n border-radius: 0.3rem;\n}\n\n.input-group-sm > .form-control:not(textarea),\n.input-group-sm > .custom-select {\n height: calc(1.5em + 0.5rem + 2px);\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .custom-select,\n.input-group-sm > .input-group-prepend > .input-group-text,\n.input-group-sm > .input-group-append > .input-group-text,\n.input-group-sm > .input-group-prepend > .btn,\n.input-group-sm > .input-group-append > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n border-radius: 0.2rem;\n}\n\n.input-group-lg > .custom-select,\n.input-group-sm > .custom-select {\n padding-right: 1.75rem;\n}\n\n.input-group > .input-group-prepend > .btn,\n.input-group > .input-group-prepend > .input-group-text,\n.input-group > .input-group-append:not(:last-child) > .btn,\n.input-group > .input-group-append:not(:last-child) > .input-group-text,\n.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\n.input-group > .input-group-append > .btn,\n.input-group > .input-group-append > .input-group-text,\n.input-group > .input-group-prepend:not(:first-child) > .btn,\n.input-group > .input-group-prepend:not(:first-child) > .input-group-text,\n.input-group > .input-group-prepend:first-child > .btn:not(:first-child),\n.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.custom-control {\n position: relative;\n display: block;\n min-height: 1.5rem;\n padding-left: 1.5rem;\n}\n\n.custom-control-inline {\n display: inline-flex;\n margin-right: 1rem;\n}\n\n.custom-control-input {\n position: absolute;\n z-index: -1;\n opacity: 0;\n}\n\n.custom-control-input:checked ~ .custom-control-label::before {\n color: #fff;\n border-color: #007bff;\n background-color: #007bff;\n}\n\n.custom-control-input:focus ~ .custom-control-label::before {\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-control-input:focus:not(:checked) ~ .custom-control-label::before {\n border-color: #80bdff;\n}\n\n.custom-control-input:not(:disabled):active ~ .custom-control-label::before {\n color: #fff;\n background-color: #b3d7ff;\n border-color: #b3d7ff;\n}\n\n.custom-control-input:disabled ~ .custom-control-label {\n color: #6c757d;\n}\n\n.custom-control-input:disabled ~ .custom-control-label::before {\n background-color: #e9ecef;\n}\n\n.custom-control-label {\n position: relative;\n margin-bottom: 0;\n vertical-align: top;\n}\n\n.custom-control-label::before {\n position: absolute;\n top: 0.25rem;\n left: -1.5rem;\n display: block;\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n content: \"\";\n background-color: #fff;\n border: #adb5bd solid 1px;\n}\n\n.custom-control-label::after {\n position: absolute;\n top: 0.25rem;\n left: -1.5rem;\n display: block;\n width: 1rem;\n height: 1rem;\n content: \"\";\n background: no-repeat 50% / 50% 50%;\n}\n\n.custom-checkbox .custom-control-label::before {\n border-radius: 0.25rem;\n}\n\n.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e\");\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before {\n border-color: #007bff;\n background-color: #007bff;\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e\");\n}\n\n.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-radio .custom-control-label::before {\n border-radius: 50%;\n}\n\n.custom-radio .custom-control-input:checked ~ .custom-control-label::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\");\n}\n\n.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-switch {\n padding-left: 2.25rem;\n}\n\n.custom-switch .custom-control-label::before {\n left: -2.25rem;\n width: 1.75rem;\n pointer-events: all;\n border-radius: 0.5rem;\n}\n\n.custom-switch .custom-control-label::after {\n top: calc(0.25rem + 2px);\n left: calc(-2.25rem + 2px);\n width: calc(1rem - 4px);\n height: calc(1rem - 4px);\n background-color: #adb5bd;\n border-radius: 0.5rem;\n transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-switch .custom-control-label::after {\n transition: none;\n }\n}\n\n.custom-switch .custom-control-input:checked ~ .custom-control-label::after {\n background-color: #fff;\n transform: translateX(0.75rem);\n}\n\n.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before {\n background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-select {\n display: inline-block;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n padding: 0.375rem 1.75rem 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n vertical-align: middle;\n background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px;\n background-color: #fff;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n appearance: none;\n}\n\n.custom-select:focus {\n border-color: #80bdff;\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-select:focus::-ms-value {\n color: #495057;\n background-color: #fff;\n}\n\n.custom-select[multiple], .custom-select[size]:not([size=\"1\"]) {\n height: auto;\n padding-right: 0.75rem;\n background-image: none;\n}\n\n.custom-select:disabled {\n color: #6c757d;\n background-color: #e9ecef;\n}\n\n.custom-select::-ms-expand {\n display: none;\n}\n\n.custom-select-sm {\n height: calc(1.5em + 0.5rem + 2px);\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n padding-left: 0.5rem;\n font-size: 0.875rem;\n}\n\n.custom-select-lg {\n height: calc(1.5em + 1rem + 2px);\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n padding-left: 1rem;\n font-size: 1.25rem;\n}\n\n.custom-file {\n position: relative;\n display: inline-block;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n margin-bottom: 0;\n}\n\n.custom-file-input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: calc(1.5em + 0.75rem + 2px);\n margin: 0;\n opacity: 0;\n}\n\n.custom-file-input:focus ~ .custom-file-label {\n border-color: #80bdff;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-file-input:disabled ~ .custom-file-label {\n background-color: #e9ecef;\n}\n\n.custom-file-input:lang(en) ~ .custom-file-label::after {\n content: \"Browse\";\n}\n\n.custom-file-input ~ .custom-file-label[data-browse]::after {\n content: attr(data-browse);\n}\n\n.custom-file-label {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n height: calc(1.5em + 0.75rem + 2px);\n padding: 0.375rem 0.75rem;\n font-weight: 400;\n line-height: 1.5;\n color: #495057;\n background-color: #fff;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n}\n\n.custom-file-label::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n z-index: 3;\n display: block;\n height: calc(1.5em + 0.75rem);\n padding: 0.375rem 0.75rem;\n line-height: 1.5;\n color: #495057;\n content: \"Browse\";\n background-color: #e9ecef;\n border-left: inherit;\n border-radius: 0 0.25rem 0.25rem 0;\n}\n\n.custom-range {\n width: 100%;\n height: calc(1rem + 0.4rem);\n padding: 0;\n background-color: transparent;\n appearance: none;\n}\n\n.custom-range:focus {\n outline: none;\n}\n\n.custom-range:focus::-webkit-slider-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range:focus::-moz-range-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range:focus::-ms-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range::-moz-focus-outer {\n border: 0;\n}\n\n.custom-range::-webkit-slider-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: -0.25rem;\n background-color: #007bff;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-range::-webkit-slider-thumb {\n transition: none;\n }\n}\n\n.custom-range::-webkit-slider-thumb:active {\n background-color: #b3d7ff;\n}\n\n.custom-range::-webkit-slider-runnable-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: #dee2e6;\n border-color: transparent;\n border-radius: 1rem;\n}\n\n.custom-range::-moz-range-thumb {\n width: 1rem;\n height: 1rem;\n background-color: #007bff;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-range::-moz-range-thumb {\n transition: none;\n }\n}\n\n.custom-range::-moz-range-thumb:active {\n background-color: #b3d7ff;\n}\n\n.custom-range::-moz-range-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: #dee2e6;\n border-color: transparent;\n border-radius: 1rem;\n}\n\n.custom-range::-ms-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: 0;\n margin-right: 0.2rem;\n margin-left: 0.2rem;\n background-color: #007bff;\n border: 0;\n border-radius: 1rem;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-range::-ms-thumb {\n transition: none;\n }\n}\n\n.custom-range::-ms-thumb:active {\n background-color: #b3d7ff;\n}\n\n.custom-range::-ms-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: transparent;\n border-color: transparent;\n border-width: 0.5rem;\n}\n\n.custom-range::-ms-fill-lower {\n background-color: #dee2e6;\n border-radius: 1rem;\n}\n\n.custom-range::-ms-fill-upper {\n margin-right: 15px;\n background-color: #dee2e6;\n border-radius: 1rem;\n}\n\n.custom-range:disabled::-webkit-slider-thumb {\n background-color: #adb5bd;\n}\n\n.custom-range:disabled::-webkit-slider-runnable-track {\n cursor: default;\n}\n\n.custom-range:disabled::-moz-range-thumb {\n background-color: #adb5bd;\n}\n\n.custom-range:disabled::-moz-range-track {\n cursor: default;\n}\n\n.custom-range:disabled::-ms-thumb {\n background-color: #adb5bd;\n}\n\n.custom-control-label::before,\n.custom-file-label,\n.custom-select {\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .custom-control-label::before,\n .custom-file-label,\n .custom-select {\n transition: none;\n }\n}\n\n.nav {\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: 0.5rem 1rem;\n}\n\n.nav-link:hover, .nav-link:focus {\n text-decoration: none;\n}\n\n.nav-link.disabled {\n color: #6c757d;\n pointer-events: none;\n cursor: default;\n}\n\n.nav-tabs {\n border-bottom: 1px solid #dee2e6;\n}\n\n.nav-tabs .nav-item {\n margin-bottom: -1px;\n}\n\n.nav-tabs .nav-link {\n border: 1px solid transparent;\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {\n border-color: #e9ecef #e9ecef #dee2e6;\n}\n\n.nav-tabs .nav-link.disabled {\n color: #6c757d;\n background-color: transparent;\n border-color: transparent;\n}\n\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: #495057;\n background-color: #fff;\n border-color: #dee2e6 #dee2e6 #fff;\n}\n\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills .nav-link {\n border-radius: 0.25rem;\n}\n\n.nav-pills .nav-link.active,\n.nav-pills .show > .nav-link {\n color: #fff;\n background-color: #007bff;\n}\n\n.nav-fill .nav-item {\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n}\n\n.navbar > .container,\n.navbar > .container-fluid {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n}\n\n.navbar-brand {\n display: inline-block;\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: 1rem;\n font-size: 1.25rem;\n line-height: inherit;\n white-space: nowrap;\n}\n\n.navbar-brand:hover, .navbar-brand:focus {\n text-decoration: none;\n}\n\n.navbar-nav {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.navbar-nav .nav-link {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-nav .dropdown-menu {\n position: static;\n float: none;\n}\n\n.navbar-text {\n display: inline-block;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n\n.navbar-collapse {\n flex-basis: 100%;\n flex-grow: 1;\n align-items: center;\n}\n\n.navbar-toggler {\n padding: 0.25rem 0.75rem;\n font-size: 1.25rem;\n line-height: 1;\n background-color: transparent;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.navbar-toggler:hover, .navbar-toggler:focus {\n text-decoration: none;\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n content: \"\";\n background: no-repeat center center;\n background-size: 100% 100%;\n}\n\n@media (max-width: 575.98px) {\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-sm > .container,\n .navbar-expand-sm > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-sm .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 767.98px) {\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 768px) {\n .navbar-expand-md {\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-md > .container,\n .navbar-expand-md > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-md .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 991.98px) {\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 992px) {\n .navbar-expand-lg {\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-lg > .container,\n .navbar-expand-lg > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-lg .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n}\n\n@media (max-width: 1199.98px) {\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n flex-flow: row nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-xl > .container,\n .navbar-expand-xl > .container-fluid {\n flex-wrap: nowrap;\n }\n .navbar-expand-xl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n}\n\n.navbar-expand {\n flex-flow: row nowrap;\n justify-content: flex-start;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n padding-right: 0;\n padding-left: 0;\n}\n\n.navbar-expand .navbar-nav {\n flex-direction: row;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n\n.navbar-expand .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n flex-wrap: nowrap;\n}\n\n.navbar-expand .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n}\n\n.navbar-expand .navbar-toggler {\n display: none;\n}\n\n.navbar-light .navbar-brand {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-nav .nav-link {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {\n color: rgba(0, 0, 0, 0.7);\n}\n\n.navbar-light .navbar-nav .nav-link.disabled {\n color: rgba(0, 0, 0, 0.3);\n}\n\n.navbar-light .navbar-nav .show > .nav-link,\n.navbar-light .navbar-nav .active > .nav-link,\n.navbar-light .navbar-nav .nav-link.show,\n.navbar-light .navbar-nav .nav-link.active {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-toggler {\n color: rgba(0, 0, 0, 0.5);\n border-color: rgba(0, 0, 0, 0.1);\n}\n\n.navbar-light .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.navbar-light .navbar-text {\n color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-text a {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-dark .navbar-brand {\n color: #fff;\n}\n\n.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {\n color: #fff;\n}\n\n.navbar-dark .navbar-nav .nav-link {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {\n color: rgba(255, 255, 255, 0.75);\n}\n\n.navbar-dark .navbar-nav .nav-link.disabled {\n color: rgba(255, 255, 255, 0.25);\n}\n\n.navbar-dark .navbar-nav .show > .nav-link,\n.navbar-dark .navbar-nav .active > .nav-link,\n.navbar-dark .navbar-nav .nav-link.show,\n.navbar-dark .navbar-nav .nav-link.active {\n color: #fff;\n}\n\n.navbar-dark .navbar-toggler {\n color: rgba(255, 255, 255, 0.5);\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n.navbar-dark .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.navbar-dark .navbar-text {\n color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-text a {\n color: #fff;\n}\n\n.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {\n color: #fff;\n}\n\n.card {\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: border-box;\n border: 1px solid rgba(0, 0, 0, 0.125);\n border-radius: 0.25rem;\n}\n\n.card > hr {\n margin-right: 0;\n margin-left: 0;\n}\n\n.card > .list-group:first-child .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.card > .list-group:last-child .list-group-item:last-child {\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.card-body {\n flex: 1 1 auto;\n padding: 1.25rem;\n}\n\n.card-title {\n margin-bottom: 0.75rem;\n}\n\n.card-subtitle {\n margin-top: -0.375rem;\n margin-bottom: 0;\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link:hover {\n text-decoration: none;\n}\n\n.card-link + .card-link {\n margin-left: 1.25rem;\n}\n\n.card-header {\n padding: 0.75rem 1.25rem;\n margin-bottom: 0;\n background-color: rgba(0, 0, 0, 0.03);\n border-bottom: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-header:first-child {\n border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;\n}\n\n.card-header + .list-group .list-group-item:first-child {\n border-top: 0;\n}\n\n.card-footer {\n padding: 0.75rem 1.25rem;\n background-color: rgba(0, 0, 0, 0.03);\n border-top: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-footer:last-child {\n border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);\n}\n\n.card-header-tabs {\n margin-right: -0.625rem;\n margin-bottom: -0.75rem;\n margin-left: -0.625rem;\n border-bottom: 0;\n}\n\n.card-header-pills {\n margin-right: -0.625rem;\n margin-left: -0.625rem;\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: 1.25rem;\n}\n\n.card-img {\n width: 100%;\n border-radius: calc(0.25rem - 1px);\n}\n\n.card-img-top {\n width: 100%;\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n\n.card-img-bottom {\n width: 100%;\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n\n.card-deck {\n display: flex;\n flex-direction: column;\n}\n\n.card-deck .card {\n margin-bottom: 15px;\n}\n\n@media (min-width: 576px) {\n .card-deck {\n flex-flow: row wrap;\n margin-right: -15px;\n margin-left: -15px;\n }\n .card-deck .card {\n display: flex;\n flex: 1 0 0%;\n flex-direction: column;\n margin-right: 15px;\n margin-bottom: 0;\n margin-left: 15px;\n }\n}\n\n.card-group {\n display: flex;\n flex-direction: column;\n}\n\n.card-group > .card {\n margin-bottom: 15px;\n}\n\n@media (min-width: 576px) {\n .card-group {\n flex-flow: row wrap;\n }\n .card-group > .card {\n flex: 1 0 0%;\n margin-bottom: 0;\n }\n .card-group > .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group > .card:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-top,\n .card-group > .card:not(:last-child) .card-header {\n border-top-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-bottom,\n .card-group > .card:not(:last-child) .card-footer {\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-top,\n .card-group > .card:not(:first-child) .card-header {\n border-top-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-bottom,\n .card-group > .card:not(:first-child) .card-footer {\n border-bottom-left-radius: 0;\n }\n}\n\n.card-columns .card {\n margin-bottom: 0.75rem;\n}\n\n@media (min-width: 576px) {\n .card-columns {\n column-count: 3;\n column-gap: 1.25rem;\n orphans: 1;\n widows: 1;\n }\n .card-columns .card {\n display: inline-block;\n width: 100%;\n }\n}\n\n.accordion > .card {\n overflow: hidden;\n}\n\n.accordion > .card:not(:first-of-type) .card-header:first-child {\n border-radius: 0;\n}\n\n.accordion > .card:not(:first-of-type):not(:last-of-type) {\n border-bottom: 0;\n border-radius: 0;\n}\n\n.accordion > .card:first-of-type {\n border-bottom: 0;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.accordion > .card:last-of-type {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.accordion > .card .card-header {\n margin-bottom: -1px;\n}\n\n.breadcrumb {\n display: flex;\n flex-wrap: wrap;\n padding: 0.75rem 1rem;\n margin-bottom: 1rem;\n list-style: none;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.breadcrumb-item + .breadcrumb-item {\n padding-left: 0.5rem;\n}\n\n.breadcrumb-item + .breadcrumb-item::before {\n display: inline-block;\n padding-right: 0.5rem;\n color: #6c757d;\n content: \"/\";\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: underline;\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n text-decoration: none;\n}\n\n.breadcrumb-item.active {\n color: #6c757d;\n}\n\n.pagination {\n display: flex;\n padding-left: 0;\n list-style: none;\n border-radius: 0.25rem;\n}\n\n.page-link {\n position: relative;\n display: block;\n padding: 0.5rem 0.75rem;\n margin-left: -1px;\n line-height: 1.25;\n color: #007bff;\n background-color: #fff;\n border: 1px solid #dee2e6;\n}\n\n.page-link:hover {\n z-index: 2;\n color: #0056b3;\n text-decoration: none;\n background-color: #e9ecef;\n border-color: #dee2e6;\n}\n\n.page-link:focus {\n z-index: 2;\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.page-item:first-child .page-link {\n margin-left: 0;\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.page-item:last-child .page-link {\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n}\n\n.page-item.active .page-link {\n z-index: 1;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.page-item.disabled .page-link {\n color: #6c757d;\n pointer-events: none;\n cursor: auto;\n background-color: #fff;\n border-color: #dee2e6;\n}\n\n.pagination-lg .page-link {\n padding: 0.75rem 1.5rem;\n font-size: 1.25rem;\n line-height: 1.5;\n}\n\n.pagination-lg .page-item:first-child .page-link {\n border-top-left-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n\n.pagination-lg .page-item:last-child .page-link {\n border-top-right-radius: 0.3rem;\n border-bottom-right-radius: 0.3rem;\n}\n\n.pagination-sm .page-link {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n.pagination-sm .page-item:first-child .page-link {\n border-top-left-radius: 0.2rem;\n border-bottom-left-radius: 0.2rem;\n}\n\n.pagination-sm .page-item:last-child .page-link {\n border-top-right-radius: 0.2rem;\n border-bottom-right-radius: 0.2rem;\n}\n\n.badge {\n display: inline-block;\n padding: 0.25em 0.4em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25rem;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .badge {\n transition: none;\n }\n}\n\na.badge:hover, a.badge:focus {\n text-decoration: none;\n}\n\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.badge-pill {\n padding-right: 0.6em;\n padding-left: 0.6em;\n border-radius: 10rem;\n}\n\n.badge-primary {\n color: #fff;\n background-color: #007bff;\n}\n\na.badge-primary:hover, a.badge-primary:focus {\n color: #fff;\n background-color: #0062cc;\n}\n\na.badge-primary:focus, a.badge-primary.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.badge-secondary {\n color: #fff;\n background-color: #6c757d;\n}\n\na.badge-secondary:hover, a.badge-secondary:focus {\n color: #fff;\n background-color: #545b62;\n}\n\na.badge-secondary:focus, a.badge-secondary.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.badge-success {\n color: #fff;\n background-color: #28a745;\n}\n\na.badge-success:hover, a.badge-success:focus {\n color: #fff;\n background-color: #1e7e34;\n}\n\na.badge-success:focus, a.badge-success.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.badge-info {\n color: #fff;\n background-color: #17a2b8;\n}\n\na.badge-info:hover, a.badge-info:focus {\n color: #fff;\n background-color: #117a8b;\n}\n\na.badge-info:focus, a.badge-info.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.badge-warning {\n color: #212529;\n background-color: #ffc107;\n}\n\na.badge-warning:hover, a.badge-warning:focus {\n color: #212529;\n background-color: #d39e00;\n}\n\na.badge-warning:focus, a.badge-warning.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.badge-danger {\n color: #fff;\n background-color: #dc3545;\n}\n\na.badge-danger:hover, a.badge-danger:focus {\n color: #fff;\n background-color: #bd2130;\n}\n\na.badge-danger:focus, a.badge-danger.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.badge-light {\n color: #212529;\n background-color: #f8f9fa;\n}\n\na.badge-light:hover, a.badge-light:focus {\n color: #212529;\n background-color: #dae0e5;\n}\n\na.badge-light:focus, a.badge-light.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.badge-dark {\n color: #fff;\n background-color: #343a40;\n}\n\na.badge-dark:hover, a.badge-dark:focus {\n color: #fff;\n background-color: #1d2124;\n}\n\na.badge-dark:focus, a.badge-dark.focus {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.jumbotron {\n padding: 2rem 1rem;\n margin-bottom: 2rem;\n background-color: #e9ecef;\n border-radius: 0.3rem;\n}\n\n@media (min-width: 576px) {\n .jumbotron {\n padding: 4rem 2rem;\n }\n}\n\n.jumbotron-fluid {\n padding-right: 0;\n padding-left: 0;\n border-radius: 0;\n}\n\n.alert {\n position: relative;\n padding: 0.75rem 1.25rem;\n margin-bottom: 1rem;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: 700;\n}\n\n.alert-dismissible {\n padding-right: 4rem;\n}\n\n.alert-dismissible .close {\n position: absolute;\n top: 0;\n right: 0;\n padding: 0.75rem 1.25rem;\n color: inherit;\n}\n\n.alert-primary {\n color: #004085;\n background-color: #cce5ff;\n border-color: #b8daff;\n}\n\n.alert-primary hr {\n border-top-color: #9fcdff;\n}\n\n.alert-primary .alert-link {\n color: #002752;\n}\n\n.alert-secondary {\n color: #383d41;\n background-color: #e2e3e5;\n border-color: #d6d8db;\n}\n\n.alert-secondary hr {\n border-top-color: #c8cbcf;\n}\n\n.alert-secondary .alert-link {\n color: #202326;\n}\n\n.alert-success {\n color: #155724;\n background-color: #d4edda;\n border-color: #c3e6cb;\n}\n\n.alert-success hr {\n border-top-color: #b1dfbb;\n}\n\n.alert-success .alert-link {\n color: #0b2e13;\n}\n\n.alert-info {\n color: #0c5460;\n background-color: #d1ecf1;\n border-color: #bee5eb;\n}\n\n.alert-info hr {\n border-top-color: #abdde5;\n}\n\n.alert-info .alert-link {\n color: #062c33;\n}\n\n.alert-warning {\n color: #856404;\n background-color: #fff3cd;\n border-color: #ffeeba;\n}\n\n.alert-warning hr {\n border-top-color: #ffe8a1;\n}\n\n.alert-warning .alert-link {\n color: #533f03;\n}\n\n.alert-danger {\n color: #721c24;\n background-color: #f8d7da;\n border-color: #f5c6cb;\n}\n\n.alert-danger hr {\n border-top-color: #f1b0b7;\n}\n\n.alert-danger .alert-link {\n color: #491217;\n}\n\n.alert-light {\n color: #818182;\n background-color: #fefefe;\n border-color: #fdfdfe;\n}\n\n.alert-light hr {\n border-top-color: #ececf6;\n}\n\n.alert-light .alert-link {\n color: #686868;\n}\n\n.alert-dark {\n color: #1b1e21;\n background-color: #d6d8d9;\n border-color: #c6c8ca;\n}\n\n.alert-dark hr {\n border-top-color: #b9bbbe;\n}\n\n.alert-dark .alert-link {\n color: #040505;\n}\n\n@keyframes progress-bar-stripes {\n from {\n background-position: 1rem 0;\n }\n to {\n background-position: 0 0;\n }\n}\n\n.progress {\n display: flex;\n height: 1rem;\n overflow: hidden;\n font-size: 0.75rem;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.progress-bar {\n display: flex;\n flex-direction: column;\n justify-content: center;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n background-color: #007bff;\n transition: width 0.6s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 1rem 1rem;\n}\n\n.progress-bar-animated {\n animation: progress-bar-stripes 1s linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .progress-bar-animated {\n animation: none;\n }\n}\n\n.media {\n display: flex;\n align-items: flex-start;\n}\n\n.media-body {\n flex: 1;\n}\n\n.list-group {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n}\n\n.list-group-item-action {\n width: 100%;\n color: #495057;\n text-align: inherit;\n}\n\n.list-group-item-action:hover, .list-group-item-action:focus {\n z-index: 1;\n color: #495057;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n\n.list-group-item-action:active {\n color: #212529;\n background-color: #e9ecef;\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 0.75rem 1.25rem;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.list-group-item.disabled, .list-group-item:disabled {\n color: #6c757d;\n pointer-events: none;\n background-color: #fff;\n}\n\n.list-group-item.active {\n z-index: 2;\n color: #fff;\n background-color: #007bff;\n border-color: #007bff;\n}\n\n.list-group-horizontal {\n flex-direction: row;\n}\n\n.list-group-horizontal .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n}\n\n.list-group-horizontal .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n}\n\n.list-group-horizontal .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n}\n\n@media (min-width: 576px) {\n .list-group-horizontal-sm {\n flex-direction: row;\n }\n .list-group-horizontal-sm .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-sm .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-sm .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n@media (min-width: 768px) {\n .list-group-horizontal-md {\n flex-direction: row;\n }\n .list-group-horizontal-md .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-md .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-md .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n@media (min-width: 992px) {\n .list-group-horizontal-lg {\n flex-direction: row;\n }\n .list-group-horizontal-lg .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-lg .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-lg .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n@media (min-width: 1200px) {\n .list-group-horizontal-xl {\n flex-direction: row;\n }\n .list-group-horizontal-xl .list-group-item {\n margin-right: -1px;\n margin-bottom: 0;\n }\n .list-group-horizontal-xl .list-group-item:first-child {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xl .list-group-item:last-child {\n margin-right: 0;\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n}\n\n.list-group-flush .list-group-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n\n.list-group-flush .list-group-item:last-child {\n margin-bottom: -1px;\n}\n\n.list-group-flush:first-child .list-group-item:first-child {\n border-top: 0;\n}\n\n.list-group-flush:last-child .list-group-item:last-child {\n margin-bottom: 0;\n border-bottom: 0;\n}\n\n.list-group-item-primary {\n color: #004085;\n background-color: #b8daff;\n}\n\n.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {\n color: #004085;\n background-color: #9fcdff;\n}\n\n.list-group-item-primary.list-group-item-action.active {\n color: #fff;\n background-color: #004085;\n border-color: #004085;\n}\n\n.list-group-item-secondary {\n color: #383d41;\n background-color: #d6d8db;\n}\n\n.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {\n color: #383d41;\n background-color: #c8cbcf;\n}\n\n.list-group-item-secondary.list-group-item-action.active {\n color: #fff;\n background-color: #383d41;\n border-color: #383d41;\n}\n\n.list-group-item-success {\n color: #155724;\n background-color: #c3e6cb;\n}\n\n.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {\n color: #155724;\n background-color: #b1dfbb;\n}\n\n.list-group-item-success.list-group-item-action.active {\n color: #fff;\n background-color: #155724;\n border-color: #155724;\n}\n\n.list-group-item-info {\n color: #0c5460;\n background-color: #bee5eb;\n}\n\n.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {\n color: #0c5460;\n background-color: #abdde5;\n}\n\n.list-group-item-info.list-group-item-action.active {\n color: #fff;\n background-color: #0c5460;\n border-color: #0c5460;\n}\n\n.list-group-item-warning {\n color: #856404;\n background-color: #ffeeba;\n}\n\n.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {\n color: #856404;\n background-color: #ffe8a1;\n}\n\n.list-group-item-warning.list-group-item-action.active {\n color: #fff;\n background-color: #856404;\n border-color: #856404;\n}\n\n.list-group-item-danger {\n color: #721c24;\n background-color: #f5c6cb;\n}\n\n.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {\n color: #721c24;\n background-color: #f1b0b7;\n}\n\n.list-group-item-danger.list-group-item-action.active {\n color: #fff;\n background-color: #721c24;\n border-color: #721c24;\n}\n\n.list-group-item-light {\n color: #818182;\n background-color: #fdfdfe;\n}\n\n.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {\n color: #818182;\n background-color: #ececf6;\n}\n\n.list-group-item-light.list-group-item-action.active {\n color: #fff;\n background-color: #818182;\n border-color: #818182;\n}\n\n.list-group-item-dark {\n color: #1b1e21;\n background-color: #c6c8ca;\n}\n\n.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {\n color: #1b1e21;\n background-color: #b9bbbe;\n}\n\n.list-group-item-dark.list-group-item-action.active {\n color: #fff;\n background-color: #1b1e21;\n border-color: #1b1e21;\n}\n\n.close {\n float: right;\n font-size: 1.5rem;\n font-weight: 700;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n opacity: .5;\n}\n\n.close:hover {\n color: #000;\n text-decoration: none;\n}\n\n.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus {\n opacity: .75;\n}\n\nbutton.close {\n padding: 0;\n background-color: transparent;\n border: 0;\n appearance: none;\n}\n\na.close.disabled {\n pointer-events: none;\n}\n\n.toast {\n max-width: 350px;\n overflow: hidden;\n font-size: 0.875rem;\n background-color: rgba(255, 255, 255, 0.85);\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.1);\n box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);\n backdrop-filter: blur(10px);\n opacity: 0;\n border-radius: 0.25rem;\n}\n\n.toast:not(:last-child) {\n margin-bottom: 0.75rem;\n}\n\n.toast.showing {\n opacity: 1;\n}\n\n.toast.show {\n display: block;\n opacity: 1;\n}\n\n.toast.hide {\n display: none;\n}\n\n.toast-header {\n display: flex;\n align-items: center;\n padding: 0.25rem 0.75rem;\n color: #6c757d;\n background-color: rgba(255, 255, 255, 0.85);\n background-clip: padding-box;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n}\n\n.toast-body {\n padding: 0.75rem;\n}\n\n.modal-open {\n overflow: hidden;\n}\n\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.modal {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1050;\n display: none;\n width: 100%;\n height: 100%;\n overflow: hidden;\n outline: 0;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 0.5rem;\n pointer-events: none;\n}\n\n.modal.fade .modal-dialog {\n transition: transform 0.3s ease-out;\n transform: translate(0, -50px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .modal.fade .modal-dialog {\n transition: none;\n }\n}\n\n.modal.show .modal-dialog {\n transform: none;\n}\n\n.modal-dialog-scrollable {\n display: flex;\n max-height: calc(100% - 1rem);\n}\n\n.modal-dialog-scrollable .modal-content {\n max-height: calc(100vh - 1rem);\n overflow: hidden;\n}\n\n.modal-dialog-scrollable .modal-header,\n.modal-dialog-scrollable .modal-footer {\n flex-shrink: 0;\n}\n\n.modal-dialog-scrollable .modal-body {\n overflow-y: auto;\n}\n\n.modal-dialog-centered {\n display: flex;\n align-items: center;\n min-height: calc(100% - 1rem);\n}\n\n.modal-dialog-centered::before {\n display: block;\n height: calc(100vh - 1rem);\n content: \"\";\n}\n\n.modal-dialog-centered.modal-dialog-scrollable {\n flex-direction: column;\n justify-content: center;\n height: 100%;\n}\n\n.modal-dialog-centered.modal-dialog-scrollable .modal-content {\n max-height: none;\n}\n\n.modal-dialog-centered.modal-dialog-scrollable::before {\n content: none;\n}\n\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n pointer-events: auto;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n outline: 0;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1040;\n width: 100vw;\n height: 100vh;\n background-color: #000;\n}\n\n.modal-backdrop.fade {\n opacity: 0;\n}\n\n.modal-backdrop.show {\n opacity: 0.5;\n}\n\n.modal-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 1rem 1rem;\n border-bottom: 1px solid #dee2e6;\n border-top-left-radius: 0.3rem;\n border-top-right-radius: 0.3rem;\n}\n\n.modal-header .close {\n padding: 1rem 1rem;\n margin: -1rem -1rem -1rem auto;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: 1.5;\n}\n\n.modal-body {\n position: relative;\n flex: 1 1 auto;\n padding: 1rem;\n}\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 1rem;\n border-top: 1px solid #dee2e6;\n border-bottom-right-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n\n.modal-footer > :not(:first-child) {\n margin-left: .25rem;\n}\n\n.modal-footer > :not(:last-child) {\n margin-right: .25rem;\n}\n\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n@media (min-width: 576px) {\n .modal-dialog {\n max-width: 500px;\n margin: 1.75rem auto;\n }\n .modal-dialog-scrollable {\n max-height: calc(100% - 3.5rem);\n }\n .modal-dialog-scrollable .modal-content {\n max-height: calc(100vh - 3.5rem);\n }\n .modal-dialog-centered {\n min-height: calc(100% - 3.5rem);\n }\n .modal-dialog-centered::before {\n height: calc(100vh - 3.5rem);\n }\n .modal-sm {\n max-width: 300px;\n }\n}\n\n@media (min-width: 992px) {\n .modal-lg,\n .modal-xl {\n max-width: 800px;\n }\n}\n\n@media (min-width: 1200px) {\n .modal-xl {\n max-width: 1140px;\n }\n}\n\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n opacity: 0;\n}\n\n.tooltip.show {\n opacity: 0.9;\n}\n\n.tooltip .arrow {\n position: absolute;\n display: block;\n width: 0.8rem;\n height: 0.4rem;\n}\n\n.tooltip .arrow::before {\n position: absolute;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-tooltip-top, .bs-tooltip-auto[x-placement^=\"top\"] {\n padding: 0.4rem 0;\n}\n\n.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^=\"top\"] .arrow {\n bottom: 0;\n}\n\n.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^=\"top\"] .arrow::before {\n top: 0;\n border-width: 0.4rem 0.4rem 0;\n border-top-color: #000;\n}\n\n.bs-tooltip-right, .bs-tooltip-auto[x-placement^=\"right\"] {\n padding: 0 0.4rem;\n}\n\n.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^=\"right\"] .arrow {\n left: 0;\n width: 0.4rem;\n height: 0.8rem;\n}\n\n.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^=\"right\"] .arrow::before {\n right: 0;\n border-width: 0.4rem 0.4rem 0.4rem 0;\n border-right-color: #000;\n}\n\n.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^=\"bottom\"] {\n padding: 0.4rem 0;\n}\n\n.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^=\"bottom\"] .arrow {\n top: 0;\n}\n\n.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^=\"bottom\"] .arrow::before {\n bottom: 0;\n border-width: 0 0.4rem 0.4rem;\n border-bottom-color: #000;\n}\n\n.bs-tooltip-left, .bs-tooltip-auto[x-placement^=\"left\"] {\n padding: 0 0.4rem;\n}\n\n.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^=\"left\"] .arrow {\n right: 0;\n width: 0.4rem;\n height: 0.8rem;\n}\n\n.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^=\"left\"] .arrow::before {\n left: 0;\n border-width: 0.4rem 0 0.4rem 0.4rem;\n border-left-color: #000;\n}\n\n.tooltip-inner {\n max-width: 200px;\n padding: 0.25rem 0.5rem;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 0.25rem;\n}\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: block;\n max-width: 276px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n}\n\n.popover .arrow {\n position: absolute;\n display: block;\n width: 1rem;\n height: 0.5rem;\n margin: 0 0.3rem;\n}\n\n.popover .arrow::before, .popover .arrow::after {\n position: absolute;\n display: block;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-popover-top, .bs-popover-auto[x-placement^=\"top\"] {\n margin-bottom: 0.5rem;\n}\n\n.bs-popover-top > .arrow, .bs-popover-auto[x-placement^=\"top\"] > .arrow {\n bottom: calc((0.5rem + 1px) * -1);\n}\n\n.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^=\"top\"] > .arrow::before {\n bottom: 0;\n border-width: 0.5rem 0.5rem 0;\n border-top-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^=\"top\"] > .arrow::after {\n bottom: 1px;\n border-width: 0.5rem 0.5rem 0;\n border-top-color: #fff;\n}\n\n.bs-popover-right, .bs-popover-auto[x-placement^=\"right\"] {\n margin-left: 0.5rem;\n}\n\n.bs-popover-right > .arrow, .bs-popover-auto[x-placement^=\"right\"] > .arrow {\n left: calc((0.5rem + 1px) * -1);\n width: 0.5rem;\n height: 1rem;\n margin: 0.3rem 0;\n}\n\n.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^=\"right\"] > .arrow::before {\n left: 0;\n border-width: 0.5rem 0.5rem 0.5rem 0;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^=\"right\"] > .arrow::after {\n left: 1px;\n border-width: 0.5rem 0.5rem 0.5rem 0;\n border-right-color: #fff;\n}\n\n.bs-popover-bottom, .bs-popover-auto[x-placement^=\"bottom\"] {\n margin-top: 0.5rem;\n}\n\n.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow {\n top: calc((0.5rem + 1px) * -1);\n}\n\n.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow::before {\n top: 0;\n border-width: 0 0.5rem 0.5rem 0.5rem;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow::after {\n top: 1px;\n border-width: 0 0.5rem 0.5rem 0.5rem;\n border-bottom-color: #fff;\n}\n\n.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^=\"bottom\"] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: 1rem;\n margin-left: -0.5rem;\n content: \"\";\n border-bottom: 1px solid #f7f7f7;\n}\n\n.bs-popover-left, .bs-popover-auto[x-placement^=\"left\"] {\n margin-right: 0.5rem;\n}\n\n.bs-popover-left > .arrow, .bs-popover-auto[x-placement^=\"left\"] > .arrow {\n right: calc((0.5rem + 1px) * -1);\n width: 0.5rem;\n height: 1rem;\n margin: 0.3rem 0;\n}\n\n.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^=\"left\"] > .arrow::before {\n right: 0;\n border-width: 0.5rem 0 0.5rem 0.5rem;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^=\"left\"] > .arrow::after {\n right: 1px;\n border-width: 0.5rem 0 0.5rem 0.5rem;\n border-left-color: #fff;\n}\n\n.popover-header {\n padding: 0.5rem 0.75rem;\n margin-bottom: 0;\n font-size: 1rem;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-top-left-radius: calc(0.3rem - 1px);\n border-top-right-radius: calc(0.3rem - 1px);\n}\n\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: 0.5rem 0.75rem;\n color: #212529;\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel.pointer-event {\n touch-action: pan-y;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n\n.carousel-inner::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.carousel-item {\n position: relative;\n display: none;\n float: left;\n width: 100%;\n margin-right: -100%;\n backface-visibility: hidden;\n transition: transform 0.6s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-item {\n transition: none;\n }\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n.carousel-item-next:not(.carousel-item-left),\n.active.carousel-item-right {\n transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-right),\n.active.carousel-item-left {\n transform: translateX(-100%);\n}\n\n.carousel-fade .carousel-item {\n opacity: 0;\n transition-property: opacity;\n transform: none;\n}\n\n.carousel-fade .carousel-item.active,\n.carousel-fade .carousel-item-next.carousel-item-left,\n.carousel-fade .carousel-item-prev.carousel-item-right {\n z-index: 1;\n opacity: 1;\n}\n\n.carousel-fade .active.carousel-item-left,\n.carousel-fade .active.carousel-item-right {\n z-index: 0;\n opacity: 0;\n transition: 0s 0.6s opacity;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-fade .active.carousel-item-left,\n .carousel-fade .active.carousel-item-right {\n transition: none;\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 15%;\n color: #fff;\n text-align: center;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-control-prev,\n .carousel-control-next {\n transition: none;\n }\n}\n\n.carousel-control-prev:hover, .carousel-control-prev:focus,\n.carousel-control-next:hover,\n.carousel-control-next:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: 0.9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n background: no-repeat 50% / 100% 100%;\n}\n\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e\");\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e\");\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 15;\n display: flex;\n justify-content: center;\n padding-left: 0;\n margin-right: 15%;\n margin-left: 15%;\n list-style: none;\n}\n\n.carousel-indicators li {\n box-sizing: content-box;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #fff;\n background-clip: padding-box;\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n opacity: .5;\n transition: opacity 0.6s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .carousel-indicators li {\n transition: none;\n }\n}\n\n.carousel-indicators .active {\n opacity: 1;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n}\n\n@keyframes spinner-border {\n to {\n transform: rotate(360deg);\n }\n}\n\n.spinner-border {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n vertical-align: text-bottom;\n border: 0.25em solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: spinner-border .75s linear infinite;\n}\n\n.spinner-border-sm {\n width: 1rem;\n height: 1rem;\n border-width: 0.2em;\n}\n\n@keyframes spinner-grow {\n 0% {\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n }\n}\n\n.spinner-grow {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n vertical-align: text-bottom;\n background-color: currentColor;\n border-radius: 50%;\n opacity: 0;\n animation: spinner-grow .75s linear infinite;\n}\n\n.spinner-grow-sm {\n width: 1rem;\n height: 1rem;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.bg-primary {\n background-color: #007bff !important;\n}\n\na.bg-primary:hover, a.bg-primary:focus,\nbutton.bg-primary:hover,\nbutton.bg-primary:focus {\n background-color: #0062cc !important;\n}\n\n.bg-secondary {\n background-color: #6c757d !important;\n}\n\na.bg-secondary:hover, a.bg-secondary:focus,\nbutton.bg-secondary:hover,\nbutton.bg-secondary:focus {\n background-color: #545b62 !important;\n}\n\n.bg-success {\n background-color: #28a745 !important;\n}\n\na.bg-success:hover, a.bg-success:focus,\nbutton.bg-success:hover,\nbutton.bg-success:focus {\n background-color: #1e7e34 !important;\n}\n\n.bg-info {\n background-color: #17a2b8 !important;\n}\n\na.bg-info:hover, a.bg-info:focus,\nbutton.bg-info:hover,\nbutton.bg-info:focus {\n background-color: #117a8b !important;\n}\n\n.bg-warning {\n background-color: #ffc107 !important;\n}\n\na.bg-warning:hover, a.bg-warning:focus,\nbutton.bg-warning:hover,\nbutton.bg-warning:focus {\n background-color: #d39e00 !important;\n}\n\n.bg-danger {\n background-color: #dc3545 !important;\n}\n\na.bg-danger:hover, a.bg-danger:focus,\nbutton.bg-danger:hover,\nbutton.bg-danger:focus {\n background-color: #bd2130 !important;\n}\n\n.bg-light {\n background-color: #f8f9fa !important;\n}\n\na.bg-light:hover, a.bg-light:focus,\nbutton.bg-light:hover,\nbutton.bg-light:focus {\n background-color: #dae0e5 !important;\n}\n\n.bg-dark {\n background-color: #343a40 !important;\n}\n\na.bg-dark:hover, a.bg-dark:focus,\nbutton.bg-dark:hover,\nbutton.bg-dark:focus {\n background-color: #1d2124 !important;\n}\n\n.bg-white {\n background-color: #fff !important;\n}\n\n.bg-transparent {\n background-color: transparent !important;\n}\n\n.border {\n border: 1px solid #dee2e6 !important;\n}\n\n.border-top {\n border-top: 1px solid #dee2e6 !important;\n}\n\n.border-right {\n border-right: 1px solid #dee2e6 !important;\n}\n\n.border-bottom {\n border-bottom: 1px solid #dee2e6 !important;\n}\n\n.border-left {\n border-left: 1px solid #dee2e6 !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-right-0 {\n border-right: 0 !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-left-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n border-color: #007bff !important;\n}\n\n.border-secondary {\n border-color: #6c757d !important;\n}\n\n.border-success {\n border-color: #28a745 !important;\n}\n\n.border-info {\n border-color: #17a2b8 !important;\n}\n\n.border-warning {\n border-color: #ffc107 !important;\n}\n\n.border-danger {\n border-color: #dc3545 !important;\n}\n\n.border-light {\n border-color: #f8f9fa !important;\n}\n\n.border-dark {\n border-color: #343a40 !important;\n}\n\n.border-white {\n border-color: #fff !important;\n}\n\n.rounded-sm {\n border-radius: 0.2rem !important;\n}\n\n.rounded {\n border-radius: 0.25rem !important;\n}\n\n.rounded-top {\n border-top-left-radius: 0.25rem !important;\n border-top-right-radius: 0.25rem !important;\n}\n\n.rounded-right {\n border-top-right-radius: 0.25rem !important;\n border-bottom-right-radius: 0.25rem !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-left {\n border-top-left-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-lg {\n border-radius: 0.3rem !important;\n}\n\n.rounded-circle {\n border-radius: 50% !important;\n}\n\n.rounded-pill {\n border-radius: 50rem !important;\n}\n\n.rounded-0 {\n border-radius: 0 !important;\n}\n\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.d-none {\n display: none !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n@media (min-width: 576px) {\n .d-sm-none {\n display: none !important;\n }\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 768px) {\n .d-md-none {\n display: none !important;\n }\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 992px) {\n .d-lg-none {\n display: none !important;\n }\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media (min-width: 1200px) {\n .d-xl-none {\n display: none !important;\n }\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n}\n\n@media print {\n .d-print-none {\n display: none !important;\n }\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n}\n\n.embed-responsive {\n position: relative;\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n}\n\n.embed-responsive::before {\n display: block;\n content: \"\";\n}\n\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n\n.embed-responsive-21by9::before {\n padding-top: 42.857143%;\n}\n\n.embed-responsive-16by9::before {\n padding-top: 56.25%;\n}\n\n.embed-responsive-4by3::before {\n padding-top: 75%;\n}\n\n.embed-responsive-1by1::before {\n padding-top: 100%;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n@media (min-width: 576px) {\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 768px) {\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 992px) {\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n}\n\n@media (min-width: 1200px) {\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n}\n\n.float-left {\n float: left !important;\n}\n\n.float-right {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-left {\n float: left !important;\n }\n .float-sm-right {\n float: right !important;\n }\n .float-sm-none {\n float: none !important;\n }\n}\n\n@media (min-width: 768px) {\n .float-md-left {\n float: left !important;\n }\n .float-md-right {\n float: right !important;\n }\n .float-md-none {\n float: none !important;\n }\n}\n\n@media (min-width: 992px) {\n .float-lg-left {\n float: left !important;\n }\n .float-lg-right {\n float: right !important;\n }\n .float-lg-none {\n float: none !important;\n }\n}\n\n@media (min-width: 1200px) {\n .float-xl-left {\n float: left !important;\n }\n .float-xl-right {\n float: right !important;\n }\n .float-xl-none {\n float: none !important;\n }\n}\n\n.overflow-auto {\n overflow: auto !important;\n}\n\n.overflow-hidden {\n overflow: hidden !important;\n}\n\n.position-static {\n position: static !important;\n}\n\n.position-relative {\n position: relative !important;\n}\n\n.position-absolute {\n position: absolute !important;\n}\n\n.position-fixed {\n position: fixed !important;\n}\n\n.position-sticky {\n position: sticky !important;\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n@supports (position: sticky) {\n .sticky-top {\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n overflow: visible;\n clip: auto;\n white-space: normal;\n}\n\n.shadow-sm {\n box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;\n}\n\n.shadow {\n box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;\n}\n\n.shadow-lg {\n box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;\n}\n\n.shadow-none {\n box-shadow: none !important;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.w-auto {\n width: auto !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.h-auto {\n height: auto !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.min-vw-100 {\n min-width: 100vw !important;\n}\n\n.min-vh-100 {\n min-height: 100vh !important;\n}\n\n.vw-100 {\n width: 100vw !important;\n}\n\n.vh-100 {\n height: 100vh !important;\n}\n\n.stretched-link::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1;\n pointer-events: auto;\n content: \"\";\n background-color: rgba(0, 0, 0, 0);\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.mt-0,\n.my-0 {\n margin-top: 0 !important;\n}\n\n.mr-0,\n.mx-0 {\n margin-right: 0 !important;\n}\n\n.mb-0,\n.my-0 {\n margin-bottom: 0 !important;\n}\n\n.ml-0,\n.mx-0 {\n margin-left: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.mt-1,\n.my-1 {\n margin-top: 0.25rem !important;\n}\n\n.mr-1,\n.mx-1 {\n margin-right: 0.25rem !important;\n}\n\n.mb-1,\n.my-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.ml-1,\n.mx-1 {\n margin-left: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.mt-2,\n.my-2 {\n margin-top: 0.5rem !important;\n}\n\n.mr-2,\n.mx-2 {\n margin-right: 0.5rem !important;\n}\n\n.mb-2,\n.my-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.ml-2,\n.mx-2 {\n margin-left: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.mt-3,\n.my-3 {\n margin-top: 1rem !important;\n}\n\n.mr-3,\n.mx-3 {\n margin-right: 1rem !important;\n}\n\n.mb-3,\n.my-3 {\n margin-bottom: 1rem !important;\n}\n\n.ml-3,\n.mx-3 {\n margin-left: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.mt-4,\n.my-4 {\n margin-top: 1.5rem !important;\n}\n\n.mr-4,\n.mx-4 {\n margin-right: 1.5rem !important;\n}\n\n.mb-4,\n.my-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.ml-4,\n.mx-4 {\n margin-left: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.mt-5,\n.my-5 {\n margin-top: 3rem !important;\n}\n\n.mr-5,\n.mx-5 {\n margin-right: 3rem !important;\n}\n\n.mb-5,\n.my-5 {\n margin-bottom: 3rem !important;\n}\n\n.ml-5,\n.mx-5 {\n margin-left: 3rem !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.pt-0,\n.py-0 {\n padding-top: 0 !important;\n}\n\n.pr-0,\n.px-0 {\n padding-right: 0 !important;\n}\n\n.pb-0,\n.py-0 {\n padding-bottom: 0 !important;\n}\n\n.pl-0,\n.px-0 {\n padding-left: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.pt-1,\n.py-1 {\n padding-top: 0.25rem !important;\n}\n\n.pr-1,\n.px-1 {\n padding-right: 0.25rem !important;\n}\n\n.pb-1,\n.py-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pl-1,\n.px-1 {\n padding-left: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.pt-2,\n.py-2 {\n padding-top: 0.5rem !important;\n}\n\n.pr-2,\n.px-2 {\n padding-right: 0.5rem !important;\n}\n\n.pb-2,\n.py-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pl-2,\n.px-2 {\n padding-left: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.pt-3,\n.py-3 {\n padding-top: 1rem !important;\n}\n\n.pr-3,\n.px-3 {\n padding-right: 1rem !important;\n}\n\n.pb-3,\n.py-3 {\n padding-bottom: 1rem !important;\n}\n\n.pl-3,\n.px-3 {\n padding-left: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.pt-4,\n.py-4 {\n padding-top: 1.5rem !important;\n}\n\n.pr-4,\n.px-4 {\n padding-right: 1.5rem !important;\n}\n\n.pb-4,\n.py-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pl-4,\n.px-4 {\n padding-left: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.pt-5,\n.py-5 {\n padding-top: 3rem !important;\n}\n\n.pr-5,\n.px-5 {\n padding-right: 3rem !important;\n}\n\n.pb-5,\n.py-5 {\n padding-bottom: 3rem !important;\n}\n\n.pl-5,\n.px-5 {\n padding-left: 3rem !important;\n}\n\n.m-n1 {\n margin: -0.25rem !important;\n}\n\n.mt-n1,\n.my-n1 {\n margin-top: -0.25rem !important;\n}\n\n.mr-n1,\n.mx-n1 {\n margin-right: -0.25rem !important;\n}\n\n.mb-n1,\n.my-n1 {\n margin-bottom: -0.25rem !important;\n}\n\n.ml-n1,\n.mx-n1 {\n margin-left: -0.25rem !important;\n}\n\n.m-n2 {\n margin: -0.5rem !important;\n}\n\n.mt-n2,\n.my-n2 {\n margin-top: -0.5rem !important;\n}\n\n.mr-n2,\n.mx-n2 {\n margin-right: -0.5rem !important;\n}\n\n.mb-n2,\n.my-n2 {\n margin-bottom: -0.5rem !important;\n}\n\n.ml-n2,\n.mx-n2 {\n margin-left: -0.5rem !important;\n}\n\n.m-n3 {\n margin: -1rem !important;\n}\n\n.mt-n3,\n.my-n3 {\n margin-top: -1rem !important;\n}\n\n.mr-n3,\n.mx-n3 {\n margin-right: -1rem !important;\n}\n\n.mb-n3,\n.my-n3 {\n margin-bottom: -1rem !important;\n}\n\n.ml-n3,\n.mx-n3 {\n margin-left: -1rem !important;\n}\n\n.m-n4 {\n margin: -1.5rem !important;\n}\n\n.mt-n4,\n.my-n4 {\n margin-top: -1.5rem !important;\n}\n\n.mr-n4,\n.mx-n4 {\n margin-right: -1.5rem !important;\n}\n\n.mb-n4,\n.my-n4 {\n margin-bottom: -1.5rem !important;\n}\n\n.ml-n4,\n.mx-n4 {\n margin-left: -1.5rem !important;\n}\n\n.m-n5 {\n margin: -3rem !important;\n}\n\n.mt-n5,\n.my-n5 {\n margin-top: -3rem !important;\n}\n\n.mr-n5,\n.mx-n5 {\n margin-right: -3rem !important;\n}\n\n.mb-n5,\n.my-n5 {\n margin-bottom: -3rem !important;\n}\n\n.ml-n5,\n.mx-n5 {\n margin-left: -3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mt-auto,\n.my-auto {\n margin-top: auto !important;\n}\n\n.mr-auto,\n.mx-auto {\n margin-right: auto !important;\n}\n\n.mb-auto,\n.my-auto {\n margin-bottom: auto !important;\n}\n\n.ml-auto,\n.mx-auto {\n margin-left: auto !important;\n}\n\n@media (min-width: 576px) {\n .m-sm-0 {\n margin: 0 !important;\n }\n .mt-sm-0,\n .my-sm-0 {\n margin-top: 0 !important;\n }\n .mr-sm-0,\n .mx-sm-0 {\n margin-right: 0 !important;\n }\n .mb-sm-0,\n .my-sm-0 {\n margin-bottom: 0 !important;\n }\n .ml-sm-0,\n .mx-sm-0 {\n margin-left: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .mt-sm-1,\n .my-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mr-sm-1,\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n }\n .mb-sm-1,\n .my-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-sm-1,\n .mx-sm-1 {\n margin-left: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .mt-sm-2,\n .my-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mr-sm-2,\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n }\n .mb-sm-2,\n .my-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-sm-2,\n .mx-sm-2 {\n margin-left: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .mt-sm-3,\n .my-sm-3 {\n margin-top: 1rem !important;\n }\n .mr-sm-3,\n .mx-sm-3 {\n margin-right: 1rem !important;\n }\n .mb-sm-3,\n .my-sm-3 {\n margin-bottom: 1rem !important;\n }\n .ml-sm-3,\n .mx-sm-3 {\n margin-left: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .mt-sm-4,\n .my-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mr-sm-4,\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n }\n .mb-sm-4,\n .my-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-sm-4,\n .mx-sm-4 {\n margin-left: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .mt-sm-5,\n .my-sm-5 {\n margin-top: 3rem !important;\n }\n .mr-sm-5,\n .mx-sm-5 {\n margin-right: 3rem !important;\n }\n .mb-sm-5,\n .my-sm-5 {\n margin-bottom: 3rem !important;\n }\n .ml-sm-5,\n .mx-sm-5 {\n margin-left: 3rem !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .pt-sm-0,\n .py-sm-0 {\n padding-top: 0 !important;\n }\n .pr-sm-0,\n .px-sm-0 {\n padding-right: 0 !important;\n }\n .pb-sm-0,\n .py-sm-0 {\n padding-bottom: 0 !important;\n }\n .pl-sm-0,\n .px-sm-0 {\n padding-left: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .pt-sm-1,\n .py-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pr-sm-1,\n .px-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pb-sm-1,\n .py-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-sm-1,\n .px-sm-1 {\n padding-left: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .pt-sm-2,\n .py-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pr-sm-2,\n .px-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pb-sm-2,\n .py-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-sm-2,\n .px-sm-2 {\n padding-left: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .pt-sm-3,\n .py-sm-3 {\n padding-top: 1rem !important;\n }\n .pr-sm-3,\n .px-sm-3 {\n padding-right: 1rem !important;\n }\n .pb-sm-3,\n .py-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pl-sm-3,\n .px-sm-3 {\n padding-left: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .pt-sm-4,\n .py-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pr-sm-4,\n .px-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pb-sm-4,\n .py-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-sm-4,\n .px-sm-4 {\n padding-left: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .pt-sm-5,\n .py-sm-5 {\n padding-top: 3rem !important;\n }\n .pr-sm-5,\n .px-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-5,\n .py-sm-5 {\n padding-bottom: 3rem !important;\n }\n .pl-sm-5,\n .px-sm-5 {\n padding-left: 3rem !important;\n }\n .m-sm-n1 {\n margin: -0.25rem !important;\n }\n .mt-sm-n1,\n .my-sm-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-sm-n1,\n .mx-sm-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-sm-n1,\n .my-sm-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-sm-n1,\n .mx-sm-n1 {\n margin-left: -0.25rem !important;\n }\n .m-sm-n2 {\n margin: -0.5rem !important;\n }\n .mt-sm-n2,\n .my-sm-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-sm-n2,\n .mx-sm-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-sm-n2,\n .my-sm-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-sm-n2,\n .mx-sm-n2 {\n margin-left: -0.5rem !important;\n }\n .m-sm-n3 {\n margin: -1rem !important;\n }\n .mt-sm-n3,\n .my-sm-n3 {\n margin-top: -1rem !important;\n }\n .mr-sm-n3,\n .mx-sm-n3 {\n margin-right: -1rem !important;\n }\n .mb-sm-n3,\n .my-sm-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-sm-n3,\n .mx-sm-n3 {\n margin-left: -1rem !important;\n }\n .m-sm-n4 {\n margin: -1.5rem !important;\n }\n .mt-sm-n4,\n .my-sm-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-sm-n4,\n .mx-sm-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-sm-n4,\n .my-sm-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-sm-n4,\n .mx-sm-n4 {\n margin-left: -1.5rem !important;\n }\n .m-sm-n5 {\n margin: -3rem !important;\n }\n .mt-sm-n5,\n .my-sm-n5 {\n margin-top: -3rem !important;\n }\n .mr-sm-n5,\n .mx-sm-n5 {\n margin-right: -3rem !important;\n }\n .mb-sm-n5,\n .my-sm-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-sm-n5,\n .mx-sm-n5 {\n margin-left: -3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mt-sm-auto,\n .my-sm-auto {\n margin-top: auto !important;\n }\n .mr-sm-auto,\n .mx-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-auto,\n .my-sm-auto {\n margin-bottom: auto !important;\n }\n .ml-sm-auto,\n .mx-sm-auto {\n margin-left: auto !important;\n }\n}\n\n@media (min-width: 768px) {\n .m-md-0 {\n margin: 0 !important;\n }\n .mt-md-0,\n .my-md-0 {\n margin-top: 0 !important;\n }\n .mr-md-0,\n .mx-md-0 {\n margin-right: 0 !important;\n }\n .mb-md-0,\n .my-md-0 {\n margin-bottom: 0 !important;\n }\n .ml-md-0,\n .mx-md-0 {\n margin-left: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .mt-md-1,\n .my-md-1 {\n margin-top: 0.25rem !important;\n }\n .mr-md-1,\n .mx-md-1 {\n margin-right: 0.25rem !important;\n }\n .mb-md-1,\n .my-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-md-1,\n .mx-md-1 {\n margin-left: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .mt-md-2,\n .my-md-2 {\n margin-top: 0.5rem !important;\n }\n .mr-md-2,\n .mx-md-2 {\n margin-right: 0.5rem !important;\n }\n .mb-md-2,\n .my-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-md-2,\n .mx-md-2 {\n margin-left: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .mt-md-3,\n .my-md-3 {\n margin-top: 1rem !important;\n }\n .mr-md-3,\n .mx-md-3 {\n margin-right: 1rem !important;\n }\n .mb-md-3,\n .my-md-3 {\n margin-bottom: 1rem !important;\n }\n .ml-md-3,\n .mx-md-3 {\n margin-left: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .mt-md-4,\n .my-md-4 {\n margin-top: 1.5rem !important;\n }\n .mr-md-4,\n .mx-md-4 {\n margin-right: 1.5rem !important;\n }\n .mb-md-4,\n .my-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-md-4,\n .mx-md-4 {\n margin-left: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .mt-md-5,\n .my-md-5 {\n margin-top: 3rem !important;\n }\n .mr-md-5,\n .mx-md-5 {\n margin-right: 3rem !important;\n }\n .mb-md-5,\n .my-md-5 {\n margin-bottom: 3rem !important;\n }\n .ml-md-5,\n .mx-md-5 {\n margin-left: 3rem !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .pt-md-0,\n .py-md-0 {\n padding-top: 0 !important;\n }\n .pr-md-0,\n .px-md-0 {\n padding-right: 0 !important;\n }\n .pb-md-0,\n .py-md-0 {\n padding-bottom: 0 !important;\n }\n .pl-md-0,\n .px-md-0 {\n padding-left: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .pt-md-1,\n .py-md-1 {\n padding-top: 0.25rem !important;\n }\n .pr-md-1,\n .px-md-1 {\n padding-right: 0.25rem !important;\n }\n .pb-md-1,\n .py-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-md-1,\n .px-md-1 {\n padding-left: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .pt-md-2,\n .py-md-2 {\n padding-top: 0.5rem !important;\n }\n .pr-md-2,\n .px-md-2 {\n padding-right: 0.5rem !important;\n }\n .pb-md-2,\n .py-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-md-2,\n .px-md-2 {\n padding-left: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .pt-md-3,\n .py-md-3 {\n padding-top: 1rem !important;\n }\n .pr-md-3,\n .px-md-3 {\n padding-right: 1rem !important;\n }\n .pb-md-3,\n .py-md-3 {\n padding-bottom: 1rem !important;\n }\n .pl-md-3,\n .px-md-3 {\n padding-left: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .pt-md-4,\n .py-md-4 {\n padding-top: 1.5rem !important;\n }\n .pr-md-4,\n .px-md-4 {\n padding-right: 1.5rem !important;\n }\n .pb-md-4,\n .py-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-md-4,\n .px-md-4 {\n padding-left: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .pt-md-5,\n .py-md-5 {\n padding-top: 3rem !important;\n }\n .pr-md-5,\n .px-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-5,\n .py-md-5 {\n padding-bottom: 3rem !important;\n }\n .pl-md-5,\n .px-md-5 {\n padding-left: 3rem !important;\n }\n .m-md-n1 {\n margin: -0.25rem !important;\n }\n .mt-md-n1,\n .my-md-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-md-n1,\n .mx-md-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-md-n1,\n .my-md-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-md-n1,\n .mx-md-n1 {\n margin-left: -0.25rem !important;\n }\n .m-md-n2 {\n margin: -0.5rem !important;\n }\n .mt-md-n2,\n .my-md-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-md-n2,\n .mx-md-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-md-n2,\n .my-md-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-md-n2,\n .mx-md-n2 {\n margin-left: -0.5rem !important;\n }\n .m-md-n3 {\n margin: -1rem !important;\n }\n .mt-md-n3,\n .my-md-n3 {\n margin-top: -1rem !important;\n }\n .mr-md-n3,\n .mx-md-n3 {\n margin-right: -1rem !important;\n }\n .mb-md-n3,\n .my-md-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-md-n3,\n .mx-md-n3 {\n margin-left: -1rem !important;\n }\n .m-md-n4 {\n margin: -1.5rem !important;\n }\n .mt-md-n4,\n .my-md-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-md-n4,\n .mx-md-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-md-n4,\n .my-md-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-md-n4,\n .mx-md-n4 {\n margin-left: -1.5rem !important;\n }\n .m-md-n5 {\n margin: -3rem !important;\n }\n .mt-md-n5,\n .my-md-n5 {\n margin-top: -3rem !important;\n }\n .mr-md-n5,\n .mx-md-n5 {\n margin-right: -3rem !important;\n }\n .mb-md-n5,\n .my-md-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-md-n5,\n .mx-md-n5 {\n margin-left: -3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mt-md-auto,\n .my-md-auto {\n margin-top: auto !important;\n }\n .mr-md-auto,\n .mx-md-auto {\n margin-right: auto !important;\n }\n .mb-md-auto,\n .my-md-auto {\n margin-bottom: auto !important;\n }\n .ml-md-auto,\n .mx-md-auto {\n margin-left: auto !important;\n }\n}\n\n@media (min-width: 992px) {\n .m-lg-0 {\n margin: 0 !important;\n }\n .mt-lg-0,\n .my-lg-0 {\n margin-top: 0 !important;\n }\n .mr-lg-0,\n .mx-lg-0 {\n margin-right: 0 !important;\n }\n .mb-lg-0,\n .my-lg-0 {\n margin-bottom: 0 !important;\n }\n .ml-lg-0,\n .mx-lg-0 {\n margin-left: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .mt-lg-1,\n .my-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mr-lg-1,\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n }\n .mb-lg-1,\n .my-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-lg-1,\n .mx-lg-1 {\n margin-left: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .mt-lg-2,\n .my-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mr-lg-2,\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n }\n .mb-lg-2,\n .my-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-lg-2,\n .mx-lg-2 {\n margin-left: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .mt-lg-3,\n .my-lg-3 {\n margin-top: 1rem !important;\n }\n .mr-lg-3,\n .mx-lg-3 {\n margin-right: 1rem !important;\n }\n .mb-lg-3,\n .my-lg-3 {\n margin-bottom: 1rem !important;\n }\n .ml-lg-3,\n .mx-lg-3 {\n margin-left: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .mt-lg-4,\n .my-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mr-lg-4,\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n }\n .mb-lg-4,\n .my-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-lg-4,\n .mx-lg-4 {\n margin-left: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .mt-lg-5,\n .my-lg-5 {\n margin-top: 3rem !important;\n }\n .mr-lg-5,\n .mx-lg-5 {\n margin-right: 3rem !important;\n }\n .mb-lg-5,\n .my-lg-5 {\n margin-bottom: 3rem !important;\n }\n .ml-lg-5,\n .mx-lg-5 {\n margin-left: 3rem !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .pt-lg-0,\n .py-lg-0 {\n padding-top: 0 !important;\n }\n .pr-lg-0,\n .px-lg-0 {\n padding-right: 0 !important;\n }\n .pb-lg-0,\n .py-lg-0 {\n padding-bottom: 0 !important;\n }\n .pl-lg-0,\n .px-lg-0 {\n padding-left: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .pt-lg-1,\n .py-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pr-lg-1,\n .px-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pb-lg-1,\n .py-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-lg-1,\n .px-lg-1 {\n padding-left: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .pt-lg-2,\n .py-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pr-lg-2,\n .px-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pb-lg-2,\n .py-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-lg-2,\n .px-lg-2 {\n padding-left: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .pt-lg-3,\n .py-lg-3 {\n padding-top: 1rem !important;\n }\n .pr-lg-3,\n .px-lg-3 {\n padding-right: 1rem !important;\n }\n .pb-lg-3,\n .py-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pl-lg-3,\n .px-lg-3 {\n padding-left: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .pt-lg-4,\n .py-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pr-lg-4,\n .px-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pb-lg-4,\n .py-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-lg-4,\n .px-lg-4 {\n padding-left: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .pt-lg-5,\n .py-lg-5 {\n padding-top: 3rem !important;\n }\n .pr-lg-5,\n .px-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-5,\n .py-lg-5 {\n padding-bottom: 3rem !important;\n }\n .pl-lg-5,\n .px-lg-5 {\n padding-left: 3rem !important;\n }\n .m-lg-n1 {\n margin: -0.25rem !important;\n }\n .mt-lg-n1,\n .my-lg-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-lg-n1,\n .mx-lg-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-lg-n1,\n .my-lg-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-lg-n1,\n .mx-lg-n1 {\n margin-left: -0.25rem !important;\n }\n .m-lg-n2 {\n margin: -0.5rem !important;\n }\n .mt-lg-n2,\n .my-lg-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-lg-n2,\n .mx-lg-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-lg-n2,\n .my-lg-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-lg-n2,\n .mx-lg-n2 {\n margin-left: -0.5rem !important;\n }\n .m-lg-n3 {\n margin: -1rem !important;\n }\n .mt-lg-n3,\n .my-lg-n3 {\n margin-top: -1rem !important;\n }\n .mr-lg-n3,\n .mx-lg-n3 {\n margin-right: -1rem !important;\n }\n .mb-lg-n3,\n .my-lg-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-lg-n3,\n .mx-lg-n3 {\n margin-left: -1rem !important;\n }\n .m-lg-n4 {\n margin: -1.5rem !important;\n }\n .mt-lg-n4,\n .my-lg-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-lg-n4,\n .mx-lg-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-lg-n4,\n .my-lg-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-lg-n4,\n .mx-lg-n4 {\n margin-left: -1.5rem !important;\n }\n .m-lg-n5 {\n margin: -3rem !important;\n }\n .mt-lg-n5,\n .my-lg-n5 {\n margin-top: -3rem !important;\n }\n .mr-lg-n5,\n .mx-lg-n5 {\n margin-right: -3rem !important;\n }\n .mb-lg-n5,\n .my-lg-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-lg-n5,\n .mx-lg-n5 {\n margin-left: -3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mt-lg-auto,\n .my-lg-auto {\n margin-top: auto !important;\n }\n .mr-lg-auto,\n .mx-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-auto,\n .my-lg-auto {\n margin-bottom: auto !important;\n }\n .ml-lg-auto,\n .mx-lg-auto {\n margin-left: auto !important;\n }\n}\n\n@media (min-width: 1200px) {\n .m-xl-0 {\n margin: 0 !important;\n }\n .mt-xl-0,\n .my-xl-0 {\n margin-top: 0 !important;\n }\n .mr-xl-0,\n .mx-xl-0 {\n margin-right: 0 !important;\n }\n .mb-xl-0,\n .my-xl-0 {\n margin-bottom: 0 !important;\n }\n .ml-xl-0,\n .mx-xl-0 {\n margin-left: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .mt-xl-1,\n .my-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mr-xl-1,\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n }\n .mb-xl-1,\n .my-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .ml-xl-1,\n .mx-xl-1 {\n margin-left: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .mt-xl-2,\n .my-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mr-xl-2,\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n }\n .mb-xl-2,\n .my-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .ml-xl-2,\n .mx-xl-2 {\n margin-left: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .mt-xl-3,\n .my-xl-3 {\n margin-top: 1rem !important;\n }\n .mr-xl-3,\n .mx-xl-3 {\n margin-right: 1rem !important;\n }\n .mb-xl-3,\n .my-xl-3 {\n margin-bottom: 1rem !important;\n }\n .ml-xl-3,\n .mx-xl-3 {\n margin-left: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .mt-xl-4,\n .my-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mr-xl-4,\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n }\n .mb-xl-4,\n .my-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .ml-xl-4,\n .mx-xl-4 {\n margin-left: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .mt-xl-5,\n .my-xl-5 {\n margin-top: 3rem !important;\n }\n .mr-xl-5,\n .mx-xl-5 {\n margin-right: 3rem !important;\n }\n .mb-xl-5,\n .my-xl-5 {\n margin-bottom: 3rem !important;\n }\n .ml-xl-5,\n .mx-xl-5 {\n margin-left: 3rem !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .pt-xl-0,\n .py-xl-0 {\n padding-top: 0 !important;\n }\n .pr-xl-0,\n .px-xl-0 {\n padding-right: 0 !important;\n }\n .pb-xl-0,\n .py-xl-0 {\n padding-bottom: 0 !important;\n }\n .pl-xl-0,\n .px-xl-0 {\n padding-left: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .pt-xl-1,\n .py-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pr-xl-1,\n .px-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pb-xl-1,\n .py-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pl-xl-1,\n .px-xl-1 {\n padding-left: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .pt-xl-2,\n .py-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pr-xl-2,\n .px-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pb-xl-2,\n .py-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pl-xl-2,\n .px-xl-2 {\n padding-left: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .pt-xl-3,\n .py-xl-3 {\n padding-top: 1rem !important;\n }\n .pr-xl-3,\n .px-xl-3 {\n padding-right: 1rem !important;\n }\n .pb-xl-3,\n .py-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pl-xl-3,\n .px-xl-3 {\n padding-left: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .pt-xl-4,\n .py-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pr-xl-4,\n .px-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pb-xl-4,\n .py-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pl-xl-4,\n .px-xl-4 {\n padding-left: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .pt-xl-5,\n .py-xl-5 {\n padding-top: 3rem !important;\n }\n .pr-xl-5,\n .px-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-5,\n .py-xl-5 {\n padding-bottom: 3rem !important;\n }\n .pl-xl-5,\n .px-xl-5 {\n padding-left: 3rem !important;\n }\n .m-xl-n1 {\n margin: -0.25rem !important;\n }\n .mt-xl-n1,\n .my-xl-n1 {\n margin-top: -0.25rem !important;\n }\n .mr-xl-n1,\n .mx-xl-n1 {\n margin-right: -0.25rem !important;\n }\n .mb-xl-n1,\n .my-xl-n1 {\n margin-bottom: -0.25rem !important;\n }\n .ml-xl-n1,\n .mx-xl-n1 {\n margin-left: -0.25rem !important;\n }\n .m-xl-n2 {\n margin: -0.5rem !important;\n }\n .mt-xl-n2,\n .my-xl-n2 {\n margin-top: -0.5rem !important;\n }\n .mr-xl-n2,\n .mx-xl-n2 {\n margin-right: -0.5rem !important;\n }\n .mb-xl-n2,\n .my-xl-n2 {\n margin-bottom: -0.5rem !important;\n }\n .ml-xl-n2,\n .mx-xl-n2 {\n margin-left: -0.5rem !important;\n }\n .m-xl-n3 {\n margin: -1rem !important;\n }\n .mt-xl-n3,\n .my-xl-n3 {\n margin-top: -1rem !important;\n }\n .mr-xl-n3,\n .mx-xl-n3 {\n margin-right: -1rem !important;\n }\n .mb-xl-n3,\n .my-xl-n3 {\n margin-bottom: -1rem !important;\n }\n .ml-xl-n3,\n .mx-xl-n3 {\n margin-left: -1rem !important;\n }\n .m-xl-n4 {\n margin: -1.5rem !important;\n }\n .mt-xl-n4,\n .my-xl-n4 {\n margin-top: -1.5rem !important;\n }\n .mr-xl-n4,\n .mx-xl-n4 {\n margin-right: -1.5rem !important;\n }\n .mb-xl-n4,\n .my-xl-n4 {\n margin-bottom: -1.5rem !important;\n }\n .ml-xl-n4,\n .mx-xl-n4 {\n margin-left: -1.5rem !important;\n }\n .m-xl-n5 {\n margin: -3rem !important;\n }\n .mt-xl-n5,\n .my-xl-n5 {\n margin-top: -3rem !important;\n }\n .mr-xl-n5,\n .mx-xl-n5 {\n margin-right: -3rem !important;\n }\n .mb-xl-n5,\n .my-xl-n5 {\n margin-bottom: -3rem !important;\n }\n .ml-xl-n5,\n .mx-xl-n5 {\n margin-left: -3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mt-xl-auto,\n .my-xl-auto {\n margin-top: auto !important;\n }\n .mr-xl-auto,\n .mx-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-auto,\n .my-xl-auto {\n margin-bottom: auto !important;\n }\n .ml-xl-auto,\n .mx-xl-auto {\n margin-left: auto !important;\n }\n}\n\n.text-monospace {\n font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !important;\n}\n\n.text-justify {\n text-align: justify !important;\n}\n\n.text-wrap {\n white-space: normal !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.text-left {\n text-align: left !important;\n}\n\n.text-right {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n@media (min-width: 576px) {\n .text-sm-left {\n text-align: left !important;\n }\n .text-sm-right {\n text-align: right !important;\n }\n .text-sm-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 768px) {\n .text-md-left {\n text-align: left !important;\n }\n .text-md-right {\n text-align: right !important;\n }\n .text-md-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 992px) {\n .text-lg-left {\n text-align: left !important;\n }\n .text-lg-right {\n text-align: right !important;\n }\n .text-lg-center {\n text-align: center !important;\n }\n}\n\n@media (min-width: 1200px) {\n .text-xl-left {\n text-align: left !important;\n }\n .text-xl-right {\n text-align: right !important;\n }\n .text-xl-center {\n text-align: center !important;\n }\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.font-weight-light {\n font-weight: 300 !important;\n}\n\n.font-weight-lighter {\n font-weight: lighter !important;\n}\n\n.font-weight-normal {\n font-weight: 400 !important;\n}\n\n.font-weight-bold {\n font-weight: 700 !important;\n}\n\n.font-weight-bolder {\n font-weight: bolder !important;\n}\n\n.font-italic {\n font-style: italic !important;\n}\n\n.text-white {\n color: #fff !important;\n}\n\n.text-primary {\n color: #007bff !important;\n}\n\na.text-primary:hover, a.text-primary:focus {\n color: #0056b3 !important;\n}\n\n.text-secondary {\n color: #6c757d !important;\n}\n\na.text-secondary:hover, a.text-secondary:focus {\n color: #494f54 !important;\n}\n\n.text-success {\n color: #28a745 !important;\n}\n\na.text-success:hover, a.text-success:focus {\n color: #19692c !important;\n}\n\n.text-info {\n color: #17a2b8 !important;\n}\n\na.text-info:hover, a.text-info:focus {\n color: #0f6674 !important;\n}\n\n.text-warning {\n color: #ffc107 !important;\n}\n\na.text-warning:hover, a.text-warning:focus {\n color: #ba8b00 !important;\n}\n\n.text-danger {\n color: #dc3545 !important;\n}\n\na.text-danger:hover, a.text-danger:focus {\n color: #a71d2a !important;\n}\n\n.text-light {\n color: #f8f9fa !important;\n}\n\na.text-light:hover, a.text-light:focus {\n color: #cbd3da !important;\n}\n\n.text-dark {\n color: #343a40 !important;\n}\n\na.text-dark:hover, a.text-dark:focus {\n color: #121416 !important;\n}\n\n.text-body {\n color: #212529 !important;\n}\n\n.text-muted {\n color: #6c757d !important;\n}\n\n.text-black-50 {\n color: rgba(0, 0, 0, 0.5) !important;\n}\n\n.text-white-50 {\n color: rgba(255, 255, 255, 0.5) !important;\n}\n\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n.text-decoration-none {\n text-decoration: none !important;\n}\n\n.text-break {\n word-break: break-word !important;\n overflow-wrap: break-word !important;\n}\n\n.text-reset {\n color: inherit !important;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n@media print {\n *,\n *::before,\n *::after {\n text-shadow: none !important;\n box-shadow: none !important;\n }\n a:not(.btn) {\n text-decoration: underline;\n }\n abbr[title]::after {\n content: \" (\" attr(title) \")\";\n }\n pre {\n white-space: pre-wrap !important;\n }\n pre,\n blockquote {\n border: 1px solid #adb5bd;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n @page {\n size: a3;\n }\n body {\n min-width: 992px !important;\n }\n .container {\n min-width: 992px !important;\n }\n .navbar {\n display: none;\n }\n .badge {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #dee2e6 !important;\n }\n .table-dark {\n color: inherit;\n }\n .table-dark th,\n .table-dark td,\n .table-dark thead th,\n .table-dark tbody + tbody {\n border-color: #dee2e6;\n }\n .table .thead-dark th {\n color: inherit;\n border-color: #dee2e6;\n }\n}\n\n/*# sourceMappingURL=bootstrap.css.map */","// Hover mixin and `$enable-hover-media-query` are deprecated.\n//\n// Originally added during our alphas and maintained during betas, this mixin was\n// designed to prevent `:hover` stickiness on iOS-an issue where hover styles\n// would persist after initial touch.\n//\n// For backward compatibility, we've kept these mixins and updated them to\n// always return their regular pseudo-classes instead of a shimmed media query.\n//\n// Issue: https://github.com/twbs/bootstrap/issues/25195\n\n@mixin hover {\n &:hover { @content; }\n}\n\n@mixin hover-focus {\n &:hover,\n &:focus {\n @content;\n }\n}\n\n@mixin plain-hover-focus {\n &,\n &:hover,\n &:focus {\n @content;\n }\n}\n\n@mixin hover-focus-active {\n &:hover,\n &:focus,\n &:active {\n @content;\n }\n}\n","// stylelint-disable declaration-no-important, selector-list-comma-newline-after\n\n//\n// Headings\n//\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: $headings-color;\n}\n\nh1, .h1 { @include font-size($h1-font-size); }\nh2, .h2 { @include font-size($h2-font-size); }\nh3, .h3 { @include font-size($h3-font-size); }\nh4, .h4 { @include font-size($h4-font-size); }\nh5, .h5 { @include font-size($h5-font-size); }\nh6, .h6 { @include font-size($h6-font-size); }\n\n.lead {\n @include font-size($lead-font-size);\n font-weight: $lead-font-weight;\n}\n\n// Type display classes\n.display-1 {\n @include font-size($display1-size);\n font-weight: $display1-weight;\n line-height: $display-line-height;\n}\n.display-2 {\n @include font-size($display2-size);\n font-weight: $display2-weight;\n line-height: $display-line-height;\n}\n.display-3 {\n @include font-size($display3-size);\n font-weight: $display3-weight;\n line-height: $display-line-height;\n}\n.display-4 {\n @include font-size($display4-size);\n font-weight: $display4-weight;\n line-height: $display-line-height;\n}\n\n\n//\n// Horizontal rules\n//\n\nhr {\n margin-top: $hr-margin-y;\n margin-bottom: $hr-margin-y;\n border: 0;\n border-top: $hr-border-width solid $hr-border-color;\n}\n\n\n//\n// Emphasis\n//\n\nsmall,\n.small {\n @include font-size($small-font-size);\n font-weight: $font-weight-normal;\n}\n\nmark,\n.mark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n//\n// Lists\n//\n\n.list-unstyled {\n @include list-unstyled;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n @include list-unstyled;\n}\n.list-inline-item {\n display: inline-block;\n\n &:not(:last-child) {\n margin-right: $list-inline-padding;\n }\n}\n\n\n//\n// Misc\n//\n\n// Builds on `abbr`\n.initialism {\n @include font-size(90%);\n text-transform: uppercase;\n}\n\n// Blockquotes\n.blockquote {\n margin-bottom: $spacer;\n @include font-size($blockquote-font-size);\n}\n\n.blockquote-footer {\n display: block;\n @include font-size($blockquote-small-font-size);\n color: $blockquote-small-color;\n\n &::before {\n content: \"\\2014\\00A0\"; // em dash, nbsp\n }\n}\n","// Lists\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n@mixin list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n","// Responsive images (ensure images don't scale beyond their parents)\n//\n// This is purposefully opt-in via an explicit class rather than being the default for all ``s.\n// We previously tried the \"images are responsive by default\" approach in Bootstrap v2,\n// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)\n// which weren't expecting the images within themselves to be involuntarily resized.\n// See also https://github.com/twbs/bootstrap/issues/18178\n.img-fluid {\n @include img-fluid;\n}\n\n\n// Image thumbnails\n.img-thumbnail {\n padding: $thumbnail-padding;\n background-color: $thumbnail-bg;\n border: $thumbnail-border-width solid $thumbnail-border-color;\n @include border-radius($thumbnail-border-radius);\n @include box-shadow($thumbnail-box-shadow);\n\n // Keep them at most 100% wide\n @include img-fluid;\n}\n\n//\n// Figures\n//\n\n.figure {\n // Ensures the caption's text aligns with the image.\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: $spacer / 2;\n line-height: 1;\n}\n\n.figure-caption {\n @include font-size($figure-caption-font-size);\n color: $figure-caption-color;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n@mixin img-fluid {\n // Part 1: Set a maximum relative to the parent\n max-width: 100%;\n // Part 2: Override the height to auto, otherwise images will be stretched\n // when setting a width and height attribute on the img element.\n height: auto;\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size.\n\n@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) {\n background-image: url($file-1x);\n\n // Autoprefixer takes care of adding -webkit-min-device-pixel-ratio and -o-min-device-pixel-ratio,\n // but doesn't convert dppx=>dpi.\n // There's no such thing as unprefixed min-device-pixel-ratio since it's nonstandard.\n // Compatibility info: https://caniuse.com/#feat=css-media-resolution\n @media only screen and (min-resolution: 192dpi), // IE9-11 don't support dppx\n only screen and (min-resolution: 2dppx) { // Standardized\n background-image: url($file-2x);\n background-size: $width-1x $height-1x;\n }\n @include deprecate(\"`img-retina()`\", \"v4.3.0\", \"v5\");\n}\n","// stylelint-disable property-blacklist\n// Single side border-radius\n\n@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) {\n @if $enable-rounded {\n border-radius: $radius;\n }\n @else if $fallback-border-radius != false {\n border-radius: $fallback-border-radius;\n }\n}\n\n@mixin border-top-radius($radius) {\n @if $enable-rounded {\n border-top-left-radius: $radius;\n border-top-right-radius: $radius;\n }\n}\n\n@mixin border-right-radius($radius) {\n @if $enable-rounded {\n border-top-right-radius: $radius;\n border-bottom-right-radius: $radius;\n }\n}\n\n@mixin border-bottom-radius($radius) {\n @if $enable-rounded {\n border-bottom-right-radius: $radius;\n border-bottom-left-radius: $radius;\n }\n}\n\n@mixin border-left-radius($radius) {\n @if $enable-rounded {\n border-top-left-radius: $radius;\n border-bottom-left-radius: $radius;\n }\n}\n\n@mixin border-top-left-radius($radius) {\n @if $enable-rounded {\n border-top-left-radius: $radius;\n }\n}\n\n@mixin border-top-right-radius($radius) {\n @if $enable-rounded {\n border-top-right-radius: $radius;\n }\n}\n\n@mixin border-bottom-right-radius($radius) {\n @if $enable-rounded {\n border-bottom-right-radius: $radius;\n }\n}\n\n@mixin border-bottom-left-radius($radius) {\n @if $enable-rounded {\n border-bottom-left-radius: $radius;\n }\n}\n","// Inline code\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-break: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n @include box-shadow($kbd-box-shadow);\n\n kbd {\n padding: 0;\n @include font-size(100%);\n font-weight: $nested-kbd-font-weight;\n @include box-shadow(none);\n }\n}\n\n// Blocks of code\npre {\n display: block;\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: $pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n@if $enable-grid-classes {\n .container {\n @include make-container();\n @include make-container-max-widths();\n }\n}\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but with 100% width for\n// fluid, full width layouts.\n\n@if $enable-grid-classes {\n .container-fluid {\n @include make-container();\n }\n}\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n@if $enable-grid-classes {\n .row {\n @include make-row();\n }\n\n // Remove the negative margin from default .row, then the horizontal padding\n // from all immediate children columns (to prevent runaway style inheritance).\n .no-gutters {\n margin-right: 0;\n margin-left: 0;\n\n > .col,\n > [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n }\n }\n}\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n@if $enable-grid-classes {\n @include make-grid-columns();\n}\n","/// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-container($gutter: $grid-gutter-width) {\n width: 100%;\n padding-right: $gutter / 2;\n padding-left: $gutter / 2;\n margin-right: auto;\n margin-left: auto;\n}\n\n\n// For each breakpoint, define the maximum width of the container in a media query\n@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) {\n @each $breakpoint, $container-max-width in $max-widths {\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n max-width: $container-max-width;\n }\n }\n}\n\n@mixin make-row($gutter: $grid-gutter-width) {\n display: flex;\n flex-wrap: wrap;\n margin-right: -$gutter / 2;\n margin-left: -$gutter / 2;\n}\n\n@mixin make-col-ready($gutter: $grid-gutter-width) {\n position: relative;\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we use `flex` values\n // later on to override this initial width.\n width: 100%;\n padding-right: $gutter / 2;\n padding-left: $gutter / 2;\n}\n\n@mixin make-col($size, $columns: $grid-columns) {\n flex: 0 0 percentage($size / $columns);\n // Add a `max-width` to ensure content within each column does not blow out\n // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari\n // do not appear to require this.\n max-width: percentage($size / $columns);\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: $size / $columns;\n margin-left: if($num == 0, 0, percentage($num));\n}\n","// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @return if($n != null and $n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width. Null for the largest (last) breakpoint.\n// The maximum value is calculated as the minimum of the next one less 0.02px\n// to work around the limitations of `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $next: breakpoint-next($name, $breakpoints);\n @return if($next, breakpoint-min($next, $breakpoints) - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $max: breakpoint-max($name, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($name, $breakpoints) {\n @content;\n }\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n // Common properties for all breakpoints\n %grid-column {\n position: relative;\n width: 100%;\n padding-right: $gutter / 2;\n padding-left: $gutter / 2;\n }\n\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n // Allow columns to stretch full width below their breakpoints\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @extend %grid-column;\n }\n }\n .col#{$infix},\n .col#{$infix}-auto {\n @extend %grid-column;\n }\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex-basis: 0;\n flex-grow: 1;\n max-width: 100%;\n }\n .col#{$infix}-auto {\n flex: 0 0 auto;\n width: auto;\n max-width: 100%; // Reset earlier grid tiers\n }\n\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n .order#{$infix}-first { order: -1; }\n\n .order#{$infix}-last { order: $columns + 1; }\n\n @for $i from 0 through $columns {\n .order#{$infix}-#{$i} { order: $i; }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n }\n}\n","//\n// Basic Bootstrap table\n//\n\n.table {\n width: 100%;\n margin-bottom: $spacer;\n color: $table-color;\n background-color: $table-bg; // Reset for nesting within parents with `background-color`.\n\n th,\n td {\n padding: $table-cell-padding;\n vertical-align: top;\n border-top: $table-border-width solid $table-border-color;\n }\n\n thead th {\n vertical-align: bottom;\n border-bottom: (2 * $table-border-width) solid $table-border-color;\n }\n\n tbody + tbody {\n border-top: (2 * $table-border-width) solid $table-border-color;\n }\n}\n\n\n//\n// Condensed table w/ half padding\n//\n\n.table-sm {\n th,\n td {\n padding: $table-cell-padding-sm;\n }\n}\n\n\n// Border versions\n//\n// Add or remove borders all around the table and between all the columns.\n\n.table-bordered {\n border: $table-border-width solid $table-border-color;\n\n th,\n td {\n border: $table-border-width solid $table-border-color;\n }\n\n thead {\n th,\n td {\n border-bottom-width: 2 * $table-border-width;\n }\n }\n}\n\n.table-borderless {\n th,\n td,\n thead th,\n tbody + tbody {\n border: 0;\n }\n}\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n tbody tr:nth-of-type(#{$table-striped-order}) {\n background-color: $table-accent-bg;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n tbody tr {\n @include hover {\n color: $table-hover-color;\n background-color: $table-hover-bg;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n@each $color, $value in $theme-colors {\n @include table-row-variant($color, theme-color-level($color, $table-bg-level), theme-color-level($color, $table-border-level));\n}\n\n@include table-row-variant(active, $table-active-bg);\n\n\n// Dark styles\n//\n// Same table markup, but inverted color scheme: dark background and light text.\n\n// stylelint-disable-next-line no-duplicate-selectors\n.table {\n .thead-dark {\n th {\n color: $table-dark-color;\n background-color: $table-dark-bg;\n border-color: $table-dark-border-color;\n }\n }\n\n .thead-light {\n th {\n color: $table-head-color;\n background-color: $table-head-bg;\n border-color: $table-border-color;\n }\n }\n}\n\n.table-dark {\n color: $table-dark-color;\n background-color: $table-dark-bg;\n\n th,\n td,\n thead th {\n border-color: $table-dark-border-color;\n }\n\n &.table-bordered {\n border: 0;\n }\n\n &.table-striped {\n tbody tr:nth-of-type(odd) {\n background-color: $table-dark-accent-bg;\n }\n }\n\n &.table-hover {\n tbody tr {\n @include hover {\n color: $table-dark-hover-color;\n background-color: $table-dark-hover-bg;\n }\n }\n }\n}\n\n\n// Responsive tables\n//\n// Generate series of `.table-responsive-*` classes for configuring the screen\n// size of where your table will overflow.\n\n.table-responsive {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $next: breakpoint-next($breakpoint, $grid-breakpoints);\n $infix: breakpoint-infix($next, $grid-breakpoints);\n\n &#{$infix} {\n @include media-breakpoint-down($breakpoint) {\n display: block;\n width: 100%;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n\n // Prevent double border on horizontal scroll due to use of `display: block;`\n > .table-bordered {\n border: 0;\n }\n }\n }\n }\n}\n","// Tables\n\n@mixin table-row-variant($state, $background, $border: null) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table-#{$state} {\n &,\n > th,\n > td {\n background-color: $background;\n }\n\n @if $border != null {\n th,\n td,\n thead th,\n tbody + tbody {\n border-color: $border;\n }\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover {\n $hover-background: darken($background, 5%);\n\n .table-#{$state} {\n @include hover {\n background-color: $hover-background;\n\n > td,\n > th {\n background-color: $hover-background;\n }\n }\n }\n }\n}\n","// stylelint-disable selector-no-qualifying-type\n\n//\n// Textual form controls\n//\n\n.form-control {\n display: block;\n width: 100%;\n height: $input-height;\n padding: $input-padding-y $input-padding-x;\n font-family: $input-font-family;\n @include font-size($input-font-size);\n font-weight: $input-font-weight;\n line-height: $input-line-height;\n color: $input-color;\n background-color: $input-bg;\n background-clip: padding-box;\n border: $input-border-width solid $input-border-color;\n\n // Note: This has no effect on `s in CSS.\n @include border-radius($input-border-radius, 0);\n\n @include box-shadow($input-box-shadow);\n @include transition($input-transition);\n\n // Unstyle the caret on ` receives focus\n // in IE and (under certain conditions) Edge, as it looks bad and cannot be made to\n // match the appearance of the native widget.\n // See https://github.com/twbs/bootstrap/issues/19398.\n color: $input-color;\n background-color: $input-bg;\n }\n}\n\n// Make file inputs better match text inputs by forcing them to new lines.\n.form-control-file,\n.form-control-range {\n display: block;\n width: 100%;\n}\n\n\n//\n// Labels\n//\n\n// For use with horizontal and inline forms, when you need the label (or legend)\n// text to align with the form controls.\n.col-form-label {\n padding-top: calc(#{$input-padding-y} + #{$input-border-width});\n padding-bottom: calc(#{$input-padding-y} + #{$input-border-width});\n margin-bottom: 0; // Override the `
\ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Client/wwwroot/sample-data/weather.json b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/sample-data/weather.json new file mode 100644 index 00000000000..23687ae7bec --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Client/wwwroot/sample-data/weather.json @@ -0,0 +1,27 @@ +[ + { + "date": "2018-05-06", + "temperatureC": 1, + "summary": "Freezing" + }, + { + "date": "2018-05-07", + "temperatureC": 14, + "summary": "Bracing" + }, + { + "date": "2018-05-08", + "temperatureC": -13, + "summary": "Freezing" + }, + { + "date": "2018-05-09", + "temperatureC": -16, + "summary": "Balmy" + }, + { + "date": "2018-05-10", + "temperatureC": -2, + "summary": "Chilly" + } +] diff --git a/tests/ServiceStack.Blazor.Tests/Server/Configure.AppHost.cs b/tests/ServiceStack.Blazor.Tests/Server/Configure.AppHost.cs new file mode 100644 index 00000000000..f9a5a24fa4a --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Configure.AppHost.cs @@ -0,0 +1,29 @@ +using Funq; +using ServiceStack; +using MyApp.ServiceInterface; + +[assembly: HostingStartup(typeof(MyApp.AppHost))] + +namespace MyApp; + +public class AppHost : AppHostBase, IHostingStartup +{ + public AppHost() : base("MyApp", typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + }); + + Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type,Authorization", + allowOriginWhitelist: new[]{ + "http://localhost:5000", + "https://localhost:5001", + "https://" + Environment.GetEnvironmentVariable("DEPLOY_CDN") + }, allowCredentials: true)); + } + + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices((context, services) => + services.ConfigureNonBreakingSameSiteCookies(context.HostingEnvironment)); +} diff --git a/tests/ServiceStack.Blazor.Tests/Server/Configure.Auth.cs b/tests/ServiceStack.Blazor.Tests/Server/Configure.Auth.cs new file mode 100644 index 00000000000..8fef3dcda2b --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Configure.Auth.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Hosting; +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.FluentValidation; + +[assembly: HostingStartup(typeof(MyApp.ConfigureAuth))] + +namespace MyApp; + +// Add any additional metadata properties you want to store in the Users Typed Session +public class CustomUserSession : AuthUserSession +{ +} + +// Custom Validator to add custom validators to built-in /register Service requiring DisplayName and ConfirmPassword +public class CustomRegistrationValidator : RegistrationValidator +{ + public CustomRegistrationValidator() + { + RuleSet(ApplyTo.Post, () => + { + RuleFor(x => x.DisplayName).NotEmpty(); + RuleFor(x => x.ConfirmPassword).NotEmpty(); + }); + } +} + +public class ConfigureAuth : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) => builder + //.ConfigureServices(services => services.AddSingleton(new MemoryCacheClient())) + .ConfigureAppHost(appHost => + { + var appSettings = appHost.AppSettings; + appHost.Plugins.Add(new AuthFeature(() => new CustomUserSession(), + new IAuthProvider[] { + new JwtAuthProvider(appSettings) { + AuthKeyBase64 = appSettings.GetString("AuthKeyBase64") ?? "cARl12kvS/Ra4moVBIaVsrWwTpXYuZ0mZf/gNLUhDW5=", + }, + new CredentialsAuthProvider(appSettings), /* Sign In with Username / Password credentials */ + new FacebookAuthProvider(appSettings), /* Create App https://developers.facebook.com/apps */ + new GoogleAuthProvider(appSettings), /* Create App https://console.developers.google.com/apis/credentials */ + new MicrosoftGraphAuthProvider(appSettings), /* Create App https://apps.dev.microsoft.com */ + }) + { + IncludeDefaultLogin = false + }); + + appHost.Plugins.Add(new RegistrationFeature()); //Enable /register Service + + //override the default registration validation with your own custom implementation + appHost.RegisterAs>(); + }); +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/Configure.AuthRepository.cs b/tests/ServiceStack.Blazor.Tests/Server/Configure.AuthRepository.cs new file mode 100644 index 00000000000..28a6f40be31 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Configure.AuthRepository.cs @@ -0,0 +1,134 @@ +using ServiceStack; +using ServiceStack.Web; +using ServiceStack.Data; +using ServiceStack.Html; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using MyApp.Client; + +[assembly: HostingStartup(typeof(MyApp.ConfigureAuthRepository))] + +namespace MyApp; + +public enum Department +{ + None, + Marketing, + Accounts, + Legal, + HumanResources, +} + +// Custom User Table with extended Metadata properties +public class AppUser : UserAuth +{ + public Department Department { get; set; } + public string? ProfileUrl { get; set; } + public string? LastLoginIp { get; set; } + + public bool IsArchived { get; set; } + public DateTime? ArchivedDate { get; set; } + + public DateTime? LastLoginDate { get; set; } +} + +public class AppUserAuthEvents : AuthEvents +{ + public override async Task OnAuthenticatedAsync(IRequest httpReq, IAuthSession session, IServiceBase authService, + IAuthTokens tokens, Dictionary authInfo, CancellationToken token = default) + { + var authRepo = HostContext.AppHost.GetAuthRepositoryAsync(httpReq); + using (authRepo as IDisposable) + { + var userAuth = (AppUser)await authRepo.GetUserAuthAsync(session.UserAuthId, token); + userAuth.ProfileUrl = session.GetProfileUrl(); + userAuth.LastLoginIp = httpReq.UserHostAddress; + userAuth.LastLoginDate = DateTime.UtcNow; + await authRepo.SaveUserAuthAsync(userAuth, token); + } + } +} + +public class ConfigureAuthRepository : IHostingStartup +{ + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices(services => services.AddSingleton(c => + new OrmLiteAuthRepository(c.Resolve()) { + UseDistinctRoleTables = true + })) + .ConfigureAppHost(appHost => { + var authRepo = appHost.Resolve(); + authRepo.InitSchema(); + CreateUser(authRepo, "admin@email.com", "Admin User", "p@55wOrd", roles: new[] { RoleNames.Admin }); + CreateUser(authRepo, "manager@email.com", "The Manager", "p@55wOrd", roles: new[] { AppRoles.Employee, AppRoles.Manager }); + CreateUser(authRepo, "employee@email.com", "A Employee", "p@55wOrd", roles: new[] { AppRoles.Employee }); + + // Removing unused UserName in Admin Users UI + appHost.Plugins.Add(new ServiceStack.Admin.AdminUsersFeature { + + // Show custom fields in Search Results + QueryUserAuthProperties = new() { + nameof(AppUser.Id), + nameof(AppUser.Email), + nameof(AppUser.DisplayName), + nameof(AppUser.Department), + nameof(AppUser.CreatedDate), + nameof(AppUser.LastLoginDate), + }, + + QueryMediaRules = new() + { + MediaRules.ExtraSmall.Show(x => new { x.Id, x.Email, x.DisplayName }), + MediaRules.Small.Show(x => x.Department), + }, + + // Add Custom Fields to Create/Edit User Forms + UserFormLayout = new() { + new() + { + Input.For(x => x.Email), + }, + new() + { + Input.For(x => x.DisplayName), + }, + new() + { + Input.For(x => x.Company), + Input.For(x => x.Department), + }, + new() { + Input.For(x => x.PhoneNumber, c => c.Type = Input.Types.Tel) + }, + new() { + Input.For(x => x.Nickname, c => { + c.Help = "Public alias (3-12 lower alpha numeric chars)"; + c.Pattern = "^[a-z][a-z0-9_.-]{3,12}$"; + //c.Required = true; + }) + }, + new() { + Input.For(x => x.ProfileUrl, c => c.Type = Input.Types.Url) + }, + new() { + Input.For(x => x.IsArchived), Input.For(x => x.ArchivedDate), + }, + } + }); + + }, + afterConfigure: appHost => { + appHost.AssertPlugin().AuthEvents.Add(new AppUserAuthEvents()); + }); + + // Add initial Users to the configured Auth Repository + public void CreateUser(IAuthRepository authRepo, string email, string name, string password, string[] roles) + { + if (authRepo.GetUserAuthByUserName(email) == null) + { + var newAdmin = new AppUser { Email = email, DisplayName = name }; + var user = authRepo.CreateUserAuth(newAdmin, password); + authRepo.AssignRoles(user, roles); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/Configure.AutoQuery.cs b/tests/ServiceStack.Blazor.Tests/Server/Configure.AutoQuery.cs new file mode 100644 index 00000000000..06a197ef215 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Configure.AutoQuery.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Hosting; +using ServiceStack; +using ServiceStack.Data; + +[assembly: HostingStartup(typeof(MyApp.ConfigureAutoQuery))] + +namespace MyApp +{ + public class ConfigureAutoQuery : IHostingStartup + { + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices(services => { + // Enable Audit History + services.AddSingleton(c => + new OrmLiteCrudEvents(c.Resolve())); + }) + .ConfigureAppHost(appHost => { + + // For TodosService + appHost.Plugins.Add(new AutoQueryDataFeature()); + + // For Bookings https://github.com/NetCoreApps/BookingsCrud + appHost.Plugins.Add(new AutoQueryFeature { + MaxLimit = 1000, + //IncludeTotal = true, + }); + + appHost.Resolve().InitSchema(); + }); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/Configure.Db.cs b/tests/ServiceStack.Blazor.Tests/Server/Configure.Db.cs new file mode 100644 index 00000000000..641d855b9d4 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Configure.Db.cs @@ -0,0 +1,50 @@ +using MyApp.ServiceModel; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using System.Data; + +[assembly: HostingStartup(typeof(MyApp.ConfigureDb))] + +namespace MyApp +{ + public class ConfigureDb : IHostingStartup + { + public void Configure(IWebHostBuilder builder) => builder + .ConfigureServices((context,services) => services.AddSingleton(new OrmLiteConnectionFactory( + context.Configuration.GetConnectionString("DefaultConnection") ?? ":memory:", + SqliteDialect.Provider))) + .ConfigureAppHost(appHost => + { + // Create non-existing Table and add Seed Data Example + using var db = appHost.Resolve().Open(); + if (db.CreateTableIfNotExists()) + { + db.CreateBooking("First Booking!", RoomType.Queen, 10, 100, "employee@email.com"); + db.CreateBooking("Booking 2", RoomType.Double, 12, 120, "manager@email.com"); + db.CreateBooking("Booking the 3rd", RoomType.Suite, 13, 130, "employee@email.com"); + } + }); + } + + public static class ConfigureDbUtils + { + static int bookingId = 0; + public static void CreateBooking(this IDbConnection db, string name, RoomType type, int roomNo, decimal cost, string by) => + db.Insert(new Booking + { + Id = ++bookingId, + Name = name, + RoomType = type, + RoomNumber = roomNo, + Cost = cost, + BookingStartDate = DateTime.UtcNow.AddDays(bookingId), + BookingEndDate = DateTime.UtcNow.AddDays(bookingId + 7), + CreatedBy = by, + CreatedDate = DateTime.UtcNow, + ModifiedBy = by, + ModifiedDate = DateTime.UtcNow, + }); + + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Server/MyApp.Server.csproj b/tests/ServiceStack.Blazor.Tests/Server/MyApp.Server.csproj new file mode 100644 index 00000000000..5bc1510bf4f --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/MyApp.Server.csproj @@ -0,0 +1,39 @@ + + + + net6.0 + enable + enable + MyApp + MyApp + + + + + + + + + + + + + + + + + $(MSBuildProjectDirectory)/../Client + $(ClientDir)/wwwroot + $(MSBuildProjectDirectory)/../Tests + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/Pages/Error.cshtml b/tests/ServiceStack.Blazor.Tests/Server/Pages/Error.cshtml new file mode 100644 index 00000000000..a74841311c3 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Pages/Error.cshtml @@ -0,0 +1,42 @@ +@page +@model MyApp.Pages.ErrorModel + + + + + + + + Error + + + + + +
+
+

Error.

+

An error occurred while processing your request.

+ + @if (Model.ShowRequestId) + { +

+ Request ID: @Model.RequestId +

+ } + +

Development Mode

+

+ Swapping to the Development environment displays detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

+
+
+ + + diff --git a/tests/ServiceStack.Blazor.Tests/Server/Pages/Error.cshtml.cs b/tests/ServiceStack.Blazor.Tests/Server/Pages/Error.cshtml.cs new file mode 100644 index 00000000000..f3fa486409d --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Pages/Error.cshtml.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using System.Diagnostics; + +namespace MyApp.Pages +{ + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + [IgnoreAntiforgeryToken] + public class ErrorModel : PageModel + { + public string? RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + private readonly ILogger _logger; + + public ErrorModel(ILogger logger) + { + _logger = logger; + } + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/Program.cs b/tests/ServiceStack.Blazor.Tests/Server/Program.cs new file mode 100644 index 00000000000..09054912936 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Program.cs @@ -0,0 +1,37 @@ +using ServiceStack; +using MyApp; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddControllersWithViews(); +builder.Services.AddRazorPages(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); +} +else +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + app.UseHttpsRedirection(); +} +app.UseHttpsRedirection(); +app.UseBlazorFrameworkFiles(); +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseServiceStack(new AppHost()); + +app.UseEndpoints(endpoints => +{ + endpoints.MapRazorPages(); + endpoints.MapControllers(); + endpoints.MapFallbackToFile("index.html"); +}); + + +app.Run(); diff --git a/tests/ServiceStack.Blazor.Tests/Server/Properties/launchSettings.json b/tests/ServiceStack.Blazor.Tests/Server/Properties/launchSettings.json new file mode 100644 index 00000000000..426fb261758 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:8345", + "sslPort": 44311 + } + }, + "profiles": { + "MyApp": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } + } diff --git a/tests/ServiceStack.Blazor.Tests/Server/ServiceInterface/MyServices.cs b/tests/ServiceStack.Blazor.Tests/Server/ServiceInterface/MyServices.cs new file mode 100644 index 00000000000..f1d55ba85aa --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/ServiceInterface/MyServices.cs @@ -0,0 +1,18 @@ +using ServiceStack; +using MyApp.ServiceModel; +using System; + +namespace MyApp.ServiceInterface; + +public class MyServices : Service +{ + public static string AssertName(string Name) => Name.IsNullOrEmpty() + ? throw new ArgumentNullException(nameof(Name)) + : Name; + + public object Any(Hello request) => + new HelloResponse { Result = $"Hello, {AssertName(request.Name)}!" }; + + public object Any(HelloSecure request) => + new HelloResponse { Result = $"Hello, {AssertName(request.Name)}!" }; +} diff --git a/tests/ServiceStack.Blazor.Tests/Server/ServiceInterface/TodosServices.cs b/tests/ServiceStack.Blazor.Tests/Server/ServiceInterface/TodosServices.cs new file mode 100644 index 00000000000..98626aa32c4 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/ServiceInterface/TodosServices.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using ServiceStack; +using MyApp.ServiceModel; + +namespace MyApp.ServiceInterface; + +public class TodosServices : Service +{ + public IAutoQueryData AutoQuery { get; set; } + + static readonly PocoDataSource Todos = PocoDataSource.Create(new Todo[] + { + new () { Id = 1, Text = "Learn" }, + new () { Id = 2, Text = "Blazor", IsFinished = true }, + new () { Id = 3, Text = "WASM!" }, + }, nextId: x => x.Select(e => e.Id).Max()); + + public object Get(QueryTodos query) + { + var db = Todos.ToDataSource(query, Request); + return AutoQuery.Execute(query, AutoQuery.CreateQuery(query, Request, db), db); + } + + public Todo Post(CreateTodo request) + { + var newTodo = new Todo { Id = Todos.NextId(), Text = request.Text }; + Todos.Add(newTodo); + return newTodo; + } + + public Todo Put(UpdateTodo request) + { + var todo = request.ConvertTo(); + Todos.TryUpdateById(todo, todo.Id); + return todo; + } + + // Handles Deleting the Todo item + public void Delete(DeleteTodo request) => Todos.TryDeleteById(request.Id); + + public void Delete(DeleteTodos request) => Todos.TryDeleteByIds(request.Ids); +} diff --git a/tests/ServiceStack.Blazor.Tests/Server/appsettings.Development.json b/tests/ServiceStack.Blazor.Tests/Server/appsettings.Development.json new file mode 100644 index 00000000000..0c208ae9181 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Server/appsettings.json b/tests/ServiceStack.Blazor.Tests/Server/appsettings.json new file mode 100644 index 00000000000..10f68b8c8b4 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/tests/ServiceStack.Blazor.Tests/Server/modules/shared/Brand.html b/tests/ServiceStack.Blazor.Tests/Server/modules/shared/Brand.html new file mode 100644 index 00000000000..5929c6dd1cf --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/modules/shared/Brand.html @@ -0,0 +1,19 @@ + + \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/modules/ui/docs/CreateBookingsDocs.html b/tests/ServiceStack.Blazor.Tests/Server/modules/ui/docs/CreateBookingsDocs.html new file mode 100644 index 00000000000..06b6cb0ebcf --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/modules/ui/docs/CreateBookingsDocs.html @@ -0,0 +1,34 @@ + + \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Server/modules/ui/docs/TodosDocs.html b/tests/ServiceStack.Blazor.Tests/Server/modules/ui/docs/TodosDocs.html new file mode 100644 index 00000000000..42ed990f9a1 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Server/modules/ui/docs/TodosDocs.html @@ -0,0 +1,40 @@ + + \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/ServiceModel/Bookings.cs b/tests/ServiceStack.Blazor.Tests/ServiceModel/Bookings.cs new file mode 100644 index 00000000000..7417bbc9b92 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/ServiceModel/Bookings.cs @@ -0,0 +1,96 @@ +// Complete declarative AutoQuery services for Bookings CRUD example: +// https://docs.servicestack.net/autoquery-crud-bookings + +using System; +using ServiceStack; +using ServiceStack.DataAnnotations; + +namespace MyApp.ServiceModel; + +[Description("Booking Details")] +[Notes("Captures a Persons Name & Room Booking information")] +public class Booking : AuditBase +{ + [AutoIncrement] + public int Id { get; set; } + public string Name { get; set; } + public RoomType RoomType { get; set; } + public int RoomNumber { get; set; } + public DateTime BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + public decimal Cost { get; set; } + public string? Notes { get; set; } + public bool? Cancelled { get; set; } +} + +public enum RoomType +{ + Single, + Double, + Queen, + Twin, + Suite, +} + +[Tag("bookings"), Description("Find Bookings")] +[Notes("Find out how to quickly create a C# Bookings App from Scratch")] +[Route("/bookings", "GET")] +[Route("/bookings/{Id}", "GET")] +[AutoApply(Behavior.AuditQuery)] +public class QueryBookings : QueryDb +{ + public int? Id { get; set; } +} + +// Uncomment below to enable DeletedBookings API to view deleted bookings: +// [Route("/bookings/deleted")] +// [AutoFilter(QueryTerm.Ensure, nameof(AuditBase.DeletedDate), Template = SqlTemplate.IsNotNull)] +// public class DeletedBookings : QueryDb {} + +[Tag("bookings"), Description("Create a new Booking")] +[Route("/bookings", "POST")] +[ValidateHasRole("Employee")] +[AutoApply(Behavior.AuditCreate)] +public class CreateBooking : ICreateDb, IReturn +{ + [Description("Name this Booking is for"), ValidateNotEmpty] + public string Name { get; set; } + public RoomType RoomType { get; set; } + [ValidateGreaterThan(0)] + public int RoomNumber { get; set; } + [ValidateGreaterThan(0)] + public decimal Cost { get; set; } + public DateTime BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + [Input(Type = "textarea")] + public string? Notes { get; set; } +} + +[Tag("bookings"), Description("Update an existing Booking")] +[Route("/booking/{Id}", "PATCH")] +[ValidateHasRole("Employee")] +[AutoApply(Behavior.AuditModify)] +public class UpdateBooking : IPatchDb, IReturn +{ + public int Id { get; set; } + public string? Name { get; set; } + public RoomType? RoomType { get; set; } + [ValidateGreaterThan(0)] + public int? RoomNumber { get; set; } + [ValidateGreaterThan(0)] + public decimal? Cost { get; set; } + public DateTime? BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + // [Input(Type = "textarea")] + public string? Notes { get; set; } + public bool? Cancelled { get; set; } +} + +[Tag("bookings"), Description("Delete a Booking")] +[Route("/booking/{Id}", "DELETE")] +[ValidateHasRole("Manager")] +[AutoApply(Behavior.AuditSoftDelete)] +public class DeleteBooking : IDeleteDb, IReturnVoid +{ + public int Id { get; set; } +} diff --git a/tests/ServiceStack.Blazor.Tests/ServiceModel/Hello.cs b/tests/ServiceStack.Blazor.Tests/ServiceModel/Hello.cs new file mode 100644 index 00000000000..62aa67bc579 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/ServiceModel/Hello.cs @@ -0,0 +1,22 @@ +using ServiceStack; + +namespace MyApp.ServiceModel; + +[Route("/hello/{Name}")] +public class Hello : IReturn +{ + public string Name { get; set; } +} + +[Route("/hellosecure/{Name}")] +[ValidateIsAuthenticated] +public class HelloSecure : IReturn +{ + public string Name { get; set; } +} + +public class HelloResponse +{ + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/ServiceModel/MyApp.ServiceModel.csproj b/tests/ServiceStack.Blazor.Tests/ServiceModel/MyApp.ServiceModel.csproj new file mode 100644 index 00000000000..2c767015087 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/ServiceModel/MyApp.ServiceModel.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + MyApp.ServiceModel + + + + + + + + + + diff --git a/tests/ServiceStack.Blazor.Tests/ServiceModel/Todos.cs b/tests/ServiceStack.Blazor.Tests/ServiceModel/Todos.cs new file mode 100644 index 00000000000..274b60c7762 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/ServiceModel/Todos.cs @@ -0,0 +1,53 @@ +using ServiceStack; +using ServiceStack.Model; +using System.Collections.Generic; + +namespace MyApp.ServiceModel; + +[Tag("todos")] +[Route("/todos", "GET")] +public class QueryTodos : QueryData +{ + public int? Id { get; set; } + public List? Ids { get; set; } + public string? TextContains { get; set; } +} + +[Tag("todos")] +[Route("/todos", "POST")] +public class CreateTodo : IPost, IReturn +{ + [ValidateNotEmpty] + public string Text { get; set; } +} + +[Tag("todos")] +[Route("/todos/{Id}", "PUT")] +public class UpdateTodo : IPut, IReturn +{ + public long Id { get; set; } + [ValidateNotEmpty] + public string Text { get; set; } + public bool IsFinished { get; set; } +} + +[Tag("todos")] +[Route("/todos/{Id}", "DELETE")] +public class DeleteTodo : IDelete, IReturnVoid +{ + public long Id { get; set; } +} + +[Tag("todos")] +[Route("/todos", "DELETE")] +public class DeleteTodos : IDelete, IReturnVoid +{ + public List Ids { get; set; } +} + +public class Todo : IHasId +{ + public long Id { get; set; } + public string Text { get; set; } + public bool IsFinished { get; set; } +} diff --git a/tests/ServiceStack.Blazor.Tests/ServiceModel/WeatherForecast.cs b/tests/ServiceStack.Blazor.Tests/ServiceModel/WeatherForecast.cs new file mode 100644 index 00000000000..326218c6ada --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/ServiceModel/WeatherForecast.cs @@ -0,0 +1,14 @@ +using System; + +namespace MyApp.ServiceModel; + +public class WeatherForecast +{ + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public string Summary { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/tests/ServiceStack.Blazor.Tests/Tests/IntegrationTest.cs b/tests/ServiceStack.Blazor.Tests/Tests/IntegrationTest.cs new file mode 100644 index 00000000000..a43f734fb64 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Tests/IntegrationTest.cs @@ -0,0 +1,44 @@ +using Funq; +using ServiceStack; +using NUnit.Framework; +using MyApp.ServiceInterface; +using MyApp.ServiceModel; + +namespace MyApp.Tests; + +public class IntegrationTest +{ + const string BaseUri = "http://localhost:2000/"; + private readonly ServiceStackHost appHost; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(IntegrationTest), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + } + } + + public IntegrationTest() + { + appHost = new AppHost() + .Init() + .Start(BaseUri); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + public IServiceClient CreateClient() => new JsonServiceClient(BaseUri); + + [Test] + public void Can_call_Hello_Service() + { + var client = CreateClient(); + + var response = client.Get(new Hello { Name = "World" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/Tests/MyApp.Tests.csproj b/tests/ServiceStack.Blazor.Tests/Tests/MyApp.Tests.csproj new file mode 100644 index 00000000000..9583b12dced --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Tests/MyApp.Tests.csproj @@ -0,0 +1,37 @@ + + + + net6.0 + enable + false + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.Blazor.Tests/Tests/PrerenderTasks.cs b/tests/ServiceStack.Blazor.Tests/Tests/PrerenderTasks.cs new file mode 100644 index 00000000000..67482fc749a --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Tests/PrerenderTasks.cs @@ -0,0 +1,156 @@ +using System; +using System.IO; +using System.Text; +using System.Reflection; +using System.Threading.Tasks; +using ServiceStack; +using ServiceStack.IO; +using ServiceStack.Text; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Configuration; +using NUnit.Framework; +using Bunit; +using static System.Console; +using RouteAttribute = Microsoft.AspNetCore.Components.RouteAttribute; + +namespace MyApp.Tests; + +[TestFixture, Category("prerender")] +public class PrerenderTasks +{ + Bunit.TestContext Context; + string ClientDir; + string WwrootDir => ClientDir.CombineWith("wwwroot"); + string PrerenderDir => WwrootDir.CombineWith("prerender"); + + public PrerenderTasks() + { + Context = new(); + var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); + ClientDir = config[nameof(ClientDir)] + ?? throw new Exception($"{nameof(ClientDir)} not defined in appsettings.json"); + FileSystemVirtualFiles.RecreateDirectory(PrerenderDir); + } + + void Render(params ComponentParameter[] parameters) where T : IComponent + { + WriteLine($"Rendering: {typeof(T).FullName}..."); + var component = Context.RenderComponent(parameters); + var route = typeof(T).GetCustomAttribute()?.Template; + if (string.IsNullOrEmpty(route)) + throw new Exception($"Couldn't infer @page for component {typeof(T).Name}"); + + var fileName = route.EndsWith("/") ? route + "index.html" : $"{route}.html"; + + var writeTo = Path.GetFullPath(PrerenderDir.CombineWith(fileName)); + WriteLine($"Written to {writeTo}"); + File.WriteAllText(writeTo, component.Markup); + } + + [Test] + public void PrerenderPages() + { + Render(); + } + + [Test] + public async Task PrerenderMarkdown() + { + var srcDir = WwrootDir.CombineWith("content").Replace('\\', '/'); + var dstDir = WwrootDir.CombineWith("docs").Replace('\\', '/'); + + var indexPage = PageTemplate.Create(WwrootDir.CombineWith("index.html")); + if (!Directory.Exists(srcDir)) throw new Exception($"{Path.GetFullPath(srcDir)} does not exist"); + FileSystemVirtualFiles.RecreateDirectory(dstDir); + + foreach (var file in new DirectoryInfo(srcDir).GetFiles("*.md", SearchOption.AllDirectories)) + { + WriteLine($"Converting {file.FullName} ..."); + + var name = file.Name.WithoutExtension(); + var docRender = await Client.MarkdownUtils.LoadDocumentAsync(name, doc => + Task.FromResult(File.ReadAllText(file.FullName))); + + if (docRender.Failed) + { + WriteLine($"Failed: {docRender.ErrorMessage}"); + continue; + } + + var dirName = dstDir.IndexOf("wwwroot") >= 0 + ? dstDir.LastRightPart("wwwroot").Replace('\\', '/') + : new DirectoryInfo(dstDir).Name; + var path = dirName.CombineWith(name == "index" ? "" : name); + + var mdBody = @$" +
+
+ {docRender.Response!.Preview!} +
+
"; + var prerenderedPage = indexPage.Render(mdBody); + string htmlPath = Path.GetFullPath(Path.Combine(dstDir, $"{name}.html")); + File.WriteAllText(htmlPath, prerenderedPage); + WriteLine($"Written to {htmlPath}"); + } + } +} + + +/// +/// Parses index.html and uses its layout to generate prerendered pages inside +/// +public class PageTemplate +{ + string? Header { get; set; } + string? Footer { get; set; } + + public PageTemplate(string? header, string? footer) + { + Header = header; + Footer = footer; + } + + public static PageTemplate Create(string indexPath) + { + if (!File.Exists(indexPath)) + throw new Exception($"{Path.GetFullPath(indexPath)} does not exist"); + + string? header = null; + string? footer = null; + + var sb = new StringBuilder(); + foreach (var line in File.ReadAllLines(indexPath)) + { + if (header == null) + { + if (line.Contains("")) + { + header = sb.ToString(); // capture up to start page marker + sb.Clear(); + } + else sb.AppendLine(line); + } + else + { + if (sb.Length == 0) + { + if (line.Contains("")) // discard up to end page marker + { + sb.AppendLine(); + continue; + } + } + else sb.AppendLine(line); + } + } + footer = sb.ToString(); + + if (string.IsNullOrEmpty(header) || string.IsNullOrEmpty(footer)) + throw new Exception($"Parsing {indexPath} failed, missing ... markers"); + + return new PageTemplate(header, footer); + } + + public string Render(string body) => Header + body + Footer; +} diff --git a/tests/ServiceStack.Blazor.Tests/Tests/UnitTest.cs b/tests/ServiceStack.Blazor.Tests/Tests/UnitTest.cs new file mode 100644 index 00000000000..08dd1e6f2de --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Tests/UnitTest.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Testing; +using MyApp.ServiceInterface; +using MyApp.ServiceModel; + +namespace MyApp.Tests; + +public class UnitTest +{ + private readonly ServiceStackHost appHost; + + public UnitTest() + { + appHost = new BasicAppHost().Init(); + appHost.Container.AddTransient(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_call_MyServices() + { + var service = appHost.Container.Resolve(); + + var response = (HelloResponse)service.Any(new Hello { Name = "World" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } +} diff --git a/tests/ServiceStack.Blazor.Tests/Tests/appsettings.json b/tests/ServiceStack.Blazor.Tests/Tests/appsettings.json new file mode 100644 index 00000000000..74951394d98 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/Tests/appsettings.json @@ -0,0 +1,3 @@ +{ + "ClientDir": "../../../../Client" +} \ No newline at end of file diff --git a/tests/ServiceStack.Blazor.Tests/sync.bat b/tests/ServiceStack.Blazor.Tests/sync.bat new file mode 100644 index 00000000000..9823240e4f2 --- /dev/null +++ b/tests/ServiceStack.Blazor.Tests/sync.bat @@ -0,0 +1,21 @@ +set TO=..\..\..\NetCoreTemplates\blazor-wasm\MyApp.Client + +COPY %TO%\MyApp.Client.csproj . +RD /q /s %TO%\MyApp.Client +MD %TO%\MyApp.Client +XCOPY /Y /E /H /C /I Client %TO%\ +MOVE MyApp.Client.csproj %TO%\ + +REM /shared/Brand.html unique to blazor-wasm +REM RD /q /s ..\..\..\NetCoreTemplates\nextjs\ui\public\modules\ +REM RD /q /s ..\..\..\NetCoreTemplates\vue-ssg\ui\public\modules\ +REM RD /q /s ..\..\..\NetCoreTemplates\vue-vite\ui\public\modules\ +RD /q /s ..\..\..\NetCoreTemplates\blazor-wasm\MyApp\wwwroot\modules\ +REM XCOPY /Y /E /H /C /I Server\modules ..\..\..\NetCoreTemplates\nextjs\ui\public\modules\ +REM XCOPY /Y /E /H /C /I Server\modules ..\..\..\NetCoreTemplates\vue-ssg\ui\publicwwwroot\modules\ +REM XCOPY /Y /E /H /C /I Server\modules ..\..\..\NetCoreTemplates\vue-vite\ui\public\modules\ +XCOPY /Y /E /H /C /I Server\modules ..\..\..\NetCoreTemplates\blazor-wasm\MyApp\wwwroot\modules\ + +COPY Server\*.cs ..\..\..\NetCoreTemplates\blazor-wasm\MyApp\ +COPY ServiceModel\*.cs ..\..\..\NetCoreTemplates\blazor-wasm\MyApp.ServiceModel\ +COPY Tests\*.cs ..\..\..\NetCoreTemplates\blazor-wasm\MyApp.Tests\ diff --git a/tests/ServiceStack.Common.Tests/ActionExecTests.cs b/tests/ServiceStack.Common.Tests/ActionExecTests.cs new file mode 100644 index 00000000000..58aebe5712b --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ActionExecTests.cs @@ -0,0 +1,40 @@ +#if !NETCORE +using System; +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class ActionExecTests + { + [Test] + public void Can_run_blocking_options_in_parallel() + { + var sw = Stopwatch.StartNew(); + + int i = 0; + + Action incrAndBlock = () => { Interlocked.Increment(ref i); Thread.Sleep(100); }; + + var actions = new[] + { + incrAndBlock, + incrAndBlock, + incrAndBlock, + incrAndBlock, + incrAndBlock, + incrAndBlock, + }; + + actions.ExecAllAndWait(timeout:TimeSpan.FromSeconds(30)); + + "Took {0}ms".Print(sw.ElapsedMilliseconds); + Assert.That(sw.ElapsedMilliseconds, Is.LessThan(400)); + Assert.That(i, Is.EqualTo(actions.Length)); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/AllowFilesTests.cs b/tests/ServiceStack.Common.Tests/AllowFilesTests.cs new file mode 100644 index 00000000000..2bd304783c5 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/AllowFilesTests.cs @@ -0,0 +1,34 @@ +using NUnit.Framework; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class AllowFilesTests + { + [Test] + public void Does_allow_valid_FilePaths() + { + using (new BasicAppHost + { + ConfigFilter = config => + { + config.AllowFileExtensions.Add("aaa"); + config.AllowFilePaths.Add("dir/**/*.zzz"); + } + }.Init()) + { + Assert.That(HttpHandlerFactory.ShouldAllow("a.js")); + Assert.That(HttpHandlerFactory.ShouldAllow("a.aaa")); + Assert.That(HttpHandlerFactory.ShouldAllow("dir/a/b/c/a.aaa")); + Assert.That(!HttpHandlerFactory.ShouldAllow("a.zzz")); + Assert.That(HttpHandlerFactory.ShouldAllow("dir/a.zzz")); + Assert.That(HttpHandlerFactory.ShouldAllow("dir/a/b/c/a.zzz")); + + Assert.That(!HttpHandlerFactory.ShouldAllow("a.json")); + Assert.That(HttpHandlerFactory.ShouldAllow("jspm_packages/a.json")); + Assert.That(HttpHandlerFactory.ShouldAllow("jspm_packages/a/b/c/a.json")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/App.config b/tests/ServiceStack.Common.Tests/App.config new file mode 100644 index 00000000000..be25b8bf498 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/App.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.Common.Tests/AttributeTests.cs b/tests/ServiceStack.Common.Tests/AttributeTests.cs new file mode 100644 index 00000000000..71321248510 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/AttributeTests.cs @@ -0,0 +1,108 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +#if !NETCORE +using System; +using System.ComponentModel; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + public interface INormalAttribute + { + string Name { get; set; } + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class NormalAttribute : Attribute, INormalAttribute + { + public string Name { get; set; } + + public NormalAttribute(string name) + { + Name = name; + } + } + + public interface IBaseAttribute + { + string Name { get; set; } + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class BaseAttribute : AttributeBase, IBaseAttribute + { + public string Name { get; set; } + + public BaseAttribute(string name) + { + Name = name; + } + } + + [Normal("a")] + [Base("b")] + public class SingleAttr {} + + [Normal("a1")] + [Normal("a2")] + [Base("b1")] + [Base("b2")] + public class ManyAttr { } + + [Normal("a1")] + [Normal("a2")] + public class RuntimeManyNormalAttr { } + + [Base("b1")] + [Base("b2")] + public class RuntimeManyBaseAttr { } + + + [TestFixture] + public class AttributeTests + { + [Test] + public void Does_return_on_FirstAttribute() + { + var o = new SingleAttr(); + + Assert.That(o.GetType().FirstAttribute().Name, Is.EqualTo("a")); + Assert.That(o.GetType().FirstAttribute().Name, Is.EqualTo("b")); + + Assert.That(o.GetType().FirstAttribute().Name, Is.EqualTo("a")); + Assert.That(o.GetType().FirstAttribute().Name, Is.EqualTo("b")); + } + + [Test] + public void Normal_attribute_returns_all_in_AllAttributes() + { + var o = new ManyAttr(); + + Assert.That(o.GetType().AllAttributes().Length, Is.EqualTo(2)); + Assert.That(o.GetType().AllAttributes().Length, Is.EqualTo(2)); + } + + [Test] + public void AttributeBase_attribute_returns_all_in_AllAttributes() + { + var o = new ManyAttr(); + + Assert.That(o.GetType().AllAttributes().Length, Is.EqualTo(2)); + Assert.That(o.GetType().AllAttributes().Length, Is.EqualTo(2)); + } + + [Test] + public void Can_add_attributes_at_runtime_to_BaseAttribute() + { + typeof(RuntimeManyBaseAttr).AddAttributes(new BaseAttribute("b3")); + + var o = new RuntimeManyBaseAttr(); + + Assert.That(o.GetType().AllAttributes().Length, Is.EqualTo(3)); + Assert.That(o.GetType().AllAttributes().Length, Is.EqualTo(3)); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/CheckWebTests.cs b/tests/ServiceStack.Common.Tests/CheckWebTests.cs new file mode 100644 index 00000000000..1a47fc0cdda --- /dev/null +++ b/tests/ServiceStack.Common.Tests/CheckWebTests.cs @@ -0,0 +1,56 @@ +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + /// + /// The Echo interface. + /// + public interface IEcho + { + /// + /// Gets or sets the sentence to echo. + /// + string Sentence { get; set; } + } + + /// + /// The Echo. + /// + public class Echo : IEcho + { + /// + /// Gets or sets the sentence. + /// + public string Sentence { get; set; } + } + + [Api("Echoes a sentence")] + [Route("/echoes", "POST", Summary = @"Echoes a sentence.")] + public class Echoes : IReturn + { + /// + /// Gets or sets the sentence to echo. + /// + [ApiMember(Name = "Sentence", + DataType = "string", + Description = "The sentence to echo.", + IsRequired = true, + ParameterType = "form")] + public string Sentence { get; set; } + } + + [Ignore("Integration Test")] + public class CheckWebTests + { + private const string BaseUri = "http://localhost:55799/"; + + [Test] + public void Can_send_echoes_POST() + { + var client = new JsonServiceClient(BaseUri); + + var response = client.Post(new Echoes { Sentence = "Foo" }); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Configuration/AppSettingsTests.cs b/tests/ServiceStack.Common.Tests/Configuration/AppSettingsTests.cs index 891e707956e..252d4177023 100644 --- a/tests/ServiceStack.Common.Tests/Configuration/AppSettingsTests.cs +++ b/tests/ServiceStack.Common.Tests/Configuration/AppSettingsTests.cs @@ -1,25 +1,326 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Configuration; +using System.Linq; using NUnit.Framework; using ServiceStack.Configuration; +using ServiceStack.OrmLite; +using ServiceStack.Text; namespace ServiceStack.Common.Tests { - public class AppSettingsTest +#if NETCORE + using Microsoft.Extensions.Configuration; + + public class NetCoreAppSettingsMemoryCollectionTest : AppSettingsTest + { + public override IAppSettings GetAppSettings() + { + var input = new Dictionary + { + {"NullableKey", null}, + {"EmptyKey", string.Empty}, + {"RealKey", "This is a real value"}, + //{"ListKey", "A,B,C,D,E"}, + {"ListKey:0", "A"}, + {"ListKey:1", "B"}, + {"ListKey:2", "C"}, + {"ListKey:3", "D"}, + {"ListKey:4", "E"}, + {"IntKey", "42"}, + {"BadIntegerKey", "This is not an integer"}, + {"DictionaryKey:A", "1"}, + {"DictionaryKey:B", "2"}, + {"DictionaryKey:C", "3"}, + {"DictionaryKey:D", "4"}, + {"DictionaryKey:E", "5"}, + {"BadDictionaryKey", "A1,B"}, + {"ObjectNoLineFeed", "{SomeSetting:Test,SomeOtherSetting:12,FinalSetting:Final}"}, + {"ObjectWithLineFeed", "{SomeSetting:Test,\r\nSomeOtherSetting:12,\r\nFinalSetting:Final}"}, + {"Email:From", "test@email.com"}, + {"Email:Subject", "The Subject"}, + }; + + var configurationBuilder = new ConfigurationBuilder(); + configurationBuilder.AddInMemoryCollection(input); + var config = configurationBuilder.Build(); + var appSettings = new NetCoreAppSettings(config); + return appSettings; + } + + public class EmailConfig + { + public string From { get; set; } + public string Subject { get; set; } + } + + [Test] + public void Can_populate_typed_config() + { + var appSettings = GetAppSettings(); + var emailConfig = appSettings.Get("Email"); + Assert.That(emailConfig.From, Is.EqualTo("test@email.com")); + Assert.That(emailConfig.Subject, Is.EqualTo("The Subject")); + } + + } +#endif + + [TestFixture] + public class EnvironmentAppSettingsTests { - private static AppSettingsBase GetAppSettings() + [Test] + public void Can_get_environment_variable() { - return new DictionarySettings(new Dictionary + var env = new EnvironmentVariableSettings(); + var path = env.Get("PATH"); + Assert.That(path, Is.Not.Null); + + var unknown = env.Get("UNKNOWN"); + Assert.That(unknown, Is.Null); + + var envVars = env.GetAllKeys(); + Assert.That(envVars.Count, Is.GreaterThan(0)); + } + } + + public class MultiAppSettingsTest : AppSettingsTest + { + public override IAppSettings GetAppSettings() + { + return new MultiAppSettings( + new DictionarySettings(GetConfigDictionary()), + new AppSettings()); + } + + public override Dictionary GetConfigDictionary() + { + var configMap = base.GetConfigDictionary(); + configMap.Remove("NullableKey"); + return configMap; + } + } + + public class AppConfigAppSettingsTest : AppSettingsTest + { + public override IAppSettings GetAppSettings() + { + return new AppSettings(); + } + + public override Dictionary GetConfigDictionary() + { + var configMap = base.GetConfigDictionary(); + configMap.Remove("NullableKey"); + return configMap; + } + } + + public class OrmLiteAppSettingsTest : AppSettingsTest + { + private OrmLiteAppSettings settings; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + settings = new OrmLiteAppSettings( + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + settings.InitSchema(); + } + + public override IAppSettings GetAppSettings() + { + var testConfig = (DictionarySettings)base.GetAppSettings(); + + using (var db = settings.DbFactory.Open()) + { + db.DeleteAll(); + + foreach (var config in testConfig.GetAll()) { - {"NullableKey", null}, - {"EmptyKey", string.Empty}, - {"RealKey", "This is a real value"}, - {"ListKey", "A,B,C,D,E"}, - {"IntKey", "42"}, - {"BadIntegerKey", "This is not an integer"}, - {"DictionaryKey", "A:1,B:2,C:3,D:4,E:5"}, - {"BadDictionaryKey", "A1,B:"}, - }); + settings.Set(config.Key, config.Value); + } + } + + return settings; + } + + [Test] + public void Can_access_ConfigSettings_directly() + { + GetAppSettings(); + using (var db = settings.DbFactory.Open()) + { + var value = db.Scalar( + "SELECT Value FROM ConfigSetting WHERE Id = @id", new { id = "RealKey" }); + + Assert.That(value, Is.EqualTo("This is a real value")); + } + } + + [Test] + public void Can_preload_AppSettings() + { + GetAppSettings(); + + var allSettings = settings.GetAll(); + var cachedSettings = new DictionarySettings(allSettings); + + Assert.That(cachedSettings.Get("RealKey"), Is.EqualTo("This is a real value")); + } + + [Test] + public void GetString_returns_null_On_Nonexistent_Key() + { + var appSettings = GetAppSettings(); + var value = appSettings.GetString("GarbageKey"); + Assert.IsNull(value); + } + + [Test] + public void GetList_returns_empty_list_On_Null_Key() + { + var appSettings = GetAppSettings(); + + var result = appSettings.GetList("GarbageKey"); + + Assert.That(result.Count, Is.EqualTo(0)); + } + + [Test] + public void Does_GetOrCreate_New_Value() + { + var appSettings = (OrmLiteAppSettings)GetAppSettings(); + + var i = 0; + + var key = "key"; + var result = appSettings.GetOrCreate(key, () => key + ++i); + Assert.That(result, Is.EqualTo("key1")); + + result = appSettings.GetOrCreate(key, () => key + ++i); + Assert.That(result, Is.EqualTo("key1")); + } + + public class AppConfig + { + public int IntValue { get; set; } + public bool BoolValue { get; set; } + } + + [Test] + public void Does_Save_Typed_Poco_Config() + { + var appSettings = (OrmLiteAppSettings)GetAppSettings(); + appSettings.Set("config", new AppConfig { + IntValue = 1, + BoolValue = true + }); + + var config = appSettings.Get("config"); + Assert.That(config.IntValue, Is.EqualTo(1)); + Assert.That(config.BoolValue); + + appSettings.Delete("config"); + config = appSettings.Get("config"); + Assert.That(config, Is.Null); + } + } + + public class DictionarySettingsTest : AppSettingsTest + { + [Test] + public void GetRequiredString_Throws_Exception_On_Nonexistent_Key() + { + var appSettings = GetAppSettings(); + try + { + appSettings.GetRequiredString("GarbageKey"); + Assert.Fail("GetString did not throw a ConfigurationErrorsException"); + } + catch (ConfigurationErrorsException ex) + { + Assert.That(ex.Message.Contains("GarbageKey")); + } + } + + [Test] + public void Does_work_with_ParseKeyValueText() + { + var textFile = @" +EmptyKey +RealKey This is a real value +ListKey A,B,C,D,E +IntKey 42 +DictionaryKey A:1,B:2,C:3,D:4,E:5 +ObjectKey {SomeSetting:Test,SomeOtherSetting:12,FinalSetting:Final}"; + + var settings = textFile.ParseKeyValueText(); + var appSettings = new DictionarySettings(settings); + + Assert.That(appSettings.Get("EmptyKey"), Is.EqualTo("").Or.Null); + Assert.That(appSettings.Get("RealKey"), Is.EqualTo("This is a real value")); + + Assert.That(appSettings.Get("IntKey", defaultValue: 1), Is.EqualTo(42)); + + var list = appSettings.GetList("ListKey"); + Assert.That(list, Has.Count.EqualTo(5)); + Assert.That(list, Is.EqualTo(new List { "A", "B", "C", "D", "E" })); + + var map = appSettings.GetDictionary("DictionaryKey"); + + Assert.That(map, Has.Count.EqualTo(5)); + Assert.That(map.Keys, Is.EqualTo(new List { "A", "B", "C", "D", "E" })); + Assert.That(map.Values, Is.EqualTo(new List { "1", "2", "3", "4", "5" })); + + var value = appSettings.Get("ObjectKey", new SimpleAppSettings()); + Assert.That(value, Is.Not.Null); + Assert.That(value.FinalSetting, Is.EqualTo("Final")); + Assert.That(value.SomeOtherSetting, Is.EqualTo(12)); + Assert.That(value.SomeSetting, Is.EqualTo("Test")); + } + + [Test] + public void Does_parse_byte_array_as_Base64() + { + var authKey = AesUtils.CreateKey(); + + var appSettings = new DictionarySettings(new Dictionary + { + { "AuthKey", Convert.ToBase64String(authKey) } + }); + + Assert.That(appSettings.Get("AuthKey"), Is.EquivalentTo(authKey)); + } + } + + public abstract class AppSettingsTest + { + public virtual IAppSettings GetAppSettings() + { + return new DictionarySettings(GetConfigDictionary()) + { + ParsingStrategy = null, + }; + } + + public virtual Dictionary GetConfigDictionary() + { + return new Dictionary + { + {"NullableKey", null}, + {"EmptyKey", string.Empty}, + {"RealKey", "This is a real value"}, + {"ListKey", "A,B,C,D,E"}, + {"IntKey", "42"}, + {"BadIntegerKey", "This is not an integer"}, + {"DictionaryKey", "A:1,B:2,C:3,D:4,E:5"}, + {"BadDictionaryKey", "A1,B:"}, + {"ObjectNoLineFeed", "{SomeSetting:Test,SomeOtherSetting:12,FinalSetting:Final}"}, + {"ObjectWithLineFeed", "{SomeSetting:Test,\r\nSomeOtherSetting:12,\r\nFinalSetting:Final}"}, + {"Email","{From:test@email.com,Subject:The Subject}"}, + }; } [Test] @@ -75,20 +376,17 @@ public void Get_Throws_Exception_On_Bad_Value() } [Test] - public void GetString_Throws_Exception_On_Nonexistent_Key() + public void Can_Get_List_From_Setting_using_generics() { var appSettings = GetAppSettings(); - try - { - appSettings.GetString("GarbageKey"); - Assert.Fail("GetString did not throw a ConfigurationErrorsException"); - } - catch (ConfigurationErrorsException ex) - { - Assert.That(ex.Message.Contains("GarbageKey")); - } - } + var value = appSettings.Get>("ListKey"); + + Assert.That(value, Has.Count.EqualTo(5)); + Assert.That(value, Is.EqualTo(new List { "A", "B", "C", "D", "E" })); + var valueWithDefault = appSettings.Get("ListKey", new List()); + Assert.That(valueWithDefault, Is.EquivalentTo(valueWithDefault)); + } [Test] public void GetList_Parses_List_From_Setting() @@ -100,21 +398,6 @@ public void GetList_Parses_List_From_Setting() Assert.That(value, Is.EqualTo(new List { "A", "B", "C", "D", "E" })); } - [Test] - public void GetList_Throws_Exception_On_Null_Key() - { - var appSettings = GetAppSettings(); - try - { - appSettings.GetList("GarbageKey"); - Assert.Fail("GetList did not throw a ConfigurationErrorsException"); - } - catch (ConfigurationErrorsException ex) - { - Assert.That(ex.Message.Contains("GarbageKey")); - } - } - [Test] public void GetDictionary_Parses_Dictionary_From_Setting() { @@ -125,6 +408,17 @@ public void GetDictionary_Parses_Dictionary_From_Setting() Assert.That(value.Keys, Is.EqualTo(new List { "A", "B", "C", "D", "E" })); Assert.That(value.Values, Is.EqualTo(new List { "1", "2", "3", "4", "5" })); } + + [Test] + public void GetKeyValuePairs_Parses_Dictionary_From_Setting() + { + var appSettings = GetAppSettings(); + var kvps = appSettings.GetKeyValuePairs("DictionaryKey"); + + Assert.That(kvps, Has.Count.EqualTo(5)); + Assert.That(kvps.Map(x => x.Key), Is.EqualTo(new List { "A", "B", "C", "D", "E" })); + Assert.That(kvps.Map(x => x.Value), Is.EqualTo(new List { "1", "2", "3", "4", "5" })); + } [Test] public void GetDictionary_Throws_Exception_On_Null_Key() @@ -157,5 +451,98 @@ public void GetDictionary_Throws_Exception_On_Bad_Value() Assert.That(ex.Message.Contains("BadDictionaryKey")); } } + + [Test] + public void Get_Returns_ObjectNoLineFeed() + { + if (!(GetAppSettings() is AppSettingsBase appSettings)) return; + + appSettings.ParsingStrategy = AppSettingsStrategy.CollapseNewLines; + var value = appSettings.Get("ObjectNoLineFeed", new SimpleAppSettings()); + Assert.That(value, Is.Not.Null); + Assert.That(value.FinalSetting, Is.EqualTo("Final")); + Assert.That(value.SomeOtherSetting, Is.EqualTo(12)); + Assert.That(value.SomeSetting, Is.EqualTo("Test")); + + value = appSettings.Get("ObjectNoLineFeed"); + Assert.That(value, Is.Not.Null); + Assert.That(value.FinalSetting, Is.EqualTo("Final")); + Assert.That(value.SomeOtherSetting, Is.EqualTo(12)); + Assert.That(value.SomeSetting, Is.EqualTo("Test")); + } + + [Test] +#if NETCORE + [Ignore("Attribute value already has its new lines collapsed")] +#endif + public void Get_Returns_ObjectWithLineFeed() + { + if (!(GetAppSettings() is AppSettingsBase appSettings)) return; + + appSettings.ParsingStrategy = AppSettingsStrategy.CollapseNewLines; + var value = appSettings.Get("ObjectWithLineFeed", new SimpleAppSettings()); + Assert.That(value, Is.Not.Null); + Assert.That(value.FinalSetting, Is.EqualTo("Final")); + Assert.That(value.SomeOtherSetting, Is.EqualTo(12)); + Assert.That(value.SomeSetting, Is.EqualTo("Test")); + + value = appSettings.Get("ObjectWithLineFeed"); + Assert.That(value, Is.Not.Null); + Assert.That(value.FinalSetting, Is.EqualTo("Final")); + Assert.That(value.SomeOtherSetting, Is.EqualTo(12)); + Assert.That(value.SomeSetting, Is.EqualTo("Test")); + } + + [Test] + public void Can_write_to_AppSettings() + { + var appSettings = GetAppSettings(); + var value = appSettings.Get("IntKey", 0); + Assert.That(value, Is.EqualTo(42)); + + appSettings.Set("IntKey", 99); + value = appSettings.Get("IntKey", 0); + Assert.That(value, Is.EqualTo(99)); + } + + public class SimpleAppSettings + { + public string SomeSetting { get; set; } + public int SomeOtherSetting { get; set; } + public string FinalSetting { get; set; } + } + + [Test] + public void Can_get_all_keys() + { + var appSettings = GetAppSettings(); + var allKeys = appSettings.GetAllKeys(); + allKeys.Remove("servicestack:license"); + + Assert.That(allKeys, Is.EquivalentTo(GetConfigDictionary().Keys)); + } + + [Test] + public void Can_search_all_keys() + { + var appSettings = GetAppSettings(); + var badKeys = appSettings.GetAllKeys().Where(x => x.Matches("Bad*")); + + Assert.That(badKeys, Is.EquivalentTo(new[] { "BadIntegerKey", "BadDictionaryKey" })); + } + + [Test] + public void Can_set_and_get_strings() + { + var exampleUrl = "https://www.example.org"; + var appSettings = GetAppSettings(); + appSettings.Set("url", exampleUrl); + var url = appSettings.Get("url"); + + Assert.That(url, Is.EqualTo(exampleUrl)); + + url = appSettings.GetString("url"); + Assert.That(url, Is.EqualTo(exampleUrl)); + } } } diff --git a/tests/ServiceStack.Common.Tests/Configuration/ConfigUtilsTests.cs b/tests/ServiceStack.Common.Tests/Configuration/ConfigUtilsTests.cs new file mode 100644 index 00000000000..b71ca5796cf --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Configuration/ConfigUtilsTests.cs @@ -0,0 +1,44 @@ +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class ConfigUtilsTests + { + public class AppHostTest : AppSelfHostBase + { + public AppHostTest() + : base("Test Config AppHost", typeof(AppHostTest).Assembly) {} + + public override void Configure(Container container) {} + } + + [Test] + public void Can_parse_AppConfig_AppSettings_with_XmlReader() + { + using (new AppHostTest().Init()) + { + var map = ConfigUtils.GetAppSettingsMap(); + Assert.That(map.Count, Is.EqualTo(11)); + Assert.That(map.Keys, Is.EquivalentTo(new[] { + "servicestack:license", + "EmptyKey", + "RealKey", + "ListKey", + "IntKey", + "BadIntegerKey", + "DictionaryKey", + "BadDictionaryKey", + "ObjectNoLineFeed", + "ObjectWithLineFeed", + "Email", + })); + } + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Configuration/NetCoreAppSettingsTests.cs b/tests/ServiceStack.Common.Tests/Configuration/NetCoreAppSettingsTests.cs new file mode 100644 index 00000000000..a8e803e74ad --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Configuration/NetCoreAppSettingsTests.cs @@ -0,0 +1,136 @@ +#if NETCORE +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Configuration; +using Microsoft.Extensions.Configuration; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class NetCoreAppSettingsTests + { + public class KeyWithSubkey + { + public string Subkey { get; set; } + } + + public static Dictionary Settings = new Dictionary + { + {"A:A1", "A_A1_Value"}, + {"A:A2:Subkey", "A_A2_Subkey_Value"}, + {"B", "B_Value"}, + {"C:List1:0", "C_List1_Value1"}, + {"C:List1:1", "C_List1_Value2"}, + {"D:Dict1:A", "D_Dict1_ValueA"}, + {"D:Dict1:B", "D_Dict1_ValueB"} + }; + + public IAppSettings GetAppSettings() + { + var configurationBuilder = new ConfigurationBuilder(); + configurationBuilder.AddInMemoryCollection(Settings); + var config = configurationBuilder.Build(); + return new NetCoreAppSettings(config); + } + + [Test] + [TestCaseSource("Settings")] + public void Can_GetString_use_NestedKey(KeyValuePair keyValue) + { + var appSettings = GetAppSettings(); + var child2Value = appSettings.GetString(keyValue.Key); + Assert.That(child2Value, Is.EqualTo(keyValue.Value)); + } + + [Test] + [TestCaseSource("Settings")] + public void Can_Get_use_NestedKey(KeyValuePair keyValue) + { + var appSettings = GetAppSettings(); + var child2Value = appSettings.Get(keyValue.Key); + Assert.That(child2Value, Is.EqualTo(keyValue.Value)); + } + + [Test] + [TestCaseSource("Settings")] + public void Can_GetType_String_with_Default_use_NestedKey(KeyValuePair keyValue) + { + var appSettings = GetAppSettings(); + var value = appSettings.Get(keyValue.Key, "default"); + Assert.That(value, Is.EqualTo(keyValue.Value)); + } + + [Test] + public void Can_GetType_Object_use_NestedKey() + { + var appSettings = GetAppSettings(); + var value = appSettings.Get("A:A2"); + Assert.That(value.Subkey, Is.EqualTo("A_A2_Subkey_Value")); + } + + [Test] + public void Can_GetType_Object_with_Default_use_NestedKey() + { + var appSettings = GetAppSettings(); + var value = appSettings.Get("A:A2", new KeyWithSubkey{ Subkey = "default" }); + Assert.That(value.Subkey, Is.EqualTo("A_A2_Subkey_Value")); + } + + [Test] + public void Can_GetAll_see_NestedKeys() + { + var appSettings = (GetAppSettings() as NetCoreAppSettings).Configuration; + var allKeyValues = appSettings.AsEnumerable(); + foreach (var key in Settings.Keys) + { + Assert.That(allKeyValues.Any(x => x.Key == key)); + } + } + + [Test] + public void Can_GetAllKeys_see_NestedKeys() + { + var appSettings = (GetAppSettings() as NetCoreAppSettings).Configuration; + var allKeyValues = appSettings.AsEnumerable(); + foreach (var key in Settings.Keys) + { + Assert.That(allKeyValues.Any(x => x.Key == key)); + } + } + + [Test] + [TestCaseSource("Settings")] + public void Can_Exists_using_NestedKey(KeyValuePair keyValue) + { + var appSettings = GetAppSettings(); + var keyExists = appSettings.Exists(keyValue.Key); + Assert.That(keyExists, Is.True); + } + + [Test] + public void Can_GetList_using_NestedKey() + { + var appSettings = GetAppSettings(); + var listValues = appSettings.GetList("C:List1"); + Assert.That(listValues, Is.Not.Null.And.Not.Empty.And.Count.EqualTo(2)); + } + + [Test] + public void Can_GetDictionary_using_NestedKey() + { + var appSettings = GetAppSettings(); + var dictValues = appSettings.GetDictionary("D:Dict1"); + Assert.That(dictValues, Is.Not.Null.And.Not.Empty.And.Count.EqualTo(2)); + } + + [Test] + public void Can_GetKeyValuePairs_using_NestedKey() + { + var appSettings = GetAppSettings(); + var dictValues = appSettings.GetKeyValuePairs("D:Dict1"); + Assert.That(dictValues, Is.Not.Null.And.Not.Empty.And.Count.EqualTo(2)); + } + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/ContainerChildTests.cs b/tests/ServiceStack.Common.Tests/ContainerChildTests.cs new file mode 100644 index 00000000000..0371b0dd46b --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ContainerChildTests.cs @@ -0,0 +1,63 @@ +using Funq; +using NUnit.Framework; + +namespace ServiceStack.Common.Tests +{ + public interface ISomeService + { } + + public class SomeService : ISomeService + { + public readonly Dependency dependancy; + + public SomeService(Dependency dependancy) + { + this.dependancy = dependancy; + } + } + + public class Dependency + { + public readonly string label; + + public Dependency(string label) + { + this.label = label; + } + } + + public class ContainerChildTests + { + [Test] + public void Can_use_child_containers() + { + Container parent = new Container(); + + // Create two childs, each with a specific instance Dependancy + Container child1 = parent.CreateChildContainer(); + Container child2 = parent.CreateChildContainer(); + + child1.Register(new Dependency("First")); + child2.Register(new Dependency("Second")); + + // Now register two factories for ISomeService. + child1.Register(x => Factory(x)); + child2.Register(x => Factory(x)); + + ISomeService resolved1 = child1.Resolve(); + ISomeService resolved2 = child2.Resolve(); + + Assert.That(((SomeService)resolved1).dependancy.label, Is.EqualTo("First")); + Assert.That(((SomeService)resolved2).dependancy.label, Is.EqualTo("Second")); + } + + public static ISomeService Factory(Container c) + { + // Register the service by type... + c.RegisterAutoWiredType(typeof(SomeService), ReuseScope.Hierarchy); + // ... and force auto-wiring to happen. + ISomeService result = (ISomeService)c.TryResolve(typeof(SomeService)); + return result; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ContainerTests.cs b/tests/ServiceStack.Common.Tests/ContainerTests.cs new file mode 100644 index 00000000000..b0916caa3fe --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ContainerTests.cs @@ -0,0 +1,103 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class ContainerTests + { + class Foo : IFoo + { + private static int Count; + + public Foo() + { + Id = Count++; + } + + public int Id { get; set; } + public IBar Bar { get; set; } + } + + interface IFoo + { + int Id { get; set; } + } + + class Bar : IBar + { + private static int Count; + + public Bar() + { + Count++; + } + + public string Name { get; set; } + } + + interface IBar + { + string Name { get; set; } + } + + [Test] + public void Does_TryResolve_from_delegate_cache() + { + var container = new Container(); + container.Register(c => new Foo { Id = 1 }); + + var instance = (Foo)container.TryResolve(typeof(Foo)); + Assert.That(instance.Id, Is.EqualTo(1)); + + instance = (Foo)container.TryResolve(typeof(Foo)); + Assert.That(instance.Id, Is.EqualTo(1)); + } + + [Test] + public void Can_use_NetCore_APIs_to_register_dependencies() + { + using (var appHost = new BasicAppHost().Init()) + { + var services = appHost.Container; + + services.AddTransient(); + services.AddSingleton(c => new Bar { Name = "bar" }); + + var bar = (Bar)services.GetService(typeof(IBar)); + Assert.That(bar.Name, Is.EqualTo("bar")); + + var foo = (Foo)services.GetService(typeof(IFoo)); + Assert.That(foo.Id, Is.EqualTo(0)); + Assert.That(ReferenceEquals(foo.Bar, bar)); + + foo = (Foo)services.GetService(typeof(IFoo)); + Assert.That(foo.Id, Is.EqualTo(1)); + Assert.That(ReferenceEquals(foo.Bar, bar)); + } + } + + [Test] + public void CreateInstance_throws_on_missing_dependency() + { + using (var appHost = new BasicAppHost().Init()) + { + var services = appHost.Container; + services.AddTransient(); + + var typeFactory = new ContainerResolveCache(appHost.Container); + + var foo = typeFactory.CreateInstance(services, typeof(IFoo), tryResolve: true); + Assert.That(foo, Is.Not.Null); + + var bar = typeFactory.CreateInstance(services, typeof(IBar), tryResolve: true); + Assert.That(bar, Is.Null); + + Assert.Throws(() => + typeFactory.CreateInstance(services, typeof(IBar), tryResolve: false)); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/CryptUtilTest.cs b/tests/ServiceStack.Common.Tests/CryptUtilTest.cs index 502851cd305..efc1bc8b6ff 100644 --- a/tests/ServiceStack.Common.Tests/CryptUtilTest.cs +++ b/tests/ServiceStack.Common.Tests/CryptUtilTest.cs @@ -1,4 +1,5 @@ -using System; +#if !NETCORE +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,8 +14,8 @@ public class CryptUtilsTest [TestCase] public void CanEncryptWithStringExtension() { - CryptUtils.Length = RsaKeyLengths.Bit1024; - CryptUtils.KeyPair = CryptUtils.CreatePublicAndPrivateKeyPair(); + RsaUtils.KeyLength = RsaKeyLengths.Bit1024; + RsaUtils.DefaultKeyPair = RsaUtils.CreatePublicAndPrivateKeyPair(); string TestStart = "Mr. Watson--come here--I want to see you."; string Encrypted; @@ -28,18 +29,21 @@ public void CanEncryptWithStringExtension() } - [TestCase] - [Test, ExpectedException(typeof(ArgumentNullException))] - public void CanEncryptWithStringExtensionFailsWithoutKeyPair() + [Test] + public void Can_sign_data_with_RSA() { - CryptUtils.Length = RsaKeyLengths.Bit1024; - CryptUtils.KeyPair = null; - string TestStart = "Mr. Watson--come here--I want to see you."; - string Encrypted; + var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + var publicKey = privateKey.ToPublicRsaParameters(); - Encrypted = TestStart.Encrypt(); - + var message = "sign this"; + var data = message.ToUtf8Bytes(); + + var signature = RsaUtils.Authenticate(data, privateKey, "SHA256", RsaKeyLengths.Bit2048); + + var verified = RsaUtils.Verify(data, signature, publicKey, "SHA256", RsaKeyLengths.Bit2048); + Assert.That(verified, Is.True); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs b/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs index e885da1d486..1c431c15184 100644 --- a/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs +++ b/tests/ServiceStack.Common.Tests/EndpointHandlerBaseTests.cs @@ -1,9 +1,12 @@ -using System; +#if !NETCORE +using System; +using System.IO; +using System.Linq; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints.Extensions; +using ServiceStack.Host; +using ServiceStack.IO; +using ServiceStack.Testing; +using ServiceStack.Web; namespace ServiceStack.Common.Tests { @@ -12,7 +15,8 @@ public class EndpointHandlerBaseTests { public IHttpRequest CreateRequest(string userHostAddress) { - var httpReq = new MockHttpRequest("test", HttpMethods.Get, ContentType.Json, "/", null, null, null) { + var httpReq = new MockHttpRequest("test", HttpMethods.Get, MimeTypes.Json, "/", null, null, null) + { UserHostAddress = userHostAddress }; return httpReq; @@ -21,11 +25,14 @@ public IHttpRequest CreateRequest(string userHostAddress) [Test] public void Can_parse_Ips() { - var result = CreateRequest("204.2.145.235").GetAttributes(); + using (new BasicAppHost().Init()) + { + var result = CreateRequest("204.2.145.235").GetAttributes(); - Assert.That(result.Has(EndpointAttributes.External)); - Assert.That(result.Has(EndpointAttributes.HttpGet)); - Assert.That(result.Has(EndpointAttributes.InSecure)); + Assert.That(result.Has(RequestAttributes.External)); + Assert.That(result.Has(RequestAttributes.HttpGet)); + Assert.That(result.Has(RequestAttributes.InSecure)); + } } [Flags] @@ -38,5 +45,61 @@ public void Can_parse_int_enums() Assert.That(result.Has(A.C)); Assert.That(!result.Has(A.D)); } + + [Test] + public void Can_mock_uploading_files() + { + using (new BasicAppHost + { + ConfigureAppHost = host => host.VirtualFiles = new MemoryVirtualFiles(), + }.Init()) + { + var ms = "mocked".ToUtf8Bytes().InMemoryStream(); + var httpFile = new HttpFile + { + ContentType = "application/x-msaccess", + FileName = "C:\\path\\to\\file.txt", + InputStream = ms, + ContentLength = ms.ToArray().Length, + }; + var mockReq = new MockHttpRequest + { + Files = new IHttpFile[] { httpFile }, + }; + //Mock Session + mockReq.Items[Keywords.Session] = new AuthUserSession { Id = "sess-id" }; + + var service = new UploadFileService + { + Request = mockReq + }; + + service.Any(new MockUploadFile()); + + var files = HostContext.VirtualFiles.GetAllFiles().ToList(); + Assert.That(files[0].ReadAllText(), Is.EqualTo("mocked")); + } + } + + public class MockUploadFile { } + + public class UploadFileService : Service + { + public object Any(MockUploadFile request) + { + for (int i = 0; i < Request.Files.Length; i++) + { + var file = Request.Files[i]; + + string fileId = Guid.NewGuid().ToString(); + var session = base.GetSession(); + var fileName = session.Id.CombineWith(fileId); + VirtualFiles.WriteFile(fileName, file.InputStream); + } + + return request; + } + } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/EnumerableExtensionsTests.cs b/tests/ServiceStack.Common.Tests/EnumerableExtensionsTests.cs index e2e3f2611fc..bb0e09f79fe 100644 --- a/tests/ServiceStack.Common.Tests/EnumerableExtensionsTests.cs +++ b/tests/ServiceStack.Common.Tests/EnumerableExtensionsTests.cs @@ -1,88 +1,144 @@ +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; using System.Linq; using ServiceStack.Text; namespace ServiceStack.Common.Tests { - [TestFixture] - public class EnumerableExtensionsTests - { - readonly int[] IntValues = new[] { 1, 2, 3 }; - readonly int[] NoValues = new int[]{}; - readonly int[] DifferentValues = new[] { 5, 6, 7}; - readonly int[] MoreIntValues = new[] { 1, 2, 3, 4 }; - readonly int[] LessIntValues = new[] { 1, 2 }; - readonly int[] UnorderedIntValues = new[] { 3, 2, 1 }; - - readonly string[] StringValues = new[] { "A", "B", "C" }; - readonly string[] NoStringValues = new string[] { }; - - [Test] - public void Can_Join() - { - Assert.That(IntValues.Join(), Is.EqualTo("1,2,3")); - } - - [Test] - public void EquivalentTo_self() - { - Assert.That(IntValues.EquivalentTo(IntValues), Is.True); - } - - [Test] - public void EquivalentTo_List() - { - Assert.That(IntValues.EquivalentTo(IntValues.ToList()), Is.True); - } - - [Test] - public void Not_EquivalentTo_NoValues() - { - Assert.That(IntValues.EquivalentTo(NoValues), Is.False); - } - - [Test] - public void Not_EquivalentTo_DifferentValues() - { - Assert.That(IntValues.EquivalentTo(DifferentValues), Is.False); - } - - [Test] - public void Not_EquivalentTo_LessIntValues() - { - Assert.That(IntValues.EquivalentTo(LessIntValues), Is.False); - } - - [Test] - public void Not_EquivalentTo_MoreIntValues() - { - Assert.That(IntValues.EquivalentTo(MoreIntValues), Is.False); - } - - [Test] - public void Not_EquivalentTo_UnorderedIntValues() - { - Assert.That(IntValues.EquivalentTo(UnorderedIntValues), Is.False); - } - - [Test] - public void Not_EquivalentTo_null() - { - Assert.That(IntValues.EquivalentTo(null), Is.False); - } - - [Test] - public void EquivalentTo_StringValues() - { - Assert.That(StringValues.EquivalentTo(NoStringValues), Is.False); - Assert.That(NoStringValues.EquivalentTo(StringValues), Is.False); - Assert.That(NoStringValues.EquivalentTo(NoStringValues), Is.True); - Assert.That(StringValues.EquivalentTo(StringValues), Is.True); - - Assert.That(StringValues.EquivalentTo(new string[] { null }), Is.False); - Assert.That(new string[] { null }.EquivalentTo(StringValues), Is.False); - } - - } + [TestFixture] + public class EnumerableExtensionsTests + { + readonly int[] IntValues = new[] { 1, 2, 3 }; + readonly int[] NoValues = new int[] { }; + readonly int[] DifferentValues = new[] { 5, 6, 7 }; + readonly int[] MoreIntValues = new[] { 1, 2, 3, 4 }; + readonly int[] LessIntValues = new[] { 1, 2 }; + readonly int[] UnorderedIntValues = new[] { 3, 2, 1 }; + + readonly string[] StringValues = new[] { "A", "B", "C" }; + readonly string[] NoStringValues = new string[] { }; + + [Test] + public void Can_FirstOrDefault() + { + Assert.That(EnumerableUtils.FirstOrDefault(IntValues), Is.EqualTo(1)); + } + + [Test] + public void Can_Skip() + { + Assert.That(EnumerableUtils.Skip(IntValues,1), Is.EqualTo(new[]{ 2, 3 })); + } + + [Test] + public void Can_Take() + { + Assert.That(EnumerableUtils.Take(IntValues, 2), Is.EqualTo(new[]{ 1, 2 })); + } + + [Test] + public void Can_Join() + { + Assert.That(IntValues.Join(), Is.EqualTo("1,2,3")); + } + + [Test] + public void EquivalentTo_self() + { + Assert.That(IntValues.EquivalentTo(IntValues), Is.True); + } + + [Test] + public void EquivalentTo_List() + { + Assert.That(IntValues.EquivalentTo(IntValues.ToList()), Is.True); + } + + [Test] + public void Not_EquivalentTo_NoValues() + { + Assert.That(IntValues.EquivalentTo(NoValues), Is.False); + } + + [Test] + public void Not_EquivalentTo_DifferentValues() + { + Assert.That(IntValues.EquivalentTo(DifferentValues), Is.False); + } + + [Test] + public void Not_EquivalentTo_LessIntValues() + { + Assert.That(IntValues.EquivalentTo(LessIntValues), Is.False); + } + + [Test] + public void Not_EquivalentTo_MoreIntValues() + { + Assert.That(IntValues.EquivalentTo(MoreIntValues), Is.False); + } + + [Test] + public void Not_EquivalentTo_UnorderedIntValues() + { + Assert.That(IntValues.EquivalentTo(UnorderedIntValues), Is.False); + } + + [Test] + public void Not_EquivalentTo_null() + { + Assert.That(IntValues.EquivalentTo(null), Is.False); + } + + [Test] + public void EquivalentTo_StringValues() + { + Assert.That(StringValues.EquivalentTo(NoStringValues), Is.False); + Assert.That(NoStringValues.EquivalentTo(StringValues), Is.False); + Assert.That(NoStringValues.EquivalentTo(NoStringValues), Is.True); + Assert.That(StringValues.EquivalentTo(StringValues), Is.True); + + Assert.That(StringValues.EquivalentTo(new string[] { null }), Is.False); + Assert.That(new string[] { null }.EquivalentTo(StringValues), Is.False); + } + + [Test] + public void EquivalentTo_Dictionary_Ordered() + { + var a = new Dictionary + { + {"A",1}, + {"B",2}, + {"C",3}, + }; + var b = new ConcurrentDictionary(); + b["A"] = 1; + b["B"] = 2; + b["C"] = 3; + + Assert.That(a.EquivalentTo(b)); + } + + [Test] + public void EquivalentTo_Dictionary_Unordered() + { + var a = new Dictionary + { + {"A",1}, + {"B",2}, + {"C",3}, + }; + var b = new Dictionary + { + {"C",3}, + {"A",1}, + {"B",2}, + }; + + Assert.That(a.EquivalentTo(b)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ExpressionUtilsTests.cs b/tests/ServiceStack.Common.Tests/ExpressionUtilsTests.cs new file mode 100644 index 00000000000..4a888d13fd3 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ExpressionUtilsTests.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using NUnit.Framework; +using ServiceStack.Common.Tests.Models; +using ServiceStack.DataAnnotations; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + public class ExpressionUtilsTests + { + abstract class AbstractBase + { + public string BaseMember { get; set; } + } + + class Derived : AbstractBase + { + public string DerivedMember { get; set; } + } + + [Test] + public void Does_GetMemberName() + { + Assert.That(ExpressionUtils.GetMemberName((Poco x) => x.Name), + Is.EqualTo("Name")); + + Assert.That(ExpressionUtils.GetMemberName((ModelWithFieldsOfNullableTypes x) => x.NId), + Is.EqualTo("NId")); + } + + public Expression> GetAssignmentExpression(Expression> expr) + { + return expr; + } + + [Test] + public void Can_get_assigned_constants() + { + Assert.That(GetAssignmentExpression(() => new Poco { Name = "Foo" }).AssignedValues(), + Is.EquivalentTo(new Dictionary { + {"Name", "Foo"} + })); + } + + [Test] + public void Can_get_assigned_expressions() + { + 2.Times(i => + { + Assert.That(GetAssignmentExpression(() => new Poco { Name = i % 2 == 0 ? "Foo" : "Bar" }).AssignedValues(), + Is.EquivalentTo(new Dictionary { + { "Name", i % 2 == 0 ? "Foo" : "Bar" } + })); + }); + } + + [Test] + public void Can_get_fields_list_from_property_expression() + { + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => x.Name), + Is.EquivalentTo(new[] { "Name" })); + + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => x.Id), + Is.EquivalentTo(new[] { "Id" })); + } + + [Test] + public void Can_get_fields_list_from_anon_object() + { + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => new { x.Id, x.Name }), + Is.EquivalentTo(new[] { "Id", "Name" })); + } + + [Test] + public void Can_get_fields_list_from_Typed_object() + { + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => new Poco { Id = x.Id, Name = x.Name }), + Is.EquivalentTo(new[] { "Id", "Name" })); + } + + [Test] + public void Can_get_fields_list_from_array() + { + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => new[] { "Id", "Name" }), + Is.EquivalentTo(new[] { "Id", "Name" })); + + var id = "Id"; + + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => new[] { id, "Na" + "me" }), + Is.EquivalentTo(new[] { "Id", "Name" })); + } + + [Test] + public void Can_get_fields_list_from_list() + { + var list = new List { "Id", "Name" }; + + Assert.That(ExpressionUtils.GetFieldNames((Poco x) => list), + Is.EquivalentTo(new[] { "Id", "Name" })); + } + + [Test] + public void Can_get_fields_from_abstract_base_class() + { + Assert.That(ExpressionUtils.GetFieldNames(p => p.BaseMember), + Is.EquivalentTo(new[] {"BaseMember"})); + Assert.That(ExpressionUtils.GetFieldNames(p => p.DerivedMember), + Is.EquivalentTo(new[] { "DerivedMember" })); + } + + public class Question + { + public int Id { get; set; } + public string Text { get; set; } + + [CustomField("json")] + public List Answers { get; set; } + } + + public class Answer + { + public int Id { get; set; } + public string Text { get; set; } + } + + [Test] + public void Can_get_assigned_ComplexTypes() + { + var assignedValues = GetAssignmentExpression(() => new Question + { + Id = 1, + Answers = new List + { + new Answer { Id = 1, Text = "Q1 Answer1" } + } + }).AssignedValues(); + + Assert.That(assignedValues.Count, Is.EqualTo(2)); + var assignedValue = (List)assignedValues["Answers"]; + Assert.That(assignedValue[0].Text, Is.EqualTo("Q1 Answer1")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Expressions/DelegateFactoryTests.cs b/tests/ServiceStack.Common.Tests/Expressions/DelegateFactoryTests.cs index 9efd7f85dc8..9981ce73225 100644 --- a/tests/ServiceStack.Common.Tests/Expressions/DelegateFactoryTests.cs +++ b/tests/ServiceStack.Common.Tests/Expressions/DelegateFactoryTests.cs @@ -1,82 +1,84 @@ using System; using System.Diagnostics; using NUnit.Framework; -using ServiceStack.Common.Expressions; +using ServiceStack.Reflection; +using System.Linq; +using System.Reflection; namespace ServiceStack.Common.Tests.Expressions { - [TestFixture] - public class DelegateFactoryTests - { - const string TextValue = "Hello, World!"; - private const int Times = 10000; - - [Test] - public void String_test_with_func_call() - { - var stopWatch = new Stopwatch(); - stopWatch.Start(); - - Func action = TextValue.ToUpper; - - for (var i=0; i < Times; i++) - { - action(); - } - - stopWatch.Stop(); - Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); - } - - [Test] - public void String_test_with_direct_call() - { - var stopWatch = new Stopwatch(); - stopWatch.Start(); - - for (var i=0; i < Times; i++) - { - TextValue.ToUpper(); - } - - stopWatch.Stop(); - Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); - } - - [Test] - public void String_test_with_reflection() - { - var stopWatch = new Stopwatch(); - stopWatch.Start(); - - var methodInfo = typeof(string).GetMethod("ToUpper", new Type[] { }); - - for (var i=0; i < Times; i++) - { - methodInfo.Invoke(TextValue, new object[] { }); - } - - stopWatch.Stop(); - Console.WriteLine("Reflection took: {0}ms", stopWatch.ElapsedMilliseconds); - } - - [Test] - public void String_test_with_delegate() - { - var stopWatch = new Stopwatch(); - stopWatch.Start(); - - var methodInfo = typeof (string).GetMethod("ToUpper", new Type[] {}); - var delMethod = DelegateFactory.Create(methodInfo); - - for (var i=0; i < Times; i++) - { - delMethod(TextValue, new object[] { }); - } - - stopWatch.Stop(); - Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); - } - - } + [TestFixture] + public class DelegateFactoryTests + { + const string TextValue = "Hello, World!"; + private const int Times = 10000; + + [Test] + public void String_test_with_func_call() + { + var stopWatch = new Stopwatch(); + stopWatch.Start(); + + Func action = TextValue.ToUpper; + + for (var i = 0; i < Times; i++) + { + action(); + } + + stopWatch.Stop(); + Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); + } + + [Test] + public void String_test_with_direct_call() + { + var stopWatch = new Stopwatch(); + stopWatch.Start(); + + for (var i = 0; i < Times; i++) + { + TextValue.ToUpper(); + } + + stopWatch.Stop(); + Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); + } + + [Test] + public void String_test_with_reflection() + { + var stopWatch = new Stopwatch(); + stopWatch.Start(); + + var methodInfo = typeof(string).GetMethod("ToUpper", new Type[] { }); + + for (var i = 0; i < Times; i++) + { + methodInfo.Invoke(TextValue, new object[] { }); + } + + stopWatch.Stop(); + Console.WriteLine("Reflection took: {0}ms", stopWatch.ElapsedMilliseconds); + } + + [Test] + public void String_test_with_delegate() + { + var stopWatch = new Stopwatch(); + stopWatch.Start(); + + var methodInfo = typeof(string).GetMethod("ToUpper", new Type[] { }); + var delMethod = DelegateFactory.Create(methodInfo); + + for (var i = 0; i < Times; i++) + { + delMethod(TextValue, new object[] { }); + } + + stopWatch.Stop(); + Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Expressions/ExpressionTests.cs b/tests/ServiceStack.Common.Tests/Expressions/ExpressionTests.cs index 4d158b59836..298d34a2b27 100644 --- a/tests/ServiceStack.Common.Tests/Expressions/ExpressionTests.cs +++ b/tests/ServiceStack.Common.Tests/Expressions/ExpressionTests.cs @@ -6,89 +6,89 @@ namespace ServiceStack.Common.Tests.Expressions { - [TestFixture] - public class ExpressionTests - { - - public int AddMethod(int a) - { - return a + 4; - } - - [Test] - public void Simple_func_and_equivalent_expression_tests() - { - Func add = x => x + x; - - Assert.That(add(4), Is.EqualTo(4 + 4)); - - Expression> addExpr = x => x + 4; - - Func addFromExpr = addExpr.Compile(); - - Assert.That(addFromExpr(4), Is.EqualTo(add(4))); - - Func addMethod = AddMethod; - - Assert.That(addMethod(4), Is.EqualTo(add(4))); - - Expression> callAddMethodExpr = x => AddMethod(x); - var addMethodCall = (MethodCallExpression) callAddMethodExpr.Body; - Assert.That(addMethodCall.Method.Name, Is.EqualTo("AddMethod")); - } - - [Test] - public void Simple_func_timing_tests() - { - // 1/5 as expensive as expression - var stopWatch = new Stopwatch(); - stopWatch.Start(); - Func add = x => x + x; - - Assert.That(add(4), Is.EqualTo(4 + 4)); - stopWatch.Stop(); - Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); - } - - [Test] - public void Simple_expression_timing_tests() - { - //5 times more expensive than Func - var stopWatch = new Stopwatch(); - stopWatch.Start(); - Expression> addExpr = x => x + 4; - - Func addFromExpr = addExpr.Compile(); - - Assert.That(addFromExpr(4), Is.EqualTo(4 + 4)); - stopWatch.Stop(); - Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); - } - - - public static int StaticAdd(int a) - { - return a + 4; - } - - [Test] - public void MethodCallExpression_to_call_a_static_method() - { - //Expression> callAddMethodExpr = Expression.Lambda>(Expression.Call(null, (MethodInfo) methodof(ExpressionTests.StaticAdd), - //new Expression[] { CS$0$0000 = Expression.Parameter(typeof(int), "x") }), new ParameterExpression[] { CS$0$0000 }); - - Expression> callAddMethodExpr = x => StaticAdd(x); - var addMethodCall = (MethodCallExpression)callAddMethodExpr.Body; - Assert.That(addMethodCall.Method.Name, Is.EqualTo("StaticAdd")); - } - - [Test] - public void Dynamic_MethodCallExpression_to_call_a_static_method() - { - - //MethodCallExpression.Call(Expression.Call(GetType().GetMethod("StaticAdd", BindingFlags.Static | BindingFlags.Public)); - - //Assert.That(addMethodCall.Method.Name, Is.EqualTo("StaticAdd")); - } - } + [TestFixture] + public class ExpressionTests + { + + public int AddMethod(int a) + { + return a + 4; + } + + [Test] + public void Simple_func_and_equivalent_expression_tests() + { + Func add = x => x + x; + + Assert.That(add(4), Is.EqualTo(4 + 4)); + + Expression> addExpr = x => x + 4; + + Func addFromExpr = addExpr.Compile(); + + Assert.That(addFromExpr(4), Is.EqualTo(add(4))); + + Func addMethod = AddMethod; + + Assert.That(addMethod(4), Is.EqualTo(add(4))); + + Expression> callAddMethodExpr = x => AddMethod(x); + var addMethodCall = (MethodCallExpression)callAddMethodExpr.Body; + Assert.That(addMethodCall.Method.Name, Is.EqualTo("AddMethod")); + } + + [Test] + public void Simple_func_timing_tests() + { + // 1/5 as expensive as expression + var stopWatch = new Stopwatch(); + stopWatch.Start(); + Func add = x => x + x; + + Assert.That(add(4), Is.EqualTo(4 + 4)); + stopWatch.Stop(); + Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); + } + + [Test] + public void Simple_expression_timing_tests() + { + //5 times more expensive than Func + var stopWatch = new Stopwatch(); + stopWatch.Start(); + Expression> addExpr = x => x + 4; + + Func addFromExpr = addExpr.Compile(); + + Assert.That(addFromExpr(4), Is.EqualTo(4 + 4)); + stopWatch.Stop(); + Console.WriteLine("Delegate took: {0}ms", stopWatch.ElapsedMilliseconds); + } + + + public static int StaticAdd(int a) + { + return a + 4; + } + + [Test] + public void MethodCallExpression_to_call_a_static_method() + { + //Expression> callAddMethodExpr = Expression.Lambda>(Expression.Call(null, (MethodInfo) methodof(ExpressionTests.StaticAdd), + //new Expression[] { CS$0$0000 = Expression.Parameter(typeof(int), "x") }), new ParameterExpression[] { CS$0$0000 }); + + Expression> callAddMethodExpr = x => StaticAdd(x); + var addMethodCall = (MethodCallExpression)callAddMethodExpr.Body; + Assert.That(addMethodCall.Method.Name, Is.EqualTo("StaticAdd")); + } + + [Test] + public void Dynamic_MethodCallExpression_to_call_a_static_method() + { + + //MethodCallExpression.Call(Expression.Call(GetType().GetMethod("StaticAdd", BindingFlags.Static | BindingFlags.Public)); + + //Assert.That(addMethodCall.Method.Name, Is.EqualTo("StaticAdd")); + } + } } diff --git a/tests/ServiceStack.Common.Tests/FluentValidation/ErrorCodeTests.cs b/tests/ServiceStack.Common.Tests/FluentValidation/ErrorCodeTests.cs index db2b2534e52..e13e3338f4b 100644 --- a/tests/ServiceStack.Common.Tests/FluentValidation/ErrorCodeTests.cs +++ b/tests/ServiceStack.Common.Tests/FluentValidation/ErrorCodeTests.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using NUnit.Framework; -using ServiceStack.FluentValidation.Validators; using ServiceStack.FluentValidation; using ServiceStack.FluentValidation.Results; @@ -39,7 +36,7 @@ public PersonValidator() RuleFor(x => x.Age).GreaterThan(100).GreaterThanOrEqualTo(100).InclusiveBetween(100, 200).LessThan(10); - RuleFor(x => x.Cars).SetCollectionValidator(new CarValidator()); + RuleForEach(x => x.Cars).SetValidator(new CarValidator()); RuleFor(x => x.Favorites).NotNull().NotEmpty().WithErrorCode("ShouldNotBeEmpty"); RuleFor(x => x.Lastname).NotEmpty(); @@ -57,7 +54,7 @@ public CarValidator() public ValidationResult Result { get; set; } - [TestFixtureSetUp] + [OneTimeSetUp] public void SetUp() { var person = new Person() @@ -123,6 +120,12 @@ public void Length() Assert.IsTrue(Result.Errors.Any(f => f.ErrorCode == ValidationErrors.Length)); } + [Test] + public void LengthContainsPlaceholders() + { + Assert.IsTrue(Result.Errors.Where(f => f.ErrorCode == ValidationErrors.Length).Any(f => f.FormattedMessagePlaceholderValues.ContainsKey("MinLength"))); + } + [Test] public void LessThan() { @@ -168,7 +171,7 @@ public void RegularExpression() [Test] public void Custom() { - Assert.AreEqual(1, Result.Errors.Where(f => f.ErrorCode == "ShouldNotBeEmpty").Count()); + Assert.AreEqual(1, Result.Errors.Count(f => f.ErrorCode == "ShouldNotBeEmpty")); } } } diff --git a/tests/ServiceStack.Common.Tests/FluentValidation/UserSeverityTests.cs b/tests/ServiceStack.Common.Tests/FluentValidation/UserSeverityTests.cs new file mode 100644 index 00000000000..aeb85738130 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/FluentValidation/UserSeverityTests.cs @@ -0,0 +1,163 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +using Funq; +using ServiceStack.FluentValidation; +using ServiceStack.Testing; +using ServiceStack.Validation; + +namespace ServiceStack.Common.Tests.FluentValidation +{ + namespace ServiceStack.FluentValidation.Tests + { + using System; + using System.Linq; + using NUnit.Framework; + using ServiceStack.FluentValidation; + + public class UserSeverityTests + { + private const string Urlbase = "http://localhost:2001/"; + + [Test] + public void Stores_user_severity_against_validation_failure() + { + var validator = new TestValidator(); + validator.RuleFor(x => x.Lastname).NotNull().WithSeverity(Severity.Info); + var result = validator.Validate(new ErrorCodeTests.Person()); + Assert.AreEqual(Severity.Info, result.Errors.Single().Severity); + } + + [Test] + public void Defaults_user_severity_to_error() + { + var validator = new TestValidator(); + validator.RuleFor(x => x.Lastname).NotNull(); + var result = validator.Validate(new ErrorCodeTests.Person()); + Assert.AreEqual(Severity.Error, result.Errors.Single().Severity); + } + + public class TestValidator : AbstractValidator + { + public TestValidator() + { + } + } + + [Test] + public void Response_returned_when_valid() + { + using (var appHost = new TestAppHost()) + { + appHost.Plugins.Add(new ValidationFeature()); + appHost.Init(); + appHost.Start(Urlbase); + + var sc = new JsonServiceClient(Urlbase); + + var response = sc.Get(new EchoRequest {Day = "Monday", Word = "Word"}); + + Assert.That(response.Day, Is.EqualTo("Monday")); + Assert.That(response.Word, Is.EqualTo("Word")); + } + } + + [Test] + public void Can_treat_warnings_and_info_as_errors() + { + using (var appHost = new TestAppHost()) + { + appHost.Plugins.Add(new ValidationFeature {TreatInfoAndWarningsAsErrors = true}); + appHost.Init(); + appHost.Start(Urlbase); + + var sc = new JsonServiceClient(Urlbase); + + Assert.Throws(() => sc.Get(new EchoRequest {Day = "Monday", Word = ""}), + "'Word' should not be empty."); + } + } + + [Test] + public void Can_return_response_when_no_failed_validations_and_TreatInfoAndWarningsAsErrors_set_false() + { + using (var appHost = new TestAppHost()) + { + appHost.Plugins.Add(new ValidationFeature {TreatInfoAndWarningsAsErrors = false}); + appHost.Init(); + appHost.Start(Urlbase); + + var sc = new JsonServiceClient(Urlbase); + + var resp = sc.Get(new EchoRequest {Day = "Monday", Word = "Word"}); + + Assert.That(resp.ResponseStatus, Is.Null); + } + } + + [Test] + public void Can_ignore_warnings_and_info_as_errors() + { + using (var appHost = new TestAppHost()) + { + appHost.Plugins.Add(new ValidationFeature {TreatInfoAndWarningsAsErrors = false}); + appHost.Init(); + appHost.Start(Urlbase); + + var sc = new JsonServiceClient(Urlbase); + + var response = sc.Get(new EchoRequest {Day = "", Word = ""}); + + Assert.That(response.ResponseStatus, Is.Not.Null); + Assert.That(response.ResponseStatus.Errors, Is.Not.Empty); + Assert.That(response.ResponseStatus.Errors.First().Meta["Severity"], Is.EqualTo("Info")); + Assert.That(response.ResponseStatus.Errors[1].Meta["Severity"], Is.EqualTo("Warning")); + } + } + + internal class TestAppHost : AppSelfHostBase + { + public Action ConfigureContainer { get; set; } + + public TestAppHost() + : base("AppHost for ValidationFeature SeverityTests", typeof(EchoService).Assembly) + { + } + + public override void Configure(Container container) + { + if (ConfigureContainer != null) + this.ConfigureContainer(container); + } + } + } + + public class EchoService : Service + { + public object Any(EchoRequest request) => new EchoResponse {Day = request.Day, Word = request.Word}; + } + + public class EchoRequestValidator : AbstractValidator + { + public EchoRequestValidator() + { + RuleFor(e => e.Word).NotEmpty().WithSeverity(Severity.Info); + RuleFor(e => e.Day).NotEmpty().WithSeverity(Severity.Warning); + } + } + + public class EchoRequest : IReturn + { + public string Word { get; set; } + public string Day { get; set; } + } + + public class EchoResponse : IHasResponseStatus + { + public string Word { get; set; } + public string Day { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/FormatTests.cs b/tests/ServiceStack.Common.Tests/FormatTests.cs new file mode 100644 index 00000000000..b08255ac172 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/FormatTests.cs @@ -0,0 +1,52 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +#if !NETCORE +using System.Runtime.Serialization; +using NUnit.Framework; +using ServiceStack.MsgPack; +using ServiceStack.ProtoBuf; + +namespace ServiceStack.Common.Tests +{ + [DataContract] + public class TestModel + { + [DataMember(Order = 1)] + public int Id { get; set; } + + [DataMember(Order = 2)] + public string Name { get; set; } + } + + [TestFixture] + public class FormatTests + { + [Test] + public void Can_serialize_ProtoBuf() + { + var dto = new TestModel { Id = 1, Name = "Name" }; + + var bytes = dto.ToProtoBuf(); + + var fromBytes = bytes.FromProtoBuf(); + + Assert.That(fromBytes.Id, Is.EqualTo(dto.Id)); + Assert.That(fromBytes.Name, Is.EqualTo(dto.Name)); + } + + [Test] + public void Can_serialize_MsgPack() + { + var dto = new TestModel { Id = 1, Name = "Name" }; + + var bytes = dto.ToMsgPack(); + + var fromBytes = bytes.FromMsgPack(); + + Assert.That(fromBytes.Id, Is.EqualTo(dto.Id)); + Assert.That(fromBytes.Name, Is.EqualTo(dto.Name)); + } + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/FunqTests.cs b/tests/ServiceStack.Common.Tests/FunqTests.cs index bad22c64c75..d332e771ebc 100644 --- a/tests/ServiceStack.Common.Tests/FunqTests.cs +++ b/tests/ServiceStack.Common.Tests/FunqTests.cs @@ -29,6 +29,6 @@ public void Test2() container.AutoWire(m); Assert.Throws(() => container.Resolve()); Assert.IsNull(m.Bar); // FAILS HERE - } + } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.Common.Tests/IdUtilsTests.cs b/tests/ServiceStack.Common.Tests/IdUtilsTests.cs index dd00b57ebfe..db232e235e7 100644 --- a/tests/ServiceStack.Common.Tests/IdUtilsTests.cs +++ b/tests/ServiceStack.Common.Tests/IdUtilsTests.cs @@ -1,9 +1,8 @@ using System; using NUnit.Framework; using ServiceStack.Common.Tests.Models; -using ServiceStack.Common.Utils; using ServiceStack.DataAnnotations; -using ServiceStack.DesignPatterns.Model; +using ServiceStack.Model; namespace ServiceStack.Common.Tests { @@ -78,6 +77,32 @@ public int CustomId } } + public class HasNonConventionalId + { + public int Id + { + get + { + return int.MaxValue; + } + } + + [PrimaryKey] + public int Idx + { + get + { + return IntValue; + } + } + } + + public class World + { + public int id { get; set; } + public int randomNumber { get; set; } + } + [Test] public void Can_get_if_HasIntId() { @@ -130,5 +155,16 @@ public void Can_get_if_HasPrimaryKeyAttribute() Assert.That(new HasPrimaryKeyAttribute().GetId(), Is.EqualTo(IntValue)); } + [Test] + public void Can_get_if_id_is_non_conventional() + { + Assert.That(new HasNonConventionalId().GetId(), Is.EqualTo(IntValue)); + } + + [Test] + public void Can_get_if_Has_lowercase_Id() + { + Assert.That(new World { id = 1 }.GetId(), Is.EqualTo(1)); + } } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/InputInfoTests.cs b/tests/ServiceStack.Common.Tests/InputInfoTests.cs new file mode 100644 index 00000000000..936db21e4a6 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/InputInfoTests.cs @@ -0,0 +1,159 @@ +#nullable enable + +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.DataAnnotations; +using ServiceStack.Html; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests; + +class MultiTypes +{ + public int Id { get; set; } + public DateTime Date { get; set; } + public DateTime? NDate { get; set; } + public bool Bool { get; set; } + public string String { get; set; } +} + +public class InputTests +{ + void AssertProp(PropertyInfo? pi, Type type, string name) + { + Assert.That(pi, Is.Not.Null); + Assert.That(pi!.Name, Is.EqualTo(name)); + Assert.That(pi!.PropertyType, Is.EqualTo(type)); + } + + [Test] + public void Does_resolve_properties() + { + AssertProp(InspectUtils.PropertyFromExpression(x => x.Id), typeof(int), nameof(MultiTypes.Id)); + AssertProp(InspectUtils.PropertyFromExpression(x => x.Date), typeof(DateTime), nameof(MultiTypes.Date)); + AssertProp(InspectUtils.PropertyFromExpression(x => x.NDate), typeof(DateTime?), nameof(MultiTypes.NDate)); + AssertProp(InspectUtils.PropertyFromExpression(x => x.Bool), typeof(bool), nameof(MultiTypes.Bool)); + AssertProp(InspectUtils.PropertyFromExpression(x => x.String), typeof(String), nameof(MultiTypes.String)); + } + + public enum EnumMemberTest + { + [EnumMember(Value = "No ne")] None = 0, + [EnumMember(Value = "Template")] Template = 1, + [EnumMember(Value = "Rule")] Rule = 3, + } + public enum EnumWithValues + { + None = 0, + [EnumMember(Value = "Member 1")] + Value1 = 1, + [DataAnnotations.Description("Member 2")] + Value2 = 2, + } + + [Flags] + public enum EnumFlags + { + Value0 = 0, + [EnumMember(Value = "Value 1")] + Value1 = 1, + [DataAnnotations.Description("Value 2")] + Value2 = 2, + Value3 = 4, + Value123 = Value1 | Value2 | Value3, + } + + [EnumAsInt] + public enum EnumAsInt + { + Value1 = 1000, + Value2 = 2000, + Value3 = 3000, + } + + public enum EnumStyle + { + lower, + UPPER, + PascalCase, + camelCase, + camelUPPER, + PascalUPPER, + } + + [Test] + public void Print_GetEnumPairs() + { + void Print(Type enumType) + { + Input.GetEnumEntries(enumType, out var entries); + entries.PrintDump(); + } + + Print(typeof(Lang)); + Print(typeof(EnumMemberTest)); + Print(typeof(EnumWithValues)); + Print(typeof(EnumFlags)); + Print(typeof(EnumAsInt)); + Print(typeof(EnumStyle)); + } + + [Test] + public void Does_resolve_enum_properties() + { + Input.GetEnumEntries(typeof(Lang), out var enumEntries); + Assert.That(enumEntries[0].Key, Is.EqualTo($"{(int)Lang.CSharp}")); + Assert.That(enumEntries[0].Value, Is.EqualTo(nameof(Lang.CSharp))); + + Input.GetEnumEntries(typeof(EnumMemberTest), out enumEntries); + Assert.That(enumEntries[0].Key, Is.EqualTo($"{(int)EnumMemberTest.None}")); + Assert.That(enumEntries[0].Value, Is.EqualTo("No ne")); + } + + [Test] + public void Does_resolve_property_names() + { + Assert.That(InspectUtils.GetFieldNames(x => x.Id), Is.EquivalentTo(new[]{ nameof(MultiTypes.Id) })); + Assert.That(InspectUtils.GetFieldNames(x => x.Date), Is.EquivalentTo(new[]{ nameof(MultiTypes.Date) })); + Assert.That(InspectUtils.GetFieldNames(x => x.NDate), Is.EquivalentTo(new[]{ nameof(MultiTypes.NDate) })); + Assert.That(InspectUtils.GetFieldNames(x => x.String), Is.EquivalentTo(new[]{ nameof(MultiTypes.String) })); + + Assert.That(InspectUtils.GetFieldNames(x => new { x.String }), Is.EquivalentTo(new[]{ nameof(MultiTypes.String) })); + Assert.That(InspectUtils.GetFieldNames(x => new { x.Id, x.Date, x.NDate, x.String }), Is.EquivalentTo(new[] { + nameof(MultiTypes.Id), nameof(MultiTypes.Date), nameof(MultiTypes.NDate), nameof(MultiTypes.String), + })); + } + + [Test] + public void Can_create_MediaRule() + { + var rule = MediaRules.Small.Show(x => new { x.Id, x.Date, x.NDate, x.String }); + Assert.That(rule.Size, Is.EqualTo(MediaSizes.Small)); + Assert.That(rule.Rule, Is.EqualTo(nameof(MediaRuleCreator.Show))); + Assert.That(rule.ApplyTo, Is.EquivalentTo(new[] { + nameof(MultiTypes.Id), nameof(MultiTypes.Date), nameof(MultiTypes.NDate), nameof(MultiTypes.String), + })); + } + + [Test] + public void Does_find_correct_min_media_size() + { + var mediaRules = new[] { + MediaRules.ExtraSmall.Show(x => new { x.Id, x.Email, x.DisplayName }), + MediaRules.Small.Show(x => new { x.Company, x.CreatedDate }), + }; + + Assert.That(mediaRules.MinVisibleSize(nameof(UserAuth.Id)), Is.EqualTo(MediaSizes.ExtraSmall)); + Assert.That(mediaRules.MinVisibleSize(nameof(UserAuth.DisplayName)), Is.EqualTo(MediaSizes.ExtraSmall)); + Assert.That(mediaRules.MinVisibleSize(nameof(UserAuth.CreatedDate)), Is.EqualTo(MediaSizes.Small)); + Assert.That(mediaRules.MinVisibleSize(nameof(UserAuth.Nickname)), Is.EqualTo(MediaSizes.Medium)); + + Assert.That(mediaRules.Reverse().MinVisibleSize(nameof(UserAuth.Id)), Is.EqualTo(MediaSizes.ExtraSmall)); + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/InspectTests.cs b/tests/ServiceStack.Common.Tests/InspectTests.cs new file mode 100644 index 00000000000..5d9e80df161 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/InspectTests.cs @@ -0,0 +1,101 @@ +using System; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + public class Table + { + public int Id { get; set; } + public string Name { get; set; } + public int Int { get; set; } + public int? NInt { get; set; } + public DateTime DateTime { get; set; } + public DateTime DateTime2 { get; set; } + } + + public class InspectTests + { + [Test] + public void Does_not_display_markdown_table_columns_with_all_default_values() + { + var rows = new[] { + new Table { Id = 1, Name = "A" }, + new Table { Id = 2, Name = "B", NInt = 0 }, + new Table { Id = 3, Name = "C", DateTime2 = DateTime.MaxValue }, + }; + + var output = Inspect.dumpTable(rows); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +| # | Id | Name | DateTime2 | +|---|----|------|------------| +| 1 | 1 | A | 0001-01-01 | +| 2 | 2 | B | 0001-01-01 | +| 3 | 3 | C | 9999-12-31 |".NormalizeNewLines())); + } + + [Test] + public void Does_not_display_html_table_columns_with_all_default_values() + { + var rows = new[] { + new Table { Id = 1, Name = "A" }, + new Table { Id = 2, Name = "B", NInt = 0 }, + new Table { Id = 3, Name = "C", DateTime2 = DateTime.MaxValue }, + }; + + var output = Inspect.htmlDump(rows); + Assert.That(output.RemoveNewLines(), Is.EqualTo(@" + + + + + + +
IdNameDateTime2
1A0001-01-01
2B0001-01-01
3C9999-12-31
+ ".RemoveNewLines())); + } + + [Test] + public void Does_display_only_specified_markdown_table_columns() + { + var rows = new[] { + new Table { Id = 1, Name = "A" }, + new Table { Id = 2, Name = "B", NInt = 0 }, + new Table { Id = 3, Name = "C", DateTime2 = DateTime.MaxValue }, + }; + + var output = Inspect.dumpTable(rows, headers:new[]{ "Id", "Int", "Name" }); + output.Print(); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +| Id | Int | Name | +|----|-----|------| +| 1 | 0 | A | +| 2 | 0 | B | +| 3 | 0 | C |".NormalizeNewLines())); + } + + [Test] + public void Does_display_only_specified_html_table_columns() + { + var rows = new[] { + new Table { Id = 1, Name = "A" }, + new Table { Id = 2, Name = "B", NInt = 0 }, + new Table { Id = 3, Name = "C", DateTime2 = DateTime.MaxValue }, + }; + + var output = Inspect.htmlDump(rows, headers:new[]{ "Id", "Int", "Name" }); + output.Print(); + Assert.That(output.RemoveNewLines(), Is.EqualTo(@" + + + + + + +
IdIntName
10A
20B
30C
+ ".RemoveNewLines())); + } + + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/IocExtensions.cs b/tests/ServiceStack.Common.Tests/IocExtensions.cs new file mode 100644 index 00000000000..1f23cb7c363 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/IocExtensions.cs @@ -0,0 +1,24 @@ +using ServiceStack.Web; + +namespace ServiceStack.Common.Tests +{ + public static class IocExtensions + { + public static void InjectRequestIntoDependencies(this object instance, IRequest req) + { + foreach (var pi in instance.GetType().GetPublicProperties()) + { + var mi = pi.GetGetMethod(); + if (mi == null) + continue; + + var dep = mi.Invoke(instance, new object[0]); + if (dep is IRequiresRequest requiresRequest) + { + requiresRequest.Request = req; + requiresRequest.InjectRequestIntoDependencies(req); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/JsonServiceClientTests.cs b/tests/ServiceStack.Common.Tests/JsonServiceClientTests.cs new file mode 100644 index 00000000000..2edd2f0d3d5 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/JsonServiceClientTests.cs @@ -0,0 +1,76 @@ +using NUnit.Framework; + +namespace ServiceStack.Common.Tests; + +public class JsonServiceClientTests +{ + [Test] + public void Does_set_BasePath_default_ServiceClient() + { + var client = new JsonServiceClient("https://example.org"); + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/json/reply/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/json/oneway/")); + } + + [Test] + public void Does_set_BasePath_default_HttpClient() + { + var client = new JsonServiceClient("https://example.org"); + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/json/reply/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/json/oneway/")); + } + + [Test] + public void Does_change_BasePath_ServiceClient() + { + var client = new JsonServiceClient("https://example.org") { + UseBasePath = "/api" + }; + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/api/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/api/")); + + client.UseBasePath = null; + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/json/reply/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/json/oneway/")); + } + + [Test] + public void Does_change_BasePath_HttpClient() + { + var client = new JsonHttpClient("https://example.org") { + UseBasePath = "/api" + }; + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/api/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/api/")); + + client.UseBasePath = null; + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/json/reply/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/json/oneway/")); + } + +#if NET6_0_OR_GREATER + [Test] + public void Does_change_BasePath_JsonApiClient() + { + var client = new JsonApiClient("https://example.org"); + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/api/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/api/")); + + client = new JsonApiClient("https://example.org") { + UseBasePath = "/json/reply" + }; + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/json/reply/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/json/reply/")); + + client.UseBasePath = "/api"; + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/api/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/api/")); + + client = new JsonApiClient("https://example.org") + .Apply(c => c.UseBasePath = "/custom"); + Assert.That(client.SyncReplyBaseUri, Is.EqualTo("https://example.org/custom/")); + Assert.That(client.AsyncOneWayBaseUri, Is.EqualTo("https://example.org/custom/")); + } +#endif + +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ManageRolesTests.cs b/tests/ServiceStack.Common.Tests/ManageRolesTests.cs new file mode 100644 index 00000000000..8c96c1d198f --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ManageRolesTests.cs @@ -0,0 +1,227 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using Amazon.DynamoDBv2; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Aws.DynamoDb; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.Host; +using ServiceStack.OrmLite; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class ManageRolesTests + { + private static Register CreateNewUserRegistration(bool? autoLogin = null) + { + var userId = Environment.TickCount % 10000; + + var newUserRegistration = new Register + { + UserName = "UserName" + userId, + DisplayName = "DisplayName" + userId, + Email = "user{0}@sf.com".Fmt(userId), + FirstName = "FirstName" + userId, + LastName = "LastName" + userId, + Password = "Password" + userId, + AutoLogin = autoLogin, + }; + return newUserRegistration; + } + + [Test] + public void By_default_assigned_roles_are_saved_in_UserAuth_table() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new []{ new BasicAuthProvider() }) + { + IncludeRegistrationService = true, + }); + }, + ConfigureContainer = container => + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + + container.Resolve().InitSchema(); + } + }.Init()) + { + using (var db = appHost.Container.Resolve().Open()) + { + var register = CreateNewUserRegistration(); + var req = new BasicRequest(register) + { + QueryString = { ["authSecret"] = appHost.Config.AdminAuthSecret = "allow" } + }; + + var response = (RegisterResponse)appHost.ExecuteService(register, req); + var userAuth = db.SingleById(response.UserId); + Assert.That(userAuth, Is.Not.Null); + + var assignResponse = (AssignRolesResponse)appHost.ExecuteService(new AssignRoles + { + UserName = userAuth.UserName, + Roles = { "TestRole" }, + Permissions = { "TestPermission" }, + }, req); + Assert.That(assignResponse.AllRoles[0], Is.EqualTo("TestRole")); + Assert.That(assignResponse.AllPermissions[0], Is.EqualTo("TestPermission")); + + userAuth = db.SingleById(response.UserId); + Assert.That(userAuth.Roles[0], Is.EqualTo("TestRole")); + Assert.That(userAuth.Permissions[0], Is.EqualTo("TestPermission")); + + appHost.ExecuteService(new UnAssignRoles + { + UserName = userAuth.UserName, + Roles = { "TestRole" }, + Permissions = { "TestPermission" }, + }, req); + + userAuth = db.SingleById(response.UserId); + Assert.That(userAuth.Roles.Count, Is.EqualTo(0)); + Assert.That(userAuth.Permissions.Count, Is.EqualTo(0)); + } + } + } + + [Test] + public void Can_assign_roles_that_persist_to_UserAuthRole_table() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new[] { new BasicAuthProvider() }) + { + IncludeRegistrationService = true, + }); + }, + ConfigureContainer = container => + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve()) { + UseDistinctRoleTables = true, + }); + + container.Resolve().InitSchema(); + } + }.Init()) + { + using (var db = appHost.Container.Resolve().Open()) + { + var register = CreateNewUserRegistration(); + var req = new BasicRequest(register); + req.QueryString["authSecret"] = appHost.Config.AdminAuthSecret = "allow"; + + var response = (RegisterResponse)appHost.ExecuteService(register, req); + var userAuth = db.SingleById(response.UserId); + + var assignResponse = (AssignRolesResponse)appHost.ExecuteService(new AssignRoles + { + UserName = userAuth.UserName, + Roles = { "TestRole" }, + Permissions = { "TestPermission" }, + }, req); + Assert.That(assignResponse.AllRoles[0], Is.EqualTo("TestRole")); + Assert.That(assignResponse.AllPermissions[0], Is.EqualTo("TestPermission")); + + Assert.That(userAuth.Roles.Count, Is.EqualTo(0)); + Assert.That(userAuth.Permissions.Count, Is.EqualTo(0)); + + var manageRoles = (IManageRoles)appHost.Container.Resolve(); + Assert.That(manageRoles.HasRole(userAuth.Id.ToString(), "TestRole")); + Assert.That(manageRoles.HasPermission(userAuth.Id.ToString(), "TestPermission")); + + appHost.ExecuteService(new UnAssignRoles + { + UserName = userAuth.UserName, + Roles = { "TestRole" }, + Permissions = { "TestPermission" }, + }, req); + + Assert.That(!manageRoles.HasRole(userAuth.Id.ToString(), "TestRole")); + Assert.That(!manageRoles.HasPermission(userAuth.Id.ToString(), "TestPermission")); + } + } + } + + [Test] + public void Can_assign_roles_that_persist_to_UserAuthRole_table_in_DynamoDb() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new[] { new BasicAuthProvider() }) + { + IncludeRegistrationService = true, + }); + }, + ConfigureContainer = container => + { + container.Register(c => new PocoDynamo(TestsConfig.CreateDynamoDBClient())); + //DynamoMetadata.Reset(); + container.Resolve().DeleteAllTables(TimeSpan.FromMinutes(1)); + + container.Register(c => new DynamoDbAuthRepository(c.Resolve())); + container.Resolve().InitSchema(); + } + }.Init()) + { + var db = appHost.Container.Resolve(); + + var register = CreateNewUserRegistration(); + var req = new BasicRequest(register) { + QueryString = {["authSecret"] = appHost.Config.AdminAuthSecret = "allow"} + }; + + var ret = appHost.ExecuteService(register, req); + var response = (RegisterResponse)ret; + var userAuth = db.GetItem(response.UserId); + + var assignResponse = (AssignRolesResponse)appHost.ExecuteService(new AssignRoles + { + UserName = userAuth.UserName, + Roles = { "TestRole" }, + Permissions = { "TestPermission" }, + }, req); + Assert.That(assignResponse.AllRoles[0], Is.EqualTo("TestRole")); + Assert.That(assignResponse.AllPermissions[0], Is.EqualTo("TestPermission")); + + Assert.That(userAuth.Roles.Count, Is.EqualTo(0)); + Assert.That(userAuth.Permissions.Count, Is.EqualTo(0)); + + var manageRoles = (IManageRoles)appHost.Container.Resolve(); + Assert.That(manageRoles.HasRole(userAuth.Id.ToString(), "TestRole")); + Assert.That(manageRoles.HasPermission(userAuth.Id.ToString(), "TestPermission")); + + appHost.ExecuteService(new UnAssignRoles + { + UserName = userAuth.UserName, + Roles = { "TestRole" }, + Permissions = { "TestPermission" }, + }, req); + + Assert.That(!manageRoles.HasRole(userAuth.Id.ToString(), "TestRole")); + Assert.That(!manageRoles.HasPermission(userAuth.Id.ToString(), "TestPermission")); + } + } + + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/MappingTests.cs b/tests/ServiceStack.Common.Tests/MappingTests.cs deleted file mode 100644 index 3ebe9a01831..00000000000 --- a/tests/ServiceStack.Common.Tests/MappingTests.cs +++ /dev/null @@ -1,334 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using NUnit.Framework; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests -{ - public class User - { - public string FirstName { get; set; } - [DataMember] - public string LastName { get; set; } - public Car Car { get; set; } - } - - public class UserFields - { - public string FirstName; - public string LastName; - public Car Car; - } - - public class SubUser : User { } - public class SubUserFields : UserFields { } - - public class Car - { - public string Name { get; set; } - public int Age { get; set; } - } - - public class UserDto - { - public string FirstName { get; set; } - public string LastName { get; set; } - public string Car { get; set; } - } - - public enum Color - { - Red, - Green, - Blue - } - - public enum OtherColor - { - Red, - Green, - Blue - } - - - public class IntNullableId - { - public int? Id { get; set; } - } - - public class IntId - { - public int Id { get; set; } - } - - public class BclTypes - { - public int Int { get; set; } - public long Long { get; set; } - public double Double { get; set; } - public decimal Decimal { get; set; } - } - - public class BclTypeStrings - { - public string Int { get; set; } - public string Long { get; set; } - public string Double { get; set; } - public string Decimal { get; set; } - } - - public class NullableConversion - { - public decimal Amount { get; set; } - } - - public class NullableConversionDto - { - public decimal? Amount { get; set; } - } - - public class NullableEnumConversion - { - public Color Color { get; set; } - } - - public class EnumConversion - { - public Color Color { get; set; } - } - - public class NullableEnumConversionDto - { - public OtherColor? Color { get; set; } - } - - public class EnumConversionDto - { - public OtherColor Color { get; set; } - } - - public class EnumConversionStringDto - { - public string Color { get; set; } - } - - public class EnumConversionIntDto - { - public int Color { get; set; } - } - - [TestFixture] - public class MappingTests - { - [Test] - public void Does_populate() - { - var user = new User() { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car() { Name = "BMW X6", Age = 3 } - }; - - var userDto = new UserDto().PopulateWith(user); - - Assert.That(userDto.FirstName, Is.EqualTo(user.FirstName)); - Assert.That(userDto.LastName, Is.EqualTo(user.LastName)); - Assert.That(userDto.Car, Is.EqualTo("{Name:BMW X6,Age:3}")); - } - - [Test] - public void Does_translate() - { - var user = new User() { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car() { Name = "BMW X6", Age = 3 } - }; - - var userDto = user.TranslateTo(); - - Assert.That(userDto.FirstName, Is.EqualTo(user.FirstName)); - Assert.That(userDto.LastName, Is.EqualTo(user.LastName)); - Assert.That(userDto.Car, Is.EqualTo("{Name:BMW X6,Age:3}")); - } - - [Test] - public void Does_enumstringconversion_translate() - { - var conversion = new EnumConversion { Color = Color.Blue }; - var conversionDto = conversion.TranslateTo(); - - Assert.That(conversionDto.Color, Is.EqualTo("Blue")); - } - - [Test] - public void Does_enumintconversion_translate() - { - var conversion = new EnumConversion { Color = Color.Green }; - var conversionDto = conversion.TranslateTo(); - - Assert.That(conversionDto.Color, Is.EqualTo(1)); - } - - [Test] - public void Does_nullableconversion_translate() - { - var conversion = new NullableConversion { Amount = 123.45m }; - var conversionDto = conversion.TranslateTo(); - - Assert.That(conversionDto.Amount, Is.EqualTo(123.45m)); - } - - [Test] - public void Does_Enumnullableconversion_translate() - { - var conversion = new NullableEnumConversion { Color = Color.Green }; - var conversionDto = conversion.TranslateTo(); - - Assert.That(conversionDto.Color, Is.EqualTo(OtherColor.Green)); - - } - - [Test] - public void Does_Enumconversion_translate() - { - var conversion = new NullableEnumConversion { Color = Color.Green }; - var conversionDto = conversion.TranslateTo(); - - Assert.That(conversionDto.Color, Is.EqualTo(OtherColor.Green)); - - } - - [Test] - public void Does_translate_nullableInt_to_and_from() - { - var nullable = new IntNullableId(); - - var nonNullable = nullable.TranslateTo(); - - nonNullable.Id = 10; - - var expectedNullable = nonNullable.TranslateTo(); - - Assert.That(expectedNullable.Id.Value, Is.EqualTo(nonNullable.Id)); - } - - [Test] - public void Does_translate_from_properties_to_fields() - { - var user = new User { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car { Name = "BMW X6", Age = 3 } - }; - - var to = user.TranslateTo(); - Assert.That(to.FirstName, Is.EqualTo(user.FirstName)); - Assert.That(to.LastName, Is.EqualTo(user.LastName)); - Assert.That(to.Car.Name, Is.EqualTo(user.Car.Name)); - Assert.That(to.Car.Age, Is.EqualTo(user.Car.Age)); - } - - [Test] - public void Does_translate_from_fields_to_properties() - { - var user = new UserFields { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car { Name = "BMW X6", Age = 3 } - }; - - var to = user.TranslateTo(); - Assert.That(to.FirstName, Is.EqualTo(user.FirstName)); - Assert.That(to.LastName, Is.EqualTo(user.LastName)); - Assert.That(to.Car.Name, Is.EqualTo(user.Car.Name)); - Assert.That(to.Car.Age, Is.EqualTo(user.Car.Age)); - } - - [Test] - public void Does_translate_from_inherited_propeties() - { - var user = new SubUser { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car { Name = "BMW X6", Age = 3 } - }; - - var to = user.TranslateTo(); - Assert.That(to.FirstName, Is.EqualTo(user.FirstName)); - Assert.That(to.LastName, Is.EqualTo(user.LastName)); - Assert.That(to.Car.Name, Is.EqualTo(user.Car.Name)); - Assert.That(to.Car.Age, Is.EqualTo(user.Car.Age)); - } - - [Test] - public void Does_translate_to_inherited_propeties() - { - var user = new User { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car { Name = "BMW X6", Age = 3 } - }; - - var to = user.TranslateTo(); - Assert.That(to.FirstName, Is.EqualTo(user.FirstName)); - Assert.That(to.LastName, Is.EqualTo(user.LastName)); - Assert.That(to.Car.Name, Is.EqualTo(user.Car.Name)); - Assert.That(to.Car.Age, Is.EqualTo(user.Car.Age)); - } - - [Test] - public void Does_coerce_from_BclTypes_to_strings() - { - var from = new BclTypes { - Int = 1, - Long = 2, - Double = 3.3, - Decimal = 4.4m, - }; - - var to = from.TranslateTo(); - Assert.That(to.Int, Is.EqualTo("1")); - Assert.That(to.Long, Is.EqualTo("2")); - Assert.That(to.Double, Is.EqualTo("3.3")); - Assert.That(to.Decimal, Is.EqualTo("4.4")); - } - - [Test] - public void Does_coerce_from_strings_to_BclTypes() - { - var from = new BclTypeStrings { - Int = "1", - Long = "2", - Double = "3.3", - Decimal = "4.4", - }; - - var to = from.TranslateTo(); - Assert.That(to.Int, Is.EqualTo(1)); - Assert.That(to.Long, Is.EqualTo(2)); - Assert.That(to.Double, Is.EqualTo(3.3d)); - Assert.That(to.Decimal, Is.EqualTo(4.4m)); - } - - [Test] - public void Does_map_only_properties_with_specified_Attribute() - { - var user = new User { - FirstName = "Demis", - LastName = "Bellot", - Car = new Car { Name = "BMW X6", Age = 3 } - }; - - var to = new User(); - to.PopulateFromPropertiesWithAttribute(user, typeof(DataMemberAttribute)); - - Assert.That(to.LastName, Is.EqualTo(user.LastName)); - Assert.That(to.FirstName, Is.Null); - Assert.That(to.Car, Is.Null); - } - } -} diff --git a/tests/ServiceStack.Common.Tests/Messaging/MqServerAppHostTests.cs b/tests/ServiceStack.Common.Tests/Messaging/MqServerAppHostTests.cs new file mode 100644 index 00000000000..f8087ce7276 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Messaging/MqServerAppHostTests.cs @@ -0,0 +1,442 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.FluentValidation; +using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; +using ServiceStack.RabbitMq; +using ServiceStack.Redis; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.Common.Tests.Messaging +{ + [TestFixture, Ignore("Can cause CI to hang")] + public class RedisMqServerAppHostTests : MqServerAppHostTests + { + public RedisMqServerAppHostTests() + { + using (var redis = ((RedisMqServer)CreateMqServer()).ClientsManager.GetClient()) + redis.FlushAll(); + } + + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new RedisMqServer(new PooledRedisClientManager()) { RetryCount = retryCount }; + } + } + + [TestFixture, Ignore("Can cause CI to hang")] + public class RabbitMqServerAppHostTests : MqServerAppHostTests + { + public RabbitMqServerAppHostTests() + { + using (var conn = ((RabbitMqServer)CreateMqServer()).ConnectionFactory.CreateConnection()) + using (var channel = conn.CreateModel()) + { + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + } + } + + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new RabbitMqServer(TestsConfig.RabbitMqHost) { + RetryCount = 1 + }; + } + } + + [TestFixture] + public class MemoryMqServerAppHostTests : MqServerAppHostTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new InMemoryTransientMessageService { RetryCount = retryCount }; + } + } + + [TestFixture] + public class BackgroundMqServerAppHostTests : MqServerAppHostTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new BackgroundMqService { RetryCount = retryCount }; + } + } + + + public class AnyTestMq + { + public int Id { get; set; } + } + + public class AnyTestMqAsync + { + public int Id { get; set; } + } + + public class AnyTestMqResponse + { + public int CorrelationId { get; set; } + } + + public class PostTestMq + { + public int Id { get; set; } + } + + public class PostTestMqResponse + { + public int CorrelationId { get; set; } + } + + public class ValidateTestMq + { + public int Id { get; set; } + } + + public class ValidateTestMqResponse + { + public int CorrelationId { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class ThrowGenericError + { + public int Id { get; set; } + } + + public class ValidateTestMqValidator : AbstractValidator + { + public ValidateTestMqValidator() + { + RuleFor(x => x.Id) + .GreaterThanOrEqualTo(0) + .WithErrorCode("PositiveIntegersOnly"); + } + } + + public class ThrowVoid + { + public string Content { get; set; } + } + + public class TestMqService : IService + { + public object Any(AnyTestMq request) + { + return new AnyTestMqResponse { CorrelationId = request.Id }; + } + + public async Task Any(AnyTestMqAsync request) + { + return await Task.Factory.StartNew(() => + new AnyTestMqResponse { CorrelationId = request.Id }); + } + + public object Post(PostTestMq request) + { + return new PostTestMqResponse { CorrelationId = request.Id }; + } + + public object Post(ValidateTestMq request) + { + return new ValidateTestMqResponse { CorrelationId = request.Id }; + } + + public object Post(ThrowGenericError request) + { + throw new ArgumentException("request"); + } + + public void Any(ThrowVoid request) + { + throw new InvalidOperationException("this is an invalid operation"); + } + } + + public class MqTestsAppHost : AppSelfHostBase + { + private readonly Func createMqServerFn; + + public MqTestsAppHost(Func createMqServerFn) + : base("Service Name", typeof(AnyTestMq).Assembly) + { + this.createMqServerFn = createMqServerFn; + } + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + container.RegisterValidators(typeof(ValidateTestMqValidator).Assembly); + + container.Register(c => createMqServerFn()); + + var mqServer = container.Resolve(); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(ExecuteMessage); + + AfterInitCallbacks.Add(appHost => mqServer.Start()); + } + } + + [TestFixture] + public abstract class MqServerAppHostTests + { + protected const string ListeningOn = "http://*:2001/"; + public const string Host = "http://localhost:2001"; + private const string BaseUri = Host + "/"; + + protected ServiceStackHost appHost; + + public abstract IMessageService CreateMqServer(int retryCount = 1); + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new MqTestsAppHost(() => CreateMqServer()) + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public virtual void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_send_to_DLQ_when_thrown_from_void_Service() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new ThrowVoid { Content = "Test" }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + mqProducer.Publish(request); + + var msg = mqClient.Get(QueueNames.Dlq, null); + mqClient.Ack(msg); + + Assert.That(msg.Error.ErrorCode, Is.EqualTo("InvalidOperationException")); + } + } + } + + [Test] + public void Can_Publish_to_AnyTestMq_Service() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new AnyTestMq { Id = 1 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + mqProducer.Publish(request); + + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get(QueueNames.In, null); + mqClient.Ack(msg); + Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + } + + [Test] + public void Can_Publish_to_AnyTestMqAsync_Service() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new AnyTestMqAsync { Id = 1 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + mqProducer.Publish(request); + + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get(QueueNames.In, null); + mqClient.Ack(msg); + Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + } + + [Test] + public void Can_Publish_to_PostTestMq_Service() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new PostTestMq { Id = 2 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + mqProducer.Publish(request); + + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get(QueueNames.In, null); + mqClient.Ack(msg); + Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + } + + [Test] + public void SendOneWay_calls_AnyTestMq_Service_via_MQ() + { + var client = new JsonServiceClient(BaseUri); + var request = new AnyTestMq { Id = 3 }; + + client.SendOneWay(request); + + using (var mqFactory = appHost.TryResolve()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get(QueueNames.In, null); + mqClient.Ack(msg); + Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + + [Test] + public void SendOneWay_calls_PostTestMq_Service_via_MQ() + { + var client = new JsonServiceClient(BaseUri); + var request = new PostTestMq { Id = 4 }; + + client.SendOneWay(request); + + using (var mqFactory = appHost.TryResolve()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get(QueueNames.In, null); + mqClient.Ack(msg); + Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + + [Test] + public void Does_execute_validation_filters() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new ValidateTestMq { Id = -10 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + mqProducer.Publish(request); + + var errorMsg = mqClient.Get(QueueNames.Dlq, null); + mqClient.Ack(errorMsg); + + Assert.That(errorMsg.Error.ErrorCode, Is.EqualTo("PositiveIntegersOnly")); + + request = new ValidateTestMq { Id = 10 }; + mqProducer.Publish(request); + var responseMsg = mqClient.Get(QueueNames.In, null); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + } + + [Test] + public void Does_handle_generic_errors() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new ThrowGenericError { Id = 1 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + mqProducer.Publish(request); + + var msg = mqClient.Get(QueueNames.Dlq, null); + mqClient.Ack(msg); + + Assert.That(msg.Error.ErrorCode, Is.EqualTo("ArgumentException")); + } + } + } + + [Test] + public void Does_execute_ReplyTo_validation_filters() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new ValidateTestMq { Id = -10 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var requestMsg = new Message(request) + { + ReplyTo = "mq:{0}.replyto".Fmt(request.GetType().Name) + }; + mqProducer.Publish(requestMsg); + + var errorMsg = mqClient.Get(requestMsg.ReplyTo, null); + mqClient.Ack(errorMsg); + + Assert.That(errorMsg.GetBody().ResponseStatus.ErrorCode, Is.EqualTo("PositiveIntegersOnly")); + + request = new ValidateTestMq { Id = 10 }; + requestMsg = new Message(request) + { + ReplyTo = "mq:{0}.replyto".Fmt(request.GetType().Name) + }; + mqProducer.Publish(requestMsg); + var responseMsg = mqClient.Get(requestMsg.ReplyTo, null); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().CorrelationId, Is.EqualTo(request.Id)); + } + } + } + + [Test] + public void Does_handle_ReplyTo_generic_errors() + { + using (var mqFactory = appHost.TryResolve()) + { + var request = new ThrowGenericError { Id = 1 }; + + using (var mqProducer = mqFactory.CreateMessageProducer()) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var requestMsg = new Message(request) + { + ReplyTo = $"mq:{request.GetType().Name}.replyto" + }; + mqProducer.Publish(requestMsg); + + var msg = mqClient.Get(requestMsg.ReplyTo, null); + mqClient.Ack(msg); + + Assert.That(msg.GetBody().ResponseStatus.ErrorCode, Is.EqualTo("ArgumentException")); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Messaging/RabbitMqTests.cs b/tests/ServiceStack.Common.Tests/Messaging/RabbitMqTests.cs new file mode 100644 index 00000000000..2c1b8f512fc --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Messaging/RabbitMqTests.cs @@ -0,0 +1,397 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using NUnit.Framework; +using RabbitMQ.Client; +using RabbitMQ.Client.Exceptions; +using ServiceStack.Messaging; +using ServiceStack.RabbitMq; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests.Messaging +{ + public class HelloRabbit + { + public string Name { get; set; } + } + + [TestFixture, Ignore("Integration Test")] + public class RabbitMqTests + { + private readonly ConnectionFactory mqFactory = new ConnectionFactory { + HostName = TestsConfig.RabbitMqHost + }; + private const string Exchange = "mq:tests"; + private const string ExchangeDlq = "mq:tests.dlq"; + private const string ExchangeTopic = "mq:tests.topic"; + private const string ExchangeFanout = "mq:tests.fanout"; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + channel.RegisterDirectExchange(Exchange); + channel.RegisterDlqExchange(ExchangeDlq); + channel.RegisterTopicExchange(ExchangeTopic); + + RegisterQueue(channel, QueueNames.In); + RegisterQueue(channel, QueueNames.Priority); + RegisterDlq(channel, QueueNames.Dlq); + RegisterTopic(channel, QueueNames.Out); + RegisterQueue(channel, QueueNames.In, exchange: ExchangeTopic); + + channel.PurgeQueue(); + } + } + + public static void RegisterQueue(IModel channel, string queueName, string exchange = Exchange) + { + var args = new Dictionary { + {"x-dead-letter-exchange", ExchangeDlq }, + {"x-dead-letter-routing-key", queueName.Replace(".inq",".dlq").Replace(".priorityq",".dlq") }, + }; + channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false, arguments: args); + channel.QueueBind(queueName, exchange, routingKey: queueName); + } + + public static void RegisterTopic(IModel channel, string queueName) + { + channel.QueueDeclare(queueName, durable: false, exclusive: false, autoDelete: false, arguments: null); + channel.QueueBind(queueName, ExchangeTopic, routingKey: queueName); + } + + public static void RegisterDlq(IModel channel, string queueName) + { + channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false, arguments: null); + channel.QueueBind(queueName, ExchangeDlq, routingKey: queueName); + } + + public void ExchangeDelete(IModel channel, string exchange) + { + try + { + channel.ExchangeDelete(exchange); + } + catch (Exception ex) + { + "Error ExchangeDelete(): {0}".Print(ex.Message); + } + } + + [Test] + public void Can_publish_messages_to_RabbitMQ() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + 5.Times(i => + { + byte[] payload = new HelloRabbit { Name = "World! #{0}".Fmt(i) }.ToJson().ToUtf8Bytes(); + var props = channel.CreateBasicProperties(); + props.Persistent = true; + + channel.BasicPublish(exchange: Exchange, + routingKey: QueueNames.In, basicProperties: props, body: payload); + + Console.WriteLine("Sent Message " + i); + Thread.Sleep(1000); + }); + } + } + + [Test] + public void Can_consume_messages_from_RabbitMQ_with_BasicGet() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + PublishHelloRabbit(channel); + + while (true) + { + var basicGetMsg = channel.BasicGet(QueueNames.In, autoAck: false); + + if (basicGetMsg == null) + { + "End of the road...".Print(); + return; + } + + var msg = basicGetMsg.Body.FromUtf8Bytes().FromJson(); + + Thread.Sleep(1000); + + channel.BasicAck(basicGetMsg.DeliveryTag, multiple: false); + } + } + } + + [Test] + public void Can_consume_messages_from_RabbitMQ_with_BasicConsume() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + var consumer = new QueueingBasicConsumer(channel); + var consumerTag = channel.BasicConsume(QueueNames.In, autoAck: false, consumer: consumer); + string recvMsg = null; + + ThreadPool.QueueUserWorkItem(_ => + { + Thread.Sleep(100); + PublishHelloRabbit(channel); + }); + + while (true) + { + try + { + var e = consumer.Queue.Dequeue(); + "Dequeued".Print(); + + var props = e.BasicProperties; + recvMsg = e.Body.FromUtf8Bytes(); + // ... process the message + recvMsg.Print(); + + channel.BasicAck(e.DeliveryTag, multiple: false); + break; + } + catch (OperationInterruptedException) + { + // The consumer was removed, either through + // channel or connection closure, or through the + // action of IModel.BasicCancel(). + "End of the road...".Print(); + break; + } + } + + Assert.That(recvMsg, Is.Not.Null); + } + } + + [Test] + public void Publishing_message_with_routingKey_sends_only_to_registered_queue() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + PublishHelloRabbit(channel); + + var basicGetMsg = channel.BasicGet(QueueNames.In, autoAck: true); + Assert.That(basicGetMsg, Is.Not.Null); + + basicGetMsg = channel.BasicGet(QueueNames.Priority, autoAck: true); + Assert.That(basicGetMsg, Is.Null); + } + } + + private static void PublishHelloRabbit(IModel channel, string text = "World!") + { + byte[] payload = new HelloRabbit { Name = text }.ToJson().ToUtf8Bytes(); + var props = channel.CreateBasicProperties(); + props.Persistent = true; + channel.BasicPublish(Exchange, QueueNames.In, props, payload); + } + + [Test] + public void Publishing_message_to_fanout_exchange_publishes_to_all_queues() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + channel.RegisterFanoutExchange(ExchangeFanout); + + RegisterQueue(channel, QueueNames.In, exchange: ExchangeFanout); + RegisterQueue(channel, QueueNames.Priority, exchange: ExchangeFanout); + + byte[] payload = new HelloRabbit { Name = "World!" }.ToJson().ToUtf8Bytes(); + var props = channel.CreateBasicProperties(); + props.Persistent = true; + + channel.BasicPublish(ExchangeFanout, QueueNames.In, props, payload); + + var basicGetMsg = channel.BasicGet(QueueNames.In, autoAck: true); + Assert.That(basicGetMsg, Is.Not.Null); + + basicGetMsg = channel.BasicGet(QueueNames.Priority, autoAck: true); + Assert.That(basicGetMsg, Is.Not.Null); + } + } + + [Test] + public void Does_publish_to_dead_letter_exchange() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.OpenChannel()) + { + PublishHelloRabbit(channel); + + var basicGetMsg = channel.BasicGet(QueueNames.In, autoAck: true); + var dlqBasicMsg = channel.BasicGet(QueueNames.Dlq, autoAck: true); + Assert.That(basicGetMsg, Is.Not.Null); + Assert.That(dlqBasicMsg, Is.Null); + + PublishHelloRabbit(channel); + + basicGetMsg = channel.BasicGet(QueueNames.In, autoAck: false); + Thread.Sleep(500); + dlqBasicMsg = channel.BasicGet(QueueNames.Dlq, autoAck: false); + Assert.That(basicGetMsg, Is.Not.Null); + Assert.That(dlqBasicMsg, Is.Null); + + channel.BasicNack(basicGetMsg.DeliveryTag, multiple: false, requeue: false); + + Thread.Sleep(500); + dlqBasicMsg = channel.BasicGet(QueueNames.Dlq, autoAck: true); + Assert.That(dlqBasicMsg, Is.Not.Null); + } + } + + [Test] + public void Can_interrupt_BasicConsumer_in_bgthread_by_closing_channel() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + string recvMsg = null; + EndOfStreamException lastEx = null; + + var bgThread = new Thread(() => + { + try + { + var consumer = new QueueingBasicConsumer(channel); + channel.BasicConsume(QueueNames.In, autoAck: false, consumer: consumer); + + while (true) + { + try + { + var e = consumer.Queue.Dequeue(); + recvMsg = e.Body.FromUtf8Bytes(); + } + catch (EndOfStreamException ex) + { + // The consumer was cancelled, the model closed, or the + // connection went away. + "EndOfStreamException in bgthread: {0}".Print(ex.Message); + lastEx = ex; + return; + } + catch (Exception ex) + { + Assert.Fail("Unexpected exception in bgthread: " + ex.Message); + } + } + } + catch (Exception ex) + { + "Exception in bgthread: {0}: {1}".Print(ex.GetType().Name, ex.Message); + } + }) + { + Name = "Closing Channel Test", + IsBackground = true, + }; + bgThread.Start(); + + PublishHelloRabbit(channel); + Thread.Sleep(100); + + //closing either throws EndOfStreamException in bgthread + channel.Close(); + //connection.Close(); + + Thread.Sleep(2000); + + Assert.That(recvMsg, Is.Not.Null); + Assert.That(lastEx, Is.Not.Null); + + "EOF...".Print(); + } + } + + [Test] + public void Can_consume_messages_with_BasicConsumer() + { + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + OperationInterruptedException lastEx = null; + + channel.Close(); + + ThreadPool.QueueUserWorkItem(_ => + { + try + { + PublishHelloRabbit(channel); + } + catch (Exception ex) + { + lastEx = ex as OperationInterruptedException; + "Caught {0}: {1}".Print(ex.GetType().Name, ex); + } + }); + + Thread.Sleep(1000); + + Assert.That(lastEx, Is.Not.Null); + + "EOF...".Print(); + } + } + + [Test] + public void Delete_all_queues_and_exchanges() + { + var exchangeNames = new[] { + Exchange, + ExchangeDlq, + ExchangeTopic, + ExchangeFanout, + QueueNames.Exchange, + QueueNames.ExchangeDlq, + QueueNames.ExchangeTopic, + }; + + using (IConnection connection = mqFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + exchangeNames.Each(x => channel.ExchangeDelete(x)); + + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + channel.DeleteQueue(); + } + } + } + + //Dummy messages to delete Queue's created else where. + public class AlwaysThrows { } + public class Hello { } + public class HelloResponse { } + public class Reverse { } + public class Rot13 { } + public class Wait { } + +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Messaging/RedisMqServerTests.cs b/tests/ServiceStack.Common.Tests/Messaging/RedisMqServerTests.cs deleted file mode 100644 index 99be790fb13..00000000000 --- a/tests/ServiceStack.Common.Tests/Messaging/RedisMqServerTests.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Funq; -using NUnit.Framework; -using ServiceStack.Configuration; -using ServiceStack.Messaging; -using ServiceStack.Redis; -using ServiceStack.Redis.Messaging; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints; - -namespace ServiceStack.Common.Tests.Messaging -{ - public class AnyTestMq - { - public int Id { get; set; } - } - - public class AnyTestMqResponse - { - public int CorrelationId { get; set; } - } - - public class PostTestMq - { - public int Id { get; set; } - } - - public class PostTestMqResponse - { - public int CorrelationId { get; set; } - } - - public class TestMqService : IService - { - public object Any(AnyTestMq request) - { - return new AnyTestMqResponse { CorrelationId = request.Id }; - } - - public object Post(PostTestMq request) - { - return new PostTestMqResponse { CorrelationId = request.Id }; - } - } - - public class AppHost : AppHostHttpListenerBase - { - public AppHost() - : base("Service Name", typeof(AnyTestMq).Assembly) { } - - public override void Configure(Container container) - { - var appSettings = new AppSettings(); - container.Register(c => new PooledRedisClientManager( - new string[] { appSettings.GetString("Redis.Host") ?? "localhost" })); - container.Register(c => new RedisMqServer(c.Resolve())); - container.Register(c => c.Resolve().MessageFactory); - - var mqServer = (RedisMqServer)container.Resolve(); - mqServer.RegisterHandler(ServiceController.ExecuteMessage); - mqServer.RegisterHandler(ServiceController.ExecuteMessage); - - mqServer.Start(); - } - } - - [TestFixture] - public class RedisMqServerTests - { - private const string ListeningOn = "http://*:1337/"; - public const string Host = "http://localhost:1337"; - private const string BaseUri = Host + "/"; - - AppHost appHost; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - appHost = new AppHost(); - appHost.Init(); - appHost.Start(ListeningOn); - - using (var redis = appHost.TryResolve().GetClient()) - redis.FlushAll(); - } - - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - appHost.Dispose(); - appHost = null; - } - - [Test] - public void Can_Publish_to_AnyTestMq_Service() - { - using (var mqFactory = appHost.TryResolve()) - { - var request = new AnyTestMq { Id = 1 }; - mqFactory.CreateMessageProducer().Publish(request); - var msg = mqFactory.CreateMessageQueueClient().Get(QueueNames.In, null) - .ToMessage(); - Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); - } - } - - [Test] - public void Can_Publish_to_PostTestMq_Service() - { - using (var mqFactory = appHost.TryResolve()) - { - var request = new PostTestMq { Id = 2 }; - mqFactory.CreateMessageProducer().Publish(request); - var msg = mqFactory.CreateMessageQueueClient().Get(QueueNames.In, null) - .ToMessage(); - Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); - } - } - - [Test] - public void SendOneWay_calls_AnyTestMq_Service_via_MQ() - { - var client = new JsonServiceClient(BaseUri); - var request = new AnyTestMq { Id = 3 }; - - client.SendOneWay(request); - - using (var mqFactory = appHost.TryResolve()) - { - var msg = mqFactory.CreateMessageQueueClient().Get(QueueNames.In, null) - .ToMessage(); - Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); - } - } - - [Test] - public void SendOneWay_calls_PostTestMq_Service_via_MQ() - { - var client = new JsonServiceClient(BaseUri); - var request = new PostTestMq { Id = 4 }; - - client.SendOneWay(request); - - using (var mqFactory = appHost.TryResolve()) - { - var msg = mqFactory.CreateMessageQueueClient().Get(QueueNames.In, null) - .ToMessage(); - Assert.That(msg.GetBody().CorrelationId, Is.EqualTo(request.Id)); - } - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/MessagingTests.cs b/tests/ServiceStack.Common.Tests/MessagingTests.cs index 07dc2822a5a..c909555cc72 100644 --- a/tests/ServiceStack.Common.Tests/MessagingTests.cs +++ b/tests/ServiceStack.Common.Tests/MessagingTests.cs @@ -1,61 +1,63 @@ -using NUnit.Framework; +#if !NETCORE +using NUnit.Framework; +using ServiceStack.Auth; using ServiceStack.Messaging; -using ServiceStack.ServiceInterface.Auth; using ServiceStack.Text; namespace ServiceStack.Common.Tests { - public class Incr - { - public int Value { get; set; } - } + public class Incr + { + public int Value { get; set; } + } public class TestUserSession : AuthUserSession { } - [TestFixture] - public class MessagingTests - { - [Test] - public void Can_serialize_IMessage_into_typed_Message() - { - var dto = new Incr { Value = 1 }; - IMessage iMsg = MessageFactory.Create(dto); - var json = iMsg.ToJson(); - var typedMessage = json.FromJson>(); - - Assert.That(typedMessage.GetBody().Value, Is.EqualTo(dto.Value)); - } - - [Test] - public void Can_serialize_object_IMessage_into_typed_Message() - { - var dto = new Incr { Value = 1 }; - var iMsg = MessageFactory.Create(dto); - var json = ((object)iMsg).ToJson(); - var typedMessage = json.FromJson>(); - - Assert.That(typedMessage.GetBody().Value, Is.EqualTo(dto.Value)); - } - - [Test] - public void Can_serialize_IMessage_ToBytes_into_typed_Message() - { - var dto = new Incr { Value = 1 }; - var iMsg = MessageFactory.Create(dto); - var bytes = iMsg.ToBytes(); - var typedMessage = bytes.ToMessage(); - - Assert.That(typedMessage.GetBody().Value, Is.EqualTo(dto.Value)); - } - - [Test] - public void Can_deserialize_concrete_type_into_IOAuthSession() - { + [TestFixture] + public class MessagingTests + { + [Test] + public void Can_serialize_IMessage_into_typed_Message() + { + var dto = new Incr { Value = 1 }; + IMessage iMsg = MessageFactory.Create(dto); + var json = iMsg.ToJson(); + var typedMessage = json.FromJson>(); + + Assert.That(typedMessage.GetBody().Value, Is.EqualTo(dto.Value)); + } + + [Test] + public void Can_serialize_object_IMessage_into_typed_Message() + { + var dto = new Incr { Value = 1 }; + var iMsg = MessageFactory.Create(dto); + var json = ((object)iMsg).ToJson(); + var typedMessage = json.FromJson>(); + + Assert.That(typedMessage.GetBody().Value, Is.EqualTo(dto.Value)); + } + + [Test] + public void Can_serialize_IMessage_ToBytes_into_typed_Message() + { + var dto = new Incr { Value = 1 }; + var iMsg = MessageFactory.Create(dto); + var bytes = iMsg.ToBytes(); + var typedMessage = bytes.ToMessage(); + + Assert.That(typedMessage.GetBody().Value, Is.EqualTo(dto.Value)); + } + + [Test] + public void Can_deserialize_concrete_type_into_IOAuthSession() + { var json = "{\"__type\":\"ServiceStack.Common.Tests.TestUserSession, ServiceStack.Common.Tests\",\"ReferrerUrl\":\"http://localhost:4629/oauth\",\"Id\":\"0412cc4654484111b2e7162a24a83753\",\"RequestToken\":\"dw4U1RUBr8r5Bx1oBZfdmNiocsMrAtBmSoFHYCZrr4\",\"RequestTokenSecret\":\"HNvCiD1a61CrutnxZoiJXQlLKNN1GAtWn7pRuafYN0\",\"CreatedAt\":\"\\/Date(1320221243138+0000)\\/\",\"LastModified\":\"\\/Date(1320221243138+0000)\\/\",\"Items\":{}}"; - var fromJson = json.FromJson(); - Assert.That(fromJson, Is.Not.Null); - } - } -} \ No newline at end of file + var fromJson = json.FromJson(); + Assert.That(fromJson, Is.Not.Null); + } + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/MockRestGatewayTests.cs b/tests/ServiceStack.Common.Tests/MockRestGatewayTests.cs new file mode 100644 index 00000000000..3092e6a762f --- /dev/null +++ b/tests/ServiceStack.Common.Tests/MockRestGatewayTests.cs @@ -0,0 +1,68 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +#if !NETCORE +using NUnit.Framework; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class MockRestGatewayTests + { + [Test] + public void Can_Mock_RestGateway() + { + var gateway = new MockRestGateway(); + + var response = gateway.Get(new TestGetRequest { Id = 1 }); + Assert.That(response, Is.Null); + + gateway.ResultsFilter = (verb, type, dto) => + verb == HttpMethods.Post + ? new TestPostResponse { + Id = (int)dto.GetId(), + Verb = verb + } + : (object)new TestResponse { + Id = (int)dto.GetId(), + Verb = verb + }; + + response = gateway.Get(new TestGetRequest { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.Verb, Is.EqualTo("GET")); + + response = gateway.Send(new TestGetRequest { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.Verb, Is.EqualTo("GET")); + + var postResponse = gateway.Post(new TestPostRequest { Id = 2 }); + Assert.That(postResponse.Id, Is.EqualTo(2)); + Assert.That(postResponse.Verb, Is.EqualTo("POST")); + } + } + + public class TestGetRequest : IGet, IReturn + { + public int Id { get; set; } + } + + public class TestResponse + { + public int Id { get; set; } + public string Verb { get; set; } + } + + public class TestPostRequest : IGet, IReturn + { + public int Id { get; set; } + } + + public class TestPostResponse + { + public int Id { get; set; } + public string Verb { get; set; } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/BuiltInsFactory.cs b/tests/ServiceStack.Common.Tests/Models/BuiltInsFactory.cs index aa344f310aa..4731b2170fb 100644 --- a/tests/ServiceStack.Common.Tests/Models/BuiltInsFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/BuiltInsFactory.cs @@ -1,55 +1,54 @@ using System; -using System.Collections.Generic; using NUnit.Framework; namespace ServiceStack.Common.Tests.Models { - public class BuiltInsFactory - : ModelFactoryBase - { - readonly string[] StringValues = new[] { - "one", "two", "three", "four", - "five", "six", "seven" - }; + public class BuiltInsFactory + : ModelFactoryBase + { + readonly string[] StringValues = new[] { + "one", "two", "three", "four", + "five", "six", "seven" + }; - public override void AssertIsEqual(string actual, string expected) - { - Assert.That(actual, Is.EqualTo(expected)); - } + public override void AssertIsEqual(string actual, string expected) + { + Assert.That(actual, Is.EqualTo(expected)); + } - public override string CreateInstance(int i) - { - return i < StringValues.Length - ? StringValues[i] - : i.ToString(); - } - } + public override string CreateInstance(int i) + { + return i < StringValues.Length + ? StringValues[i] + : i.ToString(); + } + } - public class IntFactory - : ModelFactoryBase - { - public override void AssertIsEqual(int actual, int expected) - { - Assert.That(actual, Is.EqualTo(expected)); - } + public class IntFactory + : ModelFactoryBase + { + public override void AssertIsEqual(int actual, int expected) + { + Assert.That(actual, Is.EqualTo(expected)); + } - public override int CreateInstance(int i) - { - return i; - } - } + public override int CreateInstance(int i) + { + return i; + } + } - public class DateTimeFactory - : ModelFactoryBase - { - public override void AssertIsEqual(DateTime actual, DateTime expected) - { - Assert.That(actual, Is.EqualTo(expected)); - } + public class DateTimeFactory + : ModelFactoryBase + { + public override void AssertIsEqual(DateTime actual, DateTime expected) + { + Assert.That(actual, Is.EqualTo(expected)); + } - public override DateTime CreateInstance(int i) - { - return new DateTime(i, DateTimeKind.Utc); - } - } + public override DateTime CreateInstance(int i) + { + return new DateTime(i, DateTimeKind.Utc); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/DdnContentIngest.cs b/tests/ServiceStack.Common.Tests/Models/DdnContentIngest.cs index 36436a030bf..d4526665013 100644 --- a/tests/ServiceStack.Common.Tests/Models/DdnContentIngest.cs +++ b/tests/ServiceStack.Common.Tests/Models/DdnContentIngest.cs @@ -1,1118 +1,1115 @@ using System; using System.Collections.Generic; using System.Linq; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Models { - public interface IExternal - { - string ExternalUrn { get; set; } - } - - public interface IExternalDeletable : IExternal - { - bool Delete { get; set; } - } - - public interface IContent : IExternal - { - Guid Id { get; set; } - string Urn { get; set; } - - DateTime CreatedDate { get; set; } - DateTime ModifiedDate { get; set; } - } - - public interface IContentDeletable : IContent - { - DateTime? DeletedDate { get; set; } - } - - public class MergeList - { - public bool Partial { get; set; } - public List Items { get; set; } - - public MergeList() - { - } - - public MergeList(IEnumerable items) - { - this.Items = new List(items); - } - - public override string ToString() - { - return String.Format("{0} {1} {2}s", this.Partial ? "Partial" : "Full", this.Items.NullableCount(), typeof(T).Name); - } - } - - public class CostPoint - { - public string Campaign { get; set; } - public DateTime StartDate { get; set; } - public string CostCode { get; set; } - } - - public enum ExplicitType - { - Unknown, - NotExplicit, - Explicit, - Cleaned - } - - public enum ReleaseType - { - Single, - Album, - Ep, - BoxedSet - } - - public class Batch - { - public Guid Id { get; set; } - public string Name { get; set; } - public string Path { get; set; } - public string SupplierKeyName { get; set; } - public string SupplierName { get; set; } - public string DeliveryKeyName { get; set; } - public long SequenceNumber { get; set; } - - public override string ToString() - { - return String.Format("{0} {1}", this.SupplierKeyName, this.Name); - } - } - - public class Participant - { - public string Name { get; set; } - public string Role { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } - - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.Role); - } - } - - public class ArtistUpdate : IExternal - { - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } - - public string SupplierKeyName { get; set; } - public string Name { get; set; } - - public DateTime? BirthDate { get; set; } - public string BirthPlace { get; set; } - - public DateTime? DeathDate { get; set; } - public string DeathPlace { get; set; } - - public string DecadesActive { get; set; } - - public string Biography { get; set; } - public string BiographyAuthor { get; set; } - - public List AssetIds { get; set; } - - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.ExternalRef); - } - } - - public class AssetUpdate : IExternal - { - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } - - public string SupplierKeyName { get; set; } - - public AssetType AssetType { get; set; } - - public string ExternalOwnerUrn { get; set; } - - public string FileName { get; set; } - public string FileExtension { get; set; } - public long FileSizeBytes { get; set; } - - public string MasterSha256Checksum { get; set; } - public string Md5Checksum { get; set; } - - public int? DurationMs { get; set; } - public int? BitRateKbps { get; set; } - - public int? Width { get; set; } - public int? Height { get; set; } - - public string TranscodedAssetPath { get; set; } - - public string BuildExternalRef() - { - switch (this.AssetType) - { - case AssetType.MasterCoverArt: - case AssetType.MasterArtistArt: - case AssetType.MasterLabelArt: - { - return String.Format("{0}/{1}", this.AssetType, this.MasterSha256Checksum).ToLower(); - } - case AssetType.TrackProduct: - case AssetType.TrackPreview: - { - var externalOwnerRef = Urn.Parse(this.ExternalOwnerUrn).IdValue; - return String.Format("{0}/{1}/{2}/{3}/{4}/{5}", this.AssetType, this.MasterSha256Checksum, externalOwnerRef, this.FileExtension.ToLower(), this.BitRateKbps ?? 0, this.DurationMs ?? 0).ToLower(); - } - default: - { - var message = String.Format("AssetType not supported: {0}-{1}-{2}", AssetType, FileExtension.ToLower(), MasterSha256Checksum); - throw new Exception(message); - } - } - } - - public AssetId CreateAssetId() - { - return new AssetId { AssetType = this.AssetType, ExternalUrn = this.ExternalUrn }; - } - - public override string ToString() - { - return this.ExternalRef; - } - } - - public class LabelUpdate : IExternal - { - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } - - public string SupplierKeyName { get; set; } - public string Name { get; set; } - - public DateTime? EstablishedDate { get; set; } - - public string Biography { get; set; } - public string BiographyAuthor { get; set; } - - public List AssetIds { get; set; } - - public List GetImageAssetIds() - { - return AssetIds.Where(x => x.AssetType.IsImage()).ToList(); - } - - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.ExternalRef); - } - } - - public class ProductUpdate - { - public bool Delete { get; set; } - - public string TerritoryCode { get; set; } - public string Copyright { get; set; } - public string ReportRef { get; set; } - - public bool AllowDownload { get; set; } - public bool AllowStreaming { get; set; } - public bool AllowSubscription { get; set; } - - public bool CollectionOnly { get; set; } - - public DateTime? DownloadStartDate { get; set; } - public DateTime? DownloadEndDate { get; set; } + public interface IExternal + { + string ExternalUrn { get; set; } + } + + public interface IExternalDeletable : IExternal + { + bool Delete { get; set; } + } + + public interface IContent : IExternal + { + Guid Id { get; set; } + string Urn { get; set; } + + DateTime CreatedDate { get; set; } + DateTime ModifiedDate { get; set; } + } + + public interface IContentDeletable : IContent + { + DateTime? DeletedDate { get; set; } + } + + public class MergeList + { + public bool Partial { get; set; } + public List Items { get; set; } + + public MergeList() + { + } + + public MergeList(IEnumerable items) + { + this.Items = new List(items); + } + + public override string ToString() + { + return String.Format("{0} {1} {2}s", this.Partial ? "Partial" : "Full", this.Items.NullableCount(), typeof(T).Name); + } + } + + public class CostPoint + { + public string Campaign { get; set; } + public DateTime StartDate { get; set; } + public string CostCode { get; set; } + } + + public enum ExplicitType + { + Unknown, + NotExplicit, + Explicit, + Cleaned + } + + public enum ReleaseType + { + Single, + Album, + Ep, + BoxedSet + } + + public class Batch + { + public Guid Id { get; set; } + public string Name { get; set; } + public string Path { get; set; } + public string SupplierKeyName { get; set; } + public string SupplierName { get; set; } + public string DeliveryKeyName { get; set; } + public long SequenceNumber { get; set; } + + public override string ToString() + { + return String.Format("{0} {1}", this.SupplierKeyName, this.Name); + } + } + + public class Participant + { + public string Name { get; set; } + public string Role { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } + + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.Role); + } + } + + public class ArtistUpdate : IExternal + { + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } + + public string SupplierKeyName { get; set; } + public string Name { get; set; } + + public DateTime? BirthDate { get; set; } + public string BirthPlace { get; set; } + + public DateTime? DeathDate { get; set; } + public string DeathPlace { get; set; } + + public string DecadesActive { get; set; } + + public string Biography { get; set; } + public string BiographyAuthor { get; set; } + + public List AssetIds { get; set; } + + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.ExternalRef); + } + } + + public class AssetUpdate : IExternal + { + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } + + public string SupplierKeyName { get; set; } + + public AssetType AssetType { get; set; } + + public string ExternalOwnerUrn { get; set; } + + public string FileName { get; set; } + public string FileExtension { get; set; } + public long FileSizeBytes { get; set; } + + public string MasterSha256Checksum { get; set; } + public string Md5Checksum { get; set; } + + public int? DurationMs { get; set; } + public int? BitRateKbps { get; set; } + + public int? Width { get; set; } + public int? Height { get; set; } + + public string TranscodedAssetPath { get; set; } + + public string BuildExternalRef() + { + switch (this.AssetType) + { + case AssetType.MasterCoverArt: + case AssetType.MasterArtistArt: + case AssetType.MasterLabelArt: + { + return String.Format("{0}/{1}", this.AssetType, this.MasterSha256Checksum).ToLower(); + } + case AssetType.TrackProduct: + case AssetType.TrackPreview: + { + var externalOwnerRef = Urn.Parse(this.ExternalOwnerUrn).IdValue; + return String.Format("{0}/{1}/{2}/{3}/{4}/{5}", this.AssetType, this.MasterSha256Checksum, externalOwnerRef, this.FileExtension.ToLower(), this.BitRateKbps ?? 0, this.DurationMs ?? 0).ToLower(); + } + default: + { + var message = String.Format("AssetType not supported: {0}-{1}-{2}", AssetType, FileExtension.ToLower(), MasterSha256Checksum); + throw new Exception(message); + } + } + } + + public AssetId CreateAssetId() + { + return new AssetId { AssetType = this.AssetType, ExternalUrn = this.ExternalUrn }; + } + + public override string ToString() + { + return this.ExternalRef; + } + } + + public class LabelUpdate : IExternal + { + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } + + public string SupplierKeyName { get; set; } + public string Name { get; set; } + + public DateTime? EstablishedDate { get; set; } + + public string Biography { get; set; } + public string BiographyAuthor { get; set; } + + public List AssetIds { get; set; } + + public List GetImageAssetIds() + { + return AssetIds.Where(x => x.AssetType.IsImage()).ToList(); + } + + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.ExternalRef); + } + } + + public class ProductUpdate + { + public bool Delete { get; set; } + + public string TerritoryCode { get; set; } + public string Copyright { get; set; } + public string ReportRef { get; set; } + + public bool AllowDownload { get; set; } + public bool AllowStreaming { get; set; } + public bool AllowSubscription { get; set; } + + public bool CollectionOnly { get; set; } + + public DateTime? DownloadStartDate { get; set; } + public DateTime? DownloadEndDate { get; set; } - public List CostPoints { get; set; } + public List CostPoints { get; set; } - public DateTime? StreamingStartDate { get; set; } - public DateTime? StreamingEndDate { get; set; } + public DateTime? StreamingStartDate { get; set; } + public DateTime? StreamingEndDate { get; set; } - public override string ToString() - { - return this.TerritoryCode; - } - } - - public class ReleaseChangeSet - { - public Guid BatchId { get; set; } - public string BatchName { get; set; } - public long BatchSequence { get; set; } - public string BatchPath { get; set; } - - public bool Partial { get; set; } - - public ReleaseUpdate Release { get; set; } - - public List Labels { get; set; } - public List Artists { get; set; } - public List Tracks { get; set; } - public List Assets { get; set; } - - public void UpdateBatchInfo(Batch batch) - { - this.BatchId = batch.Id; - this.BatchName = batch.Name; - this.BatchSequence = batch.SequenceNumber; - this.BatchPath = batch.Path; - } - - public override string ToString() - { - return String.Format("{0} {1} {2}", this.Release.ExternalUrn, this.BatchName, this.Partial ? "Partial" : "Full"); - } - } + public override string ToString() + { + return this.TerritoryCode; + } + } + + public class ReleaseChangeSet + { + public Guid BatchId { get; set; } + public string BatchName { get; set; } + public long BatchSequence { get; set; } + public string BatchPath { get; set; } + + public bool Partial { get; set; } + + public ReleaseUpdate Release { get; set; } + + public List Labels { get; set; } + public List Artists { get; set; } + public List Tracks { get; set; } + public List Assets { get; set; } + + public void UpdateBatchInfo(Batch batch) + { + this.BatchId = batch.Id; + this.BatchName = batch.Name; + this.BatchSequence = batch.SequenceNumber; + this.BatchPath = batch.Path; + } + + public override string ToString() + { + return String.Format("{0} {1} {2}", this.Release.ExternalUrn, this.BatchName, this.Partial ? "Partial" : "Full"); + } + } - public static class ReleaseChangeSetSerializer - { - public static string Serialize(ReleaseChangeSet changeSet) - { - return TypeSerializer.SerializeToString(changeSet); - } + public static class ReleaseChangeSetSerializer + { + public static string Serialize(ReleaseChangeSet changeSet) + { + return TypeSerializer.SerializeToString(changeSet); + } - public static ReleaseChangeSet Deserialize(string changeSetString) - { - return TypeSerializer.DeserializeFromString(changeSetString); - } - } + public static ReleaseChangeSet Deserialize(string changeSetString) + { + return TypeSerializer.DeserializeFromString(changeSetString); + } + } - public class TrackUpdate : IExternalDeletable - { - public bool Delete { get; set; } + public class TrackUpdate : IExternalDeletable + { + public bool Delete { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } - public string SupplierKeyName { get; set; } - public string Name { get; set; } + public string SupplierKeyName { get; set; } + public string Name { get; set; } - public string NameExVersion { get; set; } - public string NameVersion { get; set; } + public string NameExVersion { get; set; } + public string NameVersion { get; set; } - public string LabelText { get; set; } - public string ArtistText { get; set; } - public string ReleaseText { get; set; } + public string LabelText { get; set; } + public string ArtistText { get; set; } + public string ReleaseText { get; set; } - public string Isrc { get; set; } - public string GlobalReleaseId { get; set; } + public string Isrc { get; set; } + public string GlobalReleaseId { get; set; } - public int? SetNumber { get; set; } - public int? DiscNumber { get; set; } - public int? TrackNumber { get; set; } - public int? SequenceNumber { get; set; } + public int? SetNumber { get; set; } + public int? DiscNumber { get; set; } + public int? TrackNumber { get; set; } + public int? SequenceNumber { get; set; } - public int? DurationMs { get; set; } + public int? DurationMs { get; set; } - public ExplicitType ExplicitType { get; set; } + public ExplicitType ExplicitType { get; set; } - public string RightsHolder { get; set; } - public string Copyright { get; set; } + public string RightsHolder { get; set; } + public string Copyright { get; set; } - public List Publishers { get; set; } + public List Publishers { get; set; } - public List Genres { get; set; } - public List SubGenres { get; set; } + public List Genres { get; set; } + public List SubGenres { get; set; } - public string Review { get; set; } - public string ReviewAuthor { get; set; } + public string Review { get; set; } + public string ReviewAuthor { get; set; } - public string Lyrics { get; set; } + public string Lyrics { get; set; } - public List Participants { get; set; } + public List Participants { get; set; } - public string ExternalLabelUrn { get; set; } - public string ExternalReleaseUrn { get; set; } + public string ExternalLabelUrn { get; set; } + public string ExternalReleaseUrn { get; set; } - public MergeList ExternalArtistUrns { get; set; } - public MergeList Products { get; set; } + public MergeList ExternalArtistUrns { get; set; } + public MergeList Products { get; set; } - public List AssetIds { get; set; } + public List AssetIds { get; set; } - public void AddAssetIds(IEnumerable assetIds) - { - if (assetIds == null || !assetIds.Any()) - { - return; - } + public void AddAssetIds(IEnumerable assetIds) + { + if (assetIds == null || !assetIds.Any()) + { + return; + } - if (this.AssetIds == null) - { - this.AssetIds = new List(); - } + if (this.AssetIds == null) + { + this.AssetIds = new List(); + } - this.AssetIds.AddRange(assetIds); - } + this.AssetIds.AddRange(assetIds); + } - public List GetImageAssetIds() - { - return this.AssetIds.SafeWhere(x => x.AssetType.IsImage()).ToList(); - } + public List GetImageAssetIds() + { + return this.AssetIds.SafeWhere(x => x.AssetType.IsImage()).ToList(); + } - public List GetAudioAssetIds() - { - return this.AssetIds.SafeWhere(x => x.AssetType.IsAudio()).ToList(); - } + public List GetAudioAssetIds() + { + return this.AssetIds.SafeWhere(x => x.AssetType.IsAudio()).ToList(); + } - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.ExternalRef); - } - } + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.ExternalRef); + } + } - public class ReleaseUpdate : IExternalDeletable - { - public const string WorldTerritoryCode = "ZZ"; + public class ReleaseUpdate : IExternalDeletable + { + public const string WorldTerritoryCode = "ZZ"; - public bool Delete { get; set; } + public bool Delete { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } - public string SupplierKeyName { get; set; } - public string Name { get; set; } + public string SupplierKeyName { get; set; } + public string Name { get; set; } - public string NameExVersion { get; set; } - public string NameVersion { get; set; } + public string NameExVersion { get; set; } + public string NameVersion { get; set; } - public ReleaseType ReleaseType { get; set; } + public ReleaseType ReleaseType { get; set; } - public string LabelText { get; set; } - public string ArtistText { get; set; } + public string LabelText { get; set; } + public string ArtistText { get; set; } - public string UpcEan { get; set; } - public string GlobalReleaseId { get; set; } - public string CatalogueNumber { get; set; } + public string UpcEan { get; set; } + public string GlobalReleaseId { get; set; } + public string CatalogueNumber { get; set; } - public int? SetCount { get; set; } - public int? DiscCount { get; set; } - public int? TrackCount { get; set; } + public int? SetCount { get; set; } + public int? DiscCount { get; set; } + public int? TrackCount { get; set; } - public int? DurationMs { get; set; } - public bool ContinuousMix { get; set; } + public int? DurationMs { get; set; } + public bool ContinuousMix { get; set; } - public ExplicitType ExplicitType { get; set; } + public ExplicitType ExplicitType { get; set; } - public DateTime? ReleaseDate { get; set; } + public DateTime? ReleaseDate { get; set; } - public string RightsHolder { get; set; } - public string Copyright { get; set; } + public string RightsHolder { get; set; } + public string Copyright { get; set; } - public List Genres { get; set; } - public List SubGenres { get; set; } + public List Genres { get; set; } + public List SubGenres { get; set; } - public string Review { get; set; } - public string ReviewAuthor { get; set; } + public string Review { get; set; } + public string ReviewAuthor { get; set; } - public List Participants { get; set; } + public List Participants { get; set; } - public string ExternalLabelUrn { get; set; } + public string ExternalLabelUrn { get; set; } - public MergeList ExternalArtistUrns { get; set; } - public MergeList ExternalTrackUrns { get; set; } - public MergeList Products { get; set; } + public MergeList ExternalArtistUrns { get; set; } + public MergeList ExternalTrackUrns { get; set; } + public MergeList Products { get; set; } - public List AssetIds { get; set; } + public List AssetIds { get; set; } - public void AddAssetIds(IEnumerable assetIds) - { - if (assetIds == null || !assetIds.Any()) - { - return; - } + public void AddAssetIds(IEnumerable assetIds) + { + if (assetIds == null || !assetIds.Any()) + { + return; + } - if (this.AssetIds == null) - { - this.AssetIds = new List(); - } + if (this.AssetIds == null) + { + this.AssetIds = new List(); + } - this.AssetIds.AddRange(assetIds); - } + this.AssetIds.AddRange(assetIds); + } - public List GetImageAssetIds() - { - return this.AssetIds.SafeWhere(x => x.AssetType.IsImage()).ToList(); - } + public List GetImageAssetIds() + { + return this.AssetIds.SafeWhere(x => x.AssetType.IsImage()).ToList(); + } - public List GetAudioAssetIds() - { - return this.AssetIds.SafeWhere(x => x.AssetType.IsAudio()).ToList(); - } + public List GetAudioAssetIds() + { + return this.AssetIds.SafeWhere(x => x.AssetType.IsAudio()).ToList(); + } - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.ExternalRef); - } - } + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.ExternalRef); + } + } - public class AssetId - { - public AssetType AssetType { get; set; } - public string ExternalUrn { get; set; } + public class AssetId + { + public AssetType AssetType { get; set; } + public string ExternalUrn { get; set; } - public override string ToString() - { - return this.ExternalUrn; - } - } + public override string ToString() + { + return this.ExternalUrn; + } + } - public class Artist : IContent - { - public Guid Id { get; set; } - public string Urn { get; set; } + public class Artist : IContent + { + public Guid Id { get; set; } + public string Urn { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } - public string SupplierKeyName { get; set; } - public string Name { get; set; } + public string SupplierKeyName { get; set; } + public string Name { get; set; } - public DateTime? BirthDate { get; set; } - public string BirthPlace { get; set; } + public DateTime? BirthDate { get; set; } + public string BirthPlace { get; set; } - public DateTime? DeathDate { get; set; } - public string DeathPlace { get; set; } + public DateTime? DeathDate { get; set; } + public string DeathPlace { get; set; } - public string DecadesActive { get; set; } + public string DecadesActive { get; set; } - public string Biography { get; set; } - public string BiographyAuthor { get; set; } + public string Biography { get; set; } + public string BiographyAuthor { get; set; } - public List Assets { get; set; } + public List Assets { get; set; } - public DateTime CreatedDate { get; set; } - public DateTime ModifiedDate { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } - public List GetImageAssets() - { - return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); - } + public List GetImageAssets() + { + return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); + } - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); - } - } + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); + } + } - public class Asset : IContent - { - public Guid Id { get; set; } - public string Urn { get; set; } + public class Asset : IContent + { + public Guid Id { get; set; } + public string Urn { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } - public string SupplierKeyName { get; set; } + public string SupplierKeyName { get; set; } - public AssetType AssetType { get; set; } + public AssetType AssetType { get; set; } - public string ExternalOwnerUrn { get; set; } + public string ExternalOwnerUrn { get; set; } - public string FileName { get; set; } - public string FileExtension { get; set; } - public long FileSizeBytes { get; set; } + public string FileName { get; set; } + public string FileExtension { get; set; } + public long FileSizeBytes { get; set; } - public string MasterSha256Checksum { get; set; } - public string Md5Checksum { get; set; } + public string MasterSha256Checksum { get; set; } + public string Md5Checksum { get; set; } - public int? DurationMs { get; set; } - public int? BitRateKbps { get; set; } + public int? DurationMs { get; set; } + public int? BitRateKbps { get; set; } - public int? Width { get; set; } - public int? Height { get; set; } + public int? Width { get; set; } + public int? Height { get; set; } - public string TranscodedAssetPath { get; set; } - public string RepositoryAssetPath { get; set; } + public string TranscodedAssetPath { get; set; } + public string RepositoryAssetPath { get; set; } - public DateTime CreatedDate { get; set; } - public DateTime ModifiedDate { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } - public override string ToString() - { - return String.Format("{0} {1}", this.ExternalRef, this.Id.ToString("N")); - } - } + public override string ToString() => $"{ExternalRef} {Id:N}"; + } - public class Label : IContent - { - public Guid Id { get; set; } - public string Urn { get; set; } + public class Label : IContent + { + public Guid Id { get; set; } + public string Urn { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } - public string SupplierKeyName { get; set; } - public string Name { get; set; } + public string SupplierKeyName { get; set; } + public string Name { get; set; } - public DateTime? EstablishedDate { get; set; } + public DateTime? EstablishedDate { get; set; } - public string Biography { get; set; } - public string BiographyAuthor { get; set; } + public string Biography { get; set; } + public string BiographyAuthor { get; set; } - public List Assets { get; set; } + public List Assets { get; set; } - public DateTime CreatedDate { get; set; } - public DateTime ModifiedDate { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } - public List GetImageAssets() - { - return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); - } + public List GetImageAssets() + { + return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); + } - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); - } - } + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); + } + } - public class Product - { - public string TerritoryCode { get; set; } - public string Copyright { get; set; } - public string ReportRef { get; set; } + public class Product + { + public string TerritoryCode { get; set; } + public string Copyright { get; set; } + public string ReportRef { get; set; } - public bool AllowDownload { get; set; } - public bool AllowStreaming { get; set; } - public bool AllowSubscription { get; set; } + public bool AllowDownload { get; set; } + public bool AllowStreaming { get; set; } + public bool AllowSubscription { get; set; } - public bool CollectionOnly { get; set; } + public bool CollectionOnly { get; set; } - public DateTime? DownloadStartDate { get; set; } - public DateTime? DownloadEndDate { get; set; } + public DateTime? DownloadStartDate { get; set; } + public DateTime? DownloadEndDate { get; set; } - public List CostPoints { get; set; } + public List CostPoints { get; set; } - public DateTime? StreamingStartDate { get; set; } - public DateTime? StreamingEndDate { get; set; } + public DateTime? StreamingStartDate { get; set; } + public DateTime? StreamingEndDate { get; set; } - public override string ToString() - { - return this.TerritoryCode; - } - } + public override string ToString() + { + return this.TerritoryCode; + } + } - public class Release : IContent - { - public const string WorldTerritoryCode = "ZZ"; + public class Release : IContent + { + public const string WorldTerritoryCode = "ZZ"; - public Guid Id { get; set; } - public string Urn { get; set; } + public Guid Id { get; set; } + public string Urn { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } - public string SupplierKeyName { get; set; } - public string Name { get; set; } + public string SupplierKeyName { get; set; } + public string Name { get; set; } - public string NameExVersion { get; set; } - public string NameVersion { get; set; } + public string NameExVersion { get; set; } + public string NameVersion { get; set; } - public ReleaseType ReleaseType { get; set; } + public ReleaseType ReleaseType { get; set; } - public string LabelText { get; set; } - public string ArtistText { get; set; } + public string LabelText { get; set; } + public string ArtistText { get; set; } - public string UpcEan { get; set; } - public string GlobalReleaseId { get; set; } - public string CatalogueNumber { get; set; } + public string UpcEan { get; set; } + public string GlobalReleaseId { get; set; } + public string CatalogueNumber { get; set; } - public int SetCount { get; set; } - public int DiscCount { get; set; } - public int TrackCount { get; set; } + public int SetCount { get; set; } + public int DiscCount { get; set; } + public int TrackCount { get; set; } - public int? DurationMs { get; set; } - public bool ContinuousMix { get; set; } + public int? DurationMs { get; set; } + public bool ContinuousMix { get; set; } - public ExplicitType ExplicitType { get; set; } + public ExplicitType ExplicitType { get; set; } - public DateTime? ReleaseDate { get; set; } + public DateTime? ReleaseDate { get; set; } - public string RightsHolder { get; set; } - public string Copyright { get; set; } + public string RightsHolder { get; set; } + public string Copyright { get; set; } - public List Genres { get; set; } - public List SubGenres { get; set; } + public List Genres { get; set; } + public List SubGenres { get; set; } - public string Review { get; set; } - public string ReviewAuthor { get; set; } + public string Review { get; set; } + public string ReviewAuthor { get; set; } - public List Participants { get; set; } + public List Participants { get; set; } - public Label Label { get; set; } - public List Artists { get; set; } - public List Tracks { get; set; } - public List Products { get; set; } - public List Assets { get; set; } + public Label Label { get; set; } + public List Artists { get; set; } + public List Tracks { get; set; } + public List Products { get; set; } + public List Assets { get; set; } - public DateTime CreatedDate { get; set; } - public DateTime ModifiedDate { get; set; } - public DateTime? DeletedDate { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } + public DateTime? DeletedDate { get; set; } - public string GetPrimaryGenre() - { - return this.Genres.IsNullOrEmpty() ? null : this.Genres[0]; - } + public string GetPrimaryGenre() + { + return this.Genres.IsNullOrEmpty() ? null : this.Genres[0]; + } - public Artist GetPrimaryArtist() - { - return this.Artists.IsNullOrEmpty() ? null : this.Artists[0]; - } + public Artist GetPrimaryArtist() + { + return this.Artists.IsNullOrEmpty() ? null : this.Artists[0]; + } - public List GetImageAssets() - { - return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); - } + public List GetImageAssets() + { + return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); + } - public List GetAudioAssets() - { - return this.Assets.Where(x => x.AssetType.IsAudio()).ToList(); - } + public List GetAudioAssets() + { + return this.Assets.Where(x => x.AssetType.IsAudio()).ToList(); + } - public List GetActiveTracks() - { - return this.Tracks.SafeWhere(x => !x.CollectionOrphan).ToList(); - } + public List GetActiveTracks() + { + return this.Tracks.SafeWhere(x => !x.CollectionOrphan).ToList(); + } - public List GetOrphanTracks() - { - return this.Tracks.SafeWhere(x => x.CollectionOrphan).ToList(); - } + public List GetOrphanTracks() + { + return this.Tracks.SafeWhere(x => x.CollectionOrphan).ToList(); + } - public Product GetProduct(string territoryCode) - { - if (this.Products.IsNullOrEmpty()) - { - return null; - } + public Product GetProduct(string territoryCode) + { + if (this.Products.IsNullOrEmpty()) + { + return null; + } - var product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(territoryCode)); - if (product == null) - { - // Default to the world product if exists - product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(WorldTerritoryCode)); - } + var product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(territoryCode)); + if (product == null) + { + // Default to the world product if exists + product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(WorldTerritoryCode)); + } - return product; - } + return product; + } - public string GetDescription() - { - return String.Format("{0} by {1}", this.Name, this.ArtistText); - } + public string GetDescription() + { + return String.Format("{0} by {1}", this.Name, this.ArtistText); + } - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); - } - } + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); + } + } - public class Track : IContentDeletable - { - public Guid Id { get; set; } - public string Urn { get; set; } + public class Track : IContentDeletable + { + public Guid Id { get; set; } + public string Urn { get; set; } - public string ExternalRef { get; set; } - public string ExternalUrn { get; set; } - - public string SupplierKeyName { get; set; } - public string Name { get; set; } - - public string NameExVersion { get; set; } - public string NameVersion { get; set; } - - public string LabelText { get; set; } - public string ArtistText { get; set; } - public string ReleaseText { get; set; } - - public string Isrc { get; set; } - public string GlobalReleaseId { get; set; } - - public bool CollectionOrphan { get; set; } - - public int SetNumber { get; set; } - public int DiscNumber { get; set; } - public int TrackNumber { get; set; } - public int SequenceNumber { get; set; } - - public int? DurationMs { get; set; } - - public ExplicitType ExplicitType { get; set; } - - public string RightsHolder { get; set; } - public string Copyright { get; set; } - - public List Publishers { get; set; } - - public List Genres { get; set; } - public List SubGenres { get; set; } - - public string Review { get; set; } - public string ReviewAuthor { get; set; } - - public string Lyrics { get; set; } - - public List Participants { get; set; } - - public Label Label { get; set; } - public Release Release { get; set; } - public List Artists { get; set; } - public List Products { get; set; } - public List Assets { get; set; } - - public DateTime CreatedDate { get; set; } - public DateTime ModifiedDate { get; set; } - public DateTime? DeletedDate { get; set; } - - public string GetPrimaryGenre() - { - return this.Genres.IsNullOrEmpty() ? null : this.Genres[0]; - } - - public Artist GetPrimaryArtist() - { - return this.Artists.IsNullOrEmpty() ? null : this.Artists[0]; - } - - public List GetImageAssetIds() - { - return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); - } - - public List GetAudioAssetIds() - { - return this.Assets.Where(x => x.AssetType.IsAudio()).ToList(); - } - - public Product GetProduct(string territoryCode) - { - if (this.Products.IsNullOrEmpty()) - { - return null; - } - - var product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(territoryCode)); - if (product == null) - { - // Default to the world product if exists - product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(Release.WorldTerritoryCode)); - } - - return product; - } - - public string GetDescription() - { - return String.Format("{0} {1} ({2}) by {3}", this.SequenceNumber, this.Name, this.ReleaseText, this.ArtistText); - } - - public override string ToString() - { - return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); - } - } - - public enum AssetType - { - None, - MasterCoverArt, - MasterArtistArt, - MasterLabelArt, - ResizedCoverArt, - ResizedArtistArt, - ResizedLabelArt, - TrackProduct, - TrackPreview, - } - - public static class AssetTypeExtensions - { - public static bool IsAudio(this AssetType assetType) - { - return assetType == AssetType.TrackProduct || assetType == AssetType.TrackPreview; - } - - public static bool IsMasterImage(this AssetType assetType) - { - return assetType == AssetType.MasterCoverArt || assetType == AssetType.MasterArtistArt || assetType == AssetType.MasterLabelArt; - } - - public static bool IsResizedImage(this AssetType assetType) - { - return assetType == AssetType.ResizedCoverArt || assetType == AssetType.ResizedArtistArt || assetType == AssetType.ResizedLabelArt; - } - - public static bool IsImage(this AssetType assetType) - { - switch (assetType) - { - case AssetType.MasterCoverArt: - case AssetType.MasterArtistArt: - case AssetType.MasterLabelArt: - case AssetType.ResizedCoverArt: - case AssetType.ResizedArtistArt: - case AssetType.ResizedLabelArt: - return true; - default: - return false; - } - } - - public static AssetType GetMasterType(this AssetType assetType) - { - switch (assetType) - { - case AssetType.ResizedCoverArt: - return AssetType.MasterCoverArt; - case AssetType.ResizedArtistArt: - return AssetType.MasterArtistArt; - case AssetType.ResizedLabelArt: - return AssetType.MasterLabelArt; - default: - return assetType; - } - } - - public static AssetType GetResizedType(this AssetType assetType) - { - switch (assetType) - { - case AssetType.MasterCoverArt: - return AssetType.ResizedCoverArt; - case AssetType.MasterArtistArt: - return AssetType.ResizedArtistArt; - case AssetType.MasterLabelArt: - return AssetType.ResizedLabelArt; - default: - return assetType; - } - } - } - - public struct Urn - { - private const char IdValueSeperator = '/'; - private readonly string urnString; - - public string ResourceName - { - get; - private set; - } - - public string IdTypeName - { - get; - private set; - } - - public string IdValue - { - get; - private set; - } - - public string[] IdValues - { - get - { - return IdValue.Split(IdValueSeperator); - } - } - - public Urn(string resourceName, string idTypeName, string idValue) - : this() - { - if (resourceName == null) - { - throw new ArgumentNullException("resourceName"); - } - - if (idValue == null) - { - throw new ArgumentNullException("idValue"); - } - - this.ResourceName = resourceName.ToLower(); - this.IdTypeName = !String.IsNullOrEmpty(idTypeName) ? idTypeName.ToLower() : null; - this.IdValue = idValue; - - if (String.IsNullOrEmpty(this.IdTypeName)) - { - this.urnString = string.Format("urn:{0}:{1}", this.ResourceName, this.IdValue); - } - else - { - this.urnString = string.Format("urn:{0}:{1}:{2}", this.ResourceName, this.IdTypeName, this.IdValue); - } - } - - public Urn(string resourceName, string idValue) - : this(resourceName, null, idValue) - { - } - - public bool IsDefaultIdType() - { - return String.IsNullOrEmpty(IdTypeName); - } - - public bool IsResourceType(string resourceName) - { - return string.Compare(this.ResourceName, resourceName, true) == 0; - } - - public bool IsIdType(Type type) - { - return this.IsIdType(type.Name); - } - - public bool IsIdType(string idTypeName) - { - return string.Compare(this.IdTypeName, idTypeName, true) == 0; - } - - public override int GetHashCode() - { - return this.urnString.GetHashCode(); - } - - public bool Equals(Urn obj) - { - return String.CompareOrdinal(obj.urnString, this.urnString) == 0; - } - - public override bool Equals(object obj) - { - return obj.GetType() == typeof(Urn) && Equals(obj); - } - - public override string ToString() - { - return urnString; - } - - // Operators overloading - - public static implicit operator string(Urn urn) - { - return urn.urnString; - } - - public static bool operator ==(Urn urn1, Urn urn2) - { - return urn1.Equals(urn2); - } - - public static bool operator !=(Urn urn1, Urn urn2) - { - return !urn1.Equals(urn2); - } - - // Parsing - - public static bool IsValidUrn(string urnString) - { - var fields = urnString.Split(':'); - return (fields.Length == 3 || fields.Length == 4) && String.CompareOrdinal(fields[0], "urn") == 0; - } - - public static bool TryParse(string urnString, out Urn urn) - { - var fields = urnString.Split(':'); - - if ((fields.Length == 3 || fields.Length == 4) && String.CompareOrdinal(fields[0], "urn") == 0) - { - if (fields.Length == 4) - { - urn = new Urn(fields[1], fields[2], fields[3]); - } - else - { - urn = new Urn(fields[1], fields[2]); - } - - return true; - } - - urn = new Urn(); - return false; - } - - public static Urn Parse(string urnText) - { - if (String.IsNullOrEmpty(urnText)) - { - throw new ArgumentNullException("urnText"); - } - - var fields = urnText.Split(':'); - if ((fields.Length == 3 || fields.Length == 4) && String.CompareOrdinal(fields[0], "urn") == 0) - { - return fields.Length == 4 ? new Urn(fields[1], fields[2], fields[3]) : new Urn(fields[1], fields[2]); - } - - var msg = string.Format("Invalid URN text '{0}'", urnText); - throw new FormatException(msg); - } - - public static string GetUrnType(string urnString) - { - var urn = Parse(urnString); - return urn.ResourceName; - } - - public static long GetLongId(string urnString) - { - var urn = Parse(urnString); - return Convert.ToInt64(urn.IdValue); - } - - public static Guid GetGuidId(string urnString) - { - var urn = Parse(urnString); - return new Guid(urn.IdValue); - } - - public static string[] GetIdValues(string urnString) - { - var urn = Parse(urnString); - return urn.IdValues; - } - - public static string GetIdValue(string urnString) - { - var urn = Parse(urnString); - return urn.IdValue; - } - - public static string CleanIdValue(string idValue) - { - return idValue.Trim().ToLowerInvariant().Replace(' ', '_'); - } - - public static string GetFirstIdValue(string urnString) - { - var urn = Parse(urnString); - return urn.IdValue.Split('/')[0]; - } - - public static string GetSecondIdValue(string urnString) - { - var urn = Parse(urnString); - var parts = urn.IdValue.Split('/'); - return parts.Length > 1 ? parts[1] : null; - } - } + public string ExternalRef { get; set; } + public string ExternalUrn { get; set; } + + public string SupplierKeyName { get; set; } + public string Name { get; set; } + + public string NameExVersion { get; set; } + public string NameVersion { get; set; } + + public string LabelText { get; set; } + public string ArtistText { get; set; } + public string ReleaseText { get; set; } + + public string Isrc { get; set; } + public string GlobalReleaseId { get; set; } + + public bool CollectionOrphan { get; set; } + + public int SetNumber { get; set; } + public int DiscNumber { get; set; } + public int TrackNumber { get; set; } + public int SequenceNumber { get; set; } + + public int? DurationMs { get; set; } + + public ExplicitType ExplicitType { get; set; } + + public string RightsHolder { get; set; } + public string Copyright { get; set; } + + public List Publishers { get; set; } + + public List Genres { get; set; } + public List SubGenres { get; set; } + + public string Review { get; set; } + public string ReviewAuthor { get; set; } + + public string Lyrics { get; set; } + + public List Participants { get; set; } + + public Label Label { get; set; } + public Release Release { get; set; } + public List Artists { get; set; } + public List Products { get; set; } + public List Assets { get; set; } + + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } + public DateTime? DeletedDate { get; set; } + + public string GetPrimaryGenre() + { + return this.Genres.IsNullOrEmpty() ? null : this.Genres[0]; + } + + public Artist GetPrimaryArtist() + { + return this.Artists.IsNullOrEmpty() ? null : this.Artists[0]; + } + + public List GetImageAssetIds() + { + return this.Assets.Where(x => x.AssetType.IsImage()).ToList(); + } + + public List GetAudioAssetIds() + { + return this.Assets.Where(x => x.AssetType.IsAudio()).ToList(); + } + + public Product GetProduct(string territoryCode) + { + if (this.Products.IsNullOrEmpty()) + { + return null; + } + + var product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(territoryCode)); + if (product == null) + { + // Default to the world product if exists + product = this.Products.FirstOrDefault(x => x.TerritoryCode.EqualsIgnoreCase(Release.WorldTerritoryCode)); + } + + return product; + } + + public string GetDescription() + { + return String.Format("{0} {1} ({2}) by {3}", this.SequenceNumber, this.Name, this.ReleaseText, this.ArtistText); + } + + public override string ToString() + { + return String.Format("{0} {1}", this.Name, this.Id.ToString("N")); + } + } + + public enum AssetType + { + None, + MasterCoverArt, + MasterArtistArt, + MasterLabelArt, + ResizedCoverArt, + ResizedArtistArt, + ResizedLabelArt, + TrackProduct, + TrackPreview, + } + + public static class AssetTypeExtensions + { + public static bool IsAudio(this AssetType assetType) + { + return assetType == AssetType.TrackProduct || assetType == AssetType.TrackPreview; + } + + public static bool IsMasterImage(this AssetType assetType) + { + return assetType == AssetType.MasterCoverArt || assetType == AssetType.MasterArtistArt || assetType == AssetType.MasterLabelArt; + } + + public static bool IsResizedImage(this AssetType assetType) + { + return assetType == AssetType.ResizedCoverArt || assetType == AssetType.ResizedArtistArt || assetType == AssetType.ResizedLabelArt; + } + + public static bool IsImage(this AssetType assetType) + { + switch (assetType) + { + case AssetType.MasterCoverArt: + case AssetType.MasterArtistArt: + case AssetType.MasterLabelArt: + case AssetType.ResizedCoverArt: + case AssetType.ResizedArtistArt: + case AssetType.ResizedLabelArt: + return true; + default: + return false; + } + } + + public static AssetType GetMasterType(this AssetType assetType) + { + switch (assetType) + { + case AssetType.ResizedCoverArt: + return AssetType.MasterCoverArt; + case AssetType.ResizedArtistArt: + return AssetType.MasterArtistArt; + case AssetType.ResizedLabelArt: + return AssetType.MasterLabelArt; + default: + return assetType; + } + } + + public static AssetType GetResizedType(this AssetType assetType) + { + switch (assetType) + { + case AssetType.MasterCoverArt: + return AssetType.ResizedCoverArt; + case AssetType.MasterArtistArt: + return AssetType.ResizedArtistArt; + case AssetType.MasterLabelArt: + return AssetType.ResizedLabelArt; + default: + return assetType; + } + } + } + + public struct Urn + { + private const char IdValueSeperator = '/'; + private readonly string urnString; + + public string ResourceName + { + get; + private set; + } + + public string IdTypeName + { + get; + private set; + } + + public string IdValue + { + get; + private set; + } + + public string[] IdValues + { + get + { + return IdValue.Split(IdValueSeperator); + } + } + + public Urn(string resourceName, string idTypeName, string idValue) + : this() + { + if (resourceName == null) + { + throw new ArgumentNullException("resourceName"); + } + + if (idValue == null) + { + throw new ArgumentNullException("idValue"); + } + + this.ResourceName = resourceName.ToLower(); + this.IdTypeName = !String.IsNullOrEmpty(idTypeName) ? idTypeName.ToLower() : null; + this.IdValue = idValue; + + if (String.IsNullOrEmpty(this.IdTypeName)) + { + this.urnString = string.Format("urn:{0}:{1}", this.ResourceName, this.IdValue); + } + else + { + this.urnString = string.Format("urn:{0}:{1}:{2}", this.ResourceName, this.IdTypeName, this.IdValue); + } + } + + public Urn(string resourceName, string idValue) + : this(resourceName, null, idValue) + { + } + + public bool IsDefaultIdType() + { + return String.IsNullOrEmpty(IdTypeName); + } + + public bool IsResourceType(string resourceName) + { + return string.Compare(this.ResourceName, resourceName, true) == 0; + } + + public bool IsIdType(Type type) + { + return this.IsIdType(type.Name); + } + + public bool IsIdType(string idTypeName) + { + return string.Compare(this.IdTypeName, idTypeName, true) == 0; + } + + public override int GetHashCode() + { + return this.urnString.GetHashCode(); + } + + public bool Equals(Urn obj) + { + return String.CompareOrdinal(obj.urnString, this.urnString) == 0; + } + + public override bool Equals(object obj) + { + return obj.GetType() == typeof(Urn) && Equals(obj); + } + + public override string ToString() + { + return urnString; + } + + // Operators overloading + + public static implicit operator string(Urn urn) + { + return urn.urnString; + } + + public static bool operator ==(Urn urn1, Urn urn2) + { + return urn1.Equals(urn2); + } + + public static bool operator !=(Urn urn1, Urn urn2) + { + return !urn1.Equals(urn2); + } + + // Parsing + + public static bool IsValidUrn(string urnString) + { + var fields = urnString.Split(':'); + return (fields.Length == 3 || fields.Length == 4) && String.CompareOrdinal(fields[0], "urn") == 0; + } + + public static bool TryParse(string urnString, out Urn urn) + { + var fields = urnString.Split(':'); + + if ((fields.Length == 3 || fields.Length == 4) && String.CompareOrdinal(fields[0], "urn") == 0) + { + if (fields.Length == 4) + { + urn = new Urn(fields[1], fields[2], fields[3]); + } + else + { + urn = new Urn(fields[1], fields[2]); + } + + return true; + } + + urn = new Urn(); + return false; + } + + public static Urn Parse(string urnText) + { + if (String.IsNullOrEmpty(urnText)) + { + throw new ArgumentNullException("urnText"); + } + + var fields = urnText.Split(':'); + if ((fields.Length == 3 || fields.Length == 4) && String.CompareOrdinal(fields[0], "urn") == 0) + { + return fields.Length == 4 ? new Urn(fields[1], fields[2], fields[3]) : new Urn(fields[1], fields[2]); + } + + var msg = string.Format("Invalid URN text '{0}'", urnText); + throw new FormatException(msg); + } + + public static string GetUrnType(string urnString) + { + var urn = Parse(urnString); + return urn.ResourceName; + } + + public static long GetLongId(string urnString) + { + var urn = Parse(urnString); + return Convert.ToInt64(urn.IdValue); + } + + public static Guid GetGuidId(string urnString) + { + var urn = Parse(urnString); + return new Guid(urn.IdValue); + } + + public static string[] GetIdValues(string urnString) + { + var urn = Parse(urnString); + return urn.IdValues; + } + + public static string GetIdValue(string urnString) + { + var urn = Parse(urnString); + return urn.IdValue; + } + + public static string CleanIdValue(string idValue) + { + return idValue.Trim().ToLowerInvariant().Replace(' ', '_'); + } + + public static string GetFirstIdValue(string urnString) + { + var urn = Parse(urnString); + return urn.IdValue.Split('/')[0]; + } + + public static string GetSecondIdValue(string urnString) + { + var urn = Parse(urnString); + var parts = urn.IdValue.Split('/'); + return parts.Length > 1 ? parts[1] : null; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/IModelFactory.cs b/tests/ServiceStack.Common.Tests/Models/IModelFactory.cs index 78ebfaa2cb5..dbfb4c019e8 100644 --- a/tests/ServiceStack.Common.Tests/Models/IModelFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/IModelFactory.cs @@ -2,15 +2,15 @@ namespace ServiceStack.Common.Tests.Models { - public interface IModelFactory - { - void AssertListsAreEqual(List actualList, IList expectedList); - void AssertIsEqual(T actual, T expected); + public interface IModelFactory + { + void AssertListsAreEqual(List actualList, IList expectedList); + void AssertIsEqual(T actual, T expected); - T ExistingValue { get; } - T NonExistingValue { get; } - List CreateList(); - List CreateList2(); - T CreateInstance(int i); - } + T ExistingValue { get; } + T NonExistingValue { get; } + List CreateList(); + List CreateList2(); + T CreateInstance(int i); + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelFactoryBase.cs b/tests/ServiceStack.Common.Tests/Models/ModelFactoryBase.cs index 09c1494c338..a442f96c996 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelFactoryBase.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelFactoryBase.cs @@ -3,60 +3,60 @@ namespace ServiceStack.Common.Tests.Models { - public abstract class ModelFactoryBase - : IModelFactory - { - #region Implementation of IModelFactory - - public void AssertListsAreEqual(List actualList, IList expectedList) - { - Assert.That(actualList, Has.Count.EqualTo(expectedList.Count)); - var i = 0; - - actualList.ForEach(x => - AssertIsEqual(x, expectedList[i++])); - } - - public abstract T CreateInstance(int i); - - public abstract void AssertIsEqual(T actual, T expected); - - public T ExistingValue - { - get - { - return CreateInstance(4); - } - } - - public T NonExistingValue - { - get - { - return CreateInstance(5); - } - } - - public List CreateList() - { - return new List - { - CreateInstance(1), - CreateInstance(2), - CreateInstance(3), - CreateInstance(4), - }; - } - public List CreateList2() - { - return new List - { - CreateInstance(5), - CreateInstance(6), - CreateInstance(7), - }; - } - - #endregion - } + public abstract class ModelFactoryBase + : IModelFactory + { + #region Implementation of IModelFactory + + public void AssertListsAreEqual(List actualList, IList expectedList) + { + Assert.That(actualList, Has.Count.EqualTo(expectedList.Count)); + var i = 0; + + actualList.ForEach(x => + AssertIsEqual(x, expectedList[i++])); + } + + public abstract T CreateInstance(int i); + + public abstract void AssertIsEqual(T actual, T expected); + + public T ExistingValue + { + get + { + return CreateInstance(4); + } + } + + public T NonExistingValue + { + get + { + return CreateInstance(5); + } + } + + public List CreateList() + { + return new List + { + CreateInstance(1), + CreateInstance(2), + CreateInstance(3), + CreateInstance(4), + }; + } + public List CreateList2() + { + return new List + { + CreateInstance(5), + CreateInstance(6), + CreateInstance(7), + }; + } + + #endregion + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypes.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypes.cs index d7693fc8422..e06a3c07a8f 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypes.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypes.cs @@ -4,74 +4,75 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithComplexTypes - { - public ModelWithComplexTypes() - { - this.StringList = new List(); - this.IntList = new List(); - this.StringMap = new Dictionary(); - this.IntMap = new Dictionary(); - } + public class ModelWithComplexTypes + { + public ModelWithComplexTypes() + { + this.StringList = new List(); + this.IntList = new List(); + this.StringMap = new Dictionary(); + this.IntMap = new Dictionary(); + } - public long Id { get; set; } + public long Id { get; set; } - public List StringList { get; set; } + public List StringList { get; set; } - public List IntList { get; set; } + public List IntList { get; set; } - public Dictionary StringMap { get; set; } + public Dictionary StringMap { get; set; } - public Dictionary IntMap { get; set; } + public Dictionary IntMap { get; set; } - public ModelWithComplexTypes Child { get; set; } + public ModelWithComplexTypes Child { get; set; } - public static ModelWithComplexTypes Create(int id) - { - var row = new ModelWithComplexTypes { - Id = id, - StringList = { "val" + id + 1, "val" + id + 2, "val" + id + 3 }, - IntList = { id + 1, id + 2, id + 3 }, - StringMap = - { - {"key" + id + 1, "val" + id + 1}, - {"key" + id + 2, "val" + id + 2}, - {"key" + id + 3, "val" + id + 3}, - }, - IntMap = - { - {id + 1, id + 2}, - {id + 3, id + 4}, - {id + 5, id + 6}, - }, - Child = new ModelWithComplexTypes { Id = id * 2 }, - }; + public static ModelWithComplexTypes Create(int id) + { + var row = new ModelWithComplexTypes + { + Id = id, + StringList = { "val" + id + 1, "val" + id + 2, "val" + id + 3 }, + IntList = { id + 1, id + 2, id + 3 }, + StringMap = + { + {"key" + id + 1, "val" + id + 1}, + {"key" + id + 2, "val" + id + 2}, + {"key" + id + 3, "val" + id + 3}, + }, + IntMap = + { + {id + 1, id + 2}, + {id + 3, id + 4}, + {id + 5, id + 6}, + }, + Child = new ModelWithComplexTypes { Id = id * 2 }, + }; - return row; - } + return row; + } - public static ModelWithComplexTypes CreateConstant(int i) - { - return Create(i); - } + public static ModelWithComplexTypes CreateConstant(int i) + { + return Create(i); + } - public static void AssertIsEqual(ModelWithComplexTypes actual, ModelWithComplexTypes expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.StringList, Is.EquivalentTo(expected.StringList)); - Assert.That(actual.IntList, Is.EquivalentTo(expected.IntList)); - Assert.That(actual.StringMap, Is.EquivalentTo(expected.StringMap)); - Assert.That(actual.IntMap, Is.EquivalentTo(expected.IntMap)); + public static void AssertIsEqual(ModelWithComplexTypes actual, ModelWithComplexTypes expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.StringList, Is.EquivalentTo(expected.StringList)); + Assert.That(actual.IntList, Is.EquivalentTo(expected.IntList)); + Assert.That(actual.StringMap, Is.EquivalentTo(expected.StringMap)); + Assert.That(actual.IntMap, Is.EquivalentTo(expected.IntMap)); - if (expected.Child == null) - { - Assert.That(actual.Child, Is.Null); - } - else - { - Assert.That(actual.Child, Is.Not.Null); - AssertIsEqual(actual.Child, expected.Child); - } - } - } + if (expected.Child == null) + { + Assert.That(actual.Child, Is.Null); + } + else + { + Assert.That(actual.Child, Is.Not.Null); + AssertIsEqual(actual.Child, expected.Child); + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypesFactory.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypesFactory.cs index a3f9f6b9778..0f607dd6e5d 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypesFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithComplexTypesFactory.cs @@ -1,20 +1,20 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithComplexTypesFactory - : ModelFactoryBase - { - public static ModelWithComplexTypesFactory Instance - = new ModelWithComplexTypesFactory(); + public class ModelWithComplexTypesFactory + : ModelFactoryBase + { + public static ModelWithComplexTypesFactory Instance + = new ModelWithComplexTypesFactory(); - public override void AssertIsEqual( - ModelWithComplexTypes actual, ModelWithComplexTypes expected) - { - ModelWithComplexTypes.AssertIsEqual(actual, expected); - } + public override void AssertIsEqual( + ModelWithComplexTypes actual, ModelWithComplexTypes expected) + { + ModelWithComplexTypes.AssertIsEqual(actual, expected); + } - public override ModelWithComplexTypes CreateInstance(int i) - { - return ModelWithComplexTypes.CreateConstant(i); - } - } + public override ModelWithComplexTypes CreateInstance(int i) + { + return ModelWithComplexTypes.CreateConstant(i); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithCompositeIndexFields.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithCompositeIndexFields.cs index 00fcbb1a941..b46fe000997 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithCompositeIndexFields.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithCompositeIndexFields.cs @@ -2,21 +2,21 @@ namespace ServiceStack.Common.Tests.Models { - [CompositeIndex(true, "Composite1", "Composite2")] - public class ModelWithCompositeIndexFields - { - public string Id { get; set; } + [CompositeIndex(true, "Composite1", "Composite2")] + public class ModelWithCompositeIndexFields + { + public string Id { get; set; } - [Index] - public string Name { get; set; } + [Index] + public string Name { get; set; } - public string AlbumId { get; set; } + public string AlbumId { get; set; } - [Index(true)] - public string UniqueName { get; set; } + [Index(true)] + public string UniqueName { get; set; } - public string Composite1 { get; set; } + public string Composite1 { get; set; } - public string Composite2 { get; set; } - } + public string Composite2 { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypes.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypes.cs index 3fd89ae4261..b6b7646f96b 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypes.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypes.cs @@ -1,126 +1,128 @@ using System; using NUnit.Framework; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; using ServiceStack.DataAnnotations; using ServiceStack.Logging; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Models { - public class ModelWithFieldsOfDifferentAndNullableTypes - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfDifferentAndNullableTypes)); - - [AutoIncrement] - public int Id { get; set; } - public int? NId { get; set; } - - public long LongId { get; set; } - public long? NLongId { get; set; } - - public Guid Guid { get; set; } - public Guid? NGuid { get; set; } - - public bool Bool { get; set; } - public bool? NBool { get; set; } - - public DateTime DateTime { get; set; } - public DateTime? NDateTime { get; set; } - - public float Float { get; set; } - public float? NFloat { get; set; } - - public double Double { get; set; } - public double? NDouble { get; set; } - - public decimal Decimal { get; set; } - public decimal? NDecimal { get; set; } - - public TimeSpan TimeSpan { get; set; } - public TimeSpan? NTimeSpan { get; set; } - - public static ModelWithFieldsOfDifferentAndNullableTypes Create(int id) - { - var row = new ModelWithFieldsOfDifferentAndNullableTypes { - Id = id, - Bool = id % 2 == 0, - DateTime = DateTime.Now.AddDays(id), - Float = 1.11f + id, - Double = 1.11d + id, - Guid = Guid.NewGuid(), - LongId = 999 + id, - Decimal = id + 0.5m, - TimeSpan = TimeSpan.FromSeconds(id), - }; - - return row; - } - - public static ModelWithFieldsOfDifferentAndNullableTypes CreateConstant(int id) - { - var row = new ModelWithFieldsOfDifferentAndNullableTypes { - Id = id, - Bool = id % 2 == 0, - DateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), - Float = 1.11f + id, - Double = 1.11d + id, - Guid = new Guid(((id % 240) + 16).ToString("X") + "461D9D-47DB-4778-B3FA-458379AE9BDC"), - LongId = 999 + id, - Decimal = id + 0.5m, - TimeSpan = TimeSpan.FromSeconds(id), - }; - - return row; - } - - public static void AssertIsEqual(ModelWithFieldsOfDifferentAndNullableTypes actual, ModelWithFieldsOfDifferentAndNullableTypes expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.Guid, Is.EqualTo(expected.Guid)); - Assert.That(actual.LongId, Is.EqualTo(expected.LongId)); - Assert.That(actual.Bool, Is.EqualTo(expected.Bool)); - Assert.That(actual.TimeSpan, Is.EqualTo(expected.TimeSpan)); - - try - { - Assert.That(actual.DateTime, Is.EqualTo(expected.DateTime)); - } - catch (Exception ex) - { - Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); - Assert.That(actual.DateTime.RoundToSecond(), Is.EqualTo(expected.DateTime.RoundToSecond())); - } - - try - { - Assert.That(actual.Float, Is.EqualTo(expected.Float)); - } - catch (Exception ex) - { - Log.Error("Trouble with float precisions, trying Assert again with rounding to 10 decimals", ex); - Assert.That(Math.Round(actual.Float, 10), Is.EqualTo(Math.Round(actual.Float, 10))); - } - - try - { - Assert.That(actual.Double, Is.EqualTo(expected.Double)); - } - catch (Exception ex) - { - Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); - Assert.That(Math.Round(actual.Double, 10), Is.EqualTo(Math.Round(actual.Double, 10))); - } - - Assert.That(actual.NBool, Is.EqualTo(expected.NBool)); - Assert.That(actual.NDateTime, Is.EqualTo(expected.NDateTime)); - Assert.That(actual.NDecimal, Is.EqualTo(expected.NDecimal)); - Assert.That(actual.NDouble, Is.EqualTo(expected.NDouble)); - Assert.That(actual.NFloat, Is.EqualTo(expected.NFloat)); - Assert.That(actual.NGuid, Is.EqualTo(expected.NGuid)); - Assert.That(actual.NId, Is.EqualTo(expected.NId)); - Assert.That(actual.NLongId, Is.EqualTo(expected.NLongId)); - Assert.That(actual.NTimeSpan, Is.EqualTo(expected.NTimeSpan)); - - } - } + public class ModelWithFieldsOfDifferentAndNullableTypes + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfDifferentAndNullableTypes)); + + [AutoIncrement] + public int Id { get; set; } + public int? NId { get; set; } + + public long LongId { get; set; } + public long? NLongId { get; set; } + + public Guid Guid { get; set; } + public Guid? NGuid { get; set; } + + public bool Bool { get; set; } + public bool? NBool { get; set; } + + public DateTime DateTime { get; set; } + public DateTime? NDateTime { get; set; } + + public float Float { get; set; } + public float? NFloat { get; set; } + + public double Double { get; set; } + public double? NDouble { get; set; } + + public decimal Decimal { get; set; } + public decimal? NDecimal { get; set; } + + public TimeSpan TimeSpan { get; set; } + public TimeSpan? NTimeSpan { get; set; } + + public static ModelWithFieldsOfDifferentAndNullableTypes Create(int id) + { + var row = new ModelWithFieldsOfDifferentAndNullableTypes + { + Id = id, + Bool = id % 2 == 0, + DateTime = DateTime.Now.AddDays(id), + Float = 1.11f + id, + Double = 1.11d + id, + Guid = Guid.NewGuid(), + LongId = 999 + id, + Decimal = id + 0.5m, + TimeSpan = TimeSpan.FromSeconds(id), + }; + + return row; + } + + public static ModelWithFieldsOfDifferentAndNullableTypes CreateConstant(int id) + { + var row = new ModelWithFieldsOfDifferentAndNullableTypes + { + Id = id, + Bool = id % 2 == 0, + DateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), + Float = 1.11f + id, + Double = 1.11d + id, + Guid = new Guid(((id % 240) + 16).ToString("X") + "461D9D-47DB-4778-B3FA-458379AE9BDC"), + LongId = 999 + id, + Decimal = id + 0.5m, + TimeSpan = TimeSpan.FromSeconds(id), + }; + + return row; + } + + public static void AssertIsEqual(ModelWithFieldsOfDifferentAndNullableTypes actual, ModelWithFieldsOfDifferentAndNullableTypes expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.Guid, Is.EqualTo(expected.Guid)); + Assert.That(actual.LongId, Is.EqualTo(expected.LongId)); + Assert.That(actual.Bool, Is.EqualTo(expected.Bool)); + Assert.That(actual.TimeSpan, Is.EqualTo(expected.TimeSpan)); + + try + { + Assert.That(actual.DateTime, Is.EqualTo(expected.DateTime)); + } + catch (Exception ex) + { + Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); + Assert.That(actual.DateTime.RoundToSecond(), Is.EqualTo(expected.DateTime.RoundToSecond())); + } + + try + { + Assert.That(actual.Float, Is.EqualTo(expected.Float)); + } + catch (Exception ex) + { + Log.Error("Trouble with float precisions, trying Assert again with rounding to 10 decimals", ex); + Assert.That(Math.Round(actual.Float, 10), Is.EqualTo(Math.Round(actual.Float, 10))); + } + + try + { + Assert.That(actual.Double, Is.EqualTo(expected.Double)); + } + catch (Exception ex) + { + Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); + Assert.That(Math.Round(actual.Double, 10), Is.EqualTo(Math.Round(actual.Double, 10))); + } + + Assert.That(actual.NBool, Is.EqualTo(expected.NBool)); + Assert.That(actual.NDateTime, Is.EqualTo(expected.NDateTime)); + Assert.That(actual.NDecimal, Is.EqualTo(expected.NDecimal)); + Assert.That(actual.NDouble, Is.EqualTo(expected.NDouble)); + Assert.That(actual.NFloat, Is.EqualTo(expected.NFloat)); + Assert.That(actual.NGuid, Is.EqualTo(expected.NGuid)); + Assert.That(actual.NId, Is.EqualTo(expected.NId)); + Assert.That(actual.NLongId, Is.EqualTo(expected.NLongId)); + Assert.That(actual.NTimeSpan, Is.EqualTo(expected.NTimeSpan)); + + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypesFactory.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypesFactory.cs index 9ae7e113107..bed7fcde6df 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypesFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentAndNullableTypesFactory.cs @@ -1,20 +1,20 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithFieldsOfDifferentAndNullableTypesFactory - : ModelFactoryBase - { - public static ModelWithFieldsOfDifferentAndNullableTypesFactory Instance - = new ModelWithFieldsOfDifferentAndNullableTypesFactory(); + public class ModelWithFieldsOfDifferentAndNullableTypesFactory + : ModelFactoryBase + { + public static ModelWithFieldsOfDifferentAndNullableTypesFactory Instance + = new ModelWithFieldsOfDifferentAndNullableTypesFactory(); - public override void AssertIsEqual( - ModelWithFieldsOfDifferentAndNullableTypes actual, ModelWithFieldsOfDifferentAndNullableTypes expected) - { - ModelWithFieldsOfDifferentAndNullableTypes.AssertIsEqual(actual, expected); - } + public override void AssertIsEqual( + ModelWithFieldsOfDifferentAndNullableTypes actual, ModelWithFieldsOfDifferentAndNullableTypes expected) + { + ModelWithFieldsOfDifferentAndNullableTypes.AssertIsEqual(actual, expected); + } - public override ModelWithFieldsOfDifferentAndNullableTypes CreateInstance(int i) - { - return ModelWithFieldsOfDifferentAndNullableTypes.CreateConstant(i); - } - } + public override ModelWithFieldsOfDifferentAndNullableTypes CreateInstance(int i) + { + return ModelWithFieldsOfDifferentAndNullableTypes.CreateConstant(i); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypes.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypes.cs index e4a3d1f2065..49eb083a203 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypes.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypes.cs @@ -1,184 +1,188 @@ using System; using NUnit.Framework; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; using ServiceStack.DataAnnotations; using ServiceStack.Logging; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Models { - public class ModelWithFieldsOfDifferentTypesAsNullables - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfDifferentTypesAsNullables)); - - public int? Id { get; set; } - - public string Name { get; set; } - - public long? LongId { get; set; } - - public Guid? Guid { get; set; } - - public bool? Bool { get; set; } - - public DateTime? DateTime { get; set; } - - public double? Double { get; set; } - - public static ModelWithFieldsOfDifferentTypesAsNullables Create(int id) - { - var row = new ModelWithFieldsOfDifferentTypesAsNullables { - Id = id, - Bool = id % 2 == 0, - DateTime = System.DateTime.Now.AddDays(id), - Double = 1.11d + id, - Guid = System.Guid.NewGuid(), - LongId = 999 + id, - Name = "Name" + id - }; - - return row; - } - - public static ModelWithFieldsOfDifferentTypesAsNullables CreateConstant(int id) - { - var row = new ModelWithFieldsOfDifferentTypesAsNullables { - Id = id, - Bool = id % 2 == 0, - DateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), - Double = 1.11d + id, - Guid = new Guid(((id % 240) + 16).ToString("X") + "726E3B-9983-40B4-A8CB-2F8ADA8C8760"), - LongId = 999 + id, - Name = "Name" + id - }; - - return row; - } - - public static void AssertIsEqual(ModelWithFieldsOfDifferentTypes actual, ModelWithFieldsOfDifferentTypesAsNullables expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id.Value)); - Assert.That(actual.Name, Is.EqualTo(expected.Name)); - Assert.That(actual.Guid, Is.EqualTo(expected.Guid.Value)); - Assert.That(actual.LongId, Is.EqualTo(expected.LongId.Value)); - Assert.That(actual.Bool, Is.EqualTo(expected.Bool.Value)); - try - { - Assert.That(actual.DateTime, Is.EqualTo(expected.DateTime.Value)); - } - catch (Exception ex) - { - Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); - Assert.That(actual.DateTime.RoundToSecond(), Is.EqualTo(expected.DateTime.Value.RoundToSecond())); - } - try - { - Assert.That(actual.Double, Is.EqualTo(expected.Double.Value)); - } - catch (Exception ex) - { - Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); - Assert.That(Math.Round(actual.Double, 10), Is.EqualTo(Math.Round(actual.Double, 10))); - } - } - } - - - public class ModelWithFieldsOfDifferentTypes - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfDifferentTypes)); - - [AutoIncrement] - public int Id { get; set; } - - public string Name { get; set; } - - public long LongId { get; set; } - - public Guid Guid { get; set; } - - public bool Bool { get; set; } - - public DateTime DateTime { get; set; } - - public double Double { get; set; } - - public static ModelWithFieldsOfDifferentTypes Create(int id) - { - var row = new ModelWithFieldsOfDifferentTypes { - Id = id, - Bool = id % 2 == 0, - DateTime = DateTime.Now.AddDays(id), - Double = 1.11d + id, - Guid = Guid.NewGuid(), - LongId = 999 + id, - Name = "Name" + id - }; - - return row; - } - - public static ModelWithFieldsOfDifferentTypes CreateConstant(int id) - { - var row = new ModelWithFieldsOfDifferentTypes { - Id = id, - Bool = id % 2 == 0, - DateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), - Double = 1.11d + id, - Guid = new Guid(((id % 240) + 16).ToString("X") + "726E3B-9983-40B4-A8CB-2F8ADA8C8760"), - LongId = 999 + id, - Name = "Name" + id - }; - - return row; - } - - public override bool Equals(object obj) - { - var other = obj as ModelWithFieldsOfDifferentTypes; - if (other == null) return false; - - try - { - AssertIsEqual(this, other); - return true; - } - catch (Exception) - { - return false; - } - } - - public override int GetHashCode() - { - return (Id + Guid.ToString()).GetHashCode(); - } - - public static void AssertIsEqual(ModelWithFieldsOfDifferentTypes actual, ModelWithFieldsOfDifferentTypes expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.Name, Is.EqualTo(expected.Name)); - Assert.That(actual.Guid, Is.EqualTo(expected.Guid)); - Assert.That(actual.LongId, Is.EqualTo(expected.LongId)); - Assert.That(actual.Bool, Is.EqualTo(expected.Bool)); - try - { - Assert.That(actual.DateTime, Is.EqualTo(expected.DateTime)); - } - catch (Exception ex) - { - Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); - Assert.That(actual.DateTime.RoundToSecond(), Is.EqualTo(expected.DateTime.RoundToSecond())); - } - try - { - Assert.That(actual.Double, Is.EqualTo(expected.Double)); - } - catch (Exception ex) - { - Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); - Assert.That(Math.Round(actual.Double, 10), Is.EqualTo(Math.Round(actual.Double, 10))); - } - } - } + public class ModelWithFieldsOfDifferentTypesAsNullables + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfDifferentTypesAsNullables)); + + public int? Id { get; set; } + + public string Name { get; set; } + + public long? LongId { get; set; } + + public Guid? Guid { get; set; } + + public bool? Bool { get; set; } + + public DateTime? DateTime { get; set; } + + public double? Double { get; set; } + + public static ModelWithFieldsOfDifferentTypesAsNullables Create(int id) + { + var row = new ModelWithFieldsOfDifferentTypesAsNullables + { + Id = id, + Bool = id % 2 == 0, + DateTime = System.DateTime.Now.AddDays(id), + Double = 1.11d + id, + Guid = System.Guid.NewGuid(), + LongId = 999 + id, + Name = "Name" + id + }; + + return row; + } + + public static ModelWithFieldsOfDifferentTypesAsNullables CreateConstant(int id) + { + var row = new ModelWithFieldsOfDifferentTypesAsNullables + { + Id = id, + Bool = id % 2 == 0, + DateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), + Double = 1.11d + id, + Guid = new Guid(((id % 240) + 16).ToString("X") + "726E3B-9983-40B4-A8CB-2F8ADA8C8760"), + LongId = 999 + id, + Name = "Name" + id + }; + + return row; + } + + public static void AssertIsEqual(ModelWithFieldsOfDifferentTypes actual, ModelWithFieldsOfDifferentTypesAsNullables expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id.Value)); + Assert.That(actual.Name, Is.EqualTo(expected.Name)); + Assert.That(actual.Guid, Is.EqualTo(expected.Guid.Value)); + Assert.That(actual.LongId, Is.EqualTo(expected.LongId.Value)); + Assert.That(actual.Bool, Is.EqualTo(expected.Bool.Value)); + try + { + Assert.That(actual.DateTime, Is.EqualTo(expected.DateTime.Value)); + } + catch (Exception ex) + { + Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); + Assert.That(actual.DateTime.RoundToSecond(), Is.EqualTo(expected.DateTime.Value.RoundToSecond())); + } + try + { + Assert.That(actual.Double, Is.EqualTo(expected.Double.Value)); + } + catch (Exception ex) + { + Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); + Assert.That(Math.Round(actual.Double, 10), Is.EqualTo(Math.Round(actual.Double, 10))); + } + } + } + + + public class ModelWithFieldsOfDifferentTypes + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfDifferentTypes)); + + [AutoIncrement] + public int Id { get; set; } + + public string Name { get; set; } + + public long LongId { get; set; } + + public Guid Guid { get; set; } + + public bool Bool { get; set; } + + public DateTime DateTime { get; set; } + + public double Double { get; set; } + + public static ModelWithFieldsOfDifferentTypes Create(int id) + { + var row = new ModelWithFieldsOfDifferentTypes + { + Id = id, + Bool = id % 2 == 0, + DateTime = DateTime.Now.AddDays(id), + Double = 1.11d + id, + Guid = Guid.NewGuid(), + LongId = 999 + id, + Name = "Name" + id + }; + + return row; + } + + public static ModelWithFieldsOfDifferentTypes CreateConstant(int id) + { + var row = new ModelWithFieldsOfDifferentTypes + { + Id = id, + Bool = id % 2 == 0, + DateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), + Double = 1.11d + id, + Guid = new Guid(((id % 240) + 16).ToString("X") + "726E3B-9983-40B4-A8CB-2F8ADA8C8760"), + LongId = 999 + id, + Name = "Name" + id + }; + + return row; + } + + public override bool Equals(object obj) + { + var other = obj as ModelWithFieldsOfDifferentTypes; + if (other == null) return false; + + try + { + AssertIsEqual(this, other); + return true; + } + catch (Exception) + { + return false; + } + } + + public override int GetHashCode() + { + return (Id + Guid.ToString()).GetHashCode(); + } + + public static void AssertIsEqual(ModelWithFieldsOfDifferentTypes actual, ModelWithFieldsOfDifferentTypes expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.Name, Is.EqualTo(expected.Name)); + Assert.That(actual.Guid, Is.EqualTo(expected.Guid)); + Assert.That(actual.LongId, Is.EqualTo(expected.LongId)); + Assert.That(actual.Bool, Is.EqualTo(expected.Bool)); + try + { + Assert.That(actual.DateTime, Is.EqualTo(expected.DateTime)); + } + catch (Exception ex) + { + Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); + Assert.That(actual.DateTime.RoundToSecond(), Is.EqualTo(expected.DateTime.RoundToSecond())); + } + try + { + Assert.That(actual.Double, Is.EqualTo(expected.Double)); + } + catch (Exception ex) + { + Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); + Assert.That(Math.Round(actual.Double, 10), Is.EqualTo(Math.Round(actual.Double, 10))); + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypesFactory.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypesFactory.cs index 5299d7d0a70..4fe5ea3658d 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypesFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfDifferentTypesFactory.cs @@ -2,21 +2,21 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithFieldsOfDifferentTypesFactory - : ModelFactoryBase - { - public static ModelWithFieldsOfDifferentTypesFactory Instance - = new ModelWithFieldsOfDifferentTypesFactory(); + public class ModelWithFieldsOfDifferentTypesFactory + : ModelFactoryBase + { + public static ModelWithFieldsOfDifferentTypesFactory Instance + = new ModelWithFieldsOfDifferentTypesFactory(); - public override void AssertIsEqual( - ModelWithFieldsOfDifferentTypes actual, ModelWithFieldsOfDifferentTypes expected) - { - ModelWithFieldsOfDifferentTypes.AssertIsEqual(actual, expected); - } + public override void AssertIsEqual( + ModelWithFieldsOfDifferentTypes actual, ModelWithFieldsOfDifferentTypes expected) + { + ModelWithFieldsOfDifferentTypes.AssertIsEqual(actual, expected); + } - public override ModelWithFieldsOfDifferentTypes CreateInstance(int i) - { - return ModelWithFieldsOfDifferentTypes.CreateConstant(i); - } - } + public override ModelWithFieldsOfDifferentTypes CreateInstance(int i) + { + return ModelWithFieldsOfDifferentTypes.CreateConstant(i); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypes.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypes.cs index 15f13f1f2f0..24a2acf4b07 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypes.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypes.cs @@ -1,111 +1,112 @@ using System; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.DesignPatterns.Model; +using ServiceStack.Model; using ServiceStack.Logging; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Models { - public class ModelWithFieldsOfNullableTypes - : IHasIntId - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfNullableTypes)); - - public int Id { get; set; } - public int? NId { get; set; } - - public long? NLongId { get; set; } - - public Guid? NGuid { get; set; } - - public bool? NBool { get; set; } - - public DateTime? NDateTime { get; set; } - - public float? NFloat { get; set; } - - public double? NDouble { get; set; } - - public decimal? NDecimal { get; set; } - - public TimeSpan? NTimeSpan { get; set; } - - public static ModelWithFieldsOfNullableTypes Create(int id) - { - var row = new ModelWithFieldsOfNullableTypes { - Id = id, - NId = id, - NBool = id % 2 == 0, - NDateTime = DateTime.Now.AddDays(id), - NFloat = 1.11f + id, - NDouble = 1.11d + id, - NGuid = Guid.NewGuid(), - NLongId = 999 + id, - NDecimal = id + 0.5m, - NTimeSpan = TimeSpan.FromSeconds(id), - }; - - return row; - } - - public static ModelWithFieldsOfNullableTypes CreateConstant(int id) - { - var row = new ModelWithFieldsOfNullableTypes { - Id = id, - NId = id, - NBool = id % 2 == 0, - NDateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), - NFloat = 1.11f + id, - NDouble = 1.11d + id, - NGuid = new Guid(((id % 240) + 16).ToString("X") + "7DA519-73B6-4525-84BA-B57673B2360D"), - NLongId = 999 + id, - NDecimal = id + 0.5m, - NTimeSpan = TimeSpan.FromSeconds(id), - }; - - return row; - } - - public static void AssertIsEqual(ModelWithFieldsOfNullableTypes actual, ModelWithFieldsOfNullableTypes expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.NId, Is.EqualTo(expected.NId)); - Assert.That(actual.NGuid, Is.EqualTo(expected.NGuid)); - Assert.That(actual.NLongId, Is.EqualTo(expected.NLongId)); - Assert.That(actual.NBool, Is.EqualTo(expected.NBool)); - Assert.That(actual.NTimeSpan, Is.EqualTo(expected.NTimeSpan)); - - try - { - Assert.That(actual.NDateTime, Is.EqualTo(expected.NDateTime)); - } - catch (Exception ex) - { - Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); - Assert.That(actual.NDateTime.Value.ToUniversalTime().RoundToSecond(), Is.EqualTo(expected.NDateTime.Value.ToUniversalTime().RoundToSecond())); - } - - try - { - Assert.That(actual.NFloat, Is.EqualTo(expected.NFloat)); - } - catch (Exception ex) - { - Log.Error("Trouble with float precisions, trying Assert again with rounding to 10 decimals", ex); - Assert.That(Math.Round(actual.NFloat.Value, 10), Is.EqualTo(Math.Round(actual.NFloat.Value, 10))); - } - - try - { - Assert.That(actual.NDouble, Is.EqualTo(expected.NDouble)); - } - catch (Exception ex) - { - Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); - Assert.That(Math.Round(actual.NDouble.Value, 10), Is.EqualTo(Math.Round(actual.NDouble.Value, 10))); - } - - } - } + public class ModelWithFieldsOfNullableTypes + : IHasIntId + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ModelWithFieldsOfNullableTypes)); + + public int Id { get; set; } + public int? NId { get; set; } + + public long? NLongId { get; set; } + + public Guid? NGuid { get; set; } + + public bool? NBool { get; set; } + + public DateTime? NDateTime { get; set; } + + public float? NFloat { get; set; } + + public double? NDouble { get; set; } + + public decimal? NDecimal { get; set; } + + public TimeSpan? NTimeSpan { get; set; } + + public static ModelWithFieldsOfNullableTypes Create(int id) + { + var row = new ModelWithFieldsOfNullableTypes + { + Id = id, + NId = id, + NBool = id % 2 == 0, + NDateTime = DateTime.Now.AddDays(id), + NFloat = 1.11f + id, + NDouble = 1.11d + id, + NGuid = Guid.NewGuid(), + NLongId = 999 + id, + NDecimal = id + 0.5m, + NTimeSpan = TimeSpan.FromSeconds(id), + }; + + return row; + } + + public static ModelWithFieldsOfNullableTypes CreateConstant(int id) + { + var row = new ModelWithFieldsOfNullableTypes + { + Id = id, + NId = id, + NBool = id % 2 == 0, + NDateTime = new DateTime(1979, (id % 12) + 1, (id % 28) + 1), + NFloat = 1.11f + id, + NDouble = 1.11d + id, + NGuid = new Guid(((id % 240) + 16).ToString("X") + "7DA519-73B6-4525-84BA-B57673B2360D"), + NLongId = 999 + id, + NDecimal = id + 0.5m, + NTimeSpan = TimeSpan.FromSeconds(id), + }; + + return row; + } + + public static void AssertIsEqual(ModelWithFieldsOfNullableTypes actual, ModelWithFieldsOfNullableTypes expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.NId, Is.EqualTo(expected.NId)); + Assert.That(actual.NGuid, Is.EqualTo(expected.NGuid)); + Assert.That(actual.NLongId, Is.EqualTo(expected.NLongId)); + Assert.That(actual.NBool, Is.EqualTo(expected.NBool)); + Assert.That(actual.NTimeSpan, Is.EqualTo(expected.NTimeSpan)); + + try + { + Assert.That(actual.NDateTime, Is.EqualTo(expected.NDateTime)); + } + catch (Exception ex) + { + Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); + Assert.That(actual.NDateTime.Value.ToUniversalTime().RoundToSecond(), Is.EqualTo(expected.NDateTime.Value.ToUniversalTime().RoundToSecond())); + } + + try + { + Assert.That(actual.NFloat, Is.EqualTo(expected.NFloat)); + } + catch (Exception ex) + { + Log.Error("Trouble with float precisions, trying Assert again with rounding to 10 decimals", ex); + Assert.That(Math.Round(actual.NFloat.Value, 10), Is.EqualTo(Math.Round(actual.NFloat.Value, 10))); + } + + try + { + Assert.That(actual.NDouble, Is.EqualTo(expected.NDouble)); + } + catch (Exception ex) + { + Log.Error("Trouble with double precisions, trying Assert again with rounding to 10 decimals", ex); + Assert.That(Math.Round(actual.NDouble.Value, 10), Is.EqualTo(Math.Round(actual.NDouble.Value, 10))); + } + + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypesFactory.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypesFactory.cs index 1fde381ec79..1c04743ca2e 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypesFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithFieldsOfNullableTypesFactory.cs @@ -1,20 +1,20 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithFieldsOfNullableTypesFactory - : ModelFactoryBase - { - public static ModelWithFieldsOfNullableTypesFactory Instance - = new ModelWithFieldsOfNullableTypesFactory(); + public class ModelWithFieldsOfNullableTypesFactory + : ModelFactoryBase + { + public static ModelWithFieldsOfNullableTypesFactory Instance + = new ModelWithFieldsOfNullableTypesFactory(); - public override void AssertIsEqual( - ModelWithFieldsOfNullableTypes actual, ModelWithFieldsOfNullableTypes expected) - { - ModelWithFieldsOfNullableTypes.AssertIsEqual(actual, expected); - } + public override void AssertIsEqual( + ModelWithFieldsOfNullableTypes actual, ModelWithFieldsOfNullableTypes expected) + { + ModelWithFieldsOfNullableTypes.AssertIsEqual(actual, expected); + } - public override ModelWithFieldsOfNullableTypes CreateInstance(int i) - { - return ModelWithFieldsOfNullableTypes.CreateConstant(i); - } - } + public override ModelWithFieldsOfNullableTypes CreateInstance(int i) + { + return ModelWithFieldsOfNullableTypes.CreateConstant(i); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithIdAndName.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithIdAndName.cs index 76aa4707323..ec04f3a4c7f 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithIdAndName.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithIdAndName.cs @@ -4,61 +4,61 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithIdAndName - { - public ModelWithIdAndName() - { - } + public class ModelWithIdAndName + { + public ModelWithIdAndName() + { + } - public ModelWithIdAndName(int id) - { - Id = id; - Name = "Name" + id; - } + public ModelWithIdAndName(int id) + { + Id = id; + Name = "Name" + id; + } [AutoIncrement] - public int Id { get; set; } + public int Id { get; set; } - public string Name { get; set; } + public string Name { get; set; } - public static ModelWithIdAndName Create(int id) - { - return new ModelWithIdAndName(id); - } + public static ModelWithIdAndName Create(int id) + { + return new ModelWithIdAndName(id); + } - public static void AssertIsEqual(ModelWithIdAndName actual, ModelWithIdAndName expected) - { - if (actual == null || expected == null) - { - Assert.That(actual == expected, Is.True); - return; - } + public static void AssertIsEqual(ModelWithIdAndName actual, ModelWithIdAndName expected) + { + if (actual == null || expected == null) + { + Assert.That(actual == expected, Is.True); + return; + } - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.Name, Is.EqualTo(expected.Name)); - } + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.Name, Is.EqualTo(expected.Name)); + } - public bool Equals(ModelWithIdAndName other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Id == Id && Equals(other.Name, Name); - } + public bool Equals(ModelWithIdAndName other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Id == Id && Equals(other.Name, Name); + } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (ModelWithIdAndName)) return false; - return Equals((ModelWithIdAndName) obj); - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(ModelWithIdAndName)) return false; + return Equals((ModelWithIdAndName)obj); + } - public override int GetHashCode() - { - unchecked - { - return (Id*397) ^ (Name != null ? Name.GetHashCode() : 0); - } - } - } + public override int GetHashCode() + { + unchecked + { + return (Id * 397) ^ (Name != null ? Name.GetHashCode() : 0); + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithIdOnly.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithIdOnly.cs index 4d2684e3b2a..2c531b6a037 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithIdOnly.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithIdOnly.cs @@ -1,18 +1,18 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithIdOnly - { - public ModelWithIdOnly() - { - } + public class ModelWithIdOnly + { + public ModelWithIdOnly() + { + } - public ModelWithIdOnly(long id) - { - Id = id; - } + public ModelWithIdOnly(long id) + { + Id = id; + } - // must be long as you cannot have a table with only an autoincrement field - public long Id { get; set; } + // must be long as you cannot have a table with only an autoincrement field + public long Id { get; set; } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithIndexFields.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithIndexFields.cs index 97c93669b82..2322908380a 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithIndexFields.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithIndexFields.cs @@ -2,16 +2,16 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithIndexFields - { - public string Id { get; set; } + public class ModelWithIndexFields + { + public string Id { get; set; } - [Index] - public string Name { get; set; } + [Index] + public string Name { get; set; } - public string AlbumId { get; set; } + public string AlbumId { get; set; } - [Index(true)] - public string UniqueName { get; set; } - } + [Index(true)] + public string UniqueName { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithLongIdAndStringFields.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithLongIdAndStringFields.cs index 8201895bc2c..12a696ba7b1 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithLongIdAndStringFields.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithLongIdAndStringFields.cs @@ -1,13 +1,13 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithLongIdAndStringFields - { - public long Id { get; set; } + public class ModelWithLongIdAndStringFields + { + public long Id { get; set; } - public string Name { get; set; } + public string Name { get; set; } - public string AlbumId { get; set; } + public string AlbumId { get; set; } - public string AlbumName { get; set; } - } + public string AlbumName { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithMapAndList.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithMapAndList.cs index e7b178b7811..60c911e6a97 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithMapAndList.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithMapAndList.cs @@ -3,40 +3,40 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithMapAndList - { - public ModelWithMapAndList() - { - this.Map = new Dictionary(); - this.List = new List(); - } - - public ModelWithMapAndList(int id) - : this() - { - Id = id; - Name = "Name" + id; - } - - public int Id { get; set; } - - public string Name { get; set; } - - public Dictionary Map { get; set; } - - public List List { get; set; } - - public static ModelWithMapAndList Create(int id) - { - return new ModelWithMapAndList(id); - } - - public static void AssertIsEqual(ModelWithMapAndList actual, ModelWithMapAndList expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.Name, Is.EqualTo(expected.Name)); - Assert.That(actual.Map, Is.EquivalentTo(expected.Map)); - Assert.That(actual.List, Is.EquivalentTo(expected.List)); - } - } + public class ModelWithMapAndList + { + public ModelWithMapAndList() + { + this.Map = new Dictionary(); + this.List = new List(); + } + + public ModelWithMapAndList(int id) + : this() + { + Id = id; + Name = "Name" + id; + } + + public int Id { get; set; } + + public string Name { get; set; } + + public Dictionary Map { get; set; } + + public List List { get; set; } + + public static ModelWithMapAndList Create(int id) + { + return new ModelWithMapAndList(id); + } + + public static void AssertIsEqual(ModelWithMapAndList actual, ModelWithMapAndList expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.Name, Is.EqualTo(expected.Name)); + Assert.That(actual.Map, Is.EquivalentTo(expected.Map)); + Assert.That(actual.List, Is.EquivalentTo(expected.List)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithNamedCompositeIndex.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithNamedCompositeIndex.cs index 7e9221ed841..28670876b8e 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithNamedCompositeIndex.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithNamedCompositeIndex.cs @@ -2,21 +2,21 @@ namespace ServiceStack.Common.Tests.Models { - [CompositeIndex(true, "Composite1", "Composite2", Name = "custom_index_name")] - public class ModelWithNamedCompositeIndex - { - public string Id { get; set; } + [CompositeIndex(true, "Composite1", "Composite2", Name = "custom_index_name")] + public class ModelWithNamedCompositeIndex + { + public string Id { get; set; } - [Index] - public string Name { get; set; } + [Index] + public string Name { get; set; } - public string AlbumId { get; set; } + public string AlbumId { get; set; } - [Index(true)] - public string UniqueName { get; set; } + [Index(true)] + public string UniqueName { get; set; } - public string Composite1 { get; set; } + public string Composite1 { get; set; } - public string Composite2 { get; set; } - } + public string Composite2 { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ModelWithOnlyStringFields.cs b/tests/ServiceStack.Common.Tests/Models/ModelWithOnlyStringFields.cs index 64621d0f4c7..c8522540006 100644 --- a/tests/ServiceStack.Common.Tests/Models/ModelWithOnlyStringFields.cs +++ b/tests/ServiceStack.Common.Tests/Models/ModelWithOnlyStringFields.cs @@ -1,23 +1,24 @@ namespace ServiceStack.Common.Tests.Models { - public class ModelWithOnlyStringFields - { - public string Id { get; set; } + public class ModelWithOnlyStringFields + { + public string Id { get; set; } - public string Name { get; set; } + public string Name { get; set; } - public string AlbumId { get; set; } + public string AlbumId { get; set; } - public string AlbumName { get; set; } + public string AlbumName { get; set; } - public static ModelWithOnlyStringFields Create(string id) - { - return new ModelWithOnlyStringFields { - Id = id, - Name = "Name", - AlbumId = "AlbumId", - AlbumName = "AlbumName", - }; - } - } + public static ModelWithOnlyStringFields Create(string id) + { + return new ModelWithOnlyStringFields + { + Id = id, + Name = "Name", + AlbumId = "AlbumId", + AlbumName = "AlbumName", + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/Movie.cs b/tests/ServiceStack.Common.Tests/Models/Movie.cs index c3d02ffaeab..afcac8b772c 100644 --- a/tests/ServiceStack.Common.Tests/Models/Movie.cs +++ b/tests/ServiceStack.Common.Tests/Models/Movie.cs @@ -1,67 +1,67 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; namespace ServiceStack.Common.Tests.Models { - [DataContract] - public class Movie - { - public Movie() - { - this.Genres = new List(); - } + [DataContract] + public class Movie + { + public Movie() + { + this.Genres = new List(); + } - [DataMember] - public string Id { get; set; } + [DataMember] + public string Id { get; set; } - [DataMember] - public string Title { get; set; } + [DataMember] + public string Title { get; set; } - [DataMember] - public decimal Rating { get; set; } + [DataMember] + public decimal Rating { get; set; } - [DataMember] - public string Director { get; set; } + [DataMember] + public string Director { get; set; } - [DataMember] - public DateTime ReleaseDate { get; set; } + [DataMember] + public DateTime ReleaseDate { get; set; } - [DataMember] - public string TagLine { get; set; } + [DataMember] + public string TagLine { get; set; } - [DataMember] - public List Genres { get; set; } + [DataMember] + public List Genres { get; set; } - public bool Equals(Movie other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Equals(other.Id, Id) && Equals(other.Title, Title) && other.Rating == Rating && Equals(other.Director, Director) && other.ReleaseDate.Equals(ReleaseDate) && Equals(other.TagLine, TagLine) && Genres.EquivalentTo(other.Genres); - } + public bool Equals(Movie other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.Id, Id) && Equals(other.Title, Title) && other.Rating == Rating && Equals(other.Director, Director) && other.ReleaseDate.Equals(ReleaseDate) && Equals(other.TagLine, TagLine) && Genres.EquivalentTo(other.Genres); + } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (Movie)) return false; - return Equals((Movie) obj); - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(Movie)) return false; + return Equals((Movie)obj); + } - public override int GetHashCode() - { - unchecked - { - int result = (Id != null ? Id.GetHashCode() : 0); - result = (result*397) ^ (Title != null ? Title.GetHashCode() : 0); - result = (result*397) ^ Rating.GetHashCode(); - result = (result*397) ^ (Director != null ? Director.GetHashCode() : 0); - result = (result*397) ^ ReleaseDate.GetHashCode(); - result = (result*397) ^ (TagLine != null ? TagLine.GetHashCode() : 0); - result = (result*397) ^ (Genres != null ? Genres.GetHashCode() : 0); - return result; - } - } - } + public override int GetHashCode() + { + unchecked + { + int result = (Id != null ? Id.GetHashCode() : 0); + result = (result * 397) ^ (Title != null ? Title.GetHashCode() : 0); + result = (result * 397) ^ Rating.GetHashCode(); + result = (result * 397) ^ (Director != null ? Director.GetHashCode() : 0); + result = (result * 397) ^ ReleaseDate.GetHashCode(); + result = (result * 397) ^ (TagLine != null ? TagLine.GetHashCode() : 0); + result = (result * 397) ^ (Genres != null ? Genres.GetHashCode() : 0); + return result; + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/Poco.cs b/tests/ServiceStack.Common.Tests/Models/Poco.cs index 476cbb55146..27d1a489f99 100644 --- a/tests/ServiceStack.Common.Tests/Models/Poco.cs +++ b/tests/ServiceStack.Common.Tests/Models/Poco.cs @@ -2,6 +2,8 @@ { public class Poco { - public string Name { get; set; } + public int Id { get; set; } + public string Name { get; set; } + public int? Age { get; set; } } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/SampleOrderLine.cs b/tests/ServiceStack.Common.Tests/Models/SampleOrderLine.cs index 1ed3a7d8d8c..d25fefffc93 100644 --- a/tests/ServiceStack.Common.Tests/Models/SampleOrderLine.cs +++ b/tests/ServiceStack.Common.Tests/Models/SampleOrderLine.cs @@ -2,151 +2,152 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using ServiceStack.DesignPatterns.Model; +using ServiceStack.Model; namespace ServiceStack.Common.Tests.Models { - public class SampleOrderLine - : IHasStringId - { - public string Id { get; set; } + public class SampleOrderLine + : IHasStringId + { + public string Id { get; set; } - public string OrderUrn - { - get - { - return CreateUrn(this.UserId, this.OrderId, this.OrderLineId); - } - } + public string OrderUrn + { + get + { + return CreateUrn(this.UserId, this.OrderId, this.OrderLineId); + } + } - public long OrderId { get; set; } + public long OrderId { get; set; } - public long OrderLineId { get; set; } + public long OrderLineId { get; set; } - public DateTime CreatedDate { get; set; } + public DateTime CreatedDate { get; set; } - public Guid UserId { get; set; } + public Guid UserId { get; set; } - public string UserName { get; set; } + public string UserName { get; set; } - public Guid ProductId { get; set; } + public Guid ProductId { get; set; } - public string MflowUrn { get; set; } + public string MflowUrn { get; set; } - public string ProductType { get; set; } + public string ProductType { get; set; } - public string Description { get; set; } + public string Description { get; set; } - public string UpcEan { get; set; } + public string UpcEan { get; set; } - public string Isrc { get; set; } + public string Isrc { get; set; } - public Guid? RecommendationUserId { get; set; } + public Guid? RecommendationUserId { get; set; } - public string RecommendationUserName { get; set; } + public string RecommendationUserName { get; set; } - public string SupplierKeyName { get; set; } + public string SupplierKeyName { get; set; } - public string CostTierKeyName { get; set; } + public string CostTierKeyName { get; set; } - public string PriceTierKeyName { get; set; } + public string PriceTierKeyName { get; set; } - public decimal VatRate { get; set; } + public decimal VatRate { get; set; } - public int ProductPriceIncVat { get; set; } + public int ProductPriceIncVat { get; set; } - public int Quantity { get; set; } + public int Quantity { get; set; } - public decimal TransactionValueExVat { get; set; } + public decimal TransactionValueExVat { get; set; } - public decimal TransactionValueIncVat { get; set; } + public decimal TransactionValueIncVat { get; set; } - public decimal RecommendationDiscountRate { get; set; } + public decimal RecommendationDiscountRate { get; set; } - public decimal DistributionDiscountRate { get; set; } + public decimal DistributionDiscountRate { get; set; } - public decimal RecommendationDiscountAccruedExVat { get; set; } + public decimal RecommendationDiscountAccruedExVat { get; set; } - public decimal DistributionDiscountAccruedExVat { get; set; } + public decimal DistributionDiscountAccruedExVat { get; set; } - public decimal PromoMix { get; set; } + public decimal PromoMix { get; set; } - public decimal DiscountMix { get; set; } + public decimal DiscountMix { get; set; } - public decimal CashMix { get; set; } + public decimal CashMix { get; set; } - public decimal PromoMixValueExVat { get; set; } + public decimal PromoMixValueExVat { get; set; } - public decimal DiscountMixValueExVat { get; set; } + public decimal DiscountMixValueExVat { get; set; } - public decimal CashMixValueIncVat { get; set; } + public decimal CashMixValueIncVat { get; set; } - public string ContentUrn - { - get { return this.MflowUrn; } - set { this.MflowUrn = value; } - } + public string ContentUrn + { + get { return this.MflowUrn; } + set { this.MflowUrn = value; } + } - public string TrackUrn - { - get; - set; - } + public string TrackUrn + { + get; + set; + } - public string Title - { - get; - set; - } + public string Title + { + get; + set; + } - public string ArtistUrn - { - get; - set; - } + public string ArtistUrn + { + get; + set; + } - public string ArtistName - { - get; - set; - } + public string ArtistName + { + get; + set; + } - public string AlbumUrn - { - get; - set; - } + public string AlbumUrn + { + get; + set; + } - public string AlbumName - { - get; - set; - } + public string AlbumName + { + get; + set; + } - public static string CreateUrn(Guid userId, long orderId, long orderLineId) - { - return string.Format("urn:orderline:{0}/{1}/{2}", - userId.ToString("N"), orderId, orderLineId); - } + public static string CreateUrn(Guid userId, long orderId, long orderLineId) + { + return string.Format("urn:orderline:{0}/{1}/{2}", + userId.ToString("N"), orderId, orderLineId); + } - public static SampleOrderLine Create(Guid userId) - { - return Create(userId, 1, 1); - } + public static SampleOrderLine Create(Guid userId) + { + return Create(userId, 1, 1); + } - public static SampleOrderLine Create(Guid userId, int orderId, int orderLineId) - { - return new SampleOrderLine { - Id = CreateUrn(userId, orderId, orderLineId), - CreatedDate = DateTime.Now, - OrderId = orderId, - OrderLineId = orderLineId, - AlbumName = "AlbumName", - CashMixValueIncVat = 0.79m / 1.15m, - TransactionValueExVat = 0.79m, - ContentUrn = "urn:content:" + Guid.NewGuid().ToString("N"), - }; - } + public static SampleOrderLine Create(Guid userId, int orderId, int orderLineId) + { + return new SampleOrderLine + { + Id = CreateUrn(userId, orderId, orderLineId), + CreatedDate = DateTime.Now, + OrderId = orderId, + OrderLineId = orderLineId, + AlbumName = "AlbumName", + CashMixValueIncVat = 0.79m / 1.15m, + TransactionValueExVat = 0.79m, + ContentUrn = "urn:content:" + Guid.NewGuid().ToString("N"), + }; + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/Shipper.cs b/tests/ServiceStack.Common.Tests/Models/Shipper.cs index 681c479d964..1af895c3ac8 100644 --- a/tests/ServiceStack.Common.Tests/Models/Shipper.cs +++ b/tests/ServiceStack.Common.Tests/Models/Shipper.cs @@ -1,36 +1,36 @@ using System; -using ServiceStack.DesignPatterns.Model; +using ServiceStack.Model; namespace ServiceStack.Common.Tests.Models { - public class Shipper - : IHasIntId - { - public int Id { get; set; } - public string CompanyName { get; set; } - public ShipperType ShipperType { get; set; } - public DateTime DateCreated { get; set; } - public Guid UniqueRef { get; set; } + public class Shipper + : IHasIntId + { + public int Id { get; set; } + public string CompanyName { get; set; } + public ShipperType ShipperType { get; set; } + public DateTime DateCreated { get; set; } + public Guid UniqueRef { get; set; } - public override bool Equals(object obj) - { - var other = obj as Shipper; - if (other == null) return false; - return this.Id == other.Id && this.UniqueRef == other.UniqueRef; - } + public override bool Equals(object obj) + { + var other = obj as Shipper; + if (other == null) return false; + return this.Id == other.Id && this.UniqueRef == other.UniqueRef; + } - public override int GetHashCode() - { - return string.Concat(Id, UniqueRef).GetHashCode(); - } - } + public override int GetHashCode() + { + return string.Concat(Id, UniqueRef).GetHashCode(); + } + } - public enum ShipperType - { - All = Planes | Trains | Automobiles, - Unknown = 0, - Planes = 1, - Trains = 2, - Automobiles = 4 - } + public enum ShipperType + { + All = Planes | Trains | Automobiles, + Unknown = 0, + Planes = 1, + Trains = 2, + Automobiles = 4 + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/ShipperFactory.cs b/tests/ServiceStack.Common.Tests/Models/ShipperFactory.cs index 0387177c4ae..713784e8abe 100644 --- a/tests/ServiceStack.Common.Tests/Models/ShipperFactory.cs +++ b/tests/ServiceStack.Common.Tests/Models/ShipperFactory.cs @@ -3,28 +3,29 @@ namespace ServiceStack.Common.Tests.Models { - public class ShipperFactory - : ModelFactoryBase - { - public override Shipper CreateInstance(int i) - { - var hex = ((i % 240) + 16).ToString("X"); - return new Shipper { - Id = i, - CompanyName = "Shipper" + i, + public class ShipperFactory + : ModelFactoryBase + { + public override Shipper CreateInstance(int i) + { + var hex = ((i % 240) + 16).ToString("X"); + return new Shipper + { + Id = i, + CompanyName = "Shipper" + i, DateCreated = new DateTime(i + 1 % 3000, (i % 11) + 1, (i % 27) + 1, 0, 0, 0, DateTimeKind.Utc), - ShipperType = (ShipperType)(i % 3), - UniqueRef = new Guid(hex + "D148A5-E5F1-4E5A-8C60-52E5A80ACCC6"), - }; - } + ShipperType = (ShipperType)(i % 3), + UniqueRef = new Guid(hex + "D148A5-E5F1-4E5A-8C60-52E5A80ACCC6"), + }; + } - public override void AssertIsEqual(Shipper actual, Shipper expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.CompanyName, Is.EqualTo(expected.CompanyName)); - Assert.That(actual.ShipperType, Is.EqualTo(expected.ShipperType)); - Assert.That(actual.DateCreated, Is.EqualTo(expected.DateCreated)); - Assert.That(actual.UniqueRef, Is.EqualTo(expected.UniqueRef)); - } - } + public override void AssertIsEqual(Shipper actual, Shipper expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.CompanyName, Is.EqualTo(expected.CompanyName)); + Assert.That(actual.ShipperType, Is.EqualTo(expected.ShipperType)); + Assert.That(actual.DateCreated, Is.EqualTo(expected.DateCreated)); + Assert.That(actual.UniqueRef, Is.EqualTo(expected.UniqueRef)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Models/TaskQueue.cs b/tests/ServiceStack.Common.Tests/Models/TaskQueue.cs index 26a2539a8e3..355e15ec500 100644 --- a/tests/ServiceStack.Common.Tests/Models/TaskQueue.cs +++ b/tests/ServiceStack.Common.Tests/Models/TaskQueue.cs @@ -1,75 +1,76 @@ using System; using NUnit.Framework; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; using ServiceStack.Logging; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Models { - public class TaskQueue - { - private static readonly ILog Log = LogManager.GetLogger(typeof(TaskQueue)); - - public const string TaskLoad = "Load"; - public const string TaskIndex = "Index"; - - public const string StatusPending = "Pending"; - public const string StatusStarted = "Started"; - public const string StatusCompleted = "Completed"; - public const string StatusFailed = "Failed"; - - public const int PriorityLow = 0; - public const int PriorityMedium = 1; - public const int PriorityHigh = 2; - - public int Id { get; set; } - - public Guid? UserId { get; set; } - - public string Task { get; set; } - - public string ContentUrn { get; set; } - - public string Status { get; set; } - - public DateTime CreatedDate { get; set; } - - public int Priority { get; set; } - - public int NoOfAttempts { get; set; } - - public string ErrorMessage { get; set; } - - public static TaskQueue Create(int id) - { - return new TaskQueue { - ContentUrn = "urn:track:" + id, - CreatedDate = DateTime.Now, - Task = TaskLoad, - Status = StatusPending, - NoOfAttempts = 0, - }; - } - - public static void AssertIsEqual(TaskQueue actual, TaskQueue expected) - { - Assert.That(actual.Id, Is.EqualTo(expected.Id)); - Assert.That(actual.UserId, Is.EqualTo(expected.UserId)); - Assert.That(actual.ContentUrn, Is.EqualTo(expected.ContentUrn)); - Assert.That(actual.Status, Is.EqualTo(expected.Status)); - try - { - Assert.That(actual.CreatedDate, Is.EqualTo(expected.CreatedDate)); - } - catch (Exception ex) - { - Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); - Assert.That(actual.CreatedDate.RoundToSecond(), Is.EqualTo(expected.CreatedDate.RoundToSecond())); - } - Assert.That(actual.Priority, Is.EqualTo(expected.Priority)); - Assert.That(actual.NoOfAttempts, Is.EqualTo(expected.NoOfAttempts)); - Assert.That(actual.ErrorMessage, Is.EqualTo(expected.ErrorMessage)); - } - - } + public class TaskQueue + { + private static readonly ILog Log = LogManager.GetLogger(typeof(TaskQueue)); + + public const string TaskLoad = "Load"; + public const string TaskIndex = "Index"; + + public const string StatusPending = "Pending"; + public const string StatusStarted = "Started"; + public const string StatusCompleted = "Completed"; + public const string StatusFailed = "Failed"; + + public const int PriorityLow = 0; + public const int PriorityMedium = 1; + public const int PriorityHigh = 2; + + public int Id { get; set; } + + public Guid? UserId { get; set; } + + public string Task { get; set; } + + public string ContentUrn { get; set; } + + public string Status { get; set; } + + public DateTime CreatedDate { get; set; } + + public int Priority { get; set; } + + public int NoOfAttempts { get; set; } + + public string ErrorMessage { get; set; } + + public static TaskQueue Create(int id) + { + return new TaskQueue + { + ContentUrn = "urn:track:" + id, + CreatedDate = DateTime.Now, + Task = TaskLoad, + Status = StatusPending, + NoOfAttempts = 0, + }; + } + + public static void AssertIsEqual(TaskQueue actual, TaskQueue expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.UserId, Is.EqualTo(expected.UserId)); + Assert.That(actual.ContentUrn, Is.EqualTo(expected.ContentUrn)); + Assert.That(actual.Status, Is.EqualTo(expected.Status)); + try + { + Assert.That(actual.CreatedDate, Is.EqualTo(expected.CreatedDate)); + } + catch (Exception ex) + { + Log.Error("Trouble with DateTime precisions, trying Assert again with rounding to seconds", ex); + Assert.That(actual.CreatedDate.RoundToSecond(), Is.EqualTo(expected.CreatedDate.RoundToSecond())); + } + Assert.That(actual.Priority, Is.EqualTo(expected.Priority)); + Assert.That(actual.NoOfAttempts, Is.EqualTo(expected.NoOfAttempts)); + Assert.That(actual.ErrorMessage, Is.EqualTo(expected.ErrorMessage)); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/NativeTypesTests.cs b/tests/ServiceStack.Common.Tests/NativeTypesTests.cs new file mode 100644 index 00000000000..9c32dac3324 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/NativeTypesTests.cs @@ -0,0 +1,464 @@ +#if !NETCORE +using System; +using System.Linq; +using System.Reflection; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.NativeTypes.CSharp; +using ServiceStack.NativeTypes.Java; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + using System.Collections.Generic; + using NativeTypes; + using Testing; + + [TestFixture] + public class NativeTypesTests + { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = + new BasicAppHost(typeof(Dto).Assembly) + { + TestMode = true, + Plugins = { new NativeTypesFeature() }, + Config = new HostConfig() + }.Init(); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void GetIncludeList_Returns_IncludeList_If_NoIncludeTypes_HaveWildcard() + { + var includeTypes = new List { "Dto1", "DTO2" }; + var config = new MetadataTypesConfig + { + IncludeTypes = includeTypes + }; + + var result = MetadataExtensions.GetIncludeList(new MetadataTypes(), config); + Assert.AreEqual(includeTypes, result); + } + + [Test] + public void IncludeTypes_DoesNotReturnReferenceTypes_If_IncludeTypes_NoWildcard_Csharp() + { + var result = appHost.ExecuteService(new TypesCSharp + { + IncludeTypes = new List { "Dto" } + }); + + var stringResult = result.ToString(); + + // StringAssert.DoesNotContain("class DtoResponse", stringResult); + // StringAssert.DoesNotContain("EmbeddedRequest", stringResult); + StringAssert.DoesNotContain("class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_ReturnsReferenceTypes_If_IncludeTypes_HasWildcard_Csharp() + { + var result = appHost.ExecuteService(new TypesCSharp + { + IncludeTypes = new List { "Dto.*" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoResponse", stringResult); + StringAssert.Contains("class EmbeddedRequest", stringResult); + StringAssert.Contains("class EmbeddedResponse", stringResult); + } + + [Test] + public void AnnotatedDtoTypes_ApiMemberNonDefaultProperties_AreSorted() + { + var result = appHost.ExecuteService(new TypesCSharp + { + IncludeTypes = new List { "DtoResponse" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoResponse", stringResult); + StringAssert.Contains("[ApiMember(Description=\"ShouldBeFirstInGeneratedCode\", IsRequired=true, Name=\"ShouldBeLastInGeneratedCode\")]", stringResult); + } + + [Test] + public void IncludeTypes_DoesNotReturnReferenceTypes_If_IncludeTypes_NoWildcard_Fsharp() + { + var result = appHost.ExecuteService(new TypesFSharp + { + IncludeTypes = new List { "Dto" } + }); + + var stringResult = result.ToString(); + + // StringAssert.DoesNotContain("type DtoResponse", stringResult); + // StringAssert.DoesNotContain("EmbeddedRequest", stringResult); + StringAssert.DoesNotContain("type EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_ReturnsReferenceTypes_If_IncludeTypes_HasWildcard_Fsharp() + { + var result = appHost.ExecuteService(new TypesFSharp + { + IncludeTypes = new List { "Dto.*" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("type DtoResponse", stringResult); + StringAssert.Contains("type EmbeddedRequest", stringResult); + StringAssert.Contains("type EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_DoesNotReturnReferenceTypes_If_IncludeTypes_NoWildcard_VbNet() + { + var result = appHost.ExecuteService(new TypesVbNet() + { + IncludeTypes = new List { "Dto" } + }); + + var stringResult = result.ToString(); + + // StringAssert.DoesNotContain("Class DtoResponse", stringResult); + // StringAssert.DoesNotContain("EmbeddedRequest", stringResult); + StringAssert.DoesNotContain("Class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_ReturnsReferenceTypes_If_IncludeTypes_HasWildcard_VbNet() + { + var result = appHost.ExecuteService(new TypesVbNet + { + IncludeTypes = new List { "Dto.*" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("Class DtoResponse", stringResult); + StringAssert.Contains("Class EmbeddedRequest", stringResult); + StringAssert.Contains("Class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_DoesNotReturnReferenceTypes_If_IncludeTypes_NoWildcard_Kotlin() + { + var result = appHost.ExecuteService(new TypesKotlin + { + IncludeTypes = new List { "Dto" } + }); + + var stringResult = result.ToString(); + + // StringAssert.DoesNotContain("class DtoResponse", stringResult); + // StringAssert.DoesNotContain("EmbeddedRequest", stringResult); + StringAssert.DoesNotContain("class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_ReturnsReferenceTypes_If_IncludeTypes_HasWildcard_Kotlin() + { + var result = appHost.ExecuteService(new TypesKotlin + { + IncludeTypes = new List { "Dto.*" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoResponse", stringResult); + StringAssert.Contains("class EmbeddedRequest", stringResult); + StringAssert.Contains("class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_DoesNotReturnReferenceTypes_If_IncludeTypes_NoWildcard_Java() + { + var result = appHost.ExecuteService(new TypesJava + { + IncludeTypes = new List { "Dto" } + }); + + var stringResult = result.ToString(); + + // StringAssert.DoesNotContain("class DtoResponse", stringResult); + // StringAssert.DoesNotContain("EmbeddedRequest", stringResult); + StringAssert.DoesNotContain("class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_ReturnsReferenceTypes_If_IncludeTypes_HasWildcard_Java() + { + var result = appHost.ExecuteService(new TypesJava + { + IncludeTypes = new List { "Dto.*" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoResponse", stringResult); + StringAssert.Contains("class EmbeddedRequest", stringResult); + StringAssert.Contains("class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_DoesNotReturnReferenceTypes_If_IncludeTypes_NoWildcard_Swift() + { + var result = appHost.ExecuteService(new TypesSwift + { + IncludeTypes = new List { "Dto" } + }); + + var stringResult = result.ToString(); + + // StringAssert.DoesNotContain("class DtoResponse", stringResult); + // StringAssert.DoesNotContain("EmbeddedRequest", stringResult); + StringAssert.DoesNotContain("class EmbeddedResponse", stringResult); + } + + [Test] + public void IncludeTypes_ReturnsReferenceTypes_If_IncludeTypes_HasWildcard_Swift() + { + var result = appHost.ExecuteService(new TypesSwift + { + IncludeTypes = new List { "Dto.*" } + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoResponse", stringResult); + StringAssert.Contains("class EmbeddedRequest", stringResult); + StringAssert.Contains("class EmbeddedResponse", stringResult); + } + + [Test] + public void GetIncludeList_Returns_IncludeList_when_Returning_generic_List() + { + var includeTypes = new List { "GetRequest1", "ReturnedDto" }; + var config = new MetadataTypesConfig + { + IncludeTypes = includeTypes + }; + + var result = MetadataExtensions.GetIncludeList(new MetadataTypes(), config); + result.PrintDump(); + + Assert.AreEqual(includeTypes, result); + } + + [Test] + public void Custom_ValueTypes_defaults_to_use_opaque_strings_csharp() + { + var result = appHost.ExecuteService(new TypesCSharp + { + IncludeTypes = new List { "DtoRequestWithStructProperty" }, + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoRequestWithStructProperty", stringResult); + StringAssert.Contains("public virtual string StructType { get; set; }", stringResult); + StringAssert.Contains("public virtual string NullableStructType { get; set; }", stringResult); + } + + [Test] + public void Custom_ValueTypes_can_be_exported_csharp() + { + var result = appHost.ExecuteService(new TypesCSharp + { + IncludeTypes = new List { "DtoRequestWithStructProperty" }, + ExportValueTypes = true, + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoRequestWithStructProperty", stringResult); + StringAssert.Contains("public virtual StructType StructType { get; set; }", stringResult); + StringAssert.Contains("public virtual StructType? NullableStructType { get; set; }", stringResult); + } + + [Test] + public void Custom_ValueTypes_can_be_exported_as_different_Type_in_java() + { + JavaGenerator.TypeAliases["StructType"] = "JavaStruct"; + + var result = appHost.ExecuteService(new TypesJava + { + IncludeTypes = new List { "DtoRequestWithStructProperty" }, + ExportValueTypes = true, + }); + + var stringResult = result.ToString(); + + StringAssert.Contains("class DtoRequestWithStructProperty", stringResult); + StringAssert.Contains("public JavaStruct StructType = null;", stringResult); + StringAssert.Contains("public JavaStruct NullableStructType = null;", stringResult); + + string value; + JavaGenerator.TypeAliases.TryRemove("StructType", out value); + } + + public enum ComparisonOperator + { + Equals = 0, + NotEqual = 1, + } + + [Test] + public void Can_access_enum_with_Equals_member() + { + var enumNames = new List(); + var enumValues = new List(); + + var type = typeof(ComparisonOperator); + var names = Enum.GetNames(type); + for (var i = 0; i < names.Length; i++) + { + var name = names[i]; + var enumMember = MetadataTypesGenerator.GetEnumMember(type, name); + var value = enumMember.GetRawConstantValue(); + var enumValue = Convert.ToInt64(value).ToString(); + + enumNames.Add(name); + enumValues.Add(enumValue); + } + + Assert.That(enumNames, Is.EquivalentTo(new[]{ "Equals", "NotEqual" })); + Assert.That(enumValues, Is.EquivalentTo(new[]{ "0", "1" })); + } + + [Test] + public void Can_write_ValidateRequestAttribute() + { + var nativeTypes = appHost.AssertPlugin(); + var gen = nativeTypes.DefaultGenerator; + var attr = new ValidateRequestAttribute("HasRole('Accounts')") { + ErrorCode = "ExCode", + Message = "'Id' Is Required", + }; + var metaAttr = gen.ToAttribute(attr); + string argValue(string name) => metaAttr.Args.First(x => x.Name == name).Value; + Assert.That(metaAttr.Name, Is.EqualTo("ValidateRequest")); + Assert.That(metaAttr.Args.Count, Is.EqualTo(3)); + Assert.That(argValue(nameof(ValidateRequestAttribute.Validator)), Is.EqualTo("HasRole('Accounts')")); + Assert.That(argValue(nameof(ValidateRequestAttribute.ErrorCode)), Is.EqualTo("ExCode")); + Assert.That(argValue(nameof(ValidateRequestAttribute.Message)), Is.EqualTo("'Id' Is Required")); + + var csharp = new CSharpGenerator(new MetadataTypesConfig { + DefaultNamespaces = new List { + "ServiceStack" + } + }); + var src = csharp.GetCode(new MetadataTypes { + Types = new List { + new MetadataType { + Name = "TheType", + Attributes = new List { + metaAttr, + } + } + } + }, new BasicRequest(), appHost.TryResolve()); + + src.Print(); + + Assert.That(src, Does.Contain( + "[ValidateRequest(\"HasRole('Accounts')\", ErrorCode=\"ExCode\", Message=\"'Id' Is Required\")]")); + } + + [Test] + public void Can_generate_Swift_PocoLookupMap() + { + var typeName = "Dictionary`2"; + var genericArgs = new[] { "String", "List>" }; + + var gen = new ServiceStack.NativeTypes.Swift.SwiftGenerator(new MetadataTypesConfig()); + var type = gen.Type(typeName, genericArgs); + + Assert.That(type, Is.EqualTo("[String:[[String:Poco]]]")); + } + + [Test] + public void Does_generate_Swift_IntArray() + { + var genericArgs = new string[] { }; + + var gen = new ServiceStack.NativeTypes.Swift.SwiftGenerator(new MetadataTypesConfig()); + Assert.That(gen.Type("Int32[]", genericArgs), Is.EqualTo("[Int]")); + Assert.That(gen.Type("Int64[]", genericArgs), Is.EqualTo("[Int]")); + } + + [Test] + public void Does_generate_Swift_IntList() + { + var gen = new ServiceStack.NativeTypes.Swift.SwiftGenerator(new MetadataTypesConfig()); + Assert.That(gen.Type("List`1", new[] { "Int32" }), Is.EqualTo("[Int]")); + Assert.That(gen.Type("List`1", new[] { "Int64" }), Is.EqualTo("[Int]")); + } + + } + + public class NativeTypesTestService : Service + { + public object Any(Dto request) => request; + + public object Any(DtoRequestWithStructProperty request) => request; + } + + public class Dto : IReturn + { + public EmbeddedResponse ReferencedType { get; set; } + } + + public class DtoResponse + { + [ApiMember(Name = "ShouldBeLastInGeneratedCode", Description = "ShouldBeFirstInGeneratedCode", IsRequired = true)] + public EmbeddedRequest ReferencedType { get; set; } + } + + public class EmbeddedResponse { } + public class EmbeddedRequest { } + + + [Route("/Request1/", "GET")] + public partial class GetRequest1 : IReturn>, IGet { } + + [Route("/Request3", "GET")] + public partial class GetRequest2 : IReturn, IGet {} + + public partial class ReturnedDto + { + public virtual int Id { get; set; } + } + + public class ReturnGenericListServices : Service + { + public object Any(GetRequest1 request) => request; + public object Any(GetRequest2 request) => request; + } + + public class DtoRequestWithStructProperty : IReturn + { + public StructType StructType { get; set; } + public StructType? NullableStructType { get; set; } + } + + public struct StructType + { + public int Id; + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/NetCoreTestsRunner.cs b/tests/ServiceStack.Common.Tests/NetCoreTestsRunner.cs new file mode 100644 index 00000000000..3fd2c6bac48 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/NetCoreTestsRunner.cs @@ -0,0 +1,38 @@ +#if NUNITLITE +using NUnitLite; +using NUnit.Common; +using System.Reflection; +using ServiceStack; +using ServiceStack.Text; +using System; +using System.Globalization; +using System.Threading; + +namespace NUnitLite.Tests +{ + public class NetCoreTestsRunner + { + /// + /// The main program executes the tests. Output may be routed to + /// various locations, depending on the arguments passed. + /// + /// Run with --help for a full list of arguments supported + /// + public static int Main(string[] args) + { + var licenseKey = Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE"); + if (licenseKey.IsNullOrEmpty()) + throw new ArgumentNullException("SERVICESTACK_LICENSE", "Add Environment variable for SERVICESTACK_LICENSE"); + + Licensing.RegisterLicense(licenseKey); + //"ActivatedLicenseFeatures: ".Print(LicenseUtils.ActivatedLicenseFeatures()); + + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); + JsConfig.InitStatics(); + //JsonServiceClient client = new JsonServiceClient(); + var writer = new ExtendedTextWrapper(Console.Out); + return new AutoRun(((IReflectableType)typeof(NetCoreTestsRunner)).GetTypeInfo().Assembly).Execute(args, writer, Console.In); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/AuthUserSessionTests.cs b/tests/ServiceStack.Common.Tests/OAuth/AuthUserSessionTests.cs new file mode 100644 index 00000000000..7aa4a15baa5 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/OAuth/AuthUserSessionTests.cs @@ -0,0 +1,475 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Aws.DynamoDb; +using ServiceStack.Configuration; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.Common.Tests.OAuth +{ + public class InMemoryAuthUserSessionTests : AuthUserSessionTests + { + public override IUserAuthRepository CreateAuthRepo() + { + var inMemoryRepo = new InMemoryAuthRepository(); + inMemoryRepo.Clear(); + InitTest(inMemoryRepo); + return inMemoryRepo; + } + } + + public class RedisAuthUserSessionTests : AuthUserSessionTests + { + public override IUserAuthRepository CreateAuthRepo() + { + var appSettings = new AppSettings(); + var redisRepo = new RedisAuthRepository( + new BasicRedisClientManager(appSettings.GetString("Redis.Host") ?? "localhost")); + redisRepo.Clear(); + InitTest(redisRepo); + return redisRepo; + } + } + + [Ignore("Integration Test")] + public class DynamoDbAuthUserSessionTests : AuthUserSessionTests + { + public override IUserAuthRepository CreateAuthRepo() + { + var db = new PocoDynamo(TestsConfig.CreateDynamoDBClient()); + db.DeleteAllTables(); + var dynamoDbRepo = new DynamoDbAuthRepository(db); + dynamoDbRepo.Clear(); + InitTest(dynamoDbRepo); + dynamoDbRepo.InitSchema(); + return dynamoDbRepo; + } + } + + public class OrmLiteSqlServerAuthUserSessionTests : AuthUserSessionTests + { + public override IUserAuthRepository CreateAuthRepo() + { + var sqlServerFactory = new OrmLiteConnectionFactory( + TestsConfig.SqlServerConnString, + SqlServerDialect.Provider); + var sqlServerRepo = new OrmLiteAuthRepository(sqlServerFactory); + try { sqlServerRepo.Clear(); } catch {} + sqlServerRepo.InitSchema(); + InitTest(sqlServerRepo); + return sqlServerRepo; + } + } + + public class OrmLiteSqliteMemoryAuthUserSessionTests : AuthUserSessionTests + { + public override IUserAuthRepository CreateAuthRepo() + { + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + var sqliteRepo = new OrmLiteAuthRepository(dbFactory); + sqliteRepo.InitSchema(); + InitTest(sqliteRepo); + return sqliteRepo; + } + } + + [TestFixture] + public abstract class AuthUserSessionTests : AuthUserSessionTestsBase + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + RegisterService.AllowUpdates = true; + appHost = new BasicAppHost { + ConfigureAppHost = host => { + host.Plugins.Add(new AuthFeature(new CredentialsAuthProvider(host.AppSettings))); + } + }.Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + RegisterService.AllowUpdates = false; + appHost.Dispose(); + } + + public abstract IUserAuthRepository CreateAuthRepo(); + + public IUserAuthRepository InitAuthRepo() + { + var authRepo = CreateAuthRepo(); + appHost.Container.Register(authRepo); + return authRepo; + } + + [Test] + public async Task Does_persist_TwitterOAuth() + { + var userAuthRepository = InitAuthRepo(); + + MockAuthHttpGateway.Tokens = twitterGatewayTokens; + + var authInfo = new Dictionary { + {"user_id", "133371690876022785"}, + {"screen_name", "demisbellot"}, + }; + + var oAuthUserSession = requestContext.ReloadSession(); + + var twitterAuth = GetTwitterAuthProvider(); + await twitterAuth.OnAuthenticatedAsync(service, oAuthUserSession, twitterAuthTokens, authInfo); + + oAuthUserSession = requestContext.ReloadSession(); + + Assert.That(oAuthUserSession.UserAuthId, Is.Not.Null); + + var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); + Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); + Assert.That(userAuth.DisplayName, Is.EqualTo("Demis Bellot TW")); + + var authProviders = userAuthRepository.GetUserAuthDetails(oAuthUserSession.UserAuthId); + Assert.That(authProviders.Count, Is.EqualTo(1)); + var authProvider = authProviders[0]; + Assert.That(authProvider.UserAuthId, Is.EqualTo(userAuth.Id)); + Assert.That(authProvider.DisplayName, Is.EqualTo("Demis Bellot TW")); + Assert.That(authProvider.FirstName, Is.Null); + Assert.That(authProvider.LastName, Is.Null); + Assert.That(authProvider.RequestToken, Is.EqualTo(twitterAuthTokens.RequestToken)); + Assert.That(authProvider.RequestTokenSecret, Is.EqualTo(twitterAuthTokens.RequestTokenSecret)); + + Console.WriteLine(authProviders.Dump()); + } + + [Test] + public async Task Does_persist_FacebookOAuth() + { + var userAuthRepository = InitAuthRepo(); + + var serviceTokens = MockAuthHttpGateway.Tokens = facebookGatewayTokens; + + var oAuthUserSession = requestContext.ReloadSession(); + var facebookAuth = GetFacebookAuthProvider(); + await facebookAuth.OnAuthenticatedAsync(service, oAuthUserSession, facebookAuthTokens, + JsonObject.Parse(facebookAuth.AuthHttpGateway.DownloadFacebookUserInfo("facebookCode"))); + + oAuthUserSession = requestContext.ReloadSession(); + + Assert.That(oAuthUserSession.FacebookUserId, Is.EqualTo(serviceTokens.UserId)); + + Assert.That(oAuthUserSession.UserAuthId, Is.Not.Null); + + var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); + Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); + Assert.That(userAuth.DisplayName, Is.EqualTo(serviceTokens.DisplayName)); + Assert.That(userAuth.FirstName, Is.EqualTo(serviceTokens.FirstName)); + Assert.That(userAuth.LastName, Is.EqualTo(serviceTokens.LastName)); + Assert.That(userAuth.PrimaryEmail, Is.EqualTo(serviceTokens.Email)); + + var authProviders = userAuthRepository.GetUserAuthDetails(oAuthUserSession.UserAuthId); + Assert.That(authProviders.Count, Is.EqualTo(1)); + var authProvider = authProviders[0]; + Assert.That(authProvider.UserAuthId, Is.EqualTo(userAuth.Id)); + Assert.That(authProvider.DisplayName, Is.EqualTo(serviceTokens.DisplayName)); + Assert.That(authProvider.FirstName, Is.EqualTo(serviceTokens.FirstName)); + Assert.That(authProvider.LastName, Is.EqualTo(serviceTokens.LastName)); + Assert.That(authProvider.Email, Is.EqualTo(serviceTokens.Email)); + Assert.That(authProvider.RequestToken, Is.Null); + Assert.That(authProvider.RequestTokenSecret, Is.Null); + Assert.That(authProvider.AccessToken, Is.Null); + Assert.That(authProvider.AccessTokenSecret, Is.EqualTo(facebookAuthTokens.AccessTokenSecret)); + + Console.WriteLine(authProviders.Dump()); + } + + [Test] + public async Task Does_merge_FacebookOAuth_TwitterOAuth() + { + var userAuthRepository = InitAuthRepo(); + + var serviceTokensFb = MockAuthHttpGateway.Tokens = facebookGatewayTokens; + + var oAuthUserSession = requestContext.ReloadSession(); + var facebookAuth = GetFacebookAuthProvider(); + await facebookAuth.OnAuthenticatedAsync(service, oAuthUserSession, facebookAuthTokens, + JsonObject.Parse(facebookAuth.AuthHttpGateway.DownloadFacebookUserInfo("facebookCode"))); + + oAuthUserSession = requestContext.ReloadSession(); + + var serviceTokensTw = MockAuthHttpGateway.Tokens = twitterGatewayTokens; + var authInfo = new Dictionary { + {"user_id", "17575623"}, + {"screen_name", "demisbellot"}, + }; + var twitterAuth = GetTwitterAuthProvider(); + await twitterAuth.OnAuthenticatedAsync(service, oAuthUserSession, twitterAuthTokens, authInfo); + + oAuthUserSession = requestContext.ReloadSession(); + + Assert.That(oAuthUserSession.TwitterUserId, Is.EqualTo(authInfo["user_id"])); + Assert.That(oAuthUserSession.TwitterScreenName, Is.EqualTo(authInfo["screen_name"])); + + var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); + Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); + Assert.That(userAuth.DisplayName, Is.EqualTo(serviceTokensFb.DisplayName)); + Assert.That(userAuth.PrimaryEmail, Is.EqualTo(serviceTokensFb.Email)); + Assert.That(userAuth.FirstName, Is.EqualTo(serviceTokensFb.FirstName)); + Assert.That(userAuth.LastName, Is.EqualTo(serviceTokensFb.LastName)); + + var authProviders = userAuthRepository.GetUserAuthDetails(oAuthUserSession.UserAuthId); + Assert.That(authProviders.Count, Is.EqualTo(2)); + + Console.WriteLine(userAuth.Dump()); + Console.WriteLine(authProviders.Dump()); + } + + [Test] + public async Task Can_login_with_user_created_CreateUserAuth() + { + var userAuthRepository = InitAuthRepo(); + + var registrationService = GetRegistrationService(userAuthRepository); + + var responseObj = await registrationService.PostAsync(RegisterDto); + + if (responseObj is IHttpResult httpResult) + { + Assert.Fail("HttpResult found: " + httpResult.Dump()); + } + + var response = (RegisterResponse)responseObj; + Assert.That(response.UserId, Is.Not.Null); + + var userAuth = userAuthRepository.GetUserAuth(response.UserId); + AssertEqual(userAuth, RegisterDto); + + userAuth = userAuthRepository.GetUserAuthByUserName(RegisterDto.UserName); + AssertEqual(userAuth, RegisterDto); + + var success = userAuthRepository.TryAuthenticate(RegisterDto.UserName, RegisterDto.Password, out var userId); + Assert.That(success, Is.True); + Assert.That(userId, Is.Not.Null); + + //DynamoDb can't support both UserName and Email + if (!(userAuthRepository is DynamoDbAuthRepository)) + { + userAuth = userAuthRepository.GetUserAuthByUserName(RegisterDto.Email); + AssertEqual(userAuth, RegisterDto); + + success = userAuthRepository.TryAuthenticate(RegisterDto.Email, RegisterDto.Password, out userId); + Assert.That(success, Is.True); + Assert.That(userId, Is.Not.Null); + } + + success = userAuthRepository.TryAuthenticate(RegisterDto.UserName, "Bad Password", out userId); + Assert.That(success, Is.False); + Assert.That(userId, Is.Null); + } + + + [Test] + public async Task Can_login_with_user_created_CreateUserAuth_Email() + { + var userAuthRepository = InitAuthRepo(); + + //Clear Username so only Email is registered + RegisterDto.UserName = null; + + var registrationService = GetRegistrationService(userAuthRepository); + + var responseObj = await registrationService.PostAsync(RegisterDto); + + if (responseObj is IHttpResult httpResult) + { + Assert.Fail("HttpResult found: " + httpResult.Dump()); + } + + var response = (RegisterResponse)responseObj; + Assert.That(response.UserId, Is.Not.Null); + + var userAuth = userAuthRepository.GetUserAuth(response.UserId); + AssertEqual(userAuth, RegisterDto); + + userAuth = userAuthRepository.GetUserAuthByUserName(RegisterDto.Email); + AssertEqual(userAuth, RegisterDto); + + var success = userAuthRepository.TryAuthenticate(RegisterDto.Email, RegisterDto.Password, out var userId); + Assert.That(success, Is.True); + Assert.That(userId, Is.Not.Null); + + success = userAuthRepository.TryAuthenticate(RegisterDto.Email, "Bad Password", out userId); + Assert.That(success, Is.False); + Assert.That(userId, Is.Null); + } + + [Test] + public async Task Logging_in_pulls_all_AuthInfo_from_repo_after_logging_in_all_AuthProviders() + { + var userAuthRepository = InitAuthRepo(); + + var oAuthUserSession = requestContext.ReloadSession(); + + //Facebook + LoginWithFacebook(oAuthUserSession); + + //Twitter + MockAuthHttpGateway.Tokens = twitterGatewayTokens; + var authInfo = new Dictionary { + {"user_id", "17575623"}, + {"screen_name", "demisbellot"}, + }; + var twitterAuth = GetTwitterAuthProvider(); + await twitterAuth.OnAuthenticatedAsync(service, oAuthUserSession, twitterAuthTokens, authInfo); + Console.WriteLine("UserId: " + oAuthUserSession.UserAuthId); + + //Register + var registrationService = GetRegistrationService(userAuthRepository, oAuthUserSession, requestContext); + + var responseObj = await registrationService.PostAsync(RegisterDto); + Assert.That(responseObj as IHttpError, Is.Null, responseObj.ToString()); + + Console.WriteLine("UserId: " + oAuthUserSession.UserAuthId); + + var credentialsAuth = GetCredentialsAuthConfig(); + var loginResponse = await credentialsAuth.AuthenticateAsync(service, oAuthUserSession, + new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = RegisterDto.UserName, + Password = RegisterDto.Password, + }); + + oAuthUserSession = requestContext.ReloadSession(); + + Assert.That(oAuthUserSession.TwitterUserId, Is.EqualTo(authInfo["user_id"])); + Assert.That(oAuthUserSession.TwitterScreenName, Is.EqualTo(authInfo["screen_name"])); + + var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); + Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); + Assert.That(userAuth.DisplayName, Is.EqualTo(RegisterDto.DisplayName)); + Assert.That(userAuth.FirstName, Is.EqualTo(RegisterDto.FirstName)); + Assert.That(userAuth.LastName, Is.EqualTo(RegisterDto.LastName)); + Assert.That(userAuth.Email, Is.EqualTo(RegisterDto.Email)); + + Console.WriteLine(oAuthUserSession.Dump()); + Assert.That(oAuthUserSession.ProviderOAuthAccess.Count, Is.EqualTo(2)); + Assert.That(oAuthUserSession.IsAuthenticated, Is.True); + + var authProviders = userAuthRepository.GetUserAuthDetails(oAuthUserSession.UserAuthId); + Assert.That(authProviders.Count, Is.EqualTo(2)); + + Console.WriteLine(userAuth.Dump()); + Console.WriteLine(authProviders.Dump()); + } + + [Test] + public void Registering_twice_creates_two_registrations() + { + var userAuthRepository = InitAuthRepo(); + + var oAuthUserSession = requestContext.ReloadSession(); + + RegisterAndLogin(userAuthRepository, oAuthUserSession); + + requestContext.RemoveSession(); + + var userName1 = RegisterDto.UserName; + var userName2 = "UserName2"; + RegisterDto.UserName = userName2; + RegisterDto.Email = "as@if2.com"; + + var userAuth1 = userAuthRepository.GetUserAuthByUserName(userName1); + Assert.That(userAuth1, Is.Not.Null); + + Register(userAuthRepository, null, RegisterDto); + + userAuth1 = userAuthRepository.GetUserAuthByUserName(userName1); + var userAuth2 = userAuthRepository.GetUserAuthByUserName(userName2); + + Assert.That(userAuth1, Is.Not.Null); + Assert.That(userAuth2, Is.Not.Null); + } + + [Test] + public void Registering_twice_in_same_session_updates_registration() + { + var userAuthRepository = InitAuthRepo(); + + var oAuthUserSession = requestContext.ReloadSession(); + + oAuthUserSession = RegisterAndLogin(userAuthRepository, oAuthUserSession); + + var userName1 = RegisterDto.UserName; + var userName2 = "UserName2"; + RegisterDto.UserName = userName2; + + Register(userAuthRepository, oAuthUserSession, RegisterDto); + + var userAuth1 = userAuthRepository.GetUserAuthByUserName(userName1); + var userAuth2 = userAuthRepository.GetUserAuthByUserName(userName2); + + Assert.That(userAuth1, Is.Null); + Assert.That(userAuth2, Is.Not.Null); + } + + [Test] + public void Connecting_to_facebook_whilst_authenticated_connects_account() + { + var userAuthRepository = InitAuthRepo(); + + var oAuthUserSession = requestContext.ReloadSession(); + + oAuthUserSession = RegisterAndLogin(userAuthRepository, oAuthUserSession); + + LoginWithFacebook(oAuthUserSession); + + var userAuth = userAuthRepository.GetUserAuthByUserName(RegisterDto.UserName); + + Assert.That(userAuth.UserName, Is.EqualTo(RegisterDto.UserName)); + + var userAuthProviders = userAuthRepository.GetUserAuthDetails(userAuth.Id.ToString(CultureInfo.InvariantCulture)); + Assert.That(userAuthProviders.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_AutoLogin_whilst_Registering() + { + var userAuthRepository = InitAuthRepo(); + var oAuthUserSession = requestContext.ReloadSession(); + RegisterDto.AutoLogin = true; + Register(userAuthRepository, oAuthUserSession, RegisterDto); + + oAuthUserSession = requestContext.ReloadSession(); + Assert.That(oAuthUserSession.IsAuthenticated, Is.True); + } + + [Test] + public void Can_DeleteUserAuth() + { + var userAuthRepository = InitAuthRepo(); + + var oAuthUserSession = requestContext.ReloadSession(); + oAuthUserSession = RegisterAndLogin(userAuthRepository, oAuthUserSession); + + var userAuth = userAuthRepository.GetUserAuthByUserName(RegisterDto.UserName); + Assert.That(userAuth, Is.Not.Null); + + userAuthRepository.DeleteUserAuth(userAuth.Id.ToString()); + userAuth = userAuthRepository.GetUserAuthByUserName(RegisterDto.UserName); + Assert.That(userAuth, Is.Null); + } + + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/AuthUserSessionTestsBase.cs b/tests/ServiceStack.Common.Tests/OAuth/AuthUserSessionTestsBase.cs new file mode 100644 index 00000000000..fcf132396c9 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/OAuth/AuthUserSessionTestsBase.cs @@ -0,0 +1,234 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.Common.Tests.OAuth +{ + public abstract class AuthUserSessionTestsBase + { + public static bool LoadUserAuthRepositorys = true; + + //Can only use either 1 OrmLiteDialectProvider at 1-time SqlServer or Sqlite. + public static bool UseSqlServer = false; + + public static AuthUserSession GetNewSession2() + { + var oAuthUserSession = new AuthUserSession(); + return oAuthUserSession; + } + + public CredentialsAuthProvider GetCredentialsAuthConfig() + { + return new CredentialsAuthProvider(new AppSettings()); + } + + public TwitterAuthProvider GetTwitterAuthProvider() + { + return new TwitterAuthProvider(new AppSettings()) + { + AuthHttpGateway = new MockAuthHttpGateway(), + }; + } + + public FacebookAuthProvider GetFacebookAuthProvider() + { + return new FacebookAuthProvider(new AppSettings()) + { + AuthHttpGateway = new MockAuthHttpGateway(), + }; + } + + public class MockService : IServiceBase + { + public IAuthRepository AuthRepo { get; set; } + public IRequest Request { get; set; } + + + public T TryResolve() + { + if (typeof(T) == typeof(IAuthRepository)) + return (T)AuthRepo; + + throw new NotImplementedException(); + } + + public IResolver GetResolver() + { + return this; + } + + public T ResolveService() + { + throw new NotImplementedException(); + } + } + + + protected BasicRequest requestContext; + protected IServiceBase service; + + protected AuthTokens facebookGatewayTokens = new AuthTokens + { + UserId = "623501766", + DisplayName = "Demis Bellot FB", + FirstName = "Demis", + LastName = "Bellot", + Email = "demis.bellot@gmail.com", + }; + protected AuthTokens twitterGatewayTokens = new AuthTokens + { + DisplayName = "Demis Bellot TW" + }; + protected AuthTokens facebookAuthTokens = new AuthTokens + { + Provider = FacebookAuthProvider.Name, + AccessTokenSecret = "AAADDDCCCoR848BAMkQIZCRIKnVWZAvcKWqo7Ibvec8ebV9vJrfZAz8qVupdu5EbjFzmMmbwUFDbcNDea9H6rOn5SVn8es7KYZD", + }; + protected AuthTokens twitterAuthTokens = new AuthTokens + { + Provider = TwitterAuthProvider.Name, + RequestToken = "JGGZZ22CCqgB1GR5e0EmGFxzyxGTw2rwEFFcC8a9o7g", + RequestTokenSecret = "qKKCCUUJ2R10bMieVQZZad7iSwWkPYJmtBYzPoM9q0", + UserId = "133371690876022785", + }; + protected Register RegisterDto; + + protected void InitTest(IUserAuthRepository userAuthRepository) + { + try + { + ((IClearable)userAuthRepository).Clear(); + } + catch { /*ignore*/ } + + var appSettings = new DictionarySettings(); + + new AuthFeature(null, new IAuthProvider[] { + new CredentialsAuthProvider(), + new BasicAuthProvider(), + new FacebookAuthProvider(appSettings), + new TwitterAuthProvider(appSettings) + }) + .Register(null); + + requestContext = new BasicRequest + { + Headers = { + {"X-ss-id", SessionExtensions.CreateRandomSessionId() } + } + }; + service = new MockService { + AuthRepo = userAuthRepository, + Request = requestContext + }; + + RegisterDto = new Register + { + UserName = "UserName", + Password = "p@55word", + Email = "as@if.com", + DisplayName = "DisplayName", + FirstName = "FirstName", + LastName = "LastName", + }; + } + + public static RegisterService GetRegistrationService( + IUserAuthRepository userAuthRepository, + AuthUserSession oAuthUserSession = null, + BasicRequest request = null) + { + if (request == null) + request = new BasicRequest(); + if (oAuthUserSession == null) + oAuthUserSession = request.ReloadSession(); + + oAuthUserSession.Id = request.Response.CreateSessionId(request); + request.Items[Keywords.Session] = oAuthUserSession; + + var mockAppHost = new BasicAppHost(); + + mockAppHost.Container.Register(userAuthRepository); + + var authService = new AuthenticateService + { + Request = request, + }; + authService.SetResolver(mockAppHost); + mockAppHost.Register(authService); + + var registrationService = new RegisterService + { + Request = request, + RegistrationValidator = + new RegistrationValidator(), + }; + registrationService.SetResolver(mockAppHost); + + return registrationService; + } + + public static void AssertEqual(IUserAuth userAuth, Register request) + { + Assert.That(userAuth, Is.Not.Null); + Assert.That(userAuth.UserName, Is.EqualTo(request.UserName)); + Assert.That(userAuth.Email, Is.EqualTo(request.Email)); + Assert.That(userAuth.DisplayName, Is.EqualTo(request.DisplayName)); + Assert.That(userAuth.FirstName, Is.EqualTo(request.FirstName)); + Assert.That(userAuth.LastName, Is.EqualTo(request.LastName)); + } + + protected AuthUserSession RegisterAndLogin(IUserAuthRepository userAuthRepository, AuthUserSession oAuthUserSession) + { + Register(userAuthRepository, oAuthUserSession); + + Login(RegisterDto.UserName, RegisterDto.Password, oAuthUserSession); + + oAuthUserSession = requestContext.ReloadSession(); + return oAuthUserSession; + } + + protected object Login(string userName, string password, AuthUserSession oAuthUserSession = null) + { + if (oAuthUserSession == null) + oAuthUserSession = requestContext.ReloadSession(); + + var credentialsAuth = GetCredentialsAuthConfig(); + return credentialsAuth.AuthenticateAsync(service, oAuthUserSession, + new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = RegisterDto.UserName, + Password = RegisterDto.Password, + }).GetResult(); + } + + protected object Register(IUserAuthRepository userAuthRepository, AuthUserSession oAuthUserSession, Register register = null) + { + if (register == null) + register = RegisterDto; + + var registrationService = GetRegistrationService(userAuthRepository, oAuthUserSession, requestContext); + var response = registrationService.Post(register); + Assert.That(response as IHttpError, Is.Null); + return response; + } + + protected void LoginWithFacebook(AuthUserSession oAuthUserSession) + { + MockAuthHttpGateway.Tokens = facebookGatewayTokens; + var facebookAuth = GetFacebookAuthProvider(); + facebookAuth.OnAuthenticatedAsync(service, oAuthUserSession, facebookAuthTokens, + JsonObject.Parse(facebookAuth.AuthHttpGateway.DownloadFacebookUserInfo("facebookCode"))).Wait(); + Console.WriteLine("UserId: " + oAuthUserSession.UserAuthId); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/CredentialsServiceTests.cs b/tests/ServiceStack.Common.Tests/OAuth/CredentialsServiceTests.cs index 295a86b2536..8cc5dc0f4f0 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/CredentialsServiceTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/CredentialsServiceTests.cs @@ -1,83 +1,82 @@ -using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; +#if !NETCORE +using System.Reflection; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Web; namespace ServiceStack.Common.Tests.OAuth { - [TestFixture] - public class CredentialsServiceTests - { - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - AuthService.Init(() => new AuthUserSession(), - new CredentialsAuthProvider()); - } - - public AuthService GetAuthService() - { - var authService = new AuthService { - RequestContext = new MockRequestContext(), - //ServiceExceptionHandler = (req, ex) => - // ValidationFeature.HandleException(new BasicResolver(), req, ex) - }; - return authService; - } - - class ValidateServiceRunner : ServiceRunner + [TestFixture] + public class CredentialsServiceTests + { + public class CredentialsTestAppHost : BasicAppHost { - public ValidateServiceRunner(IAppHost appHost, ActionContext actionContext) - : base(appHost, actionContext) {} + public CredentialsTestAppHost() : base(typeof(CredentialsServiceTests).Assembly) {} + + public override void Configure(Container container) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(), + })); + } - public override object HandleException(IRequestContext requestContext, T request, System.Exception ex) + public override IServiceRunner CreateServiceRunner(ActionContext actionContext) { - return DtoUtils.HandleException(new BasicResolver(), request, ex); + return new ValidateServiceRunner(this, actionContext); } } - public object GetAuthService(AuthService authService, Auth request) + class ValidateServiceRunner : ServiceRunner { - var serviceRunner = new ValidateServiceRunner(null, new ActionContext { - Id = "GET Auth", - ServiceAction = (service, req) => ((AuthService)service).Get((Auth)req) - }); + public ValidateServiceRunner(IAppHost appHost, ActionContext actionContext) + : base(appHost, actionContext) { } - return serviceRunner.Process(authService.RequestContext, authService, request); + public override Task HandleExceptionAsync(IRequest req, T requestDto, System.Exception ex) + { + return DtoUtils.CreateErrorResponse(requestDto, ex).InTask(); + } } - [Test] - public void Empty_request_invalidates_all_fields() + [Test] + public void Empty_request_invalidates_all_fields() { - var authService = GetAuthService(); + using (var appHost = new CredentialsTestAppHost().Init()) + { + var response = (HttpError)appHost.ExecuteService( + new Authenticate { provider = CredentialsAuthProvider.Name }); - var response = (HttpError)GetAuthService(authService, new Auth()); - var errors = response.GetFieldErrors(); + var errors = response.GetFieldErrors(); - Assert.That(errors.Count, Is.EqualTo(2)); - Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[0].FieldName, Is.EqualTo("UserName")); - Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[1].FieldName, Is.EqualTo("Password")); + Assert.That(errors.Count, Is.EqualTo(2)); + Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[0].FieldName, Is.EqualTo("UserName")); + Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[1].FieldName, Is.EqualTo("Password")); + } } - [Test] - public void Requires_UserName_and_Password() - { - var authService = GetAuthService(); - - var response = (HttpError)GetAuthService(authService, - new Auth { provider = AuthService.CredentialsProvider }); + [Test] + public void Requires_UserName_and_Password() + { + using (var appHost = new CredentialsTestAppHost().Init()) + { + var response = (HttpError)appHost.ExecuteService( + new Authenticate { provider = AuthenticateService.CredentialsProvider }); - var errors = response.GetFieldErrors(); + var errors = response.GetFieldErrors(); - Assert.That(errors.Count, Is.EqualTo(2)); - Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[0].FieldName, Is.EqualTo("UserName")); - Assert.That(errors[1].FieldName, Is.EqualTo("Password")); - Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); - } - } -} \ No newline at end of file + Assert.That(errors.Count, Is.EqualTo(2)); + Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[0].FieldName, Is.EqualTo("UserName")); + Assert.That(errors[1].FieldName, Is.EqualTo("Password")); + Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); + } + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/MockAuthHttpGateway.cs b/tests/ServiceStack.Common.Tests/OAuth/MockAuthHttpGateway.cs index 4c7ecb8a360..acc165f30c5 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/MockAuthHttpGateway.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/MockAuthHttpGateway.cs @@ -1,24 +1,28 @@ -using ServiceStack.ServiceInterface.Auth; +#if !NETCORE +using System.Threading; +using System.Threading.Tasks; +using ServiceStack.Auth; using ServiceStack.Text; namespace ServiceStack.Common.Tests.OAuth { - public class MockAuthHttpGateway : IAuthHttpGateway - { - static MockAuthHttpGateway() - { - Tokens = new OAuthTokens { - UserId = "623501766", - DisplayName = "Demis Bellot", - FirstName = "Demis", - LastName = "Bellot", - Email = "demis.bellot@gmail.com", - }; - } - - public static IOAuthTokens Tokens { get; set; } - - static string JsonFacebook = @"{{ + public class MockAuthHttpGateway : IAuthHttpGateway + { + static MockAuthHttpGateway() + { + Tokens = new AuthTokens + { + UserId = "623501766", + DisplayName = "Demis Bellot", + FirstName = "Demis", + LastName = "Bellot", + Email = "demis.bellot@gmail.com", + }; + } + + public static IAuthTokens Tokens { get; set; } + + static string JsonFacebook = @"{{ ""id"": ""{0}"", ""name"": ""{1}"", ""first_name"": ""{2}"", @@ -38,9 +42,9 @@ static MockAuthHttpGateway() ""verified"": true, ""updated_time"": ""2011-10-08T08:43:41+0000"" }}"; - static string JsonTwitter = @"[{{""is_translator"":false,""geo_enabled"":false,""profile_background_color"":""000000"",""protected"":false,""default_profile"":false,""profile_background_tile"":false,""created_at"":""Sun Nov 23 17:42:51 +0000 2008"",""name"":""{0}"",""profile_background_image_url_https"":""https:\/\/si0.twimg.com\/profile_background_images\/192991651\/twitter-bg.jpg"",""profile_sidebar_fill_color"":""2A372F"",""listed_count"":36,""notifications"":null,""utc_offset"":0,""friends_count"":267,""description"":""StackExchangarista, JavaScript, C#, Web & Mobile developer. Creator of the ServiceStack.NET projects. "",""following"":null,""verified"":false,""profile_sidebar_border_color"":""D9D082"",""followers_count"":796,""profile_image_url"":""http:\/\/a2.twimg.com\/profile_images\/1598852740\/avatar_normal.png"",""contributors_enabled"":false,""profile_image_url_https"":""https:\/\/si0.twimg.com\/profile_images\/1598852740\/avatar_normal.png"",""status"":{{""possibly_sensitive"":false,""place"":null,""retweet_count"":37,""in_reply_to_screen_name"":null,""created_at"":""Mon Nov 07 02:34:23 +0000 2011"",""retweeted"":false,""in_reply_to_status_id_str"":null,""in_reply_to_user_id_str"":null,""contributors"":null,""id_str"":""133371690876022785"",""retweeted_status"":{{""possibly_sensitive"":false,""place"":null,""retweet_count"":37,""in_reply_to_screen_name"":null,""created_at"":""Mon Nov 07 02:32:15 +0000 2011"",""retweeted"":false,""in_reply_to_status_id_str"":null,""in_reply_to_user_id_str"":null,""contributors"":null,""id_str"":""133371151551447041"",""in_reply_to_user_id"":null,""in_reply_to_status_id"":null,""source"":""\u003Ca href=\""http:\/\/www.arstechnica.com\"" rel=\""nofollow\""\u003EArs auto-tweeter\u003C\/a\u003E"",""geo"":null,""favorited"":false,""id"":133371151551447041,""coordinates"":null,""truncated"":false,""text"":""Google: Microsoft uses patents when products \""stop succeeding\"": http:\/\/t.co\/50QFc1uJ by @binarybits""}},""in_reply_to_user_id"":null,""in_reply_to_status_id"":null,""source"":""web"",""geo"":null,""favorited"":false,""id"":133371690876022785,""coordinates"":null,""truncated"":false,""text"":""RT @arstechnica: Google: Microsoft uses patents when products \""stop succeeding\"": http:\/\/t.co\/50QFc1uJ by @binarybits""}},""profile_use_background_image"":true,""favourites_count"":238,""location"":""New York"",""id_str"":""17575623"",""default_profile_image"":false,""show_all_inline_media"":false,""profile_text_color"":""ABB8AF"",""screen_name"":""demisbellot"",""statuses_count"":9638,""profile_background_image_url"":""http:\/\/a0.twimg.com\/profile_background_images\/192991651\/twitter-bg.jpg"",""url"":""http:\/\/www.servicestack.net\/mythz_blog\/"",""time_zone"":""London"",""profile_link_color"":""43594A"",""id"":17575623,""follow_request_sent"":null,""lang"":""en""}}]"; + static string JsonTwitter = @"[{{""is_translator"":false,""geo_enabled"":false,""profile_background_color"":""000000"",""protected"":false,""default_profile"":false,""profile_background_tile"":false,""created_at"":""Sun Nov 23 17:42:51 +0000 2008"",""name"":""{0}"",""profile_background_image_url_https"":""https:\/\/si0.twimg.com\/profile_background_images\/192991651\/twitter-bg.jpg"",""profile_sidebar_fill_color"":""2A372F"",""listed_count"":36,""notifications"":null,""utc_offset"":0,""friends_count"":267,""description"":""StackExchangarista, JavaScript, C#, Web & Mobile developer. Creator of the ServiceStack.NET projects. "",""following"":null,""verified"":false,""profile_sidebar_border_color"":""D9D082"",""followers_count"":796,""profile_image_url"":""http:\/\/a2.twimg.com\/profile_images\/1598852740\/avatar_normal.png"",""contributors_enabled"":false,""profile_image_url_https"":""https:\/\/si0.twimg.com\/profile_images\/1598852740\/avatar_normal.png"",""status"":{{""possibly_sensitive"":false,""place"":null,""retweet_count"":37,""in_reply_to_screen_name"":null,""created_at"":""Mon Nov 07 02:34:23 +0000 2011"",""retweeted"":false,""in_reply_to_status_id_str"":null,""in_reply_to_user_id_str"":null,""contributors"":null,""id_str"":""133371690876022785"",""retweeted_status"":{{""possibly_sensitive"":false,""place"":null,""retweet_count"":37,""in_reply_to_screen_name"":null,""created_at"":""Mon Nov 07 02:32:15 +0000 2011"",""retweeted"":false,""in_reply_to_status_id_str"":null,""in_reply_to_user_id_str"":null,""contributors"":null,""id_str"":""133371151551447041"",""in_reply_to_user_id"":null,""in_reply_to_status_id"":null,""source"":""\u003Ca href=\""http:\/\/www.arstechnica.com\"" rel=\""nofollow\""\u003EArs auto-tweeter\u003C\/a\u003E"",""geo"":null,""favorited"":false,""id"":133371151551447041,""coordinates"":null,""truncated"":false,""text"":""Google: Microsoft uses patents when products \""stop succeeding\"": http:\/\/t.co\/50QFc1uJ by @binarybits""}},""in_reply_to_user_id"":null,""in_reply_to_status_id"":null,""source"":""web"",""geo"":null,""favorited"":false,""id"":133371690876022785,""coordinates"":null,""truncated"":false,""text"":""RT @arstechnica: Google: Microsoft uses patents when products \""stop succeeding\"": http:\/\/t.co\/50QFc1uJ by @binarybits""}},""profile_use_background_image"":true,""favourites_count"":238,""location"":""New York"",""id_str"":""17575623"",""default_profile_image"":false,""show_all_inline_media"":false,""profile_text_color"":""ABB8AF"",""screen_name"":""demisbellot"",""statuses_count"":9638,""profile_background_image_url"":""http:\/\/a0.twimg.com\/profile_background_images\/192991651\/twitter-bg.jpg"",""url"":""http:\/\/www.servicestack.net\/mythz_blog\/"",""time_zone"":""London"",""profile_link_color"":""43594A"",""id"":17575623,""follow_request_sent"":null,""lang"":""en""}}]"; - static string JsonYammer = @"{ + static string JsonYammer = @"{ ""job_title"":""Developer"", ""summary"":""I am a developer at XYZ Corp."", ""activated_at"":""2012/12/21 12:21:12 +0000"", @@ -115,27 +119,120 @@ static MockAuthHttpGateway() ""full_name"":""{1}"" }"; - public string DownloadTwitterUserInfo(string twitterUserId) - { - twitterUserId.ThrowIfNullOrEmpty("twitterUserId"); + public Task VerifyTwitterAccessTokenAsync(string consumerKey, string consumerSecret, string accessToken, + string accessTokenSecret, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + public string DownloadTwitterUserInfo(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret, string twitterUserId) + { + twitterUserId.ThrowIfNullOrEmpty("twitterUserId"); + return JsonTwitter.Fmt(Tokens.DisplayName); + } + + public Task DownloadTwitterUserInfoAsync(string consumerKey, string consumerSecret, string accessToken, + string accessTokenSecret, string twitterUserId, CancellationToken token = default) + { + return DownloadTwitterUserInfo(consumerKey, consumerSecret, accessToken, accessTokenSecret, twitterUserId).InTask(); + } + + public Task VerifyFacebookAccessTokenAsync(string appId, string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + public string DownloadFacebookUserInfo(string facebookCode, params string[] fields) + { + facebookCode.ThrowIfNullOrEmpty("facebookCode"); + + return JsonFacebook.Fmt(Tokens.UserId, Tokens.DisplayName, + Tokens.FirstName, Tokens.LastName, Tokens.Email); + } + + public Task DownloadFacebookUserInfoAsync(string facebookCode, string[] fields, CancellationToken token = default) + { + return DownloadFacebookUserInfo(facebookCode, fields).InTask(); + } + + public bool VerifyGoogleAccessToken(string consumerKey, string accessToken) + { + throw new System.NotImplementedException(); + } - return JsonTwitter.Fmt(Tokens.DisplayName); - } + public Task DownloadGithubUserEmailsInfoAsync(string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } - public string DownloadFacebookUserInfo(string facebookCode) - { - facebookCode.ThrowIfNullOrEmpty("facebookCode"); + public string DownloadGoogleUserInfo(string accessToken) + { + throw new System.NotImplementedException(); + } - return JsonFacebook.Fmt(Tokens.UserId, Tokens.DisplayName, - Tokens.FirstName, Tokens.LastName, Tokens.Email); - } + public Task DownloadGoogleUserInfoAsync(string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } - public string DownloadYammerUserInfo(string yammerUserId) - { + public string DownloadMicrosoftUserInfo(string accessToken) + { + throw new System.NotImplementedException(); + } + + public Task DownloadMicrosoftUserInfoAsync(string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + public string CreateMicrosoftPhotoUrl(string accessToken, string savePhotoSize = null) + { + throw new System.NotImplementedException(); + } + + public Task CreateMicrosoftPhotoUrlAsync(string accessToken, string savePhotoSize = null, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + public string DownloadYammerUserInfo(string yammerUserId) + { yammerUserId.ThrowIfNullOrEmpty("yammerUserId"); return JsonYammer.Fmt(Tokens.UserId, Tokens.DisplayName, Tokens.FirstName, Tokens.LastName, Tokens.Email); - } - } -} \ No newline at end of file + } + + public Task DownloadYammerUserInfoAsync(string yammerUserId) + { + return DownloadYammerUserInfo(yammerUserId).InTask(); + } + + public string DownloadGithubUserInfo(string accessToken) + { + throw new System.NotImplementedException(); + } + + public Task DownloadGithubUserInfoAsync(string accessToken, CancellationToken token = default) + { + throw new System.NotImplementedException(); + } + + public string DownloadGithubUserEmailsInfo(string accessToken) + { + throw new System.NotImplementedException(); + } + + public bool VerifyTwitterAccessToken(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret, + out string userId, out string email) + { + throw new System.NotImplementedException(); + } + + public bool VerifyFacebookAccessToken(string appId, string accessToken) + { + throw new System.NotImplementedException(); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTests.cs b/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTests.cs deleted file mode 100644 index 1a1a646f693..00000000000 --- a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTests.cs +++ /dev/null @@ -1,317 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests.OAuth -{ - [TestFixture] - public class OAuthUserSessionTests : OAuthUserSessionTestsBase - { - [Test, TestCaseSource("UserAuthRepositorys")] - public void Does_persist_TwitterOAuth(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - MockAuthHttpGateway.Tokens = twitterGatewayTokens; - - var authInfo = new Dictionary { - {"user_id", "133371690876022785"}, - {"screen_name", "demisbellot"}, - }; - - var oAuthUserSession = requestContext.ReloadSession(); - - var twitterAuth = GetTwitterAuthProvider(); - twitterAuth.OnAuthenticated(service, oAuthUserSession, twitterAuthTokens, authInfo); - - oAuthUserSession = requestContext.ReloadSession(); - - Assert.That(oAuthUserSession.UserAuthId, Is.Not.Null); - - var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); - Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); - Assert.That(userAuth.DisplayName, Is.EqualTo("Demis Bellot TW")); - - var authProviders = userAuthRepository.GetUserOAuthProviders(oAuthUserSession.UserAuthId); - Assert.That(authProviders.Count, Is.EqualTo(1)); - var authProvider = authProviders[0]; - Assert.That(authProvider.UserAuthId, Is.EqualTo(userAuth.Id)); - Assert.That(authProvider.DisplayName, Is.EqualTo("Demis Bellot TW")); - Assert.That(authProvider.FirstName, Is.Null); - Assert.That(authProvider.LastName, Is.Null); - Assert.That(authProvider.RequestToken, Is.EqualTo(twitterAuthTokens.RequestToken)); - Assert.That(authProvider.RequestTokenSecret, Is.EqualTo(twitterAuthTokens.RequestTokenSecret)); - - Console.WriteLine(authProviders.Dump()); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Does_persist_FacebookOAuth(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var serviceTokens = MockAuthHttpGateway.Tokens = facebookGatewayTokens; - - var oAuthUserSession = requestContext.ReloadSession(); - var authInfo = new Dictionary { }; - var facebookAuth = GetFacebookAuthProvider(); - facebookAuth.OnAuthenticated(service, oAuthUserSession, facebookAuthTokens, authInfo); - - oAuthUserSession = requestContext.ReloadSession(); - - Assert.That(oAuthUserSession.FacebookUserId, Is.EqualTo(serviceTokens.UserId)); - - Assert.That(oAuthUserSession.UserAuthId, Is.Not.Null); - - var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); - Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); - Assert.That(userAuth.DisplayName, Is.EqualTo(serviceTokens.DisplayName)); - Assert.That(userAuth.FirstName, Is.EqualTo(serviceTokens.FirstName)); - Assert.That(userAuth.LastName, Is.EqualTo(serviceTokens.LastName)); - Assert.That(userAuth.PrimaryEmail, Is.EqualTo(serviceTokens.Email)); - - var authProviders = userAuthRepository.GetUserOAuthProviders(oAuthUserSession.UserAuthId); - Assert.That(authProviders.Count, Is.EqualTo(1)); - var authProvider = authProviders[0]; - Assert.That(authProvider.UserAuthId, Is.EqualTo(userAuth.Id)); - Assert.That(authProvider.DisplayName, Is.EqualTo(serviceTokens.DisplayName)); - Assert.That(authProvider.FirstName, Is.EqualTo(serviceTokens.FirstName)); - Assert.That(authProvider.LastName, Is.EqualTo(serviceTokens.LastName)); - Assert.That(authProvider.Email, Is.EqualTo(serviceTokens.Email)); - Assert.That(authProvider.RequestToken, Is.Null); - Assert.That(authProvider.RequestTokenSecret, Is.Null); - Assert.That(authProvider.AccessToken, Is.Null); - Assert.That(authProvider.AccessTokenSecret, Is.EqualTo(facebookAuthTokens.AccessTokenSecret)); - - Console.WriteLine(authProviders.Dump()); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Does_merge_FacebookOAuth_TwitterOAuth(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var serviceTokensFb = MockAuthHttpGateway.Tokens = facebookGatewayTokens; - - var oAuthUserSession = requestContext.ReloadSession(); - var facebookAuth = GetFacebookAuthProvider(); - facebookAuth.OnAuthenticated(service, oAuthUserSession, facebookAuthTokens, new Dictionary()); - - oAuthUserSession = requestContext.ReloadSession(); - - var serviceTokensTw = MockAuthHttpGateway.Tokens = twitterGatewayTokens; - var authInfo = new Dictionary { - {"user_id", "133371690876022785"}, - {"screen_name", "demisbellot"}, - }; - var twitterAuth = GetTwitterAuthProvider(); - twitterAuth.OnAuthenticated(service, oAuthUserSession, twitterAuthTokens, authInfo); - - oAuthUserSession = requestContext.ReloadSession(); - - Assert.That(oAuthUserSession.TwitterUserId, Is.EqualTo(authInfo["user_id"])); - Assert.That(oAuthUserSession.TwitterScreenName, Is.EqualTo(authInfo["screen_name"])); - - var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); - Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); - Assert.That(userAuth.DisplayName, Is.EqualTo(serviceTokensFb.DisplayName)); - Assert.That(userAuth.PrimaryEmail, Is.EqualTo(serviceTokensFb.Email)); - Assert.That(userAuth.FirstName, Is.EqualTo(serviceTokensFb.FirstName)); - Assert.That(userAuth.LastName, Is.EqualTo(serviceTokensFb.LastName)); - - var authProviders = userAuthRepository.GetUserOAuthProviders(oAuthUserSession.UserAuthId); - Assert.That(authProviders.Count, Is.EqualTo(2)); - - Console.WriteLine(userAuth.Dump()); - Console.WriteLine(authProviders.Dump()); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Can_login_with_user_created_CreateUserAuth(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var registrationService = GetRegistrationService(userAuthRepository); - - var responseObj = registrationService.Post(registrationDto); - - var httpResult = responseObj as IHttpResult; - if (httpResult != null) - { - Assert.Fail("HttpResult found: " + httpResult.Dump()); - } - - var response = (RegistrationResponse)responseObj; - Assert.That(response.UserId, Is.Not.Null); - - var userAuth = userAuthRepository.GetUserAuth(response.UserId); - AssertEqual(userAuth, registrationDto); - - userAuth = userAuthRepository.GetUserAuthByUserName(registrationDto.UserName); - AssertEqual(userAuth, registrationDto); - - userAuth = userAuthRepository.GetUserAuthByUserName(registrationDto.Email); - AssertEqual(userAuth, registrationDto); - - UserAuth userId; - var success = userAuthRepository.TryAuthenticate(registrationDto.UserName, registrationDto.Password, out userId); - Assert.That(success, Is.True); - Assert.That(userId, Is.Not.Null); - - success = userAuthRepository.TryAuthenticate(registrationDto.Email, registrationDto.Password, out userId); - Assert.That(success, Is.True); - Assert.That(userId, Is.Not.Null); - - success = userAuthRepository.TryAuthenticate(registrationDto.UserName, "Bad Password", out userId); - Assert.That(success, Is.False); - Assert.That(userId, Is.Null); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Logging_in_pulls_all_AuthInfo_from_repo_after_logging_in_all_AuthProviders(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var oAuthUserSession = requestContext.ReloadSession(); - - //Facebook - LoginWithFacebook(oAuthUserSession); - - //Twitter - MockAuthHttpGateway.Tokens = twitterGatewayTokens; - var authInfo = new Dictionary { - {"user_id", "133371690876022785"}, - {"screen_name", "demisbellot"}, - }; - var twitterAuth = GetTwitterAuthProvider(); - twitterAuth.OnAuthenticated(service, oAuthUserSession, twitterAuthTokens, authInfo); - Console.WriteLine("UserId: " + oAuthUserSession.UserAuthId); - - //Register - var registrationService = GetRegistrationService(userAuthRepository, oAuthUserSession, requestContext); - - var responseObj = registrationService.Post(registrationDto); - Assert.That(responseObj as IHttpError, Is.Null, responseObj.ToString()); - - Console.WriteLine("UserId: " + oAuthUserSession.UserAuthId); - - var credentialsAuth = GetCredentialsAuthConfig(); - var loginResponse = credentialsAuth.Authenticate(service, oAuthUserSession, - new Auth - { - provider = CredentialsAuthProvider.Name, - UserName = registrationDto.UserName, - Password = registrationDto.Password, - }); - - loginResponse.PrintDump(); - oAuthUserSession = requestContext.ReloadSession(); - - Assert.That(oAuthUserSession.TwitterUserId, Is.EqualTo(authInfo["user_id"])); - Assert.That(oAuthUserSession.TwitterScreenName, Is.EqualTo(authInfo["screen_name"])); - - var userAuth = userAuthRepository.GetUserAuth(oAuthUserSession.UserAuthId); - Assert.That(userAuth.Id.ToString(CultureInfo.InvariantCulture), Is.EqualTo(oAuthUserSession.UserAuthId)); - Assert.That(userAuth.DisplayName, Is.EqualTo(registrationDto.DisplayName)); - Assert.That(userAuth.FirstName, Is.EqualTo(registrationDto.FirstName)); - Assert.That(userAuth.LastName, Is.EqualTo(registrationDto.LastName)); - Assert.That(userAuth.Email, Is.EqualTo(registrationDto.Email)); - - Console.WriteLine(oAuthUserSession.Dump()); - Assert.That(oAuthUserSession.ProviderOAuthAccess.Count, Is.EqualTo(2)); - Assert.That(oAuthUserSession.IsAuthenticated, Is.True); - - var authProviders = userAuthRepository.GetUserOAuthProviders(oAuthUserSession.UserAuthId); - Assert.That(authProviders.Count, Is.EqualTo(2)); - - Console.WriteLine(userAuth.Dump()); - Console.WriteLine(authProviders.Dump()); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Registering_twice_creates_two_registrations(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var oAuthUserSession = requestContext.ReloadSession(); - - RegisterAndLogin(userAuthRepository, oAuthUserSession); - - requestContext.RemoveSession(); - - var userName1 = registrationDto.UserName; - var userName2 = "UserName2"; - registrationDto.UserName = userName2; - registrationDto.Email = "as@if2.com"; - - var userAuth1 = userAuthRepository.GetUserAuthByUserName(userName1); - Assert.That(userAuth1, Is.Not.Null); - - Register(userAuthRepository, oAuthUserSession, registrationDto); - - userAuth1 = userAuthRepository.GetUserAuthByUserName(userName1); - var userAuth2 = userAuthRepository.GetUserAuthByUserName(userName2); - - Assert.That(userAuth1, Is.Not.Null); - Assert.That(userAuth2, Is.Not.Null); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Registering_twice_in_same_session_updates_registration(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var oAuthUserSession = requestContext.ReloadSession(); - - oAuthUserSession = RegisterAndLogin(userAuthRepository, oAuthUserSession); - - var userName1 = registrationDto.UserName; - var userName2 = "UserName2"; - registrationDto.UserName = userName2; - - Register(userAuthRepository, oAuthUserSession, registrationDto); - - var userAuth1 = userAuthRepository.GetUserAuthByUserName(userName1); - var userAuth2 = userAuthRepository.GetUserAuthByUserName(userName2); - - Assert.That(userAuth1, Is.Null); - Assert.That(userAuth2, Is.Not.Null); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Connecting_to_facebook_whilst_authenticated_connects_account(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - - var oAuthUserSession = requestContext.ReloadSession(); - - oAuthUserSession = RegisterAndLogin(userAuthRepository, oAuthUserSession); - - LoginWithFacebook(oAuthUserSession); - - var userAuth = userAuthRepository.GetUserAuthByUserName(registrationDto.UserName); - - Assert.That(userAuth.UserName, Is.EqualTo(registrationDto.UserName)); - - var userAuthProviders = userAuthRepository.GetUserOAuthProviders(userAuth.Id.ToString(CultureInfo.InvariantCulture)); - Assert.That(userAuthProviders.Count, Is.EqualTo(1)); - } - - [Test, TestCaseSource("UserAuthRepositorys")] - public void Can_AutoLogin_whilst_Registering(IUserAuthRepository userAuthRepository) - { - InitTest(userAuthRepository); - var oAuthUserSession = requestContext.ReloadSession(); - registrationDto.AutoLogin = true; - Register(userAuthRepository, oAuthUserSession, registrationDto); - - oAuthUserSession = requestContext.ReloadSession(); - Assert.That(oAuthUserSession.IsAuthenticated, Is.True); - } - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTestsBase.cs b/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTestsBase.cs deleted file mode 100644 index 855e776b3dd..00000000000 --- a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionTestsBase.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using Moq; -using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.Redis; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; - -namespace ServiceStack.Common.Tests.OAuth -{ - public abstract class OAuthUserSessionTestsBase - { - public static bool LoadUserAuthRepositorys = true; - - //Can only use either 1 OrmLiteDialectProvider at 1-time SqlServer or Sqlite. - public static bool UseSqlServer = false; - - public static AuthUserSession GetNewSession2() - { - var oAuthUserSession = new AuthUserSession(); - return oAuthUserSession; - } - - public CredentialsAuthProvider GetCredentialsAuthConfig() - { - return new CredentialsAuthProvider(new AppSettings()) { - }; - } - - public TwitterAuthProvider GetTwitterAuthProvider() - { - return new TwitterAuthProvider(new AppSettings()) { - AuthHttpGateway = new MockAuthHttpGateway(), - }; - } - - public FacebookAuthProvider GetFacebookAuthProvider() - { - return new FacebookAuthProvider(new AppSettings()) { - AuthHttpGateway = new MockAuthHttpGateway(), - }; - } - - public IEnumerable UserAuthRepositorys - { - get - { - if (!LoadUserAuthRepositorys) yield break; - - var inMemoryRepo = new InMemoryAuthRepository(); - inMemoryRepo.Clear(); - yield return new TestCaseData(inMemoryRepo); - - var appSettings = new AppSettings(); - var redisRepo = new RedisAuthRepository(new BasicRedisClientManager(new string[] { appSettings.GetString("Redis.Host") ?? "localhost" })); - redisRepo.Clear(); - yield return new TestCaseData(redisRepo); - - if (UseSqlServer) - { - var connStr = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\App_Data\auth.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True"; - var sqlServerFactory = new OrmLiteConnectionFactory(connStr, SqlServerOrmLiteDialectProvider.Instance); - var sqlServerRepo = new OrmLiteAuthRepository(sqlServerFactory); - sqlServerRepo.DropAndReCreateTables(); - yield return new TestCaseData(sqlServerRepo); - } - else - { - var dbFactory = new OrmLiteConnectionFactory( - ":memory:", autoDisposeConnection:false, dialectProvider:SqliteDialect.Provider); - var sqliteRepo = new OrmLiteAuthRepository(dbFactory); - sqliteRepo.CreateMissingTables(); - sqliteRepo.Clear(); - yield return new TestCaseData(sqliteRepo); - - var dbFilePath = "~/App_Data/auth.sqlite".MapProjectPath(); - if (File.Exists(dbFilePath)) File.Delete(dbFilePath); - var sqliteDbFactory = new OrmLiteConnectionFactory(dbFilePath); - var sqliteDbRepo = new OrmLiteAuthRepository(sqliteDbFactory); - sqliteDbRepo.CreateMissingTables(); - yield return new TestCaseData(sqliteDbRepo); - } - } - } - - protected Mock mockService; - protected MockRequestContext requestContext; - protected IServiceBase service; - - protected OAuthTokens facebookGatewayTokens = new OAuthTokens { - UserId = "623501766", - DisplayName = "Demis Bellot FB", - FirstName = "Demis", - LastName = "Bellot", - Email = "demis.bellot@gmail.com", - }; - protected OAuthTokens twitterGatewayTokens = new OAuthTokens { - DisplayName = "Demis Bellot TW" - }; - protected OAuthTokens facebookAuthTokens = new OAuthTokens { - Provider = FacebookAuthProvider.Name, - AccessTokenSecret = "AAADDDCCCoR848BAMkQIZCRIKnVWZAvcKWqo7Ibvec8ebV9vJrfZAz8qVupdu5EbjFzmMmbwUFDbcNDea9H6rOn5SVn8es7KYZD", - }; - protected OAuthTokens twitterAuthTokens = new OAuthTokens { - Provider = TwitterAuthProvider.Name, - RequestToken = "JGGZZ22CCqgB1GR5e0EmGFxzyxGTw2rwEFFcC8a9o7g", - RequestTokenSecret = "qKKCCUUJ2R10bMieVQZZad7iSwWkPYJmtBYzPoM9q0", - UserId = "133371690876022785", - }; - protected Registration registrationDto; - - protected void InitTest(IUserAuthRepository userAuthRepository) - { - ((IClearable)userAuthRepository).Clear(); - - var appsettingsMock = new Mock(); - var appSettings = appsettingsMock.Object; - - new AuthFeature(null, new IAuthProvider[] { - new CredentialsAuthProvider(), - new BasicAuthProvider(), - new FacebookAuthProvider(appSettings), - new TwitterAuthProvider(appSettings) - }).Register(null); - - mockService = new Mock(); - mockService.Expect(x => x.TryResolve()).Returns(userAuthRepository); - requestContext = new MockRequestContext(); - mockService.Expect(x => x.RequestContext).Returns(requestContext); - service = mockService.Object; - - registrationDto = new Registration { - UserName = "UserName", - Password = "p@55word", - Email = "as@if.com", - DisplayName = "DisplayName", - FirstName = "FirstName", - LastName = "LastName", - }; - } - - public static RegistrationService GetRegistrationService( - IUserAuthRepository userAuthRepository, - AuthUserSession oAuthUserSession = null, - MockRequestContext requestContext = null) - { - if (requestContext == null) - requestContext = new MockRequestContext(); - if (oAuthUserSession == null) - oAuthUserSession = requestContext.ReloadSession(); - - var httpReq = requestContext.Get(); - var httpRes = requestContext.Get(); - oAuthUserSession.Id = httpRes.CreateSessionId(httpReq); - httpReq.Items[ServiceExtensions.RequestItemsSessionKey] = oAuthUserSession; - - var mockAppHost = new BasicAppHost { - Container = requestContext.Container - }; - - requestContext.Container.Register(userAuthRepository); - - var authService = new AuthService { - RequestContext = requestContext, - }; - authService.SetAppHost(mockAppHost); - mockAppHost.Register(authService); - - var registrationService = new RegistrationService { - UserAuthRepo = userAuthRepository, - RequestContext = requestContext, - RegistrationValidator = - new RegistrationValidator { UserAuthRepo = RegistrationServiceTests.GetStubRepo() }, - }; - registrationService.SetAppHost(mockAppHost); - - return registrationService; - } - - public static void AssertEqual(UserAuth userAuth, Registration request) - { - Assert.That(userAuth, Is.Not.Null); - Assert.That(userAuth.UserName, Is.EqualTo(request.UserName)); - Assert.That(userAuth.Email, Is.EqualTo(request.Email)); - Assert.That(userAuth.DisplayName, Is.EqualTo(request.DisplayName)); - Assert.That(userAuth.FirstName, Is.EqualTo(request.FirstName)); - Assert.That(userAuth.LastName, Is.EqualTo(request.LastName)); - } - - protected AuthUserSession RegisterAndLogin(IUserAuthRepository userAuthRepository, AuthUserSession oAuthUserSession) - { - Register(userAuthRepository, oAuthUserSession); - - Login(registrationDto.UserName, registrationDto.Password, oAuthUserSession); - - oAuthUserSession = requestContext.ReloadSession(); - return oAuthUserSession; - } - - protected object Login(string userName, string password, AuthUserSession oAuthUserSession = null) - { - if (oAuthUserSession == null) - oAuthUserSession = requestContext.ReloadSession(); - - var credentialsAuth = GetCredentialsAuthConfig(); - return credentialsAuth.Authenticate(service, oAuthUserSession, - new Auth { - provider = CredentialsAuthProvider.Name, - UserName = registrationDto.UserName, - Password = registrationDto.Password, - }); - } - - protected object Register(IUserAuthRepository userAuthRepository, AuthUserSession oAuthUserSession, Registration registration = null) - { - if (registration == null) - registration = registrationDto; - - var registrationService = GetRegistrationService(userAuthRepository, oAuthUserSession, requestContext); - var response = registrationService.Post(registration); - Assert.That(response as IHttpError, Is.Null); - return response; - } - - protected void LoginWithFacebook(AuthUserSession oAuthUserSession) - { - MockAuthHttpGateway.Tokens = facebookGatewayTokens; - var facebookAuth = GetFacebookAuthProvider(); - facebookAuth.OnAuthenticated(service, oAuthUserSession, facebookAuthTokens, new Dictionary()); - Console.WriteLine("UserId: " + oAuthUserSession.UserAuthId); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionWithoutTestSourceTests.cs b/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionWithoutTestSourceTests.cs deleted file mode 100644 index 0d77dd33cc1..00000000000 --- a/tests/ServiceStack.Common.Tests/OAuth/OAuthUserSessionWithoutTestSourceTests.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Configuration; -using ServiceStack.OrmLite; -using ServiceStack.OrmLite.SqlServer; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.Redis; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests.OAuth -{ - [TestFixture, Explicit("Manual OAuth Test with iteration over data stores")] - public class OAuthUserSessionWithoutTestSourceTests - { - private OAuthUserSessionTests tests; - private readonly List userAuthRepositorys = new List(); - - OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory( - ":memory:", false, SqliteOrmLiteDialectProvider.Instance); - - [SetUp] - public void SetUp() - { - try - { - tests = new OAuthUserSessionTests(); - var inMemoryRepo = new InMemoryAuthRepository(); - inMemoryRepo.Clear(); - userAuthRepositorys.Add(inMemoryRepo); - - var appSettings = new AppSettings(); - var redisRepo = new RedisAuthRepository(new BasicRedisClientManager(new string[] { appSettings.GetString("Redis.Host") ?? "localhost" })); - redisRepo.Clear(); - userAuthRepositorys.Add(redisRepo); - - if (OAuthUserSessionTestsBase.UseSqlServer) - { - var connStr = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\App_Data\auth.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True"; - var sqlServerFactory = new OrmLiteConnectionFactory(connStr, SqlServerOrmLiteDialectProvider.Instance); - var sqlServerRepo = new OrmLiteAuthRepository(sqlServerFactory); - sqlServerRepo.DropAndReCreateTables(); - } - else - { - var sqliteInMemoryRepo = new OrmLiteAuthRepository(dbFactory); - dbFactory.Run(db => { - db.CreateTable(true); - db.CreateTable(true); - }); - sqliteInMemoryRepo.Clear(); - userAuthRepositorys.Add(sqliteInMemoryRepo); - - var sqliteDbFactory = new OrmLiteConnectionFactory( - "~/App_Data/auth.sqlite".MapProjectPath()); - var sqliteDbRepo = new OrmLiteAuthRepository(sqliteDbFactory); - sqliteDbRepo.CreateMissingTables(); - userAuthRepositorys.Add(sqliteDbRepo); - } - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - throw; - } - } - - [Test] - public void Does_persist_TwitterOAuth() - { - userAuthRepositorys.ForEach(x => tests.Does_persist_TwitterOAuth(x)); - } - - [Test] - public void Does_persist_FacebookOAuth() - { - userAuthRepositorys.ForEach(x => tests.Does_persist_FacebookOAuth(x)); - } - - [Test] - public void Does_merge_FacebookOAuth_TwitterOAuth() - { - userAuthRepositorys.ForEach(x => tests.Does_merge_FacebookOAuth_TwitterOAuth(x)); - } - - [Test] - public void Can_login_with_user_created_CreateUserAuth() - { - userAuthRepositorys.ForEach(x => tests.Can_login_with_user_created_CreateUserAuth(x)); - } - - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthRepositoryTests.cs b/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthRepositoryTests.cs new file mode 100644 index 00000000000..eb48ffd5c49 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthRepositoryTests.cs @@ -0,0 +1,134 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +#if !NETCORE +using System.Net; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Testing; + +namespace ServiceStack.Common.Tests.OAuth +{ + public class OrmLiteUserAuthRepositoryTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost(typeof(OrmLiteUserAuthRepositoryTests).Assembly) + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { + new CredentialsAuthProvider(), + }) + { + IncludeRegistrationService = true, + }); + }, + ConfigureContainer = container => + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider) { + AutoDisposeConnection = false, + }); + + container.Register(c => new OrmLiteAuthRepository(c.Resolve())); + container.Resolve().InitSchema(); + } + }.Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + private object RegisterUser(string email = "as@if.com") + { + using (var db = appHost.Resolve().Open()) + { + db.Delete(q => q.Email == email); + } + + var response = appHost.ExecuteService(new Register + { + Password = "p@55word", + Email = email, + DisplayName = "DisplayName", + FirstName = "FirstName", + LastName = "LastName", + }); + + Assert.That(response as RegisterResponse, Is.Not.Null, response.ToString()); + + return response; + } + + [Test] + public void Can_attempt_multiple_invalid_logins_without_being_locked_out() + { + RegisterUser(email: "as@if.com"); + + 3.Times(() => + { + var response = appHost.ExecuteService(new Authenticate + { + UserName = "as@if.com", + Password = "wrongpassword" + }); + }); + + using (var db = appHost.Resolve().Open()) + { + var user = db.Single(q => q.Email == "as@if.com"); + Assert.That(user.LockedDate, Is.Null); + } + } + + [Test] + public void Does_lockout_user_after_reaching_max_invalid_logins_limit() + { + RegisterUser(email: "as@if.com"); + + var feature = appHost.GetPlugin(); + feature.MaxLoginAttempts = 3; + + feature.MaxLoginAttempts.Value.Times(i => + { + appHost.ExecuteService(new Authenticate { + UserName = "as@if.com", + Password = "wrongpassword" + }); + + using (var db = appHost.Resolve().Open()) + { + var user = db.Single(q => q.Email == "as@if.com"); + Assert.That(user.LastLoginAttempt, Is.Not.Null); + Assert.That(user.InvalidLoginAttempts, Is.EqualTo(i + 1)); //0 index + } + }); + + using (var db = appHost.Resolve().Open()) + { + var user = db.Single(q => q.Email == "as@if.com"); + Assert.That(user.LockedDate, Is.Not.Null); + } + + var response = appHost.ExecuteService(new Authenticate + { + UserName = "as@if.com", + Password = "p@55word" + }); + + var httpError = (HttpError)response; + Assert.That(httpError.Message, Is.EqualTo("This account has been locked")); + Assert.That(httpError.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthTests.cs b/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthTests.cs index 4ffa84cee37..699b2c415af 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/OrmLiteUserAuthTests.cs @@ -1,10 +1,9 @@ -using System; +#if !NETCORE +using System.Data; using System.IO; using NUnit.Framework; -using ServiceStack.Common.Utils; +using ServiceStack.Auth; using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceInterface.Auth; using ServiceStack.Text; namespace ServiceStack.Common.Tests.OAuth @@ -12,43 +11,41 @@ namespace ServiceStack.Common.Tests.OAuth [TestFixture] public class OrmLiteUserAuthTests { - [Test] + private static IDbConnection OpenDbConnection() + { + OrmLiteConfig.DialectProvider = SqliteDialect.Provider; + var connectionString = "~/App_Data/db.sqlite".MapAbsolutePath(); + if (File.Exists(connectionString)) + File.Delete(connectionString); + + var openDbConnection = connectionString.OpenDbConnection(); + return openDbConnection; + } + + private static UserAuth GetUserAuth() + { + var jsv = "{Id:0,UserName:UserName,Email:as@if.com,PrimaryEmail:as@if.com,FirstName:FirstName,LastName:LastName,DisplayName:DisplayName,Salt:WMQi/g==,PasswordHash:oGdE40yKOprIgbXQzEMSYZe3vRCRlKGuqX2i045vx50=,Roles:[],Permissions:[],CreatedDate:2012-03-20T07:53:48.8720739Z,ModifiedDate:2012-03-20T07:53:48.8720739Z}"; + var userAuth = jsv.ConvertTo(); + return userAuth; + } + + [Test] public void Can_insert_table_with_UserAuth() - { - OrmLiteConfig.DialectProvider = SqliteOrmLiteDialectProvider.Instance; - var connectionString = "~/App_Data/db.sqlite".MapAbsolutePath(); - if (File.Exists(connectionString)) - File.Delete(connectionString); - - using (var db = connectionString.OpenDbConnection()) + { + using (var db = OpenDbConnection()) { - db.CreateTable(true); - - //var userAuth = new UserAuth { - // Id = 1, - // UserName = "UserName", - // Email = "a@b.com", - // PrimaryEmail = "c@d.com", - // FirstName = "FirstName", - // LastName = "LastName", - // DisplayName = "DisplayName", - // Salt = "Salt", - // PasswordHash = "PasswordHash", - // CreatedDate = DateTime.Now, - // ModifiedDate = DateTime.UtcNow, - //}; - - var jsv = "{Id:0,UserName:UserName,Email:as@if.com,PrimaryEmail:as@if.com,FirstName:FirstName,LastName:LastName,DisplayName:DisplayName,Salt:WMQi/g==,PasswordHash:oGdE40yKOprIgbXQzEMSYZe3vRCRlKGuqX2i045vx50=,Roles:[],Permissions:[],CreatedDate:2012-03-20T07:53:48.8720739Z,ModifiedDate:2012-03-20T07:53:48.8720739Z}"; - var userAuth = jsv.To(); - - db.Insert(userAuth); + db.DropAndCreateTable(); - var rows = db.Select(q => q.UserName == "UserName"); + var userAuth = GetUserAuth(); - Console.WriteLine(rows[0].Dump()); + db.Insert(userAuth); + + var rows = db.Select(q => q.UserName == "UserName"); Assert.That(rows[0].UserName, Is.EqualTo(userAuth.UserName)); } - } + } + } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/RegistrationServiceTests.cs b/tests/ServiceStack.Common.Tests/OAuth/RegistrationServiceTests.cs index 7776eff88fe..81ca59b3c1f 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/RegistrationServiceTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/RegistrationServiceTests.cs @@ -1,216 +1,230 @@ -using Moq; +#if !NETCORE +using System.Collections.Generic; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common.Web; +using ServiceStack.Auth; using ServiceStack.FluentValidation; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Host; +using ServiceStack.Testing; namespace ServiceStack.Common.Tests.OAuth { - [TestFixture] - public class RegistrationServiceTests - { - static BasicAppHost _appHost = null; - static readonly AuthUserSession authUserSession = new AuthUserSession(); + [TestFixture] + public class RegistrationServiceTests + { + static AuthUserSession authUserSession = new AuthUserSession(); - static IAppHost GetAppHost() + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() { - if (_appHost == null) + appHost = new BasicAppHost { - _appHost = new BasicAppHost(); - var authService = new AuthService(); - authService.SetAppHost(_appHost); - _appHost.Container.Register(authService); - _appHost.Container.Register(authUserSession); - } - return _appHost; + ConfigureContainer = c => + { + var authService = new AuthenticateService(); + c.Register(authService); + c.Register(authUserSession); + AuthenticateService.Init(() => authUserSession, new CredentialsAuthProvider()); + } + }.Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public static IUserAuthRepository GetStubRepo() + { + var authRepo = new InMemoryAuthRepository(); + return authRepo; } - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - AuthService.Init(() => authUserSession, new CredentialsAuthProvider()); - } - - public static IUserAuthRepository GetStubRepo() - { - var mock = new Mock(); - mock.Expect(x => x.GetUserAuthByUserName(It.IsAny())) - .Returns((UserAuth)null); - mock.Expect(x => x.CreateUserAuth(It.IsAny(), It.IsAny())) - .Returns(new UserAuth { Id = 1 }); - - return mock.Object; - } - - public static RegistrationService GetRegistrationService( - AbstractValidator validator = null, - IUserAuthRepository authRepo=null, - string contentType=null) - { - var requestContext = new MockRequestContext(); - if (contentType != null) - { - requestContext.ResponseContentType = contentType; - } - var userAuthRepository = authRepo ?? GetStubRepo(); - var service = new RegistrationService { - RegistrationValidator = validator ?? new RegistrationValidator { UserAuthRepo = userAuthRepository }, - UserAuthRepo = userAuthRepository, - RequestContext = requestContext, - }; - - var appHost = GetAppHost(); - appHost.Register(userAuthRepository); - service.SetAppHost(appHost); + + public static RegisterService GetRegistrationService( + AbstractValidator validator = null, + IUserAuthRepository authRepo = null, + string contentType = null) + { + var requestContext = new BasicRequest(); + if (contentType != null) + { + requestContext.ResponseContentType = contentType; + } + var userAuthRepository = authRepo ?? GetStubRepo(); + HostContext.Container.Register(userAuthRepository); + + var service = new RegisterService + { + RegistrationValidator = validator ?? new RegistrationValidator(), + Request = requestContext, + }; + + HostContext.Container.Register(userAuthRepository); + + (HostContext.TryResolve() as InMemoryAuthRepository)?.Clear(); return service; - } - - [Test] - public void Empty_Registration_is_invalid() - { - var service = GetRegistrationService(); - - var response = PostRegistrationError(service, new Registration()); - var errors = response.GetFieldErrors(); - - Assert.That(errors.Count, Is.EqualTo(3)); - Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[0].FieldName, Is.EqualTo("Password")); - Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[1].FieldName, Is.EqualTo("UserName")); - Assert.That(errors[2].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[2].FieldName, Is.EqualTo("Email")); - } - - private static HttpError PostRegistrationError(RegistrationService service, Registration registration) - { - var response = (HttpError) service.RunAction(registration, (svc, req) => svc.Post(req)); - return response; - } - - [Test] - public void Empty_Registration_is_invalid_with_FullRegistrationValidator() - { - var service = GetRegistrationService(new FullRegistrationValidator()); - - var response = PostRegistrationError(service, new Registration()); + } + + [Test] + public void Empty_Registration_is_invalid() + { + var service = GetRegistrationService(); + + var response = PostRegistrationError(service, new Register()); + var errors = response.GetFieldErrors(); + + Assert.That(errors.Count, Is.EqualTo(3)); + Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[0].FieldName, Is.EqualTo("Password")); + Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[1].FieldName, Is.EqualTo("UserName")); + Assert.That(errors[2].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[2].FieldName, Is.EqualTo("Email")); + } + + private static HttpError PostRegistrationError(RegisterService service, Register register) + { + var response = (HttpError)service.RunAction(register, (svc, req) => svc.Post(req)); + return response; + } + + [Test] + public void Empty_Registration_is_invalid_with_FullRegistrationValidator() + { + var service = GetRegistrationService(new FullRegistrationValidator()); + + var response = PostRegistrationError(service, new Register()); var errors = response.GetFieldErrors(); - Assert.That(errors.Count, Is.EqualTo(4)); - Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[0].FieldName, Is.EqualTo("Password")); - Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[1].FieldName, Is.EqualTo("UserName")); - Assert.That(errors[2].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[2].FieldName, Is.EqualTo("Email")); - Assert.That(errors[3].ErrorCode, Is.EqualTo("NotEmpty")); - Assert.That(errors[3].FieldName, Is.EqualTo("DisplayName")); - } - - [Test] - public void Accepts_valid_registration() - { - var service = GetRegistrationService(); - - var request = GetValidRegistration(); - - var response = service.Post(request); - - Assert.That(response as RegistrationResponse, Is.Not.Null); - } - - public static Registration GetValidRegistration(bool autoLogin=false) - { - var request = new Registration { - DisplayName = "DisplayName", - Email = "my@email.com", - FirstName = "FirstName", - LastName = "LastName", - Password = "Password", - UserName = "UserName", - AutoLogin = autoLogin, - }; - return request; - } - - [Test] - public void Requires_unique_UserName_and_Email() - { - var mock = new Mock(); - var mockExistingUser = new UserAuth(); - mock.Expect(x => x.GetUserAuthByUserName(It.IsAny())) - .Returns(mockExistingUser); - - var service = new RegistrationService { - RegistrationValidator = new RegistrationValidator { UserAuthRepo = mock.Object }, - UserAuthRepo = mock.Object, + Assert.That(errors.Count, Is.EqualTo(4)); + Assert.That(errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[0].FieldName, Is.EqualTo("Password")); + Assert.That(errors[1].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[1].FieldName, Is.EqualTo("UserName")); + Assert.That(errors[2].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[2].FieldName, Is.EqualTo("Email")); + Assert.That(errors[3].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors[3].FieldName, Is.EqualTo("DisplayName")); + } + + [Test] + public async Task Accepts_valid_registration() + { + var service = GetRegistrationService(); + + var request = GetValidRegistration(); + + var response = await service.PostAsync(request); + + Assert.That(response as RegisterResponse, Is.Not.Null); + } + + public static Register GetValidRegistration(bool autoLogin = false) + { + var request = new Register + { + DisplayName = "DisplayName", + Email = "my@email.com", + FirstName = "FirstName", + LastName = "LastName", + Password = "Password", + UserName = "UserName", + AutoLogin = autoLogin, }; + return request; + } - var request = new Registration { - DisplayName = "DisplayName", - Email = "my@email.com", - FirstName = "FirstName", - LastName = "LastName", - Password = "Password", - UserName = "UserName", - }; + [Test] + public void Requires_unique_UserName_and_Email() + { + ClearSession(); + (HostContext.TryResolve() as InMemoryAuthRepository)?.Clear(); + + var authRepo = new InMemoryAuthRepository(); + authRepo.CreateUserAuth(new UserAuth { + Email = "my@email.com", + UserName = "UserName", + }, "password"); + appHost.Register(authRepo); + + var service = new RegisterService + { + RegistrationValidator = new RegistrationValidator(), + }; + + var request = new Register + { + DisplayName = "DisplayName", + Email = "my@email.com", + FirstName = "FirstName", + LastName = "LastName", + Password = "Password", + UserName = "UserName", + }; var response = PostRegistrationError(service, request); var errors = response.GetFieldErrors(); - Assert.That(errors.Count, Is.EqualTo(2)); - Assert.That(errors[0].ErrorCode, Is.EqualTo("AlreadyExists")); - Assert.That(errors[0].FieldName, Is.EqualTo("UserName")); - Assert.That(errors[1].ErrorCode, Is.EqualTo("AlreadyExists")); - Assert.That(errors[1].FieldName, Is.EqualTo("Email")); - } + Assert.That(errors.Count, Is.EqualTo(2)); + Assert.That(errors[0].ErrorCode, Is.EqualTo("AlreadyExists")); + Assert.That(errors[0].FieldName, Is.EqualTo("UserName")); + Assert.That(errors[1].ErrorCode, Is.EqualTo("AlreadyExists")); + Assert.That(errors[1].FieldName, Is.EqualTo("Email")); + } + + private void ClearSession() + { + authUserSession = new AuthUserSession(); + appHost.Container.Register(c => null); + } - [Test] - public void Registration_with_Html_ContentType_And_Continue_returns_302_with_Location() - { - var service = GetRegistrationService(null, null, ContentType.Html); + [Test] + public async Task Registration_with_Html_ContentType_And_Continue_returns_302_with_Location() + { + var service = GetRegistrationService(null, null, MimeTypes.Html); - var request = GetValidRegistration(); - request.Continue = "http://localhost/home"; + var request = GetValidRegistration(); - var response = service.Post(request) as HttpResult; + service.Request.QueryString[Keywords.Continue] = "http://localhost/home"; + var response = (await service.PostAsync(request)) as HttpResult; - Assert.That(response, Is.Not.Null); - Assert.That(response.Status, Is.EqualTo(302)); - Assert.That(response.Headers[HttpHeaders.Location], Is.EqualTo("http://localhost/home")); - } + Assert.That(response, Is.Not.Null); + Assert.That(response.Status, Is.EqualTo(302)); + Assert.That(response.Headers[HttpHeaders.Location], Is.EqualTo("http://localhost/home")); + } - [Test] - public void Registration_with_EmptyString_Continue_returns_RegistrationResponse() - { - var service = GetRegistrationService(null, null, ContentType.Html); + [Test] + public async Task Registration_with_EmptyString_Continue_returns_RegistrationResponse() + { + var service = GetRegistrationService(null, null, MimeTypes.Html); - var request = GetValidRegistration(); - request.Continue = string.Empty; + var request = GetValidRegistration(); + service.Request.QueryString[Keywords.Continue] = string.Empty; - var response = service.Post(request); + var response = await service.PostAsync(request); - Assert.That(response as HttpResult, Is.Null); - Assert.That(response as RegistrationResponse, Is.Not.Null); - } + Assert.That(response as HttpResult, Is.Null); + Assert.That(response as RegisterResponse, Is.Not.Null); + } - [Test] - public void Registration_with_Json_ContentType_And_Continue_returns_RegistrationResponse_with_ReferrerUrl() - { - var service = GetRegistrationService(null, null, ContentType.Json); + [Test] + public async Task Registration_with_Json_ContentType_And_Continue_returns_RegistrationResponse_with_ReferrerUrl() + { + var service = GetRegistrationService(null, null, MimeTypes.Json); - var request = GetValidRegistration(); - request.Continue = "http://localhost/home"; + var request = GetValidRegistration(); + service.Request.QueryString[Keywords.Continue] = "http://localhost/home"; - var response = service.Post(request); + var response = await service.PostAsync(request); - Assert.That(response as HttpResult, Is.Null); - Assert.That(response as RegistrationResponse, Is.Not.Null); - Assert.That(((RegistrationResponse)response).ReferrerUrl, Is.EqualTo("http://localhost/home")); - } - } -} \ No newline at end of file + Assert.That(response as HttpResult, Is.Null); + Assert.That(response as RegisterResponse, Is.Not.Null); + Assert.That(((RegisterResponse)response).ReferrerUrl, Is.EqualTo("http://localhost/home")); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/OAuth/RequiredRolesTests.cs b/tests/ServiceStack.Common.Tests/OAuth/RequiredRolesTests.cs index df25a52f2ca..a0b4902f9df 100644 --- a/tests/ServiceStack.Common.Tests/OAuth/RequiredRolesTests.cs +++ b/tests/ServiceStack.Common.Tests/OAuth/RequiredRolesTests.cs @@ -1,19 +1,40 @@ -using System.Linq; +#if !NETCORE +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Testing; namespace ServiceStack.Common.Tests.OAuth { [TestFixture] public class RequiredRolesTests { - [TestFixtureSetUp] + private ServiceStackHost appHost; + + [OneTimeSetUp] public void TestFixtureSetUp() { - AuthService.Init(() => new AuthUserSession(), new CredentialsAuthProvider()); + appHost = new BasicAppHost + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new[] { new CredentialsAuthProvider() }) + { + IncludeRegistrationService = true, + }); + }, + + }.Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); } public class MockUserAuthRepository : InMemoryAuthRepository @@ -24,26 +45,27 @@ public MockUserAuthRepository(UserAuth userAuth) this.userAuth = userAuth; } - public override UserAuth GetUserAuthByUserName(string userNameOrEmail) - { - return null; - } + public override IUserAuth GetUserAuthByUserName(string userNameOrEmail) => null; - public override UserAuth CreateUserAuth(UserAuth newUser, string password) - { - return userAuth; - } + public override async Task GetUserAuthByUserNameAsync(string userNameOrEmail, CancellationToken token = default) + => GetUserAuthByUserName(userNameOrEmail); - public override UserAuth GetUserAuth(IAuthSession authSession, IOAuthTokens tokens) - { - return userAuth; - } + public override IUserAuth CreateUserAuth(IUserAuth newUser, string password) => userAuth; + public override async Task CreateUserAuthAsync(IUserAuth newUser, string password, CancellationToken token = default) + => CreateUserAuth(newUser, password); - public override bool TryAuthenticate(string userName, string password, out UserAuth userAuth) + public override IUserAuth GetUserAuth(IAuthSession authSession, IAuthTokens tokens) => userAuth; + public override async Task GetUserAuthAsync(IAuthSession authSession, IAuthTokens tokens, CancellationToken token = default) + => GetUserAuth(authSession, tokens); + + public override bool TryAuthenticate(string userName, string password, out IUserAuth userAuth) { userAuth = this.userAuth; return true; } + + public override async Task TryAuthenticateAsync(string userName, string password, CancellationToken token = default) => + this.userAuth; } private MockUserAuthRepository userAuth; @@ -55,46 +77,43 @@ public void SetUp() userAuth = new MockUserAuthRepository(userWithAdminRole); } - private RegistrationService GetRegistrationService() + private RegisterService GetRegistrationService() { var registrationService = RegistrationServiceTests.GetRegistrationService(authRepo: userAuth); var request = RegistrationServiceTests.GetValidRegistration(autoLogin: true); - registrationService.Post(request); + registrationService.PostAsync(request); return registrationService; } [Test] - public void Does_validate_RequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() + public async Task Does_validate_RequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() { var registrationService = GetRegistrationService(); var requiredRole = new RequiredRoleAttribute(RoleNames.Admin); - var requestContext = (MockRequestContext)registrationService.RequestContext; - requestContext.Container.Register(userAuth); - var httpRes = requestContext.Get(); + var request = registrationService.Request; + HostContext.Container.Register(userAuth); + var httpRes = request.Response; - requiredRole.Execute( - requestContext.Get(), - httpRes, - null); + await requiredRole.ExecuteAsync(request, request.Response, request.OperationName); Assert.That(!httpRes.IsClosed); } [Test] - public void Does_validate_AssertRequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() + public async Task Does_validate_AssertRequiredRoles_with_UserAuthRepo_When_Role_not_in_Session() { var registrationService = GetRegistrationService(); - var requestContext = (MockRequestContext)registrationService.RequestContext; - requestContext.Container.Register(userAuth); - var httpRes = requestContext.Get(); + var request = registrationService.Request; + HostContext.Container.Register(userAuth); - RequiredRoleAttribute.AssertRequiredRoles(requestContext, RoleNames.Admin); + await RequiredRoleAttribute.AssertRequiredRoleAsync(request, RoleNames.Admin); - Assert.That(!httpRes.IsClosed); + Assert.That(!request.Response.IsClosed); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/AdhocFastPerfTests.cs b/tests/ServiceStack.Common.Tests/Perf/AdhocFastPerfTests.cs index 104dee7a255..6365e17f890 100644 --- a/tests/ServiceStack.Common.Tests/Perf/AdhocFastPerfTests.cs +++ b/tests/ServiceStack.Common.Tests/Perf/AdhocFastPerfTests.cs @@ -6,97 +6,97 @@ namespace ServiceStack.Common.Tests.Perf { - [Ignore] - [TestFixture] - public class AdhocFastPerfTests - : PerfTestBase - { - public AdhocFastPerfTests() - { - //this.MultipleIterations = new List { 1000, 10000, 100000, 1000000 }; - this.MultipleIterations = new List { 10000 }; - } - - public static byte[] ToByteArray(string hexString) - { - var numberChars = hexString.Length; - var bytes = new byte[numberChars / 2]; - for (var i = 0; i < numberChars; i += 2) - { - bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); - } - return bytes; - } - - [Test] - public void Compare_small_ConvertBytes() - { - var byteArrayValue = new byte[] { 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, }; - - CompareMultipleRuns( - - "Convert.FromBase64String", () => Convert.FromBase64String(Convert.ToBase64String(byteArrayValue)), - "Encoding.Default", () => Encoding.Default.GetBytes(Encoding.Default.GetString(byteArrayValue)) - ); - } - - [Test] - public void Compare_medium_ConvertBytes() - { - var byteArrayValue = ToByteArray("151C2F00020000000D000E0014002100FFFFFFFF4269746D617020496D616765005061696E742E506963747572650001050000020000000700000050427275736800000000000000000080540000424D80540000000000007600000028000000C0000000E0000000010004000000000000540000CE0E0000D80E0000000000000000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFB009A00A9009A9AA9A900009AA9ABE9EB0B0BB09A0AB0A9A9B0FA0FA0CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFE9A09A9EBEBFBB0BB0AB09AC9090AB0BCB0BA9E9AA9A90B000009AAB09009BEB0BAD0EB9E9F9B0C0B0FADB0F0BEB0FCBC0BCBFB0F0BBE0B09BA0BBBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFA9DABEBFFFADFFADBF0BEBBAFAF0FBBAB9ADABADBE0AB0BCBFBC090E0A9AFA9BC90BB9AFABEE0BB0FA9ABEBE9B0FBA9AB9A9A0FB09E0BDAFA0DBE9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFB0FABFFFAFAFEABCBAA9F09AF0B9BBCBE9EBE9ADA9A990FAB0000BFA9090B09E0BAF00A9ADAB9BCBE9F0BCF0BE9FA9EB9CA90FBEAF0BFBA9ADBA9ABFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FE99A9FAFFFFEBDA9ADBCBFA9BA9EAFACB0B9AF9A9AFAEB0900BB9A0000A9AF0BBCB0B9E9BADAFAB0BABEBBBC9EAA9EBEABBE90B9B0B0BCBE9A9FADAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFBAFBA9BEBE09ABFEBABAB0F0F0F9DBFBBAFAB0FAF0B090BCBC00090B0B0A0BBE9B0BCA9AF9A9BC9E9FAD00ABAB9FA9CB9C90B0FABFF09ADBFEB00B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCBE9ABDEFBDBBFFCAB0F0D0FB0BBA0ABF0FDA9F0A90009A09A0B00000000D0BDA9AFADA9BDBEBFABABBADABFBDA9E0BEB9EBABE9A9EB0FE9AB09FAFBAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B9E9FABADAFEB0BBDE9BABBA9FEDBBF0BFABC0A900BFE0BC0900B090B0B0BFAFE9A9A900A0B0E9CF0C0B0F0CADABF0F0ABBCB0B0BCBEB0A9AFA9A9E9BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFABA9F9FAF0FCBCAB0BE90EDABBABCBFA090B090FBFEF009A0B00A000F0B00B0BE9EBAF9FBFBBBBABB09FABB0F9AFA9FBCFBCB0E9B9A9FAC9F0BC9F0BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCBF0DA0A0FBEBABBDEF9AFBBADA9CB0A0BCA00BAF0BFFE9BA9009090B09ACBBAFF0BADB0A0BADACBDE9CA0BC0BAAF0FBAEB00B0B9A0F9EB9ABAFABABBEBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0BA9BFBACB9EDAB0BAF9AE9A9FA90900090B0F0BFBFE000CB0A00009A9B0ADB0BE900A99ADABFBABEA99A0BF0F9AF0FF0BFADA0E9BABBEBC90BC9E0BCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9E9AF00FBFEBA9EBBC9A09BCA000A09A9ABCB9BFFEE9AF0B009090BAFBEB9BAF0BAFF9ACB0BFACBDBBE0DBFAF9EB0B0BE909A99B00BF0B0AABCBABDBBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0BA9AFBCBCBBEBBCABAD000090909009AC90B0AA9FF090B0B00A0BC90F090F9EBCB0AF9ABF0B9BAA9CB0A00FAABCBEBDAFAF0E09BE90FBF9CBB0BCA0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF0FBDA0BABE90CB9B0FA9AB000A00B0A9A9A9F9EBFE0BC00090900BA9BEB0BABCB0FB0BCB0FBEBDBFA9E9BFADBCBA9A0BE90BBB0E9AFA90FA00BE9A9BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A0B0EBFBCB9EBBAF0F0BC90B0090000909A9E0BBFEE900B0DA000900FA0B0B0BBE9B0BEB0B0AB0A0F0BBC0A99ABAD0BFF9EB0C009A909EBA9E9F0BCADBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9BDBFBB00BE0BAC9AFA9ABFE09A00909A0BCBA9AEBE90AB00A90A9ABFBE9F00FC9AEBC909ADB9EBFB0BC0B09AE9CB0F0A0A90B9EB090FAB0FA9A0FA90ABFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0A000CBE9BE99BFA90F090AB00000009090F0BFBFE0B0DA900090BCBA90AB0BEB90BAFADBA0FB0EBEBABEBC9AA9A9ABF90FA009A9EB09E9AFADA9CA9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB9FB9A9AE9BEFAF9A9ABEB9EBCB00000A0B0BE9AFF0FA090B00A90B0FADB009BAE9ADBAB0FFB0FBF09BF00B0D0F0EB00AB09EB0DA90A9AF0B0B0CB00B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0A00EBCB9BEB0BA0F0B09AE90B00B00090A909FFF09009A00090A0F9A9BAB0B0BFADA0D0F0B0BA9A9E00AF0A0BA9BC9E909AB09A09A9CA9ADACA90B0BCFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9B9BB0BE9E9E909F0BCBEB90B9CB00900BB0FAABEE0B9E090B0BDBBAF0E90C9AE90B0BAB09AFDABE9ADB9A909A9E00A90E90D0A09E0B09A9A090A00009BFE000909FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0CACBE0BA9A9AB00B0B0BC0BCAB0B0000009AFBE9A9E090A0009ABEFABBAB009BADAF09ABE9ABBDAFBAFA9E9AD090B0A90A0A9CB0900B0DADB0B000900BC90000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB9ADBE9FA9E9EB00F0F9A9E900BCB0B900F90FBEDA9A09090A9A90BC0DB0B09AFB00BCBCB0BCBEB0BDA9E0BC0A0BC090A9090B09A9B00B0A00009000900000000009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00A9AA9A0BF0B0BFBA90ACB0B0F0B0B00A90ABAFE90ADA0A0090DAFB0BA0BC0AFAC0BCB0BADAB0B0FEBA90B00B0900BCA9CB0A00A0000B09090900000000009000009BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9BF0F9FADA0BBFF0E90A99ABCB090B0E9000B9FE90E9009009AFAA9A9A9F0A909BBB0B0BC9A9EBDB0B9E0BCA9000BA009A0090B0909A900A0000000000000000090009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9A9AB0BBF0F0B0B9EBDAE90B0E0BC9AF0B00E9F0A9A9A090A9A9FAFCBB0B0B00FAF0E9AB0B0BAB0F0BBF0B0A9A909A9090A0000000009090000000000090009000000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCBE9AF0F09AFAF0A9EA90A90B090B09A90B0BAF090009A0909BE9BA9AFBBC0A90F0B0A9CB0F0DAFABE0000900000000A0A9090A9A900A0000000000000000000000009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09A9ADBF0BBE9B0BBE90BBCA909A009A9AC9A0BEBA0F0009A0BEBBE09F0009A90BABE090B0B0BABBCB090B000090009090900A090000900009000000090000000009009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9A9F0A00ABE9B0FA09ABC0B9E0A9F9ADA9A9E9D00C90A9000F0BDA0DA0FBBE9E09F9FA0B0E0BCBCBAD0A009000000000000009000000090000000000000000000900000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA9A0B9DA9CB9EB0BDAD0BBC0B09000A90BF0BAA9A9A9009A90BAAFFABBA0A9A9A0A0BDAC9B09A9BE9A909000000000000009000900900000090000000000000000000900FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9ADA0A09AB0A0BE0B0A9E0B00B0B0B0A900F09E09000B000B0BFF0B0F9F9BE9A9E9BEA9BA0DA9E09E9000000000000000000000000000000000000000000000900000009BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE09A9BC9A9CBE9E9F0F0B09A9AD00B09C0B0B0BC9AA9A009A9ADABFADAABABCBCB09EB9C009A9A09B0A00000000009000000000000900000000000000000090000000909C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09A9C00A90A09A9A0A0BCBA0D0A0BC9A9A900BE9AC90090BCBFAFABCBADA9BA9A0A9BCAB0F0B090A0090000090900000009000000000090000000009000900000000000BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFE90A9A90A90B090909A9A0DBA0990B00B9E09F0A9A09A000B0BFDEBE9FBEBEFAD9000B0090A0F0BCB000009000000009000000000000000000000900000000000009000BF0BFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBFFA09000090090000000909A009A0A00B00A90A0F009A09A9ADA0BADBB0A9F09B9A0F0BADB0A990BCB0000900000000000000000000000000009000000000000000000009FE0BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA909090009000000000000000009A00909A09BC0BFF09AC090090BFF0FAE0BF9ABBEE0B0A9F00A900A090090900000090000000000000000000000000000000000009000900BF09FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF909090000000000000000000000900090BF009E00B0BA0A90B0A9AFA9ABA9BFABAD00BFF0900BA9DA0F0B0B00000090900000000000000000000000000000000900000000009A9ED0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000090000000000000900000009000000B0B0B0BECBDA0090CB9EBFF0F009CBBAB0BEBE909E0A9009000B00090000000900000000000000000000000000000000000090000900BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00909000000000900000000000000000009009009A09BF0A090A0B0ABBEBEFAFEBBCB9ADAF00A9AF090A9A9E9009000900000000000000000000000000000000000000900000090009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09000000900000000000000000000000000000A9A009FEA9BCA9090BB0FFFFABF0BCBEAB0BFEB09E9A0A90009000009000000000000000000000000000000000000000000090090090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000000000000000000000000090000000009000909AF0DA090E0F0FFFEBEDFA9EBA99AF0BF09ABE09009A9A09090000000000000000000000000000000090000000000000000000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00009009000000900000000900000000000000009A00BF0BA09A99BBFAABFFBB0BE9BCBA90F0FE090BCA9A0009A000000000000000000000000000090000000000900900000000090D0BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9000000000090000000000000000000000000000090A0BC9AD00A000BFBCBCBEF0BAFBCBAB0BABCBAF09009A9A0900900000000000000090000000000000000000000000000000900A9FEFFFFFFFFFFFFFFCBF9FF9FFFFFFFFD99F9FFFFFFFF000900090000000000000900000000000000000000009BEBE90A909E9F0BBFFA9EBC9B0B0BCF09EF0BC9A09A00090000000000000000000000090000000000000000000000090090A99EBFFFFFFFEF9A9BF9FF9F9F0F0BDBFFFB0FB9F09FFFFE00000900000000000000000000000000000000000090BAE900A90BABBAFAFEA9EB0BAAF0FEB00AFBE9A0900909A00000000000000000000000000000000000000000000000000009C0A9FFFFFFFB9DBDFDBFDBFBF9FBDBE999DDB9CB99A990FF090000900000000000000000000000000000000900009FBAF09A09E9E9E90BCB0E9EBDAB0DAF9CAFFE9E0B0A0090909000000000000000000000000000000000000000009000000B0900BFFFE90DB0FBFFDBFDF9FBD9F9BFFABDBFBDBDB0F90900000009090009000900090000000009000000000000A9E90A09F0BFAFAFEBBCB9E9EBF0BAF0AB9BAFA9A0909A00000000000000000000000000000000000000000000000000000000BCBFC9909B0FBDBFFF9FBE9DAF9FDB9DBBDBDBCBF99ADA00000000000000000000000000000000000000000009BEFA09A00BF0BE9A9E0B0A9A9E0B009EF0E0FE9AC90A000900000900000000000000009000000000000000000000000000900B09009ACBF0F9DBDAF9FBDFFBF9ADB9FFBCBDBDBF09F0909090000000000000000000000000000000000000009A9A909AD0B00ADCB0F0900909A9A9E0A90BFFA9EB0A090900090000000090009000000000000000000000000000000009000909009A09909F9FBFFF9F9FF99F9FDF9FB9DBDA9B99DB0B9000000000000000000000000000009000000000000000AF0E90ABCBFBEB0E9A0B00A000900C90000BEF0F9ADA000900000000000000000000000000000090000000000000000000000000090A9F09B9F9BFBFF9BFF9FBBDBDFFB9F9F9FABD9CB0909090000000000000000000000000000000000000909A90A90DA009BCBB0F00F090900B0000B0009AF0AF009A9000000000000000000009000000000000000000900000000000090009009009BFBCBFDBDF9FCB9FBDF9FB9ADF9F9B0D9A9B90000000909009000009009009000000000000009000009E0B0F0A9FAEAB0CB0B000000000900D0009009AF00B000009090000900090090000000000000000000000000090000000000900090BDBC99FBDBFBF9FB9EF9FBFF0F9F0F9ADF9BBD9E9A90900000000000000000000000000000000000000A9A0BCB0ADA009F0EB0009A900B009AC000000000009A0F0090000000000000000000000000009000000000000000000009000000900090B9AFBDBFFDBF9FDBDFF9F9FFDBF9BDB9BD0B09000000900000000000000000000000000009000000900090009009ADA0B90BCB000090900009C0D00000000090B0009000090000000000000000090000000000000000000000000000000090B9CB9DBFF99F9FB9F9B9FFFB9BF9BE9F0BCBD0B9B9090900900000000000000000000000000000000000B0A9A9A9A09A9E0AD0B09009ACA00000090090000009000090000000009000000000000900000000000000000000000000000000090909B9EBDB9FBFFBCFBFFFBDBDFF9EF9F9FDBB9BD0D0B000000009000090000000000000000000000009090090000009A090900A000A9A90909000000C00090000000000000000000090000090000000000009000000900000000000000900900A9DA9F9F9FF0F9BDB9F9BDBEBF9BD9B9E9B9C99A9A09090900000000000000000000000000000090000A00B00B09A9A09A0A9A9090900090000090090900000000009000009000000000900009000000000000000000000900000000000000099A99F9B0F9BF9FDB9F9FFF9F9FFFFBEDBCF9B0F9C9B09A00090000900000009000900000090000000000900090A00090009000000009090B090000000E000000000000000000900900900000000000000900000000000000000000900000000009E9ADBBDF9B9B9F0BF9B9FBF9B99F9F9B9EDBCB909C090900000000000090000000000900000000009009A0009090009000900909A00A0000000900009000000000000900000000090000900009000000000000000000000000000000000909AD9BDB9DB0F9E9F9F9BDF9BDBFDEF9F0FDB9B9B9CB0B9090090900000000000000000000000000000000A000A0000000000000000009090900900C0D09C09000000000000900000000009000900000000000900000000000000000000000000099BDB9EB9F9F9B0B9F9FB0F9F0BB9ADB9B09E9E9A9090A00900000009000000000000900000000000009009090000000000000900090000009A090A00C0000009000090000000009000000000000009009000000000000000000000000090099A9A9E99DB9B9BDBDB9E99F9A9BDBDF9AFDF9B99C9B0090900000900000000000000000000000000090009000000900000000000090000909A000C0D0D0F0909000900000000090000090000000009000000009000000000900000000090000009DB99FB90DADA9B9F9FB9B9F9BDBA9F99A9EDB0B0D9A900900900000000009000000000000000000000000900900000000090000009090009090900CAC0C0000000000000000000000000000000000000000000000000000000000000000009A9A9F990F9B99BD0B9090D0F9FCBD9F0BE9F990F9B0A9CA90000000000000000090000000009000000000000000000000000000090000009000E0C0C9C909000900009000900000000000009000000000000000000000000000900000000000909D9ADAF9AD0BD0BD0BDB9F9A9B90B0DF990BAF090D9009009000000009000000000909000000000000009000000000000000000000090B00F0D009A000C090000000009000009000000000009009000000900000000090000000000000000909A9BDB99099F0B90BD9B0B0BD0F9F9B9ADABD99BDA9A9009000090000000000000000000000000000000000000900900000000090090000900DE900D0D000000090090000000000009000000000000000000000090000000000000009000000BC9BC9B0BDA9090F90B0C9D90B90B09CB99D0B09CB90D0B00909000000000000000000000000000000000000090000000000000000000009ADAD00C000009C00000000000090000090000900000000000000000000000000000000000000000909B0B9C99090B9F9AB9F9B0BBD0B9F9B90B0F0F0B0F0B0909000000000000000000000000000900000000000000000000000000000000900C0DAD090C90C00000000000000009090000000000900000090000900000000000000000000000090B90D9A9ACB0BD0909C90B0BD90BD00A9CBDA999099909000000000090000000000000000900000000000000000000000000000000000000009ECF0E00C09000090090000900000000900900000000900000000000000000000000000000090090F9BC90999D9A9ADA9A90D09A9A9FBD0B909F0AD00BCB09090909000000009000090000000000000000000000000000000000000000000090009C90D0900009000000090000000000000000900090000000000000000900000000000000000009090B0B0B00B90999909A9B09C9090BD0F9A9990B00909A00000000000000000000000000000000000000000000000000000000000000000009E9C00CAC09C00000000000000090000900900000000090009000900000000000900000900000B0B090099C9BD0F0B0F9F990DB9BDA909B90D0F09090A9C9090000000000000000000000000000000000000000000000000000000090000000900C09E9090000090900000900900000000900900900900000000000000000000000000000000990D009BDA9A90B9BDB90B0F9B9ADADB9E9EB9B09ADA990B0000900900000000000000000000000000000000000009000000000000000000000000FC000C0C0090C0A009000000000900000000000000000000000000090000000000900000090090B9090999B9C999CBD99BC9F9BDBDE909DADA99090090090000000090000000000000000000009000000000900000900009000000090090000909C9090090009C0D000000000900000009009090909009000900000000000000000000000090B009BE90F0DB9BE9B9ADF9B9BDBBDBFFF0B9BDAC9A9A090090090000000000000000000000000000000000000000000000000900000000009000C00AC0C000C9009000000000000000000009000000000000000000000000000000000000009A099B099B9B90F99B9F9B9BDBDBDFFF9F0FDADA99A9C900B0000000000000000000000000000000000000900000000000000000009000000000909C9C9A90C9000C0E90090000900009000000009000009000000000000000000000000000090990B0D0BC9F9F99BDF9BDFDB9BFFFBDFFFB099F9AD90B09009009000000000000000000000900900000000000000000000900090000090909000CCAC00C00000CB0D0C00000000009000900000000900000000000000000009000000090009A90E909B999B09BDBDB9F9BBFFDF9FDFBF9FDFCB0F90A9000900000009000000000000000000000000000000000000000900000009090000000090B0C9E90D0D0B0C0CBC900090000000000090090000900900900009009000000000000000009099BD09FBDF9BDB9BDB9FD99BFFFFFFDFFFBFBDB0F99E9A909090000000000000000000000000000000000000000000000000000000909009A000C9F0C0CAC00C09C9C0E090000090009000000000900000000000000000000000000000000909F09A9B09B9F9F9F9B9DBBFFFDBFDBFFFFBDFDEDB9E9909C00000900000090000000000000000000000000000000000000009000000000000090C9CC0C90909C9CE9E0C9C00009000900009009A0000000000000000000000000000000000900B09BDBD9F0F9FB9BDBDBFD9BDBDFFFFF9FDFFBDB0F9BCB0B0090000000000000000000000000000000000000000000000000000009000090900CBCA0F0CAC0CAC90C9CBC9E9000000009000000090090900090000000000000009009000000B9DB09B09B99B9D9F9BDB99BFDBFBFFFFFFFBF9FE9F0F0BC9090009000000000000000000000000000000000000000000000000090000090000909C0DC0F090D090E9CAC0C0C0C900900000009000000000000000000000090000000000000090B09F0DBF0BD0BB99F9BDBD9BBDBDBF0DB99FFFDBFF9BD9B0BC9000000900000000000000000000900000000000009000000000000000000900000FC0FC0C0C0E0C9C0D0F09C9A0000000090000900090000000009000000000000000000009A999B9B9099DB9D9E90BDA9B9D99F9E9FBDFFF9FBFDBFCBADBC9A09000000000000000000000000000000000000000000000000000009000000000C0DEC0DAD009C9CA9E0C0CA0C09000900009000000009000000000000090000000000000909ADAD9E9F9FB0B9B99B909909A9B0999BDBBBDBFF9E9E9BD909B090000000000000000000000000000000090000000000000000900000090000909C9E90FC0E9EC0E9C09C9009C9CAD000A00009000090009000000009000090000000000000BD9B90B9B9B09DBE9DBCBB90F990D9F0F9FDFDBF9FFBF9F9EB9FC9E0000000000000090000000000000000000000000000000900000000000000000BCCDC0F0D0DAD0E9CA0C9C0009CAD0909000090900000000000000000000000000090000D0B09F9DA99BDB999B0999CBB9EBB0B9B9E9BFF9FBDF9FDAD9E9AB099900000000000000000000000000090000000000000000000000000000900000C9ACBCCADEADE0D0AD0AC00D0C0D0A000090000A000000000000000000000000000000090B9F9A9B9F0DB9ADBC9BCB99D099D9F9F9BF9F9FFDFB9EBDBBDBD9FCA0000900000000000000090000000000000000000000000000009000000009090EDCCCBDE0D0C9CAD0CD0BC00E9E0D009A00000909000000000000000000000090000090B9DB9DBDA99B9F9B99BF9B9F0BDA9B09FFFDFFFFFFBDFF9FBCBDBF0B90D0000000000000000000090090000000000000000000000000009000000000CD0BB0CE0FCADAD00F000C0C90C9E0F000900900000000900000000000000000000000BD9EB90B09B9F9F09F9F999D099999999F99FFFFFF9FFFBDB9F9FBC9F9E900000000090000000000000009000000000000000000000000000000000000DACCC9E9C0FC0CAD00DAD09ACBC0D00BC00B00090009000000000000900000000000000B99B9F9BD9F9B9F9BB9F9A9B9BD9BDF99F99FFFFFFFDFF0F09BCBF9CBDA900000000000000000000000000009000000009000000000000000000000090DAD9E9CAD0BCF0DAD0C0C0C90CB0E9C9A000900009000000000000000000000000009BDAD9E9BF0B0BDB9BDD99999D9D9F999DB9DBDFFFFFDFF9F9BFFBDBFBF0F0F090000000000000000000000000000000000000000000000000000000090C0DCC0E0D0EC90CAC0E0DAC90E90C9C0E90900A0900000000000000000000900000099E9B9B99F99BDB9BDB9B99F9990909999099FDFDFFFFFB9FB9F9BDBF0F9F990000000000000000000000090000000090000000000000000000090009000CBC0AD0F0D09ECBCBC9C0DA0D0EDA0BC900A009000009000000000000000000000090B9F9FDBF9BF99DBDA99CB09999B9B09BF99999FFFDFFDFD90B9FFBDF9DBDBE90000000000000000000000000000000000000000000000000000000000009CF09EC0E0C090C9CA0F0CD0E90CDC00E9009000B090000000000090000000000000BDA9F9BDBD9BE999BDF9999900B9F9BFFFF099099DFDFBFBDBDB9FFBFFBDADF0F0900000000000000000000000000000000000000000000000000000000900CDC9E9C90F0E9E0DC0CB0C9CE9A9AD00F00A9000000000000000000000000000909F9F9AF9BFBD9BE9B9909090B9BFBFFFBFFFFFF9D9B9FD90B90BFFDFDBFFFFBF0000000000000000000000000900000000000000000000000000000000000F0C9E9E0AC0C9C0F0909CC9E090C0D00F0090009000000000000000000000000009F99BDF99F9DBAD99CB090B9F9FFFFFBFFFFFFFFF00999BFBD9F9FFFFFFDBDFC9C90000000000000000000090000000000000000000000000009000000900D0CBECCD0D09E0F0C0CAC0BC0F0E9E0BC0900090009090000000000000000000009A9AF9B9BF9BBD9B9B909009BFF9FFFF9FFFFBFFFFF0000999A99BDBFBF9FFFFFFB0A000000009000000090000000000000000000000000000000000900000EDFC9E9AC0DA9C0F0F009C0BC0D009C0BCE9000090000000000000000000000000BDBDBDBF9BFDFBD0F090009BDBF9BFBC0BDBD09B90B909000990BDBDFDFFFFF9FDF99000000000000000000000000000900090009000090090000090000090000FE9EC9E0CCBDCD00DA9CC9E0F0E0FC090090000900009000000000000000000DB99BDB99F9B9DB9090000B090090909990909909D0000009A09F9BFFFBFFDBFFE9E0000000000000000000000000000000000000009000000000000009000DED09CC9E0D0BCCA0AD0CCE9A0D0C9D009E0000090000000000000000000000099A9FBDB9DA9B9FB009000909909B90999B0F9BDEF90999F9A9C9999BF9BDFDBFFF9F090000000000000000000000000000000000000000000000000009A000DAD0FECBC9CADE0BCDCADA90CDCADACACFC90009000090000000000000000000009F909F9FBDBDF9DB90B9F090909099090999099999F9FFFFDB09F0BDBFDFBBF9FDFBDA900009000000009000000090000000000000000000000000900009000C0F00BCACBC0DCCB0D00CE9A0F0CD0D00E0900009000000000000000000000000B9FB99A99B9B9B99E90B9F9BCB9DA9DB9FDBDF9FFFFFFF9FFDB09BDBDBB9FDDBFBEDBD00000000000000000009000009009000000000000000900000900009A9DCFDC9C9C0F0E9CCA0D09CC90CB0F0FC900000000900000000000000000000090F9DBD9BD9F0F9BC9BD9B9DB99F999B9F9BDBFFBFDFFFFFF9A9DB099BDDB9FBFDFFDBCB0000000000000000000000000000090000000000000000900000090CCAD0CA0F0CBC0D0E90DA0CA9ACF0CC0C000090900000009000000000009BF0099BB9B9BFDBB9B9B99B90BC9B99F9DBF9F9BDBF9DF9FFFF9F0F99B9DBBDABFDBDFBFFFE90090000000000000000000000009000000000090000000000900000C9AD0F0DC0F0C9CAD0CA09C90CD00DA9EDE90000000900000000000000000BF000BD0F0F09B9C9F9DA90BD99A9F9B9B99B9DB999BBFFFFDFF9F9F0D0B9DB9D9FBFD9FDBDF900000000000000000000900000000000090000009000900000009CBCDED000F00F0E9CAD0D0E0E9A0F0CC090C00090090000000000000000000909090B99B9BD9BB99A9D9F9B09D09BC99F9DA90F9D09B9FDBDF99A99B99F9DBF9DFBFFFFFBEDA900000009000009000000000000000000000000009000000000C0C0E9EFC90C90C9C0D00A0909C0D0DA9ECE90000000000000000000000000000000BDBD9F9B0D9F9DB9B909BF9BD09B0B9B99F90B9FDFBDFA9F9F9F0DB9B9F9FFBDFFFFDFDB00090000000000000000000900900900000090000000000090090D0D9C9C0AC9ACB0E90CBC9CACADACE9CC900009000000090000000000000000909B99CB9AD9F9F09B9AD09BD9090B999D99CB09B9FFFFDBFDF0BD09BB9F9FBDFFDFFFFDFFED0900000000000000000000000000000000000000000009000000C0F0CADECD0C900D00F00CA909C0D09CB0C909000900000000000000000000000009CBB9F9DB9B99F9D99B909B9B99E99A9B9090D9BD9FFDBDBDB9B99DB9F9DBDFFFFFFFFDBBC00900000000000000009000000900000900000090000009009E9C0FCDA9AC9E0FC0F0CF09CEDA9E0DE0CDA00000000000000009000009000009090F9DFF9B99F9F99B9BD9F909D9F99A99009B090B0B90FBDF9BD90F9BDBDBFFFFFFFFFFFFDE9900000000000000000000000000009000009000000900000000C9C0BCFCD0E9C09E0DA0DE0900C9CA9CB09000090000090000000000000000000090BB99BDBF9F99F9BDA99090B0990900990990BC90099DB9BDB0999F9F9F9FDFFFFFFFFDFBCA0909000000000009000000090090000000000000000090090D0E9CC9CBCAD0E9E0DACDE0DACAD0E9C0C000900000000000000000000000000909A9BD9BDBD9BDFBDBDB9DA9B909B09C90B099CB99F0909B9BC909B9F9B9FBFFFFFFFFFFFFED0900000000009000000000000000000900000009000009009AC0C90C9EBC0DAC9C0F0C9E0F0C9DAD0CADA90000000900000000900000000000000090DBF9F9FBDB9DBDBDB9D09AD909B00D9B0B99F999BDFFD9B9B99F99FFFDFFFFFFFFFFFFDFF00090000000000000000000000900000000000000090000C0DCBCDACDCF9C9ACBC0F0E9C0F0AC0AD0D0C0090009000000000000000000000000009B99B9FBDFBDBF9BDBDBBD990B0999B09D99B99BDFFFFFF0D09DB9F99FFFFFFFFFFFFFFFFCDA90000000000000000000000000009000000000090000909C09C0CDA9E0CA0CD09E0D0CBC0DC9ED0E0F090000900000000000000009000000090909FFF9BDBDBDBDBDB9F9D9A999099BD9B9BDDF9FFFFFFFC9B9F9BDBFFFDFFFFFFFFFFFFFFFB00000900000000000000000000000000000900000009000A9EC9EBCDE9F09C9A0E0DACBC0DA9AC0F0DC00009000000000000000000000000900009BF9BDF9FBDBDBDBDF9F9B9DB099AD9BDBF9FBFFFFFFFFDB9DB9F9BDBDFFFFFFFFFFFFFFD90D0090000900000000009000000000009000000000000000DCDAF0D0F0FCC0AC0D0BC90C9E0CCDAD0E9AD090A00009009000000000000000000009A99F9F9FBDB9BDBDB9FBF9F90B0999BDBD9BBDFFFFFFFF0D9B9FFFFFFFBFFFFFFFFFFFFFFFF00000000000000000000000000009000000000000000009ADADC9EF0FCB0D09E0D0ED0F090B00DADCE0C0A09009000000000000000000000000909F9BFBF9DBDF9F9BDF9D9F9BD990F90BDBD9FBFFFFFFFF9BDF9BDBDF9FDFFFFFFFFFFFFFFCBF000000000000009000000000090000000000009000000000DAFE9EF0FE000C0DAD00E0CAC0DA0D0BCDE909000000000000900000000000000000B0BD9F9FBDB9B9F9F9FBF9BDB9E999BDB9BD99FFFFFFFD9BBBFDFFFBFFFFFFFFFFFFFFFFFBD0900000000000000000000000000009000000000000000009ED0FF0FFAD0C9ADAC0DE9C9C9A0C9CACDA9C000090000000000000000000900900099F9FFF9F9F9F9F9BDBF9DBDBDB99A9D99F9B9FFFFFFFFFFDFDFFBFDFDBDBDFFFFFFFFFFFDF9E00090000000000000000000000000000900000000900900CB0FE0FF0FF90C00D0F00C0A00D0BCADF0CF09090000090000000000000000000009A99F99FBDBDBDBFDB9F9FBDB9BDBD9B0FB9DBDBDFFFFFFFFFFFBFDFBFFFFFFFFFFFFFFFFFFDE9000000000009000000000000000000000000000000000909CFF9FDAFDAC90E9E00DA0D0C9AC09C00F0CE00000090000090000900000000000009A9FFBDF9F9FDFDF9F9F9BDBF9B9BF999DBD9BDBFFFFFFFFFFFDFFFDF9F99FBDFFFFFFFFFFFF0900000000000000090000000909000000000000000090CAC9CAFAFDAFF00C9C9EDAC90CB0C9ACBCFCE90900090000090000000000000000000009F9FDFBF9B9BD9FB9F9F9BD9F9F90BDB99B9DBDFFFFFFFFFDFFFFFF9F9FFBDFFFFFFFFFFFDE90000000000000000000000000000000000000000000009C9EBDCF0BFCB0E9E0E9C0D0E90C9AC9CBC090000900000000000000000900000000099BDBDBBDDBDBDBFD9B9B99F9F9B99F9A99F9F9BFFFFFFFFFFFFFB9F9F9F9BDBFBFDFFFFFFFE9000000009090000000000900000000000000000009090DE9ECD0EBCFCBFD00D0D0ADAD00DA0D0E9CADE90000000000000000000000000090090009BDBFDBBDBDBDB9FDDBDB99BF9DF9F9DB999F9BFFFFFFFFFFDEDF0F9FBFFFDFDFFFFFFFF9F000000090000000000000000900000900000000000000000C90BC9CDABCF0CF0ACD0C0ECD0DAC9CE9C0000900000090000009000000000000000090BBDBFDBF9F9BDA9BBDA9F099A9B09B99F9F9FDFFFFFFFFFCB9B9F9F9DFFFFBFFFFFBFFFE9090090000000000000009000000900000000000090000090FCDCBCBCDCBC090DC9ADAD09AC0C9E0DCBDE900009000000000000000000000000000009FFBDBDBBDBDB9D0909D09E9D99F9D9F9BDB9BFFFFFFF99BDBC9090B90B9BDFFDFFFFFFD000000000000000000000000000000000000090000009000C0000C0C9E9EFCAC0A0CC0CBCC9E9E0D0AC00000000000000000000000000000000000909B9F9B9BDB9BD9A9A990B0990B0B9AB9BDBDFFFFFFDD0BC990A90B090B9FEFF9FBFDFA9000000000000000000000000000000000000000000000000090DAD0DAD0FC99C9C9CB0F0C0BC0C0DACD0FC9090000000090000000000000000900000909FCBF9F90F9A99D99A9090A90909D0D9BDBF9FFFFEB909A09909C99F9F9F9FFFDBFBDB00090000000000090000000000900000000000000900000900C0C00CDAC9EF0CAC00C90DAC0BCBC0DACD00E000900090000090000000900000000000090BBDBCBFB9D9B0B09099A9909090B9B9DBDBFFFFFD0E909000909A09B0FDFBDEBCBDBC09000000900000000000000090000000000000000000000000900DA0CDAD0FF0D09E9CA0D0D0D0DE0D9ADF090000900000000000000000000000000090099B9B99DB9A9D090B009000A909099FBFBDFFFFDA9909090B9A999CDFBF0F9999B9A0900000000000000000009000000000000000000000009000000C90CD00DE9EC0CAC9C0CDACACACA0D0ECC000009000000000000000000000000000000090B9F0B0B0BD909BC90BD09990B090F99BDFFFFDF090B009090000AFB0D099A09ADBC900000000000000000000000000900000000009000000000000000C90EDE9ED0F0D00ADA0C9C9C9CDAC9E9ED09A0000090000000000000000000000000000909D090900B0F00090BFA00909A99BFDBFFFFE99F00090F0009090DF000099F9B0B0000090000000090000000000000009090000000900000000909C90CC9C0DEBD0CAC9C0D09AC0FCBCDAC9E9CA0D09000000090009000000000090000090090B0B90909090B0900009DF00909099BBDBFFF9E099090BC9000000A9009B090F0D0900000000000000000900000900000000009000000009090C0000C9A0CBCBCDCAD09C09A0E09E00C0ADF0CCB0DA000900909000000000000000000000000000990B0B000BC0000F0BE009A909A9F9FFFFFF99A09009A00909090009E909B90B000000000000000000000000000000000000009000090000C90F0D0C0D0CDCBE09C0E0BC0D0D0C9EDADC0EDBCDE090B0C9A000000000000000000000000000909AD090900900909A090990090B9DBBDBFFF9E009009000000000009E909E9CB009000000000009000000000000009090A90900000900000DA0C0C000D0CBCBED0CBC9C0BC0CA9E090DCAFDAC0E9E000AB0C0000000000000000000000000000909A90099C000000900000900099B9FFBF9FF90909009009000009FE90A99A90900090000000000000000000900000009000000000000090009009E9C0E9CBC9FE9CAC9C0DA9C09CECA9C0EDBE9C9F0DDEB090000000000000000000000000000909ADB0B09090000099B009090F9B9F9FFBDF9CA090090009C9FBD00990BCB009000000090000000000009000900000009009009000000090C9C00C9C0C9CF0F90D0DA9CADC0FCA90DCBC9E0DE9ECBFAFC000090000000000000000000000000090909009BDAD9CB9A0009A09B99FFBFF9F0B9B0900909B0B9A0009BCBF0909000000000000000000000000000009000000000900090000C00009C000DACBCFCCACAC0CE9CAFC09CFCAC9ECDE9ECBDAFC090A000000090000000000000900000909A90B09009A0B000909009B09FB99F9FF9F00900900000900909A09009000000000000000000000009000000000009000900000900909090D0C090D0C9CBCB0D0DAD09CAD0ADE009CBED0F0EDBEFFF900D9C90000000000000000000000000090990D9E0909900900909909DB99FBFF9F90DB0090909090090B09090900000000090000000090000000000090000000900090000000C00C000900E0DACF0FE0E9C0ADAD0FCFADEDE9C9ADAF9EDFBEFEF0A9A009000000000000000000000000000A9A990B000990900000B090F99F9B9E9B0900000009090090000000000000000000009000000900000000000090000000009009090D09C0C0AD0D0D0DE9FC9CADCC00E0F0DADACADEFFDEFBFAFFBDADFED0000000000000000000000009009099090A9090900000900009FB9BF9FFF9F9DAD000000000090909000000090000000000000000000000090000090009090900000000E0C00909C000C0F0DE99CAD00BCF0D0FEF0E9DEBEBEBFEFFFFFEDFADA09A09000000000000000000000000000909090000090000999B999F9FBF9DA9B99A90900000000000000000000009000090000000000009000090000900000000000009C909C00C09CF0F0DE9EE9C0FCC90DAD0D0ED0E9FDFFFFBFFFEFFADFAD009000000090000000000000000909B0009000900009090BE9DADB9F9F9FB9F0F09000090090000000000000000000000000090009009000000000B00900090090009C000C00D090C00D0CF0FFCBED0BCE0C0ADADBEDE0CBEFFEFFEFFBFFEBDA0009009000000000000000000000909B9A09000090CA9C9D9B9B9F9FBDF9F9DB9F9BD9F090090000000000000000009000000000000000000900D00D00A90000009009CD09C00C0C9C0C9E0F0FADCBEC90DADC0CAC9ADCBCBFBFFFFFFEFFBFE0D000A900000000000000000000000909C99A9DBDA999B9FB9FDF9BDBDBFF9BBDB9E90B00090000000000900900000000000000000000000000C9A9FA9ED009090000C0A00C09C00B00BCE9CDADDFAFC9EDE0C9E9C9EDCBCFDFEFFFFBFFFFEFE9000900000000000000009000009090B9B9B9DB9BF9FBDFB9DB9B9FBFFFF9FFDBDF9B9009000900900000000000000000009000000000009000FADFCBDE90F000090090D0D00C090C0DC09CFADFEADBFE9E9CBC0E9E9EADC9AFFFEFFEFFFFFF9E90009A090000000000000000000009099ADB09F99BF9FBDFFBFDF9F9F9FFF9BF0B9FC9009000000090000000000000000000009000000000900DEBFEFBEF0DCB0000C0000D090C09C00FCB0DFA9DECBFEBEDCBC90C0DCACFC9FFFFFFFFEBFEFEFE9009000000000000000000009090B0D9BDBDBF9DBF9FB9BD9FBFBF9FB9FF9F9F09B00000000000000000000000000000009000000090000090DFBFFE9EDACC9CA909C000C090C00D00DCF0DFCADBF0FFFABC0EDADA9CBCBEBFFFFFFFFFFFBFC9000009009000000000000000000909B90B9B99FBD9FBDFFBFBDBDBDBCB9DA9BDB0009000000000000000000009009000000000000000000000FAFFFBFDAD0F0C9C0C09C900C09CDACD0E9EBC9C9ECFFF0FCDE90CC9EFC9EDFEFFEFFEFFFFFCB000909A00000090000000900000909B09F9FF9FB9FBDBDB99F9FDFFBDBD9A9D090909000000000000000000000000009000000000900009000DBDFAFCFADAD0C9C0C90C000D09C000DAC9CBCFCBCF9E9EF0FA9EDEBCC0BCDADBFFFFFFFFFEFBC0900000000000000090000000090909DA9B99B9DBDFBDBDBF9F9B9BDBDBC9B09A90000009009000000900009000000000000000900009000090FAFFBF0FC0C9CAC90C090D000CA0DC0DADEDF0EDACBCF9EFDECBC9CBDCCADCADFBFFFFFEFFFEF00009009000000000000000000009A999F0F9FBBDB9FB9BDB9F9F9CB9A9B00909090000000000000900000000000000000000900000000C0000DFFFFFF0FDE0DC0CB0C000D0D0D00F0CD0F0FFFADFCF0F9FAFBCFACCADADADCFAFFFEFBFFFFFF0F09009000900000000000000000009A99B9B0DDBDBDBDBF9DB9EB99F9D0090B000000000000000000000000000000900900000009000900909EBFFEBCF0C0D009C0C90D000C00C9C9CAD0F0FFFFAFBFEF0FFCF0CDADAD0C0DADFEFFFFFBEFBEF0000000000000900000000000090909DA9DBDBBB9B9F9F99BBD99DB09B0909009090090000000000009000000090000000000000009000000CBFFFBDF0DAD0E9C009C00C0D00D0C0CADCF0FFFBFFFEFBFFEBE9EF0D0DE0F9EDADBFFFEFFFFFFDF0909009000000000000000090009A9BDB9F9F9DBDBDB9DBC99A9B0F09A000900000000000000900000000090000000000090090000009000BDFFFFEBEDC0D0C09C00D09E09E0DAD0DADADF0FEFFFFFEFBDF9E9EBCE0DCCC00DECBFFFFFFFFFAFC0A090000000000000000000000090090B9B9BBDB9BDBB9B9BD0990909090090000000000090000000000000000090000000000000000090CBFFFFFCBCBC0D0C09C00E09C0D00D0E0D0F0FFFFFEBFFDFEEBEFFDEDBDADA9FCAD9FCBFFEFFEFFF090000000000000000900000000909B9BDBDBC9B9F9BD0F9F9A9F09A900090009000900000000090000000000000000090000009009000009EFFFFFBCBCCBC0BCC09C9C00D0CD0C9DE9CF0FFFBFFDAFADBDFBFAFACECADCC0D0ECBEFFBFFFFADAC090009000000000000000009009B0D099B99BDB9BE9B9B0D9900900909090000000000000000000000000009000000000000000B009CC9FFFFEFBCFCC90C9C0A9C000CD00F00FCE0DE9FC9EFCBEDADAFAFEFFFFBDBDADADE9C9CD0FFFFFFFEF9C00900000000000000000000090099BCBDBBDBDAD99BC99A009B09000000000000000000000000000090000000900000090009000000BCFBFFBFEF9E9ED0C0D0C09CD0A9C0CD0D0DE9EFBE9EBC9EDEDFFFBFFFFFEFEDADADE9E0FC9EFBEFFFAFBC00000000000000000000000090A09B09C9B9B9BBD9BC999A090090900090000000000000000000000000000000900000000000900009EFFFFFBFE9C00D0C0C9C00AD0C9C9ACADA9E9CFCFC9EF0FBFAFFFEBFEFFBFFFFFE9EDBCBCBDFFFFBFFCA9000009000000000000000090999009B9BC9BD0D0B90B00900090000900009000090090009000900000090000000900000909000900CBFFFFFFCBEDED0E90D0AD0D0C9CACD0DCDE9EFB0F0FE9FBEFFFAFFFFFBFFFAFFAFFFBEDF0FEFBFEFEDA90090000000000000000090000000A990D09BD9B9B9A900B09090090000000009000000000000000000000000000000000900000000DBFFFFFFEBF0D00D0CC00D0C0C9E0C9C9E9E9EDBCF0F9FFEFFFBFFFFFFFFEFFFFFFFBEFFBEFDBEFFFFBFFC0000000000009000000000009090900B9B099A909C9090900000000090090000000000000000000900900009009000900000000900ADBFFFFFFFCF0CF0D09AD0D0F0C9C9CADCF0DEAFFFFEFAF9FAFEFFFFFFFFFFFFFFFFFFFFFFBEFFBFFFEFBF090000090000000000000000000909009CB0D9BDA99A090090090090000000000000000900000000000090000000000000000900090EFFFFFFFBF0F0C0CC0C0C0C0D0C9E9C0E9EBDF0FFAFBFFEFFFBFFEFBEFFFFBFEFFEFFFEFFFFBFFEFFFBCF00090000000000000000000009000090B099A9C9900900090090000000000009000900000009000000000090090090009000900090DBFFFFFFFFFE9E9CB0D0DAD0D0E9C0C9E9C9CE9FFFDFFCFBFFFFFFFFFFFFFEFFFBFFFFBFFEFFFEFFFBFCFB0900000000000000000000000000090090B090B09A9009000000000090000000000000000000090009000000000000900090000B0EFFFFFFFFFFE9CD0D0C0C0D0E0C9C0CDADCFEFBFFAAF0FBEFFAFFFFFFFFFBFFFFFFFFFFFFFFFFFFFBFEFBFC0A0900000900000000000009000900900909A90B00900090090009000090000000000900000000000000900009000A0090090AD0FDBFFFFFFFFFFFE0C0C9CBC00D0D0D0F0CDA0DADADFFBFEFFBFFFFEBFFFBFFFFFFFFFFFFFFBFFBFFFFFFFEBF09000009000090000000000000000000900090909000900000000000000090009000000090000000000000000009090000000DADAFFFFFFFFFFFFF9F0F0C0C9C90C0CAD0DACDE9CFFAFFEFFBFEFFFFFFFEFFEFFFFBFEFBFFEFFFFEFFFFFFFFFC90090900000000090009000000000900009000090909000900090000000000000000000000090090000000900000000009009AFFFFFFFFFFFFFFFFECD0C9C90CAC9E9C0C0D0F0FBCBDFFFBFFFFFFFBFFFFFFFBFEFFFFFEFBFFEFFFFFEFBFAFCBC0B0000000000000000000000000000000009090000000000000009000000000000000000000000090900000909AC9090009EFFFBFFFFFFFFFFFFE9F00DAC0C9C9C0C0D0F0F0DECBFFAFFFEFFFBFEFFFFFBFFFFBFFFFFFFFFFFBFFFBFFFFFFBE9000B00000900000000000900000000909000000090009000090000000000000000900009000000000000900000900009000BFFFFFFFFFFFFFFFFFC0FC0D0D0C0C9C9CAD0CCFADBFCBFFFFFFFFFFFFFEBFFFFFFFFFFFBFFFFBFFFFFFFFFFFEFF0900090000000000000000000000000000000009000000000000000000000009000000000000009000000000900009000090BDAFFFFFFFFFFFFFFBFC0D0C0CB0CBC0E9C0DA9CDACBFCFFFBFFBEFFBFFFFFEFBEFFFFAFFFFFEFFFFFEFFFAFFBDAC009000900000090000000000009000000000000009000009000000900000900000000900009000000000009009000009000CBFFFFFFFFFFFFFFFEDAD0F0D0C0D0C9C0D0EDCB0FDADBFFFFFFFFFFFFFFFFFFFFFBFFFFFEFBFFFEBFFFFFFFEFFE90900090000000000000000000000000000000000000000000000000000000000000000000000000090009000AC0090B000DBFFFFFFFFFFFFFFFADAD0C0C0C0D0C9C0DAC9CADEDAFFFAFFFAFFFBFEFBFFBFFFFFEFFFFFFFFFFFFFFFFAFFFFFAD00009A00000000000000000000000000000090000000009000000000000000000009000000000009000000090909A000000BCBFFFFFFFFFFFFFFF0DC0D0DAD0CB0CBC0D0E9DCB0FDADFFFFFFFFFFFFFFEFFFFFFFFFFFBFFFFFFFFFBFFFFFFFFEFC00090B09090000000900000000000000000009000000000000900000900000900000009000090000900000000009090900BFFFFFFFFFFFFFFEFF0DAC9C0C9CC9C0D0C9CCADEDAFFAFFFFFFBEFFBFFFFFFEBFFFFBEFFFFFFEBFFFFFFFFEFFFF0B0900000000009000000000900000000000000000900000000000000000090000000009009000000000909000909000000DFFFFFFFFFFFFFFFFBCF0C9E0D0E09C0D0F0E9AD0F0FCBDFFFFFFFFFFFFFFBFFFFFBFFFFFFEFBFFFFFEFFBFFBFFF0FC000909000000000000000000000000000000000000000000000000000000000000000000000000900000009000000B09FBFFFFFFFFFFFFFFFFDE9ED0C9C0C9C0F0C0C9CDCF0FCBFFAFBEFFFFFFFEFFFFFFFFFFFFFBFFFFFFFFFFFFEFFFFEFFBDE9000009000000000000000000000000900000000009000000000090000000009009000000900000000000000009000AFFFFFFFFFFFFFFFFFEF0CD0C9C0D0C0D0C9C9CE0F0FCBF0FFFFFFBFFFBFFFFFEFFFFEFFFFFFFFFFFFFFBFFFFFFFBFEFBCA9090000900000000000000000000900000900000000000000090000900009000000009000000009000B0090900009FFFFFFFFFFFFFFFFFFFBF0ADAC9E0DAC0DAC9E90F0F0FCFF0FFFFFFEFFEFFBFFFBFFFFFBEFFFFFFEBFEFFFFFBFFFFFFBCF9C0A09000000009009000000009000000000009000000090090000000000900000900000000000000900000000099FFFFFFFFFFFFFFFFFFFFFCFD0C9C0D0C9C0D0C0CDC9CF9ADAFFFFFFFFFFFFFFFFFFFBFFFFFBEFBFFFFFFFFFFFFEFFFFBEFBCA909000000900000009000000000000000000000000000000000000000000000000900000009009000909009090FFFFFFFFFFFFFFFFFFFFFEBC0C9CAD0C9C0F0C9CBCADEBCFFFFBFFFBFFBFFBFFFBFFFEFFFFFFFFEFFFFFBFFEFFFFFBEFFFFCF90C009090000000000000000000000000000000000000000009000000900009009000009090090000000000000BFFFFFFFFFFFFFFFFFFFFFBCBCBC9C0D0E9C0D0E9C9DE9CFBCBCFFBEFFFFFFFEFFEFFFFFFBFFFFFFFBFFFFFFBFFFFFFFFFFBFAFB0900000009009000000900000000000900000000090000000000000000000000000900000000009000090909FFFFFFFFFFFFFFFFFFFFFFDFC9C0C9C0D0C9C0D0CAC0DE9CFBFBFFFFFFFEFFFFBFFFBFFBFEFFBFFFFFFFEFFFFFFBFFFFFAFFFFDE9E0909000000000000000000009000000000090900009000000000000090000009000000900900009090000FFFFFFFFFFFFFFFFFFFFFFFFADE9CBC0D00D0E9C9C9CFA9EF0FCFFFFFFBFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFEFFEBFFFEFBEBE09000090000000900000090000000000009000000000000009009000000000000000900000009A9000000FBFFFFFFFFFFFFFFFFFFFFFEBCD0C9C0DACDAC9C0E9ED0DCF0FBFFAFFFFFFFFBFFFFBFEFFFFFFFFFFFFEFFFBFFAFFFFFFFFFFFFFFDBDA09000009000000009000000009000000000000000000000000000000000900009000909090000000090FFFFFFFFFFFFFFFFFFFFFFFDFCADAC9C0D00D0C9C9CCBCEB0FEDADFFFFFFFBFFFFEFFFFFFBFFBFFFFEFFFBFFFFFFFFFFFFFFFFBEFEFADBC09000009000900000000000000090000000000000000000000000000000090000000000C90C9C90CBFFFFFFFFFFFFFFFFFFFFFFFBE9D0D0CBC0D0C9CAD0D0C9CDE9FBFBFFFBEFFFFEFFFFFFFBFEFFFFFFFFBFFFFEFFFFFBFFBFEFBFFFBFBDBCA9000000000000900000000000000000000900090000900000009000900000000090000B000B0A00BFFFFFFFFFFFFFFFFFFFFFFFFEFCED0E9C0DAD0E9C0F0ADE9ADE9EDEFFFFFFEFFFFBFFFFFFFFFEFFFBFFFFBFFFBFFFFFEFFFFFEFFFFFFEFE9009000000000000090090000000000900000000000000900000000000000000900009000BC0009FFFFFFFFFFFFFFFFFFFFFFFFFFF9E90C9C0D0C0C9C0D0CDC9EDE9EFBFBFFFFBFFFFFFFFEBFFFFFBFFFEFFFFEFFFFFEFFFFFFFBFFFEBFEFBF9EF0090000900000000000909090900000000000000000000000000000000900000090090009090AFFFFFFFFFFFFFFFFFFFFFFFFFFFE9CF0C9E0C9C9C0DAC9CBC9E9FF0FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFBFFFBFCFF9EDA0090000000900000000000000000000000000090000000000000009000090000000090000DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9CD0C9C0E9CBC0D0E9CFCBC0FFBFFFFFFFFFBFFFFBFFFFAFFFFFFFFFBFFFFFFFFFFFBFFEFFFFFFFFFFBEFFAD090000009000000090000000900090000090000000009009000090000000000909000090FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCF0E9C0D0D0C0D0C9CCBCBCFF0FCBFFFBEFFFFFFEFFFFFFFFFBFEBFFFEFFFFEFBFFFEFFBFFFFFFFEFFAFFDBCF0C000000000000900000090000000090000000000000000000000000090009000009090CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF0C9CAD0E0D0D0ADACBC9CBF0FBFFFFFFFFBEFFFFFFFEFFFFFFFFFFBFFFFBFFFFFFFFFFFFFFEFBFFBFFFBEFBFA909090000090000009000000000000000000000090000000090000000000000090000BBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FD00D0C9C0DACD0C9C0FED0FDE9EBFFFFFFFFFBFFFBFFBFFFFFFFFFFFFFFFFFFFFBFFFFFFBFFFFFFFFFFFBCFCBCA000000000000900900900090000000000000000000000000000900090090000090CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFC0CF0C9C0D0C90C9CADD09EF0FBFFFFFFFFFFFFFFFFFFFFFFAFFFFFFFBFFFFFFFEFFFFEFFFFFFFFFFEBFFEFFBFCB09090000000000000A000900009000009000000000009000009000000000090900BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF9F0C9E0D00F0CDAC9D0EDE9CFADE9FFFFFBFFBFFFFFFFFFFFFFFFFFFEFFFEFFFFFFFFFFFFFFFFEFFFFFEFFBFFCBC9C0009000090009090900000000009000000000090000000000000900909000ACBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9E0C9C0DACD0CF00DACE9CBCBE9FBFFFFFFFFFFFEFFFFFFEFFFFFEFBFFFFFFFBFFFFFFFFFBEFFBFFBFFFFBFFEBFFFFBE9009000000000000B00900000000000000900000000009000900000000909BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED0DAC90C90C90CD0C9DE9CF0DFCFBFFFFEFFFEFFFFFFBFFBFFFFFFFFFFFFBFEFFBFEFBFFFFFFFFFFFFFFFFFFFEBCBCBCBC0000000090090000009000000000900000000900900900E0009000000CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBCD0D0ED0CBCC90E9CA0DE9EFAFBDEFFFBFFFBFFBFFBEFFFFFFFFBFFFBFFFFFFFFFFFFFFFFFBFFFFFEFBFFEBFFBFFFFFBE9AD0900900A9009090000090000000000000000000000090900009000DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBEDADE0D00D0C90E9C0DCDE9E9CDBCFBFFFFFFFFFFFFFFFFFFFFEFFFFFFFFBFFFFFFFFFFFFFFFFFEFFFFFEFFFFFFFFFBFBFFFF0B009A0990C9AC00090000090000090090090009090000009000C9FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDAD0C9C0DE0D0C9C0DA9E9CBDEBEFBFFFEFFBFFFFFFFFFFFFFFBFFFEBFFEFFFFBFFFFFFFEBFFFFFFFBFFFFFFFFFFAFFFFFBFBFEBC09FACB9E9BC9000900009090000000000900000909000090B0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCBC9CBC09C0F0C0F0CD0DE9E9F9EDAFFFFFFFEBFFEBFFFBFFFFFFFFFFFFFFFEFFFEFFFFFFFFFFFBFFFFFFBFFFFFFBFFBFFFFFBFB9A9DACB9EBFA9E0C0900000000000900000900000090090CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9E0C9CC9C0D0D0DACF0DE9ECFBFFFFFBFFFFFFFFFFFFFEFFFFFBFFFFBFFFFFFFBFFFBFFFEBFFFFFEFFFEFFEBFFFFBFFFFBFFFFEDABDBFEFDADE9FBCA9A909009090009000009000000F0FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FC9C9E09C09CBC0D0D0DADE9BCF0FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFEFBFFFBFFFFFBFBFDE9FBFBFFBFFCBDAC00A09000000000090009090F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF9E0D0C9EC9C0C0F0CBCBCF0FCFBFFFFFFEBFFFFFBFFBFFFBFFAFFFBFFFEFFFFFFFFFEFFFFFFFEFFBFFFFFFFFFFBFFFBFFFFFBFFFFAFBEFFFEDAFEBFFEDBF09C0009A90900000000ACBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC0D9E0D009CAD0D0C9CE9E9EDBBCFBFFFFFFFFFAFFFFEFFFFFFFFFFEFBFFFFFFFFFFBFFFFFFFFBFFFFFFFFFFFFFFFBFFFFBFFFFFBFFFFBFBFBFDBDFAFBE9EF0BDAD00C0AD09000D09FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE0D0CDCC9C0DAD0F0DCDE9ECFBDEFFFBFFFBFFFFFFFFBFFFFFFFFFFFFFBFEBFFEFFFFFAFFFFFFFEFFFEFFFFFEFBFFBFFFFFFFBFFBFBFFFEFFAFFBFFFFFF0FCADAF0BFCAACC99AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0BD0C9A009C09C0D0CDADA9E9F0FBFBFFFFFFFFFFFBFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFBFFFFFFFBFFFBFFFFFFFBFFBFFFBFFFFFFEFBFBFBFFAFFFBEF0FFADBFCBFCBFDFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FCCCBCDCFC0BCC9CADADADCFDAFDEFFFFFFFEFFBFFEFFFFEFBFFFFFFFFBFFFFFFBFFFBFFFFFFEFFBFFFFFFFEFFBFBFFFFFFBFFFFBFBFBFFEFFEBFFFBFFBFFBCFBCEBDEBCFAFEBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9A9C00000DC9AC0D0C9CFADADEBDBFFFBFFFFFFFFFFFFBFFFFFEFFFFEFFFBFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFBFBFFFFFFFFFFFFFFBFBFFFFBFFFFFFADBCFBDEBDFBFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9FCD0DEDCD00CC9CBCBCF0DCBCBDEBFFFFFFFBFFFFBFFFFFFFFFBFFFBFFFFEFFFEFFFFFFFBEFFFFFEFFFEFFFFFFEFFFFFFBFFBFBFFFFBFBFFFFBFFFFFFFFEFFEBEDEBCAFCBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E9E0909AC909C90CD0CF0BCBDEBDEBFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFBFFFFFFBFFFFBFFFBFFFFFBFFBFFFFFFFFFBFBFFFFFFFFFFFFFFFFFBE9E9EBCBFDBEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F9C0DCCCC9ECCACC9ACF9EDEDE9EBFFFFFBFFFBFFFFFFBFFBFFFFFFFFFFFBFFBFFBFFFFFFFFFFFFFFFFFFFFFFFFFBFFBFFFFFFFFFFFFFFFFFFFFFFFFFFAFE9EDBCF9EDAFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE9C00B09C909C9BCD90CF09E9FDFBFFFFEFFFFEFBFEFFEFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFFEFBFFFBFBFBFBFFFFFFFFFFFFFFFFFFDBDE9ECBCE9EDADEFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD0FCDCC0CCD0CC00ECF0CFCBCBE9FFFFFFFFFFFFFFFFFFFFFEFFBFFBFEFFFEFFFEFFFEFFEBFFEBFFEFBFEBFFFFBFFFBFFFFFFFFFBFFFFFFFFFFFFFEFBEF0FCBDE9FCBCFBFFEFBEFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBECF00090B09A090DD09CF9CBCFE9FEBFFFBFFBFFFFFFBFFBFFBFFFFFFFFBFFBFFBFFBFFBFFFFFFFFBFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFBFBCF9EDADA0F0ADA9E9ADBEDBEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED90DCFCCCCCCDECCACDE9CADCB9EDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFBFFFFBFBFBFBFFFFFFFFFFFFBFEFFBECB0DCEDCEDCEDCEFCE9EDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0EC0009090900909CBC0CED0FCFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFBFFFFFFFFFFFFFFFFFFBFFBFBEDBFCFAD9E9DAD9E9DADBC9ECBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9DEDCCDCCCDCCD0DCBDBDADADADEBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE9E9CAC9E0DAC9E0DAC9E9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0CA900B00B00B00E00C0C0DADADBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDEFDEFDEFDEFDFFFFFFFFFFFFFFF000000000000000000000105000000000000A9AD05FE"); - var encodedString = Encoding.Default.GetString(byteArrayValue); - var base64String = Convert.ToBase64String(byteArrayValue); - - Console.WriteLine("Original length: {0}, Encoding length: {1}, Base65 length: {2}", - byteArrayValue.Length, encodedString.Length, base64String.Length); - - CompareMultipleRuns( - "Convert.FromBase64String", () => Convert.FromBase64String(Convert.ToBase64String(byteArrayValue)), - "Encoding.Default", () => Encoding.Default.GetBytes(Encoding.Default.GetString(byteArrayValue)) - ); - } - - [Test] - public void Compare_Type_test_with_Parse_Func() - { - var testClassWithType = new TestClassWithType { Type = typeof(string) }; - var testClassWithFunc = new TestClassWithFunc { GetValueFn = value => value }; - - CompareMultipleRuns( - "TestClassWithType", () => testClassWithType.GetValue("test"), - "TestClassWithFunc", () => testClassWithFunc.GetValue("test") - ); - } - - - } - - public class TestClassWithType - { - public Type Type { get; set; } - - public object GetValue(string value) - { - if (Type == typeof(string)) - { - return value; - } - - return null; - } - } - - public class TestClassWithFunc - { - public ParseStringDelegate GetValueFn; - - public object GetValue(string value) - { - if (GetValueFn != null) - { - return GetValueFn(value); - } - return null; - } - } + [Ignore("Benchmarks")] + [TestFixture] + public class AdhocFastPerfTests + : PerfTestBase + { + public AdhocFastPerfTests() + { + //this.MultipleIterations = new List { 1000, 10000, 100000, 1000000 }; + this.MultipleIterations = new List { 10000 }; + } + + public static byte[] ToByteArray(string hexString) + { + var numberChars = hexString.Length; + var bytes = new byte[numberChars / 2]; + for (var i = 0; i < numberChars; i += 2) + { + bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); + } + return bytes; + } + + [Test] + public void Compare_small_ConvertBytes() + { + var byteArrayValue = new byte[] { 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, }; + + CompareMultipleRuns( + + "Convert.FromBase64String", () => Convert.FromBase64String(Convert.ToBase64String(byteArrayValue)), + "Encoding.Default", () => Encoding.GetEncoding(0).GetBytes(Encoding.GetEncoding(0).GetString(byteArrayValue)) + ); + } + + [Test] + public void Compare_medium_ConvertBytes() + { + var byteArrayValue = ToByteArray("151C2F00020000000D000E0014002100FFFFFFFF4269746D617020496D616765005061696E742E506963747572650001050000020000000700000050427275736800000000000000000080540000424D80540000000000007600000028000000C0000000E0000000010004000000000000540000CE0E0000D80E0000000000000000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFB009A00A9009A9AA9A900009AA9ABE9EB0B0BB09A0AB0A9A9B0FA0FA0CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFE9A09A9EBEBFBB0BB0AB09AC9090AB0BCB0BA9E9AA9A90B000009AAB09009BEB0BAD0EB9E9F9B0C0B0FADB0F0BEB0FCBC0BCBFB0F0BBE0B09BA0BBBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFA9DABEBFFFADFFADBF0BEBBAFAF0FBBAB9ADABADBE0AB0BCBFBC090E0A9AFA9BC90BB9AFABEE0BB0FA9ABEBE9B0FBA9AB9A9A0FB09E0BDAFA0DBE9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFB0FABFFFAFAFEABCBAA9F09AF0B9BBCBE9EBE9ADA9A990FAB0000BFA9090B09E0BAF00A9ADAB9BCBE9F0BCF0BE9FA9EB9CA90FBEAF0BFBA9ADBA9ABFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FE99A9FAFFFFEBDA9ADBCBFA9BA9EAFACB0B9AF9A9AFAEB0900BB9A0000A9AF0BBCB0B9E9BADAFAB0BABEBBBC9EAA9EBEABBE90B9B0B0BCBE9A9FADAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFBAFBA9BEBE09ABFEBABAB0F0F0F9DBFBBAFAB0FAF0B090BCBC00090B0B0A0BBE9B0BCA9AF9A9BC9E9FAD00ABAB9FA9CB9C90B0FABFF09ADBFEB00B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCBE9ABDEFBDBBFFCAB0F0D0FB0BBA0ABF0FDA9F0A90009A09A0B00000000D0BDA9AFADA9BDBEBFABABBADABFBDA9E0BEB9EBABE9A9EB0FE9AB09FAFBAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B9E9FABADAFEB0BBDE9BABBA9FEDBBF0BFABC0A900BFE0BC0900B090B0B0BFAFE9A9A900A0B0E9CF0C0B0F0CADABF0F0ABBCB0B0BCBEB0A9AFA9A9E9BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFABA9F9FAF0FCBCAB0BE90EDABBABCBFA090B090FBFEF009A0B00A000F0B00B0BE9EBAF9FBFBBBBABB09FABB0F9AFA9FBCFBCB0E9B9A9FAC9F0BC9F0BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCBF0DA0A0FBEBABBDEF9AFBBADA9CB0A0BCA00BAF0BFFE9BA9009090B09ACBBAFF0BADB0A0BADACBDE9CA0BC0BAAF0FBAEB00B0B9A0F9EB9ABAFABABBEBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0BA9BFBACB9EDAB0BAF9AE9A9FA90900090B0F0BFBFE000CB0A00009A9B0ADB0BE900A99ADABFBABEA99A0BF0F9AF0FF0BFADA0E9BABBEBC90BC9E0BCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9E9AF00FBFEBA9EBBC9A09BCA000A09A9ABCB9BFFEE9AF0B009090BAFBEB9BAF0BAFF9ACB0BFACBDBBE0DBFAF9EB0B0BE909A99B00BF0B0AABCBABDBBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0BA9AFBCBCBBEBBCABAD000090909009AC90B0AA9FF090B0B00A0BC90F090F9EBCB0AF9ABF0B9BAA9CB0A00FAABCBEBDAFAF0E09BE90FBF9CBB0BCA0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF0FBDA0BABE90CB9B0FA9AB000A00B0A9A9A9F9EBFE0BC00090900BA9BEB0BABCB0FB0BCB0FBEBDBFA9E9BFADBCBA9A0BE90BBB0E9AFA90FA00BE9A9BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A0B0EBFBCB9EBBAF0F0BC90B0090000909A9E0BBFEE900B0DA000900FA0B0B0BBE9B0BEB0B0AB0A0F0BBC0A99ABAD0BFF9EB0C009A909EBA9E9F0BCADBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9BDBFBB00BE0BAC9AFA9ABFE09A00909A0BCBA9AEBE90AB00A90A9ABFBE9F00FC9AEBC909ADB9EBFB0BC0B09AE9CB0F0A0A90B9EB090FAB0FA9A0FA90ABFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0A000CBE9BE99BFA90F090AB00000009090F0BFBFE0B0DA900090BCBA90AB0BEB90BAFADBA0FB0EBEBABEBC9AA9A9ABF90FA009A9EB09E9AFADA9CA9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB9FB9A9AE9BEFAF9A9ABEB9EBCB00000A0B0BE9AFF0FA090B00A90B0FADB009BAE9ADBAB0FFB0FBF09BF00B0D0F0EB00AB09EB0DA90A9AF0B0B0CB00B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0A00EBCB9BEB0BA0F0B09AE90B00B00090A909FFF09009A00090A0F9A9BAB0B0BFADA0D0F0B0BA9A9E00AF0A0BA9BC9E909AB09A09A9CA9ADACA90B0BCFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9B9BB0BE9E9E909F0BCBEB90B9CB00900BB0FAABEE0B9E090B0BDBBAF0E90C9AE90B0BAB09AFDABE9ADB9A909A9E00A90E90D0A09E0B09A9A090A00009BFE000909FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0CACBE0BA9A9AB00B0B0BC0BCAB0B0000009AFBE9A9E090A0009ABEFABBAB009BADAF09ABE9ABBDAFBAFA9E9AD090B0A90A0A9CB0900B0DADB0B000900BC90000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB9ADBE9FA9E9EB00F0F9A9E900BCB0B900F90FBEDA9A09090A9A90BC0DB0B09AFB00BCBCB0BCBEB0BDA9E0BC0A0BC090A9090B09A9B00B0A00009000900000000009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00A9AA9A0BF0B0BFBA90ACB0B0F0B0B00A90ABAFE90ADA0A0090DAFB0BA0BC0AFAC0BCB0BADAB0B0FEBA90B00B0900BCA9CB0A00A0000B09090900000000009000009BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9BF0F9FADA0BBFF0E90A99ABCB090B0E9000B9FE90E9009009AFAA9A9A9F0A909BBB0B0BC9A9EBDB0B9E0BCA9000BA009A0090B0909A900A0000000000000000090009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9A9AB0BBF0F0B0B9EBDAE90B0E0BC9AF0B00E9F0A9A9A090A9A9FAFCBB0B0B00FAF0E9AB0B0BAB0F0BBF0B0A9A909A9090A0000000009090000000000090009000000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCBE9AF0F09AFAF0A9EA90A90B090B09A90B0BAF090009A0909BE9BA9AFBBC0A90F0B0A9CB0F0DAFABE0000900000000A0A9090A9A900A0000000000000000000000009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09A9ADBF0BBE9B0BBE90BBCA909A009A9AC9A0BEBA0F0009A0BEBBE09F0009A90BABE090B0B0BABBCB090B000090009090900A090000900009000000090000000009009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9A9F0A00ABE9B0FA09ABC0B9E0A9F9ADA9A9E9D00C90A9000F0BDA0DA0FBBE9E09F9FA0B0E0BCBCBAD0A009000000000000009000000090000000000000000000900000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA9A0B9DA9CB9EB0BDAD0BBC0B09000A90BF0BAA9A9A9009A90BAAFFABBA0A9A9A0A0BDAC9B09A9BE9A909000000000000009000900900000090000000000000000000900FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9ADA0A09AB0A0BE0B0A9E0B00B0B0B0A900F09E09000B000B0BFF0B0F9F9BE9A9E9BEA9BA0DA9E09E9000000000000000000000000000000000000000000000900000009BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE09A9BC9A9CBE9E9F0F0B09A9AD00B09C0B0B0BC9AA9A009A9ADABFADAABABCBCB09EB9C009A9A09B0A00000000009000000000000900000000000000000090000000909C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09A9C00A90A09A9A0A0BCBA0D0A0BC9A9A900BE9AC90090BCBFAFABCBADA9BA9A0A9BCAB0F0B090A0090000090900000009000000000090000000009000900000000000BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFE90A9A90A90B090909A9A0DBA0990B00B9E09F0A9A09A000B0BFDEBE9FBEBEFAD9000B0090A0F0BCB000009000000009000000000000000000000900000000000009000BF0BFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBFFA09000090090000000909A009A0A00B00A90A0F009A09A9ADA0BADBB0A9F09B9A0F0BADB0A990BCB0000900000000000000000000000000009000000000000000000009FE0BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA909090009000000000000000009A00909A09BC0BFF09AC090090BFF0FAE0BF9ABBEE0B0A9F00A900A090090900000090000000000000000000000000000000000009000900BF09FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF909090000000000000000000000900090BF009E00B0BA0A90B0A9AFA9ABA9BFABAD00BFF0900BA9DA0F0B0B00000090900000000000000000000000000000000900000000009A9ED0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000090000000000000900000009000000B0B0B0BECBDA0090CB9EBFF0F009CBBAB0BEBE909E0A9009000B00090000000900000000000000000000000000000000000090000900BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00909000000000900000000000000000009009009A09BF0A090A0B0ABBEBEFAFEBBCB9ADAF00A9AF090A9A9E9009000900000000000000000000000000000000000000900000090009FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09000000900000000000000000000000000000A9A009FEA9BCA9090BB0FFFFABF0BCBEAB0BFEB09E9A0A90009000009000000000000000000000000000000000000000000090090090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000000000000000000000000090000000009000909AF0DA090E0F0FFFEBEDFA9EBA99AF0BF09ABE09009A9A09090000000000000000000000000000000090000000000000000000BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00009009000000900000000900000000000000009A00BF0BA09A99BBFAABFFBB0BE9BCBA90F0FE090BCA9A0009A000000000000000000000000000090000000000900900000000090D0BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9000000000090000000000000000000000000000090A0BC9AD00A000BFBCBCBEF0BAFBCBAB0BABCBAF09009A9A0900900000000000000090000000000000000000000000000000900A9FEFFFFFFFFFFFFFFCBF9FF9FFFFFFFFD99F9FFFFFFFF000900090000000000000900000000000000000000009BEBE90A909E9F0BBFFA9EBC9B0B0BCF09EF0BC9A09A00090000000000000000000000090000000000000000000000090090A99EBFFFFFFFEF9A9BF9FF9F9F0F0BDBFFFB0FB9F09FFFFE00000900000000000000000000000000000000000090BAE900A90BABBAFAFEA9EB0BAAF0FEB00AFBE9A0900909A00000000000000000000000000000000000000000000000000009C0A9FFFFFFFB9DBDFDBFDBFBF9FBDBE999DDB9CB99A990FF090000900000000000000000000000000000000900009FBAF09A09E9E9E90BCB0E9EBDAB0DAF9CAFFE9E0B0A0090909000000000000000000000000000000000000000009000000B0900BFFFE90DB0FBFFDBFDF9FBD9F9BFFABDBFBDBDB0F90900000009090009000900090000000009000000000000A9E90A09F0BFAFAFEBBCB9E9EBF0BAF0AB9BAFA9A0909A00000000000000000000000000000000000000000000000000000000BCBFC9909B0FBDBFFF9FBE9DAF9FDB9DBBDBDBCBF99ADA00000000000000000000000000000000000000000009BEFA09A00BF0BE9A9E0B0A9A9E0B009EF0E0FE9AC90A000900000900000000000000009000000000000000000000000000900B09009ACBF0F9DBDAF9FBDFFBF9ADB9FFBCBDBDBF09F0909090000000000000000000000000000000000000009A9A909AD0B00ADCB0F0900909A9A9E0A90BFFA9EB0A090900090000000090009000000000000000000000000000000009000909009A09909F9FBFFF9F9FF99F9FDF9FB9DBDA9B99DB0B9000000000000000000000000000009000000000000000AF0E90ABCBFBEB0E9A0B00A000900C90000BEF0F9ADA000900000000000000000000000000000090000000000000000000000000090A9F09B9F9BFBFF9BFF9FBBDBDFFB9F9F9FABD9CB0909090000000000000000000000000000000000000909A90A90DA009BCBB0F00F090900B0000B0009AF0AF009A9000000000000000000009000000000000000000900000000000090009009009BFBCBFDBDF9FCB9FBDF9FB9ADF9F9B0D9A9B90000000909009000009009009000000000000009000009E0B0F0A9FAEAB0CB0B000000000900D0009009AF00B000009090000900090090000000000000000000000000090000000000900090BDBC99FBDBFBF9FB9EF9FBFF0F9F0F9ADF9BBD9E9A90900000000000000000000000000000000000000A9A0BCB0ADA009F0EB0009A900B009AC000000000009A0F0090000000000000000000000000009000000000000000000009000000900090B9AFBDBFFDBF9FDBDFF9F9FFDBF9BDB9BD0B09000000900000000000000000000000000009000000900090009009ADA0B90BCB000090900009C0D00000000090B0009000090000000000000000090000000000000000000000000000000090B9CB9DBFF99F9FB9F9B9FFFB9BF9BE9F0BCBD0B9B9090900900000000000000000000000000000000000B0A9A9A9A09A9E0AD0B09009ACA00000090090000009000090000000009000000000000900000000000000000000000000000000090909B9EBDB9FBFFBCFBFFFBDBDFF9EF9F9FDBB9BD0D0B000000009000090000000000000000000000009090090000009A090900A000A9A90909000000C00090000000000000000000090000090000000000009000000900000000000000900900A9DA9F9F9FF0F9BDB9F9BDBEBF9BD9B9E9B9C99A9A09090900000000000000000000000000000090000A00B00B09A9A09A0A9A9090900090000090090900000000009000009000000000900009000000000000000000000900000000000000099A99F9B0F9BF9FDB9F9FFF9F9FFFFBEDBCF9B0F9C9B09A00090000900000009000900000090000000000900090A00090009000000009090B090000000E000000000000000000900900900000000000000900000000000000000000900000000009E9ADBBDF9B9B9F0BF9B9FBF9B99F9F9B9EDBCB909C090900000000000090000000000900000000009009A0009090009000900909A00A0000000900009000000000000900000000090000900009000000000000000000000000000000000909AD9BDB9DB0F9E9F9F9BDF9BDBFDEF9F0FDB9B9B9CB0B9090090900000000000000000000000000000000A000A0000000000000000009090900900C0D09C09000000000000900000000009000900000000000900000000000000000000000000099BDB9EB9F9F9B0B9F9FB0F9F0BB9ADB9B09E9E9A9090A00900000009000000000000900000000000009009090000000000000900090000009A090A00C0000009000090000000009000000000000009009000000000000000000000000090099A9A9E99DB9B9BDBDB9E99F9A9BDBDF9AFDF9B99C9B0090900000900000000000000000000000000090009000000900000000000090000909A000C0D0D0F0909000900000000090000090000000009000000009000000000900000000090000009DB99FB90DADA9B9F9FB9B9F9BDBA9F99A9EDB0B0D9A900900900000000009000000000000000000000000900900000000090000009090009090900CAC0C0000000000000000000000000000000000000000000000000000000000000000009A9A9F990F9B99BD0B9090D0F9FCBD9F0BE9F990F9B0A9CA90000000000000000090000000009000000000000000000000000000090000009000E0C0C9C909000900009000900000000000009000000000000000000000000000900000000000909D9ADAF9AD0BD0BD0BDB9F9A9B90B0DF990BAF090D9009009000000009000000000909000000000000009000000000000000000000090B00F0D009A000C090000000009000009000000000009009000000900000000090000000000000000909A9BDB99099F0B90BD9B0B0BD0F9F9B9ADABD99BDA9A9009000090000000000000000000000000000000000000900900000000090090000900DE900D0D000000090090000000000009000000000000000000000090000000000000009000000BC9BC9B0BDA9090F90B0C9D90B90B09CB99D0B09CB90D0B00909000000000000000000000000000000000000090000000000000000000009ADAD00C000009C00000000000090000090000900000000000000000000000000000000000000000909B0B9C99090B9F9AB9F9B0BBD0B9F9B90B0F0F0B0F0B0909000000000000000000000000000900000000000000000000000000000000900C0DAD090C90C00000000000000009090000000000900000090000900000000000000000000000090B90D9A9ACB0BD0909C90B0BD90BD00A9CBDA999099909000000000090000000000000000900000000000000000000000000000000000000009ECF0E00C09000090090000900000000900900000000900000000000000000000000000000090090F9BC90999D9A9ADA9A90D09A9A9FBD0B909F0AD00BCB09090909000000009000090000000000000000000000000000000000000000000090009C90D0900009000000090000000000000000900090000000000000000900000000000000000009090B0B0B00B90999909A9B09C9090BD0F9A9990B00909A00000000000000000000000000000000000000000000000000000000000000000009E9C00CAC09C00000000000000090000900900000000090009000900000000000900000900000B0B090099C9BD0F0B0F9F990DB9BDA909B90D0F09090A9C9090000000000000000000000000000000000000000000000000000000090000000900C09E9090000090900000900900000000900900900900000000000000000000000000000000990D009BDA9A90B9BDB90B0F9B9ADADB9E9EB9B09ADA990B0000900900000000000000000000000000000000000009000000000000000000000000FC000C0C0090C0A009000000000900000000000000000000000000090000000000900000090090B9090999B9C999CBD99BC9F9BDBDE909DADA99090090090000000090000000000000000000009000000000900000900009000000090090000909C9090090009C0D000000000900000009009090909009000900000000000000000000000090B009BE90F0DB9BE9B9ADF9B9BDBBDBFFF0B9BDAC9A9A090090090000000000000000000000000000000000000000000000000900000000009000C00AC0C000C9009000000000000000000009000000000000000000000000000000000000009A099B099B9B90F99B9F9B9BDBDBDFFF9F0FDADA99A9C900B0000000000000000000000000000000000000900000000000000000009000000000909C9C9A90C9000C0E90090000900009000000009000009000000000000000000000000000090990B0D0BC9F9F99BDF9BDFDB9BFFFBDFFFB099F9AD90B09009009000000000000000000000900900000000000000000000900090000090909000CCAC00C00000CB0D0C00000000009000900000000900000000000000000009000000090009A90E909B999B09BDBDB9F9BBFFDF9FDFBF9FDFCB0F90A9000900000009000000000000000000000000000000000000000900000009090000000090B0C9E90D0D0B0C0CBC900090000000000090090000900900900009009000000000000000009099BD09FBDF9BDB9BDB9FD99BFFFFFFDFFFBFBDB0F99E9A909090000000000000000000000000000000000000000000000000000000909009A000C9F0C0CAC00C09C9C0E090000090009000000000900000000000000000000000000000000909F09A9B09B9F9F9F9B9DBBFFFDBFDBFFFFBDFDEDB9E9909C00000900000090000000000000000000000000000000000000009000000000000090C9CC0C90909C9CE9E0C9C00009000900009009A0000000000000000000000000000000000900B09BDBD9F0F9FB9BDBDBFD9BDBDFFFFF9FDFFBDB0F9BCB0B0090000000000000000000000000000000000000000000000000000009000090900CBCA0F0CAC0CAC90C9CBC9E9000000009000000090090900090000000000000009009000000B9DB09B09B99B9D9F9BDB99BFDBFBFFFFFFFBF9FE9F0F0BC9090009000000000000000000000000000000000000000000000000090000090000909C0DC0F090D090E9CAC0C0C0C900900000009000000000000000000000090000000000000090B09F0DBF0BD0BB99F9BDBD9BBDBDBF0DB99FFFDBFF9BD9B0BC9000000900000000000000000000900000000000009000000000000000000900000FC0FC0C0C0E0C9C0D0F09C9A0000000090000900090000000009000000000000000000009A999B9B9099DB9D9E90BDA9B9D99F9E9FBDFFF9FBFDBFCBADBC9A09000000000000000000000000000000000000000000000000000009000000000C0DEC0DAD009C9CA9E0C0CA0C09000900009000000009000000000000090000000000000909ADAD9E9F9FB0B9B99B909909A9B0999BDBBBDBFF9E9E9BD909B090000000000000000000000000000000090000000000000000900000090000909C9E90FC0E9EC0E9C09C9009C9CAD000A00009000090009000000009000090000000000000BD9B90B9B9B09DBE9DBCBB90F990D9F0F9FDFDBF9FFBF9F9EB9FC9E0000000000000090000000000000000000000000000000900000000000000000BCCDC0F0D0DAD0E9CA0C9C0009CAD0909000090900000000000000000000000000090000D0B09F9DA99BDB999B0999CBB9EBB0B9B9E9BFF9FBDF9FDAD9E9AB099900000000000000000000000000090000000000000000000000000000900000C9ACBCCADEADE0D0AD0AC00D0C0D0A000090000A000000000000000000000000000000090B9F9A9B9F0DB9ADBC9BCB99D099D9F9F9BF9F9FFDFB9EBDBBDBD9FCA0000900000000000000090000000000000000000000000000009000000009090EDCCCBDE0D0C9CAD0CD0BC00E9E0D009A00000909000000000000000000000090000090B9DB9DBDA99B9F9B99BF9B9F0BDA9B09FFFDFFFFFFBDFF9FBCBDBF0B90D0000000000000000000090090000000000000000000000000009000000000CD0BB0CE0FCADAD00F000C0C90C9E0F000900900000000900000000000000000000000BD9EB90B09B9F9F09F9F999D099999999F99FFFFFF9FFFBDB9F9FBC9F9E900000000090000000000000009000000000000000000000000000000000000DACCC9E9C0FC0CAD00DAD09ACBC0D00BC00B00090009000000000000900000000000000B99B9F9BD9F9B9F9BB9F9A9B9BD9BDF99F99FFFFFFFDFF0F09BCBF9CBDA900000000000000000000000000009000000009000000000000000000000090DAD9E9CAD0BCF0DAD0C0C0C90CB0E9C9A000900009000000000000000000000000009BDAD9E9BF0B0BDB9BDD99999D9D9F999DB9DBDFFFFFDFF9F9BFFBDBFBF0F0F090000000000000000000000000000000000000000000000000000000090C0DCC0E0D0EC90CAC0E0DAC90E90C9C0E90900A0900000000000000000000900000099E9B9B99F99BDB9BDB9B99F9990909999099FDFDFFFFFB9FB9F9BDBF0F9F990000000000000000000000090000000090000000000000000000090009000CBC0AD0F0D09ECBCBC9C0DA0D0EDA0BC900A009000009000000000000000000000090B9F9FDBF9BF99DBDA99CB09999B9B09BF99999FFFDFFDFD90B9FFBDF9DBDBE90000000000000000000000000000000000000000000000000000000000009CF09EC0E0C090C9CA0F0CD0E90CDC00E9009000B090000000000090000000000000BDA9F9BDBD9BE999BDF9999900B9F9BFFFF099099DFDFBFBDBDB9FFBFFBDADF0F0900000000000000000000000000000000000000000000000000000000900CDC9E9C90F0E9E0DC0CB0C9CE9A9AD00F00A9000000000000000000000000000909F9F9AF9BFBD9BE9B9909090B9BFBFFFBFFFFFF9D9B9FD90B90BFFDFDBFFFFBF0000000000000000000000000900000000000000000000000000000000000F0C9E9E0AC0C9C0F0909CC9E090C0D00F0090009000000000000000000000000009F99BDF99F9DBAD99CB090B9F9FFFFFBFFFFFFFFF00999BFBD9F9FFFFFFDBDFC9C90000000000000000000090000000000000000000000000009000000900D0CBECCD0D09E0F0C0CAC0BC0F0E9E0BC0900090009090000000000000000000009A9AF9B9BF9BBD9B9B909009BFF9FFFF9FFFFBFFFFF0000999A99BDBFBF9FFFFFFB0A000000009000000090000000000000000000000000000000000900000EDFC9E9AC0DA9C0F0F009C0BC0D009C0BCE9000090000000000000000000000000BDBDBDBF9BFDFBD0F090009BDBF9BFBC0BDBD09B90B909000990BDBDFDFFFFF9FDF99000000000000000000000000000900090009000090090000090000090000FE9EC9E0CCBDCD00DA9CC9E0F0E0FC090090000900009000000000000000000DB99BDB99F9B9DB9090000B090090909990909909D0000009A09F9BFFFBFFDBFFE9E0000000000000000000000000000000000000009000000000000009000DED09CC9E0D0BCCA0AD0CCE9A0D0C9D009E0000090000000000000000000000099A9FBDB9DA9B9FB009000909909B90999B0F9BDEF90999F9A9C9999BF9BDFDBFFF9F090000000000000000000000000000000000000000000000000009A000DAD0FECBC9CADE0BCDCADA90CDCADACACFC90009000090000000000000000000009F909F9FBDBDF9DB90B9F090909099090999099999F9FFFFDB09F0BDBFDFBBF9FDFBDA900009000000009000000090000000000000000000000000900009000C0F00BCACBC0DCCB0D00CE9A0F0CD0D00E0900009000000000000000000000000B9FB99A99B9B9B99E90B9F9BCB9DA9DB9FDBDF9FFFFFFF9FFDB09BDBDBB9FDDBFBEDBD00000000000000000009000009009000000000000000900000900009A9DCFDC9C9C0F0E9CCA0D09CC90CB0F0FC900000000900000000000000000000090F9DBD9BD9F0F9BC9BD9B9DB99F999B9F9BDBFFBFDFFFFFF9A9DB099BDDB9FBFDFFDBCB0000000000000000000000000000090000000000000000900000090CCAD0CA0F0CBC0D0E90DA0CA9ACF0CC0C000090900000009000000000009BF0099BB9B9BFDBB9B9B99B90BC9B99F9DBF9F9BDBF9DF9FFFF9F0F99B9DBBDABFDBDFBFFFE90090000000000000000000000009000000000090000000000900000C9AD0F0DC0F0C9CAD0CA09C90CD00DA9EDE90000000900000000000000000BF000BD0F0F09B9C9F9DA90BD99A9F9B9B99B9DB999BBFFFFDFF9F9F0D0B9DB9D9FBFD9FDBDF900000000000000000000900000000000090000009000900000009CBCDED000F00F0E9CAD0D0E0E9A0F0CC090C00090090000000000000000000909090B99B9BD9BB99A9D9F9B09D09BC99F9DA90F9D09B9FDBDF99A99B99F9DBF9DFBFFFFFBEDA900000009000009000000000000000000000000009000000000C0C0E9EFC90C90C9C0D00A0909C0D0DA9ECE90000000000000000000000000000000BDBD9F9B0D9F9DB9B909BF9BD09B0B9B99F90B9FDFBDFA9F9F9F0DB9B9F9FFBDFFFFDFDB00090000000000000000000900900900000090000000000090090D0D9C9C0AC9ACB0E90CBC9CACADACE9CC900009000000090000000000000000909B99CB9AD9F9F09B9AD09BD9090B999D99CB09B9FFFFDBFDF0BD09BB9F9FBDFFDFFFFDFFED0900000000000000000000000000000000000000000009000000C0F0CADECD0C900D00F00CA909C0D09CB0C909000900000000000000000000000009CBB9F9DB9B99F9D99B909B9B99E99A9B9090D9BD9FFDBDBDB9B99DB9F9DBDFFFFFFFFDBBC00900000000000000009000000900000900000090000009009E9C0FCDA9AC9E0FC0F0CF09CEDA9E0DE0CDA00000000000000009000009000009090F9DFF9B99F9F99B9BD9F909D9F99A99009B090B0B90FBDF9BD90F9BDBDBFFFFFFFFFFFFDE9900000000000000000000000000009000009000000900000000C9C0BCFCD0E9C09E0DA0DE0900C9CA9CB09000090000090000000000000000000090BB99BDBF9F99F9BDA99090B0990900990990BC90099DB9BDB0999F9F9F9FDFFFFFFFFDFBCA0909000000000009000000090090000000000000000090090D0E9CC9CBCAD0E9E0DACDE0DACAD0E9C0C000900000000000000000000000000909A9BD9BDBD9BDFBDBDB9DA9B909B09C90B099CB99F0909B9BC909B9F9B9FBFFFFFFFFFFFFED0900000000009000000000000000000900000009000009009AC0C90C9EBC0DAC9C0F0C9E0F0C9DAD0CADA90000000900000000900000000000000090DBF9F9FBDB9DBDBDB9D09AD909B00D9B0B99F999BDFFD9B9B99F99FFFDFFFFFFFFFFFFDFF00090000000000000000000000900000000000000090000C0DCBCDACDCF9C9ACBC0F0E9C0F0AC0AD0D0C0090009000000000000000000000000009B99B9FBDFBDBF9BDBDBBD990B0999B09D99B99BDFFFFFF0D09DB9F99FFFFFFFFFFFFFFFFCDA90000000000000000000000000009000000000090000909C09C0CDA9E0CA0CD09E0D0CBC0DC9ED0E0F090000900000000000000009000000090909FFF9BDBDBDBDBDB9F9D9A999099BD9B9BDDF9FFFFFFFC9B9F9BDBFFFDFFFFFFFFFFFFFFFB00000900000000000000000000000000000900000009000A9EC9EBCDE9F09C9A0E0DACBC0DA9AC0F0DC00009000000000000000000000000900009BF9BDF9FBDBDBDBDF9F9B9DB099AD9BDBF9FBFFFFFFFFDB9DB9F9BDBDFFFFFFFFFFFFFFD90D0090000900000000009000000000009000000000000000DCDAF0D0F0FCC0AC0D0BC90C9E0CCDAD0E9AD090A00009009000000000000000000009A99F9F9FBDB9BDBDB9FBF9F90B0999BDBD9BBDFFFFFFFF0D9B9FFFFFFFBFFFFFFFFFFFFFFFF00000000000000000000000000009000000000000000009ADADC9EF0FCB0D09E0D0ED0F090B00DADCE0C0A09009000000000000000000000000909F9BFBF9DBDF9F9BDF9D9F9BD990F90BDBD9FBFFFFFFFF9BDF9BDBDF9FDFFFFFFFFFFFFFFCBF000000000000009000000000090000000000009000000000DAFE9EF0FE000C0DAD00E0CAC0DA0D0BCDE909000000000000900000000000000000B0BD9F9FBDB9B9F9F9FBF9BDB9E999BDB9BD99FFFFFFFD9BBBFDFFFBFFFFFFFFFFFFFFFFFBD0900000000000000000000000000009000000000000000009ED0FF0FFAD0C9ADAC0DE9C9C9A0C9CACDA9C000090000000000000000000900900099F9FFF9F9F9F9F9BDBF9DBDBDB99A9D99F9B9FFFFFFFFFFDFDFFBFDFDBDBDFFFFFFFFFFFDF9E00090000000000000000000000000000900000000900900CB0FE0FF0FF90C00D0F00C0A00D0BCADF0CF09090000090000000000000000000009A99F99FBDBDBDBFDB9F9FBDB9BDBD9B0FB9DBDBDFFFFFFFFFFFBFDFBFFFFFFFFFFFFFFFFFFDE9000000000009000000000000000000000000000000000909CFF9FDAFDAC90E9E00DA0D0C9AC09C00F0CE00000090000090000900000000000009A9FFBDF9F9FDFDF9F9F9BDBF9B9BF999DBD9BDBFFFFFFFFFFFDFFFDF9F99FBDFFFFFFFFFFFF0900000000000000090000000909000000000000000090CAC9CAFAFDAFF00C9C9EDAC90CB0C9ACBCFCE90900090000090000000000000000000009F9FDFBF9B9BD9FB9F9F9BD9F9F90BDB99B9DBDFFFFFFFFFDFFFFFF9F9FFBDFFFFFFFFFFFDE90000000000000000000000000000000000000000000009C9EBDCF0BFCB0E9E0E9C0D0E90C9AC9CBC090000900000000000000000900000000099BDBDBBDDBDBDBFD9B9B99F9F9B99F9A99F9F9BFFFFFFFFFFFFFB9F9F9F9BDBFBFDFFFFFFFE9000000009090000000000900000000000000000009090DE9ECD0EBCFCBFD00D0D0ADAD00DA0D0E9CADE90000000000000000000000000090090009BDBFDBBDBDBDB9FDDBDB99BF9DF9F9DB999F9BFFFFFFFFFFDEDF0F9FBFFFDFDFFFFFFFF9F000000090000000000000000900000900000000000000000C90BC9CDABCF0CF0ACD0C0ECD0DAC9CE9C0000900000090000009000000000000000090BBDBFDBF9F9BDA9BBDA9F099A9B09B99F9F9FDFFFFFFFFFCB9B9F9F9DFFFFBFFFFFBFFFE9090090000000000000009000000900000000000090000090FCDCBCBCDCBC090DC9ADAD09AC0C9E0DCBDE900009000000000000000000000000000009FFBDBDBBDBDB9D0909D09E9D99F9D9F9BDB9BFFFFFFF99BDBC9090B90B9BDFFDFFFFFFD000000000000000000000000000000000000090000009000C0000C0C9E9EFCAC0A0CC0CBCC9E9E0D0AC00000000000000000000000000000000000909B9F9B9BDB9BD9A9A990B0990B0B9AB9BDBDFFFFFFDD0BC990A90B090B9FEFF9FBFDFA9000000000000000000000000000000000000000000000000090DAD0DAD0FC99C9C9CB0F0C0BC0C0DACD0FC9090000000090000000000000000900000909FCBF9F90F9A99D99A9090A90909D0D9BDBF9FFFFEB909A09909C99F9F9F9FFFDBFBDB00090000000000090000000000900000000000000900000900C0C00CDAC9EF0CAC00C90DAC0BCBC0DACD00E000900090000090000000900000000000090BBDBCBFB9D9B0B09099A9909090B9B9DBDBFFFFFD0E909000909A09B0FDFBDEBCBDBC09000000900000000000000090000000000000000000000000900DA0CDAD0FF0D09E9CA0D0D0D0DE0D9ADF090000900000000000000000000000000090099B9B99DB9A9D090B009000A909099FBFBDFFFFDA9909090B9A999CDFBF0F9999B9A0900000000000000000009000000000000000000000009000000C90CD00DE9EC0CAC9C0CDACACACA0D0ECC000009000000000000000000000000000000090B9F0B0B0BD909BC90BD09990B090F99BDFFFFDF090B009090000AFB0D099A09ADBC900000000000000000000000000900000000009000000000000000C90EDE9ED0F0D00ADA0C9C9C9CDAC9E9ED09A0000090000000000000000000000000000909D090900B0F00090BFA00909A99BFDBFFFFE99F00090F0009090DF000099F9B0B0000090000000090000000000000009090000000900000000909C90CC9C0DEBD0CAC9C0D09AC0FCBCDAC9E9CA0D09000000090009000000000090000090090B0B90909090B0900009DF00909099BBDBFFF9E099090BC9000000A9009B090F0D0900000000000000000900000900000000009000000009090C0000C9A0CBCBCDCAD09C09A0E09E00C0ADF0CCB0DA000900909000000000000000000000000000990B0B000BC0000F0BE009A909A9F9FFFFFF99A09009A00909090009E909B90B000000000000000000000000000000000000009000090000C90F0D0C0D0CDCBE09C0E0BC0D0D0C9EDADC0EDBCDE090B0C9A000000000000000000000000000909AD090900900909A090990090B9DBBDBFFF9E009009000000000009E909E9CB009000000000009000000000000009090A90900000900000DA0C0C000D0CBCBED0CBC9C0BC0CA9E090DCAFDAC0E9E000AB0C0000000000000000000000000000909A90099C000000900000900099B9FFBF9FF90909009009000009FE90A99A90900090000000000000000000900000009000000000000090009009E9C0E9CBC9FE9CAC9C0DA9C09CECA9C0EDBE9C9F0DDEB090000000000000000000000000000909ADB0B09090000099B009090F9B9F9FFBDF9CA090090009C9FBD00990BCB009000000090000000000009000900000009009009000000090C9C00C9C0C9CF0F90D0DA9CADC0FCA90DCBC9E0DE9ECBFAFC000090000000000000000000000000090909009BDAD9CB9A0009A09B99FFBFF9F0B9B0900909B0B9A0009BCBF0909000000000000000000000000000009000000000900090000C00009C000DACBCFCCACAC0CE9CAFC09CFCAC9ECDE9ECBDAFC090A000000090000000000000900000909A90B09009A0B000909009B09FB99F9FF9F00900900000900909A09009000000000000000000000009000000000009000900000900909090D0C090D0C9CBCB0D0DAD09CAD0ADE009CBED0F0EDBEFFF900D9C90000000000000000000000000090990D9E0909900900909909DB99FBFF9F90DB0090909090090B09090900000000090000000090000000000090000000900090000000C00C000900E0DACF0FE0E9C0ADAD0FCFADEDE9C9ADAF9EDFBEFEF0A9A009000000000000000000000000000A9A990B000990900000B090F99F9B9E9B0900000009090090000000000000000000009000000900000000000090000000009009090D09C0C0AD0D0D0DE9FC9CADCC00E0F0DADACADEFFDEFBFAFFBDADFED0000000000000000000000009009099090A9090900000900009FB9BF9FFF9F9DAD000000000090909000000090000000000000000000000090000090009090900000000E0C00909C000C0F0DE99CAD00BCF0D0FEF0E9DEBEBEBFEFFFFFEDFADA09A09000000000000000000000000000909090000090000999B999F9FBF9DA9B99A90900000000000000000000009000090000000000009000090000900000000000009C909C00C09CF0F0DE9EE9C0FCC90DAD0D0ED0E9FDFFFFBFFFEFFADFAD009000000090000000000000000909B0009000900009090BE9DADB9F9F9FB9F0F09000090090000000000000000000000000090009009000000000B00900090090009C000C00D090C00D0CF0FFCBED0BCE0C0ADADBEDE0CBEFFEFFEFFBFFEBDA0009009000000000000000000000909B9A09000090CA9C9D9B9B9F9FBDF9F9DB9F9BD9F090090000000000000000009000000000000000000900D00D00A90000009009CD09C00C0C9C0C9E0F0FADCBEC90DADC0CAC9ADCBCBFBFFFFFFEFFBFE0D000A900000000000000000000000909C99A9DBDA999B9FB9FDF9BDBDBFF9BBDB9E90B00090000000000900900000000000000000000000000C9A9FA9ED009090000C0A00C09C00B00BCE9CDADDFAFC9EDE0C9E9C9EDCBCFDFEFFFFBFFFFEFE9000900000000000000009000009090B9B9B9DB9BF9FBDFB9DB9B9FBFFFF9FFDBDF9B9009000900900000000000000000009000000000009000FADFCBDE90F000090090D0D00C090C0DC09CFADFEADBFE9E9CBC0E9E9EADC9AFFFEFFEFFFFFF9E90009A090000000000000000000009099ADB09F99BF9FBDFFBFDF9F9F9FFF9BF0B9FC9009000000090000000000000000000009000000000900DEBFEFBEF0DCB0000C0000D090C09C00FCB0DFA9DECBFEBEDCBC90C0DCACFC9FFFFFFFFEBFEFEFE9009000000000000000000009090B0D9BDBDBF9DBF9FB9BD9FBFBF9FB9FF9F9F09B00000000000000000000000000000009000000090000090DFBFFE9EDACC9CA909C000C090C00D00DCF0DFCADBF0FFFABC0EDADA9CBCBEBFFFFFFFFFFFBFC9000009009000000000000000000909B90B9B99FBD9FBDFFBFBDBDBDBCB9DA9BDB0009000000000000000000009009000000000000000000000FAFFFBFDAD0F0C9C0C09C900C09CDACD0E9EBC9C9ECFFF0FCDE90CC9EFC9EDFEFFEFFEFFFFFCB000909A00000090000000900000909B09F9FF9FB9FBDBDB99F9FDFFBDBD9A9D090909000000000000000000000000009000000000900009000DBDFAFCFADAD0C9C0C90C000D09C000DAC9CBCFCBCF9E9EF0FA9EDEBCC0BCDADBFFFFFFFFFEFBC0900000000000000090000000090909DA9B99B9DBDFBDBDBF9F9B9BDBDBC9B09A90000009009000000900009000000000000000900009000090FAFFBF0FC0C9CAC90C090D000CA0DC0DADEDF0EDACBCF9EFDECBC9CBDCCADCADFBFFFFFEFFFEF00009009000000000000000000009A999F0F9FBBDB9FB9BDB9F9F9CB9A9B00909090000000000000900000000000000000000900000000C0000DFFFFFF0FDE0DC0CB0C000D0D0D00F0CD0F0FFFADFCF0F9FAFBCFACCADADADCFAFFFEFBFFFFFF0F09009000900000000000000000009A99B9B0DDBDBDBDBF9DB9EB99F9D0090B000000000000000000000000000000900900000009000900909EBFFEBCF0C0D009C0C90D000C00C9C9CAD0F0FFFFAFBFEF0FFCF0CDADAD0C0DADFEFFFFFBEFBEF0000000000000900000000000090909DA9DBDBBB9B9F9F99BBD99DB09B0909009090090000000000009000000090000000000000009000000CBFFFBDF0DAD0E9C009C00C0D00D0C0CADCF0FFFBFFFEFBFFEBE9EF0D0DE0F9EDADBFFFEFFFFFFDF0909009000000000000000090009A9BDB9F9F9DBDBDB9DBC99A9B0F09A000900000000000000900000000090000000000090090000009000BDFFFFEBEDC0D0C09C00D09E09E0DAD0DADADF0FEFFFFFEFBDF9E9EBCE0DCCC00DECBFFFFFFFFFAFC0A090000000000000000000000090090B9B9BBDB9BDBB9B9BD0990909090090000000000090000000000000000090000000000000000090CBFFFFFCBCBC0D0C09C00E09C0D00D0E0D0F0FFFFFEBFFDFEEBEFFDEDBDADA9FCAD9FCBFFEFFEFFF090000000000000000900000000909B9BDBDBC9B9F9BD0F9F9A9F09A900090009000900000000090000000000000000090000009009000009EFFFFFBCBCCBC0BCC09C9C00D0CD0C9DE9CF0FFFBFFDAFADBDFBFAFACECADCC0D0ECBEFFBFFFFADAC090009000000000000000009009B0D099B99BDB9BE9B9B0D9900900909090000000000000000000000000009000000000000000B009CC9FFFFEFBCFCC90C9C0A9C000CD00F00FCE0DE9FC9EFCBEDADAFAFEFFFFBDBDADADE9C9CD0FFFFFFFEF9C00900000000000000000000090099BCBDBBDBDAD99BC99A009B09000000000000000000000000000090000000900000090009000000BCFBFFBFEF9E9ED0C0D0C09CD0A9C0CD0D0DE9EFBE9EBC9EDEDFFFBFFFFFEFEDADADE9E0FC9EFBEFFFAFBC00000000000000000000000090A09B09C9B9B9BBD9BC999A090090900090000000000000000000000000000000900000000000900009EFFFFFBFE9C00D0C0C9C00AD0C9C9ACADA9E9CFCFC9EF0FBFAFFFEBFEFFBFFFFFE9EDBCBCBDFFFFBFFCA9000009000000000000000090999009B9BC9BD0D0B90B00900090000900009000090090009000900000090000000900000909000900CBFFFFFFCBEDED0E90D0AD0D0C9CACD0DCDE9EFB0F0FE9FBEFFFAFFFFFBFFFAFFAFFFBEDF0FEFBFEFEDA90090000000000000000090000000A990D09BD9B9B9A900B09090090000000009000000000000000000000000000000000900000000DBFFFFFFEBF0D00D0CC00D0C0C9E0C9C9E9E9EDBCF0F9FFEFFFBFFFFFFFFEFFFFFFFBEFFBEFDBEFFFFBFFC0000000000009000000000009090900B9B099A909C9090900000000090090000000000000000000900900009009000900000000900ADBFFFFFFFCF0CF0D09AD0D0F0C9C9CADCF0DEAFFFFEFAF9FAFEFFFFFFFFFFFFFFFFFFFFFFBEFFBFFFEFBF090000090000000000000000000909009CB0D9BDA99A090090090090000000000000000900000000000090000000000000000900090EFFFFFFFBF0F0C0CC0C0C0C0D0C9E9C0E9EBDF0FFAFBFFEFFFBFFEFBEFFFFBFEFFEFFFEFFFFBFFEFFFBCF00090000000000000000000009000090B099A9C9900900090090000000000009000900000009000000000090090090009000900090DBFFFFFFFFFE9E9CB0D0DAD0D0E9C0C9E9C9CE9FFFDFFCFBFFFFFFFFFFFFFEFFFBFFFFBFFEFFFEFFFBFCFB0900000000000000000000000000090090B090B09A9009000000000090000000000000000000090009000000000000900090000B0EFFFFFFFFFFE9CD0D0C0C0D0E0C9C0CDADCFEFBFFAAF0FBEFFAFFFFFFFFFBFFFFFFFFFFFFFFFFFFFBFEFBFC0A0900000900000000000009000900900909A90B00900090090009000090000000000900000000000000900009000A0090090AD0FDBFFFFFFFFFFFE0C0C9CBC00D0D0D0F0CDA0DADADFFBFEFFBFFFFEBFFFBFFFFFFFFFFFFFFBFFBFFFFFFFEBF09000009000090000000000000000000900090909000900000000000000090009000000090000000000000000009090000000DADAFFFFFFFFFFFFF9F0F0C0C9C90C0CAD0DACDE9CFFAFFEFFBFEFFFFFFFEFFEFFFFBFEFBFFEFFFFEFFFFFFFFFC90090900000000090009000000000900009000090909000900090000000000000000000000090090000000900000000009009AFFFFFFFFFFFFFFFFECD0C9C90CAC9E9C0C0D0F0FBCBDFFFBFFFFFFFBFFFFFFFBFEFFFFFEFBFFEFFFFFEFBFAFCBC0B0000000000000000000000000000000009090000000000000009000000000000000000000000090900000909AC9090009EFFFBFFFFFFFFFFFFE9F00DAC0C9C9C0C0D0F0F0DECBFFAFFFEFFFBFEFFFFFBFFFFBFFFFFFFFFFFBFFFBFFFFFFBE9000B00000900000000000900000000909000000090009000090000000000000000900009000000000000900000900009000BFFFFFFFFFFFFFFFFFC0FC0D0D0C0C9C9CAD0CCFADBFCBFFFFFFFFFFFFFEBFFFFFFFFFFFBFFFFBFFFFFFFFFFFEFF0900090000000000000000000000000000000009000000000000000000000009000000000000009000000000900009000090BDAFFFFFFFFFFFFFFBFC0D0C0CB0CBC0E9C0DA9CDACBFCFFFBFFBEFFBFFFFFEFBEFFFFAFFFFFEFFFFFEFFFAFFBDAC009000900000090000000000009000000000000009000009000000900000900000000900009000000000009009000009000CBFFFFFFFFFFFFFFFEDAD0F0D0C0D0C9C0D0EDCB0FDADBFFFFFFFFFFFFFFFFFFFFFBFFFFFEFBFFFEBFFFFFFFEFFE90900090000000000000000000000000000000000000000000000000000000000000000000000000090009000AC0090B000DBFFFFFFFFFFFFFFFADAD0C0C0C0D0C9C0DAC9CADEDAFFFAFFFAFFFBFEFBFFBFFFFFEFFFFFFFFFFFFFFFFAFFFFFAD00009A00000000000000000000000000000090000000009000000000000000000009000000000009000000090909A000000BCBFFFFFFFFFFFFFFF0DC0D0DAD0CB0CBC0D0E9DCB0FDADFFFFFFFFFFFFFFEFFFFFFFFFFFBFFFFFFFFFBFFFFFFFFEFC00090B09090000000900000000000000000009000000000000900000900000900000009000090000900000000009090900BFFFFFFFFFFFFFFEFF0DAC9C0C9CC9C0D0C9CCADEDAFFAFFFFFFBEFFBFFFFFFEBFFFFBEFFFFFFEBFFFFFFFFEFFFF0B0900000000009000000000900000000000000000900000000000000000090000000009009000000000909000909000000DFFFFFFFFFFFFFFFFBCF0C9E0D0E09C0D0F0E9AD0F0FCBDFFFFFFFFFFFFFFBFFFFFBFFFFFFEFBFFFFFEFFBFFBFFF0FC000909000000000000000000000000000000000000000000000000000000000000000000000000900000009000000B09FBFFFFFFFFFFFFFFFFDE9ED0C9C0C9C0F0C0C9CDCF0FCBFFAFBEFFFFFFFEFFFFFFFFFFFFFBFFFFFFFFFFFFEFFFFEFFBDE9000009000000000000000000000000900000000009000000000090000000009009000000900000000000000009000AFFFFFFFFFFFFFFFFFEF0CD0C9C0D0C0D0C9C9CE0F0FCBF0FFFFFFBFFFBFFFFFEFFFFEFFFFFFFFFFFFFFBFFFFFFFBFEFBCA9090000900000000000000000000900000900000000000000090000900009000000009000000009000B0090900009FFFFFFFFFFFFFFFFFFFBF0ADAC9E0DAC0DAC9E90F0F0FCFF0FFFFFFEFFEFFBFFFBFFFFFBEFFFFFFEBFEFFFFFBFFFFFFBCF9C0A09000000009009000000009000000000009000000090090000000000900000900000000000000900000000099FFFFFFFFFFFFFFFFFFFFFCFD0C9C0D0C9C0D0C0CDC9CF9ADAFFFFFFFFFFFFFFFFFFFBFFFFFBEFBFFFFFFFFFFFFEFFFFBEFBCA909000000900000009000000000000000000000000000000000000000000000000900000009009000909009090FFFFFFFFFFFFFFFFFFFFFEBC0C9CAD0C9C0F0C9CBCADEBCFFFFBFFFBFFBFFBFFFBFFFEFFFFFFFFEFFFFFBFFEFFFFFBEFFFFCF90C009090000000000000000000000000000000000000000009000000900009009000009090090000000000000BFFFFFFFFFFFFFFFFFFFFFBCBCBC9C0D0E9C0D0E9C9DE9CFBCBCFFBEFFFFFFFEFFEFFFFFFBFFFFFFFBFFFFFFBFFFFFFFFFFBFAFB0900000009009000000900000000000900000000090000000000000000000000000900000000009000090909FFFFFFFFFFFFFFFFFFFFFFDFC9C0C9C0D0C9C0D0CAC0DE9CFBFBFFFFFFFEFFFFBFFFBFFBFEFFBFFFFFFFEFFFFFFBFFFFFAFFFFDE9E0909000000000000000000009000000000090900009000000000000090000009000000900900009090000FFFFFFFFFFFFFFFFFFFFFFFFADE9CBC0D00D0E9C9C9CFA9EF0FCFFFFFFBFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFEFFEBFFFEFBEBE09000090000000900000090000000000009000000000000009009000000000000000900000009A9000000FBFFFFFFFFFFFFFFFFFFFFFEBCD0C9C0DACDAC9C0E9ED0DCF0FBFFAFFFFFFFFBFFFFBFEFFFFFFFFFFFFEFFFBFFAFFFFFFFFFFFFFFDBDA09000009000000009000000009000000000000000000000000000000000900009000909090000000090FFFFFFFFFFFFFFFFFFFFFFFDFCADAC9C0D00D0C9C9CCBCEB0FEDADFFFFFFFBFFFFEFFFFFFBFFBFFFFEFFFBFFFFFFFFFFFFFFFFBEFEFADBC09000009000900000000000000090000000000000000000000000000000090000000000C90C9C90CBFFFFFFFFFFFFFFFFFFFFFFFBE9D0D0CBC0D0C9CAD0D0C9CDE9FBFBFFFBEFFFFEFFFFFFFBFEFFFFFFFFBFFFFEFFFFFBFFBFEFBFFFBFBDBCA9000000000000900000000000000000000900090000900000009000900000000090000B000B0A00BFFFFFFFFFFFFFFFFFFFFFFFFEFCED0E9C0DAD0E9C0F0ADE9ADE9EDEFFFFFFEFFFFBFFFFFFFFFEFFFBFFFFBFFFBFFFFFEFFFFFEFFFFFFEFE9009000000000000090090000000000900000000000000900000000000000000900009000BC0009FFFFFFFFFFFFFFFFFFFFFFFFFFF9E90C9C0D0C0C9C0D0CDC9EDE9EFBFBFFFFBFFFFFFFFEBFFFFFBFFFEFFFFEFFFFFEFFFFFFFBFFFEBFEFBF9EF0090000900000000000909090900000000000000000000000000000000900000090090009090AFFFFFFFFFFFFFFFFFFFFFFFFFFFE9CF0C9E0C9C9C0DAC9CBC9E9FF0FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFBFFFBFCFF9EDA0090000000900000000000000000000000000090000000000000009000090000000090000DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9CD0C9C0E9CBC0D0E9CFCBC0FFBFFFFFFFFFBFFFFBFFFFAFFFFFFFFFBFFFFFFFFFFFBFFEFFFFFFFFFFBEFFAD090000009000000090000000900090000090000000009009000090000000000909000090FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCF0E9C0D0D0C0D0C9CCBCBCFF0FCBFFFBEFFFFFFEFFFFFFFFFBFEBFFFEFFFFEFBFFFEFFBFFFFFFFEFFAFFDBCF0C000000000000900000090000000090000000000000000000000000090009000009090CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF0C9CAD0E0D0D0ADACBC9CBF0FBFFFFFFFFBEFFFFFFFEFFFFFFFFFFBFFFFBFFFFFFFFFFFFFFEFBFFBFFFBEFBFA909090000090000009000000000000000000000090000000090000000000000090000BBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FD00D0C9C0DACD0C9C0FED0FDE9EBFFFFFFFFFBFFFBFFBFFFFFFFFFFFFFFFFFFFFBFFFFFFBFFFFFFFFFFFBCFCBCA000000000000900900900090000000000000000000000000000900090090000090CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFC0CF0C9C0D0C90C9CADD09EF0FBFFFFFFFFFFFFFFFFFFFFFFAFFFFFFFBFFFFFFFEFFFFEFFFFFFFFFFEBFFEFFBFCB09090000000000000A000900009000009000000000009000009000000000090900BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF9F0C9E0D00F0CDAC9D0EDE9CFADE9FFFFFBFFBFFFFFFFFFFFFFFFFFFEFFFEFFFFFFFFFFFFFFFFEFFFFFEFFBFFCBC9C0009000090009090900000000009000000000090000000000000900909000ACBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9E0C9C0DACD0CF00DACE9CBCBE9FBFFFFFFFFFFFEFFFFFFEFFFFFEFBFFFFFFFBFFFFFFFFFBEFFBFFBFFFFBFFEBFFFFBE9009000000000000B00900000000000000900000000009000900000000909BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED0DAC90C90C90CD0C9DE9CF0DFCFBFFFFEFFFEFFFFFFBFFBFFFFFFFFFFFFBFEFFBFEFBFFFFFFFFFFFFFFFFFFFEBCBCBCBC0000000090090000009000000000900000000900900900E0009000000CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBCD0D0ED0CBCC90E9CA0DE9EFAFBDEFFFBFFFBFFBFFBEFFFFFFFFBFFFBFFFFFFFFFFFFFFFFFBFFFFFEFBFFEBFFBFFFFFBE9AD0900900A9009090000090000000000000000000000090900009000DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBEDADE0D00D0C90E9C0DCDE9E9CDBCFBFFFFFFFFFFFFFFFFFFFFEFFFFFFFFBFFFFFFFFFFFFFFFFFEFFFFFEFFFFFFFFFBFBFFFF0B009A0990C9AC00090000090000090090090009090000009000C9FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDAD0C9C0DE0D0C9C0DA9E9CBDEBEFBFFFEFFBFFFFFFFFFFFFFFBFFFEBFFEFFFFBFFFFFFFEBFFFFFFFBFFFFFFFFFFAFFFFFBFBFEBC09FACB9E9BC9000900009090000000000900000909000090B0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCBC9CBC09C0F0C0F0CD0DE9E9F9EDAFFFFFFFEBFFEBFFFBFFFFFFFFFFFFFFFEFFFEFFFFFFFFFFFBFFFFFFBFFFFFFBFFBFFFFFBFB9A9DACB9EBFA9E0C0900000000000900000900000090090CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9E0C9CC9C0D0D0DACF0DE9ECFBFFFFFBFFFFFFFFFFFFFEFFFFFBFFFFBFFFFFFFBFFFBFFFEBFFFFFEFFFEFFEBFFFFBFFFFBFFFFEDABDBFEFDADE9FBCA9A909009090009000009000000F0FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FC9C9E09C09CBC0D0D0DADE9BCF0FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFEFBFFFBFFFFFBFBFDE9FBFBFFBFFCBDAC00A09000000000090009090F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF9E0D0C9EC9C0C0F0CBCBCF0FCFBFFFFFFEBFFFFFBFFBFFFBFFAFFFBFFFEFFFFFFFFFEFFFFFFFEFFBFFFFFFFFFFBFFFBFFFFFBFFFFAFBEFFFEDAFEBFFEDBF09C0009A90900000000ACBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC0D9E0D009CAD0D0C9CE9E9EDBBCFBFFFFFFFFFAFFFFEFFFFFFFFFFEFBFFFFFFFFFFBFFFFFFFFBFFFFFFFFFFFFFFFBFFFFBFFFFFBFFFFBFBFBFDBDFAFBE9EF0BDAD00C0AD09000D09FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE0D0CDCC9C0DAD0F0DCDE9ECFBDEFFFBFFFBFFFFFFFFBFFFFFFFFFFFFFBFEBFFEFFFFFAFFFFFFFEFFFEFFFFFEFBFFBFFFFFFFBFFBFBFFFEFFAFFBFFFFFF0FCADAF0BFCAACC99AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0BD0C9A009C09C0D0CDADA9E9F0FBFBFFFFFFFFFFFBFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFBFFFFFFFBFFFBFFFFFFFBFFBFFFBFFFFFFEFBFBFBFFAFFFBEF0FFADBFCBFCBFDFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FCCCBCDCFC0BCC9CADADADCFDAFDEFFFFFFFEFFBFFEFFFFEFBFFFFFFFFBFFFFFFBFFFBFFFFFFEFFBFFFFFFFEFFBFBFFFFFFBFFFFBFBFBFFEFFEBFFFBFFBFFBCFBCEBDEBCFAFEBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9A9C00000DC9AC0D0C9CFADADEBDBFFFBFFFFFFFFFFFFBFFFFFEFFFFEFFFBFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFBFBFFFFFFFFFFFFFFBFBFFFFBFFFFFFADBCFBDEBDFBFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9FCD0DEDCD00CC9CBCBCF0DCBCBDEBFFFFFFFBFFFFBFFFFFFFFFBFFFBFFFFEFFFEFFFFFFFBEFFFFFEFFFEFFFFFFEFFFFFFBFFBFBFFFFBFBFFFFBFFFFFFFFEFFEBEDEBCAFCBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E9E0909AC909C90CD0CF0BCBDEBDEBFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFBFFFFFFBFFFFBFFFBFFFFFBFFBFFFFFFFFFBFBFFFFFFFFFFFFFFFFFBE9E9EBCBFDBEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F9C0DCCCC9ECCACC9ACF9EDEDE9EBFFFFFBFFFBFFFFFFBFFBFFFFFFFFFFFBFFBFFBFFFFFFFFFFFFFFFFFFFFFFFFFBFFBFFFFFFFFFFFFFFFFFFFFFFFFFFAFE9EDBCF9EDAFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE9C00B09C909C9BCD90CF09E9FDFBFFFFEFFFFEFBFEFFEFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFFEFBFFFBFBFBFBFFFFFFFFFFFFFFFFFFDBDE9ECBCE9EDADEFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD0FCDCC0CCD0CC00ECF0CFCBCBE9FFFFFFFFFFFFFFFFFFFFFEFFBFFBFEFFFEFFFEFFFEFFEBFFEBFFEFBFEBFFFFBFFFBFFFFFFFFFBFFFFFFFFFFFFFEFBEF0FCBDE9FCBCFBFFEFBEFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBECF00090B09A090DD09CF9CBCFE9FEBFFFBFFBFFFFFFBFFBFFBFFFFFFFFBFFBFFBFFBFFBFFFFFFFFBFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFBFBCF9EDADA0F0ADA9E9ADBEDBEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED90DCFCCCCCCDECCACDE9CADCB9EDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFBFFFFBFBFBFBFFFFFFFFFFFFBFEFFBECB0DCEDCEDCEDCEFCE9EDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0EC0009090900909CBC0CED0FCFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFBFFFFFFFFFFFFFFFFFFBFFBFBEDBFCFAD9E9DAD9E9DADBC9ECBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9DEDCCDCCCDCCD0DCBDBDADADADEBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE9E9CAC9E0DAC9E0DAC9E9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0CA900B00B00B00E00C0C0DADADBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDEFDEFDEFDEFDFFFFFFFFFFFFFFF000000000000000000000105000000000000A9AD05FE"); + var encodedString = Encoding.GetEncoding(0).GetString(byteArrayValue); + var base64String = Convert.ToBase64String(byteArrayValue); + + Console.WriteLine("Original length: {0}, Encoding length: {1}, Base65 length: {2}", + byteArrayValue.Length, encodedString.Length, base64String.Length); + + CompareMultipleRuns( + "Convert.FromBase64String", () => Convert.FromBase64String(Convert.ToBase64String(byteArrayValue)), + "Encoding.Default", () => Encoding.GetEncoding(0).GetBytes(Encoding.GetEncoding(0).GetString(byteArrayValue)) + ); + } + + [Test] + public void Compare_Type_test_with_Parse_Func() + { + var testClassWithType = new TestClassWithType { Type = typeof(string) }; + var testClassWithFunc = new TestClassWithFunc { GetValueFn = value => value }; + + CompareMultipleRuns( + "TestClassWithType", () => testClassWithType.GetValue("test"), + "TestClassWithFunc", () => testClassWithFunc.GetValue("test") + ); + } + + + } + + public class TestClassWithType + { + public Type Type { get; set; } + + public object GetValue(string value) + { + if (Type == typeof(string)) + { + return value; + } + + return null; + } + } + + public class TestClassWithFunc + { + public ParseStringDelegate GetValueFn; + + public object GetValue(string value) + { + if (GetValueFn != null) + { + return GetValueFn(value); + } + return null; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/DateTimePerf.cs b/tests/ServiceStack.Common.Tests/Perf/DateTimePerf.cs index 671c46d3e09..5761545e26f 100644 --- a/tests/ServiceStack.Common.Tests/Perf/DateTimePerf.cs +++ b/tests/ServiceStack.Common.Tests/Perf/DateTimePerf.cs @@ -7,123 +7,124 @@ namespace ServiceStack.Common.Tests.Perf { - [TestFixture] - public class DateTimePerf - : PerfTestBase - { - public DateTimePerf() - { - this.MultipleIterations = new List { 10000 }; - } - - - [Test] - public void PrintFormats() - { - var now = DateTime.Now; - var nowWithoutTime = new DateTime(now.Date.Ticks); - - Log(now.ToShortDateString()); - Log(now.ToShortTimeString()); - Log(now.ToLongTimeString()); - Log(now.ToLongTimeString()); - Log(now.ToString()); - Log(DateTimeSerializer.ToDateTimeString(now)); - Log(DateTimeSerializer.ToShortestXsdDateTimeString(now)); - - Log("\n"); - Log(nowWithoutTime.ToShortDateString()); - Log(nowWithoutTime.ToShortTimeString()); - Log(nowWithoutTime.ToLongTimeString()); - Log(nowWithoutTime.ToLongTimeString()); - Log(nowWithoutTime.ToString()); - Log(DateTimeSerializer.ToDateTimeString(nowWithoutTime)); - Log(DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime)); - } - - [Test] - public void Compare_DateTime_Serializtion() - { - var now = DateTime.Now; - var nowWithoutTime = new DateTime(now.Date.Ticks); - - CompareMultipleRuns( - "now.ToString()", () => now.ToString(), - "XmlConvert.ToString(now, XmlDateTimeSerializationMode.Utc)", () => XmlConvert.ToString(now, XmlDateTimeSerializationMode.Utc) - ); - - CompareMultipleRuns( - "now.ToString()", () => now.ToString(), - "XmlConvert.ToString(now, DateTimeFormat)", () => XmlConvert.ToString(now, DateTimeSerializer.XsdDateTimeFormat) - ); - - CompareMultipleRuns( - "ToDateTimeString(now)", () => DateTimeSerializer.ToDateTimeString(now), - "ToDateOrDateTimeString(now)", () => DateTimeSerializer.ToShortestXsdDateTimeString(now) - ); - - CompareMultipleRuns( - "ToDateTimeString(nowWithoutTime)", () => DateTimeSerializer.ToDateTimeString(nowWithoutTime), - "ToDateOrDateTimeString(nowWithoutTime)", () => DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime) - ); - } - - [Test] - public void Compare_DateTime_DeSerializtion() - { - var nowStr = DateTime.Now.ToString(); - var nowXmlStr = XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.Utc); - var nowXmlExact = XmlConvert.ToString(DateTime.UtcNow, DateTimeSerializer.XsdDateTimeFormat); - - CompareMultipleRuns( - "DateTime.Parse(now.ToString())", () => DateTime.Parse(nowStr), - "XmlConvert.ToString", () => XmlConvert.ToDateTime(nowXmlStr, XmlDateTimeSerializationMode.Utc) - ); - - CompareMultipleRuns( - "DateTime.ParseExact(utcNow, DateTimeFormat, null)", () => DateTime.ParseExact(nowXmlExact, DateTimeSerializer.XsdDateTimeFormat, null), - "XmlConvert.ToString", () => XmlConvert.ToDateTime(nowXmlExact, DateTimeSerializer.XsdDateTimeFormat) - ); - } - - [Test] - public void Compare_Serialization() - { - var now = DateTime.Now; - CompareMultipleRuns( - "FromDateTimeString(ToDateTimeString(now))", () => DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(now)), - "FromDateOrDateTimeString(ToDateOrDateTimeString(now))", () => DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(now)) - ); - - Assert.That(now, Is.EqualTo(DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(now)))); - Assert.That(now, Is.EqualTo(DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(now)))); - - var nowWithoutTime = new DateTime(now.Date.Ticks); - CompareMultipleRuns( - "FromDateTimeString(ToDateTimeString(nowWithoutTime))", () => DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(nowWithoutTime)), - "FromDateOrDateTimeString(ToDateOrDateTimeString(nowWithoutTime))", () => DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime)) - ); - - Assert.That(nowWithoutTime, Is.EqualTo(DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(nowWithoutTime)))); - Assert.That(nowWithoutTime, Is.EqualTo(DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime)))); - - Log("OK"); - } - - [Test] - public void Compare_Parsing() - { - const string dateTimeStr = "2010-11-22T11:11:11.001Z"; - - CompareMultipleRuns( - "XmlConvert.ToDateTime()", () => XmlConvert.ToDateTime(dateTimeStr, XmlDateTimeSerializationMode.Utc), - "DateTime.ParseExact()", () => DateTime.ParseExact(dateTimeStr, - DateTimeSerializer.XsdDateTimeFormat3F, null, - DateTimeStyles.AdjustToUniversal) - ); - } - - } + [TestFixture] + public class DateTimePerf + : PerfTestBase + { + public DateTimePerf() + { + this.MultipleIterations = new List { 10000 }; + } + + + [Test] + public void PrintFormats() + { + var now = DateTime.Now; + var nowWithoutTime = new DateTime(now.Date.Ticks); + + Log(now.ToString("d")); + Log(now.ToString("t")); + Log(now.ToString("D")); + Log(now.ToString("T")); + Log(now.ToString()); + Log(DateTimeSerializer.ToDateTimeString(now)); + Log(DateTimeSerializer.ToShortestXsdDateTimeString(now)); + + Log("\n"); + Log(nowWithoutTime.ToString("d")); + Log(nowWithoutTime.ToString("t")); + Log(nowWithoutTime.ToString("D")); + Log(nowWithoutTime.ToString("T")); + Log(nowWithoutTime.ToString()); + Log(DateTimeSerializer.ToDateTimeString(nowWithoutTime)); + Log(DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime)); + } + + [Test] + public void Compare_DateTime_Serializtion() + { + var now = DateTime.Now; + var nowWithoutTime = new DateTime(now.Date.Ticks); + + CompareMultipleRuns( + "now.ToString()", () => now.ToString(), + "XmlConvert.ToString(now, XmlDateTimeSerializationMode.Utc)", () => XmlConvert.ToString(now, XmlDateTimeSerializationMode.Utc) + ); + + CompareMultipleRuns( + "now.ToString()", () => now.ToString(), + "XmlConvert.ToString(now, DateTimeFormat)", () => XmlConvert.ToString(now, DateTimeSerializer.XsdDateTimeFormat) + ); + + CompareMultipleRuns( + "ToDateTimeString(now)", () => DateTimeSerializer.ToDateTimeString(now), + "ToDateOrDateTimeString(now)", () => DateTimeSerializer.ToShortestXsdDateTimeString(now) + ); + + CompareMultipleRuns( + "ToDateTimeString(nowWithoutTime)", () => DateTimeSerializer.ToDateTimeString(nowWithoutTime), + "ToDateOrDateTimeString(nowWithoutTime)", () => DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime) + ); + } + + [Test] + public void Compare_DateTime_DeSerializtion() + { + var nowStr = DateTime.Now.ToString(); + var nowXmlStr = XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.Utc); + var nowXmlExact = XmlConvert.ToString(DateTime.UtcNow, DateTimeSerializer.XsdDateTimeFormat); + + CompareMultipleRuns( + "DateTime.Parse(now.ToString())", () => DateTime.Parse(nowStr), + "XmlConvert.ToString", () => XmlConvert.ToDateTime(nowXmlStr, XmlDateTimeSerializationMode.Utc) + ); +#if !NETCORE + CompareMultipleRuns( + "DateTime.ParseExact(utcNow, DateTimeFormat, null)", () => DateTime.ParseExact(nowXmlExact, DateTimeSerializer.XsdDateTimeFormat, null), + "XmlConvert.ToString", () => XmlConvert.ToDateTime(nowXmlExact, DateTimeSerializer.XsdDateTimeFormat) + ); +#endif + } + + [Test] + public void Compare_Serialization() + { + var now = DateTime.Now; + CompareMultipleRuns( + "FromDateTimeString(ToDateTimeString(now))", () => DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(now)), + "FromDateOrDateTimeString(ToDateOrDateTimeString(now))", () => DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(now)) + ); + + Assert.That(now, Is.EqualTo(DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(now)))); + Assert.That(now, Is.EqualTo(DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(now)))); + + var nowWithoutTime = new DateTime(now.Date.Ticks); + CompareMultipleRuns( + "FromDateTimeString(ToDateTimeString(nowWithoutTime))", () => DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(nowWithoutTime)), + "FromDateOrDateTimeString(ToDateOrDateTimeString(nowWithoutTime))", () => DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime)) + ); + + Assert.That(nowWithoutTime, Is.EqualTo(DateTimeSerializer.ParseDateTime(DateTimeSerializer.ToDateTimeString(nowWithoutTime)))); + Assert.That(nowWithoutTime, Is.EqualTo(DateTimeSerializer.ParseShortestXsdDateTime(DateTimeSerializer.ToShortestXsdDateTimeString(nowWithoutTime)))); + + Log("OK"); + } + + [Test] + public void Compare_Parsing() + { + const string dateTimeStr = "2010-11-22T11:11:11.001Z"; + + CompareMultipleRuns( + "XmlConvert.ToDateTime()", () => XmlConvert.ToDateTime(dateTimeStr, XmlDateTimeSerializationMode.Utc), + "DateTime.ParseExact()", () => DateTime.ParseExact(dateTimeStr, + DateTimeSerializer.XsdDateTimeFormat3F, null, + DateTimeStyles.AdjustToUniversal) + ); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/IdUtilsPerf.cs b/tests/ServiceStack.Common.Tests/Perf/IdUtilsPerf.cs index 6df9223e7a6..52b41b3dbdc 100644 --- a/tests/ServiceStack.Common.Tests/Perf/IdUtilsPerf.cs +++ b/tests/ServiceStack.Common.Tests/Perf/IdUtilsPerf.cs @@ -1,99 +1,98 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.DesignPatterns.Model; +using ServiceStack.Model; namespace ServiceStack.Common.Tests.Perf { - [Ignore("Benchmarks for measuring Id access")] - [TestFixture] - public class IdUtilsPerf - : PerfTestBase - { - public IdUtilsPerf() - { - this.MultipleIterations = new List { 100000 }; - } + [Ignore("Benchmarks for measuring Id access")] + [TestFixture] + public class IdUtilsPerf + : PerfTestBase + { + public IdUtilsPerf() + { + this.MultipleIterations = new List { 100000 }; + } - public static object OldGetId(T entity) - { - const string idField = "Id"; + public static object OldGetId(T entity) + { + const string idField = "Id"; - var guidEntity = entity as IHasGuidId; - if (guidEntity != null) - { - return guidEntity.Id; - } + var guidEntity = entity as IHasGuidId; + if (guidEntity != null) + { + return guidEntity.Id; + } - var intEntity = entity as IHasIntId; - if (intEntity != null) - { - return intEntity.Id; - } + var intEntity = entity as IHasIntId; + if (intEntity != null) + { + return intEntity.Id; + } - var longEntity = entity as IHasLongId; - if (longEntity != null) - { - return longEntity.Id; - } + var longEntity = entity as IHasLongId; + if (longEntity != null) + { + return longEntity.Id; + } - var stringEntity = entity as IHasStringId; - if (stringEntity != null) - { - return stringEntity.Id; - } + var stringEntity = entity as IHasStringId; + if (stringEntity != null) + { + return stringEntity.Id; + } - var propertyInfo = typeof(T).GetProperty(idField); - if (propertyInfo != null) - { - return propertyInfo.GetGetMethod().Invoke(entity, new object[0]); - } + var propertyInfo = typeof(T).GetProperty(idField); + if (propertyInfo != null) + { + return propertyInfo.GetGetMethod().Invoke(entity, new object[0]); + } - if (typeof(T).IsValueType || typeof(T) == typeof(string)) - { - return entity.GetHashCode(); - } + if (typeof(T).IsValueType || typeof(T) == typeof(string)) + { + return entity.GetHashCode(); + } - throw new NotSupportedException("Cannot retrieve value of Id field, use IHasId<>"); - } + throw new NotSupportedException("Cannot retrieve value of Id field, use IHasId<>"); + } - private void CompareForInstance(T obj) - { - CompareMultipleRuns( - "OldGetId", () => OldGetId(obj), - "obj.GetId()", () => obj.GetId() - ); - } + private void CompareForInstance(T obj) + { + CompareMultipleRuns( + "OldGetId", () => OldGetId(obj), + "obj.GetId()", () => obj.GetId() + ); + } - [Test] - public void Compare_HasIntId() - { - CompareForInstance(new IdUtilsTests.HasIntId()); - } + [Test] + public void Compare_HasIntId() + { + CompareForInstance(new IdUtilsTests.HasIntId()); + } - [Test] - public void Compare_HasGenericIdInt() - { - CompareForInstance(new IdUtilsTests.HasGenericIdInt()); - } + [Test] + public void Compare_HasGenericIdInt() + { + CompareForInstance(new IdUtilsTests.HasGenericIdInt()); + } - [Test] - public void Compare_HasGenericIdString() - { - CompareForInstance(new IdUtilsTests.HasGenericIdString()); - } + [Test] + public void Compare_HasGenericIdString() + { + CompareForInstance(new IdUtilsTests.HasGenericIdString()); + } - [Test] - public void Compare_HasIdStringProperty() - { - CompareForInstance(new IdUtilsTests.HasIdStringProperty()); - } + [Test] + public void Compare_HasIdStringProperty() + { + CompareForInstance(new IdUtilsTests.HasIdStringProperty()); + } - [Test] - public void Compare_HasIdProperty() - { - CompareForInstance(new IdUtilsTests.HasIdProperty()); - } - } + [Test] + public void Compare_HasIdProperty() + { + CompareForInstance(new IdUtilsTests.HasIdProperty()); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/PropertyAccessorPerf.cs b/tests/ServiceStack.Common.Tests/Perf/PropertyAccessorPerf.cs deleted file mode 100644 index adea4416fcd..00000000000 --- a/tests/ServiceStack.Common.Tests/Perf/PropertyAccessorPerf.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; -using NUnit.Framework; -using ServiceStack.Common.Reflection; -using ServiceStack.Common.Tests.Models; - -namespace ServiceStack.Common.Tests.Perf -{ - [Ignore("Benchmark for comparing property access")] - [TestFixture] - public class PropertyAccessorPerf - : PerfTestBase - { - public PropertyAccessorPerf() - { - this.MultipleIterations = new List { 1000000 }; - } - - public static class TestAcessor - { - public static Func TypedGetPropertyFn(PropertyInfo pi) - { - var mi = pi.GetGetMethod(); - return (Func)Delegate.CreateDelegate(typeof(Func), mi); - } - - /// - /// Required to cast the return ValueType to an object for caching - /// - public static Func ValueUnTypedGetPropertyFn(PropertyInfo pi) - { - var typedPropertyFn = TypedGetPropertyFn(pi); - return x => typedPropertyFn(x); - } - - public static Func ValueUnTypedGetPropertyTypeFn_Reflection(PropertyInfo pi) - { - var mi = typeof(StaticAccessors).GetMethod("TypedGetPropertyFn"); - var genericMi = mi.MakeGenericMethod(pi.PropertyType); - var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi }); - return x => typedGetPropertyFn.Method.Invoke(x, new object[] { }); - } - - public static Func ValueUnTypedGetPropertyTypeFn_Expr(PropertyInfo pi) - { - var mi = typeof(StaticAccessors).GetMethod("TypedGetPropertyFn"); - var genericMi = mi.MakeGenericMethod(pi.PropertyType); - var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi }); - - var typedMi = typedGetPropertyFn.Method; - var obj = Expression.Parameter(typeof(object), "oFunc"); - var expr = Expression.Lambda>( - Expression.Convert( - Expression.Call( - Expression.Convert(obj, typedMi.DeclaringType), - typedMi - ), - typeof(object) - ), - obj - ); - return expr.Compile(); - } - - - /// - /// Func to set the Strongly-typed field - /// - public static Action TypedSetPropertyFn(PropertyInfo pi) - { - var mi = pi.GetSetMethod(); - return (Action)Delegate.CreateDelegate(typeof(Action), mi); - } - - /// - /// Required to cast the ValueType to an object for caching - /// - public static Action ValueUnTypedSetPropertyFn(PropertyInfo pi) - { - var typedPropertyFn = TypedSetPropertyFn(pi); - return (x, y) => typedPropertyFn(x, (TId)y); - } - - public static Action ValueUnTypedSetPropertyTypeFn_Reflection(PropertyInfo pi) - { - var mi = typeof (StaticAccessors).GetMethod("TypedSetPropertyFn"); - var genericMi = mi.MakeGenericMethod(pi.PropertyType); - var typedSetPropertyFn = (Delegate) genericMi.Invoke(null, new[] {pi}); - - return (x, y) => typedSetPropertyFn.Method.Invoke(x, new[] { y }); - } - - public static Action ValueUnTypedSetPropertyTypeFn_Expr(PropertyInfo pi) - { - var mi = typeof(StaticAccessors).GetMethod("TypedSetPropertyFn"); - var genericMi = mi.MakeGenericMethod(pi.PropertyType); - var typedSetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi }); - - var typedMi = typedSetPropertyFn.Method; - var paramFunc = Expression.Parameter(typeof(object), "oFunc"); - var paramValue = Expression.Parameter(typeof(object), "oValue"); - var expr = Expression.Lambda>( - Expression.Call( - Expression.Convert(paramFunc, typedMi.DeclaringType), - typedMi, - Expression.Convert(paramValue, pi.PropertyType) - ), - paramFunc, - paramValue - ); - return expr.Compile(); - } - } - - private void CompareGet(Func reflection, Func expr) - where T : new() - { - var obj = new T(); - CompareMultipleRuns( - "GET Reflection", () => reflection(obj), - "GET Expression", () => expr(obj) - ); - } - - private void CompareSet( - Action reflection, Action expr, TArg arg) - where T : new() - { - var obj = new T(); - CompareMultipleRuns( - "SET Reflection", () => reflection(obj, arg), - "SET Expression", () => expr(obj, arg) - ); - } - - [Test] - public void Compare_get_int() - { - var fieldPi = typeof(ModelWithIdAndName).GetProperty("Id"); - CompareGet - ( - TestAcessor.ValueUnTypedGetPropertyTypeFn_Reflection(fieldPi), - TestAcessor.ValueUnTypedGetPropertyTypeFn_Expr(fieldPi) - ); - CompareSet - ( - TestAcessor.ValueUnTypedSetPropertyTypeFn_Reflection(fieldPi), - TestAcessor.ValueUnTypedSetPropertyTypeFn_Expr(fieldPi), - 1 - ); - } - - [Test] - public void Compare_get_string() - { - var fieldPi = typeof(ModelWithIdAndName).GetProperty("Name"); - CompareGet - ( - TestAcessor.ValueUnTypedGetPropertyTypeFn_Reflection(fieldPi), - TestAcessor.ValueUnTypedGetPropertyTypeFn_Expr(fieldPi) - ); - - CompareSet - ( - TestAcessor.ValueUnTypedSetPropertyTypeFn_Reflection(fieldPi), - TestAcessor.ValueUnTypedSetPropertyTypeFn_Expr(fieldPi), - "A" - ); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/ReflectionTests.cs b/tests/ServiceStack.Common.Tests/Perf/ReflectionTests.cs index d11fe6864e4..92ccd75e15a 100644 --- a/tests/ServiceStack.Common.Tests/Perf/ReflectionTests.cs +++ b/tests/ServiceStack.Common.Tests/Perf/ReflectionTests.cs @@ -7,67 +7,71 @@ namespace ServiceStack.Common.Tests.Perf { - [Ignore("Benchmark for comparing expressions / delegates around generic methods.")] - [TestFixture] - public class ReflectionTests - : PerfTestBase - { - public ReflectionTests() - : base() - { - this.MultipleIterations = new List { 100000000 }; - } + [Ignore("Benchmark for comparing expressions / delegates around generic methods.")] + [TestFixture] + public class ReflectionTests + : PerfTestBase + { + public ReflectionTests() + : base() + { + this.MultipleIterations = new List { 100000000 }; + } - public static Func GetPropertyValueMethodViaExpressions( - Type type, PropertyInfo propertyInfo) - { - var getMethodInfo = propertyInfo.GetGetMethod(); - var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam"); - var instanceParam = Expression.Convert(oInstanceParam, type); + public static Func GetPropertyValueMethodViaExpressions( + Type type, PropertyInfo propertyInfo) + { + var getMethodInfo = propertyInfo.GetGetMethod(); + var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam"); + var instanceParam = Expression.Convert(oInstanceParam, type); - var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo); - var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object)); + var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo); + var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object)); - var propertyGetFn = Expression.Lambda> - ( - oExprCallPropertyGetFn, - oInstanceParam - ).Compile(); + var propertyGetFn = Expression.Lambda> + ( + oExprCallPropertyGetFn, + oInstanceParam + ).Compile(); - return propertyGetFn; - } + return propertyGetFn; + } - public static Func GetPropertyValueMethodViaDelegate( - Type type, PropertyInfo propertyInfo) - { - var mi = typeof(ReflectionTests).GetMethod("CreateFunc"); + public static Func GetPropertyValueMethodViaDelegate( + Type type, PropertyInfo propertyInfo) + { + var mi = typeof(ReflectionTests).GetMethod("CreateFunc"); - var genericMi = mi.MakeGenericMethod(type, propertyInfo.PropertyType); - var del = genericMi.Invoke(null, new[] { propertyInfo.GetGetMethod() }); + var genericMi = mi.MakeGenericMethod(type, propertyInfo.PropertyType); + var del = genericMi.Invoke(null, new[] { propertyInfo.GetGetMethod() }); - return (Func) del; - } + return (Func)del; + } - public static Func CreateFunc(MethodInfo mi) - { - var del = (Func)Delegate.CreateDelegate(typeof(Func), mi); - return x => del((T1) x); - } + public static Func CreateFunc(MethodInfo mi) + { +#if !NETCORE + var del = (Func)Delegate.CreateDelegate(typeof(Func), mi); +#else + var del = (Func)mi.CreateDelegate(typeof(Func)); +#endif + return x => del((T1)x); + } - [Test] - public void Compare() - { - var model = ModelWithIdAndName.Create(1); - var pi = model.GetType().GetProperty("Name"); - var simpleExpr = GetPropertyValueMethodViaExpressions(typeof(ModelWithIdAndName), pi); - var simpleDelegate = GetPropertyValueMethodViaDelegate(typeof(ModelWithIdAndName), pi); + [Test] + public void Compare() + { + var model = ModelWithIdAndName.Create(1); + var pi = model.GetType().GetProperty("Name"); + var simpleExpr = GetPropertyValueMethodViaExpressions(typeof(ModelWithIdAndName), pi); + var simpleDelegate = GetPropertyValueMethodViaDelegate(typeof(ModelWithIdAndName), pi); - CompareMultipleRuns( - "Expressions", () => simpleExpr(model), - "Delegate", () => simpleDelegate(model) - ); + CompareMultipleRuns( + "Expressions", () => simpleExpr(model), + "Delegate", () => simpleDelegate(model) + ); - } + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/StringParsePerf.cs b/tests/ServiceStack.Common.Tests/Perf/StringParsePerf.cs index 1a446f51521..a423e8ecf3c 100644 --- a/tests/ServiceStack.Common.Tests/Perf/StringParsePerf.cs +++ b/tests/ServiceStack.Common.Tests/Perf/StringParsePerf.cs @@ -1,226 +1,226 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Perf { - [Ignore("Benchmarks for deserializing basic .NET types")] - [TestFixture] - public class StringParsePerf - : PerfTestBase - { - public StringParsePerf() - { - this.MultipleIterations = new List { 10000 }; - } - - public List CreateList(Func createStringFn, int noOfTimes) - { - var list = new List(); - for (var i=0; i < noOfTimes; i++) - { - list.Add(createStringFn(i)); - } - return list; - } - - [Test] - public void Compare_ints() - { - CompareMultipleRuns( - "int.Parse", () => int.Parse("1"), - "SCU.Parse", () => TypeSerializer.DeserializeFromString("1") - ); - } - - [Test] - public void Compare_longs() - { - CompareMultipleRuns( - "long.Parse", () => long.Parse("1"), - "SCU.Parse", () => TypeSerializer.DeserializeFromString("1") - ); - } - - [Test] - public void Compare_Guids() - { - CompareMultipleRuns( - "new Guid", () => new Guid("AC800C9C-B8BE-4829-868A-B43CFF7B2AFD"), - "SCU.Parse", () => TypeSerializer.DeserializeFromString("AC800C9C-B8BE-4829-868A-B43CFF7B2AFD") - ); - } - - [Test] - public void Compare_DateTime() - { - const string dateTimeStr = "2009-12-20T19:24:37.4379982Z"; - CompareMultipleRuns( - "DateTime.Parse", () => DateTime.Parse(dateTimeStr), - "SCU.Parse", () => TypeSerializer.DeserializeFromString(dateTimeStr) - ); - } - - private static string[] SplitList(string listStr) - { - return listStr.Substring(1, listStr.Length - 2).Split(','); - } - - [Test] - public void Compare_IntList() - { - const string intValues = "[0,1,2,3,4,5,6,7,8,9]"; - CompareMultipleRuns( - "intValues.Split(',').ConvertAll", () => SplitList(intValues).ConvertAll(x => int.Parse(x)), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(intValues) - ); - } - - [Test] - public void Compare_LongList() - { - const string longValues = "[0,1,2,3,4,5,6,7,8,9]"; - CompareMultipleRuns( - "intValues.Split(',').ConvertAll", () => SplitList(longValues).ConvertAll(x => long.Parse(x)), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(longValues) - ); - } - - [Test] - public void Compare_StringArray() - { - const string stringValues = "[a,b,c,d,e,f,g,h,i,j]"; - CompareMultipleRuns( - "TextExtensions.FromCsvFields", () => TextExtensions.FromCsvFields(stringValues.Split(',')), - "SCU.Parse", () => TypeSerializer.DeserializeFromString(stringValues) - ); - } - - [Test] - public void Compare_DoubleArray() - { - const string stringValues = "[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.1]"; - CompareMultipleRuns( - ".Split(',').ConvertAll(x => double.Parse(x))", () => SplitList(stringValues).ConvertAll(x => double.Parse(x)), - "SCU.Parse", () => TypeSerializer.DeserializeFromString(stringValues) - ); - } - - [Test] - public void Compare_GuidArray() - { - const string stringValues = "[8F403A5E-CDFC-4C6F-B0EB-C055C1C8BA60,5673BAC7-BAC5-4B3F-9B69-4180E6227508,B0CA730F-14C9-4D00-AC7F-07E7DE8D566E,4E26AF94-6B13-4F89-B192-36C6ABE73DAE,08491B16-2270-4DF9-8AEE-A8861A791C50]"; - CompareMultipleRuns( - ".Split(',').ConvertAll(x => new Guid(x))", () => SplitList(stringValues).ConvertAll(x => new Guid(x)), - "SCU.Parse", () => TypeSerializer.DeserializeFromString(stringValues) - ); - } - - [Test] - public void Compare_StringList() - { - const string stringValues = "[a,b,c,d,e,f,g,h,i,j]"; - CompareMultipleRuns( - "stringValues.Split(',').FromCsvFields()", () => SplitList(stringValues).FromCsvFields(), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) - ); - } - - [Test] - public void Compare_DoubleList() - { - const string stringValues = "[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.1]"; - CompareMultipleRuns( - ".Split(',').ConvertAll(x => double.Parse(x))", () => SplitList(stringValues).ConvertAll(x => double.Parse(x)), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) - ); - } - - [Test] - public void Compare_GuidList() - { - const string stringValues = "[8F403A5E-CDFC-4C6F-B0EB-C055C1C8BA60,5673BAC7-BAC5-4B3F-9B69-4180E6227508,B0CA730F-14C9-4D00-AC7F-07E7DE8D566E,4E26AF94-6B13-4F89-B192-36C6ABE73DAE,08491B16-2270-4DF9-8AEE-A8861A791C50]"; - CompareMultipleRuns( - ".Split(',').ConvertAll(x => new Guid(x))", () => SplitList(stringValues).ConvertAll(x => new Guid(x)), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) - ); - } - - [Test] - public void Compare_StringHashSet() - { - const string stringValues = "[a,b,c,d,e,f,g,h,i,j]"; - CompareMultipleRuns( - "new HashSet(.Split(',').FromCsvFields())", () => new HashSet(SplitList(stringValues).FromCsvFields()), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) - ); - } - - [Test] - public void Compare_IntHashSet() - { - const string stringValues = "[0,1,2,3,4,5,6,7,8,9]"; - CompareMultipleRuns( - "new HashSet(.Split(',').ConvertAll(x => int.Parse(x))", () => new HashSet(SplitList(stringValues).ConvertAll(x => int.Parse(x))), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) - ); - } - - [Test] - public void Compare_DoubleHashSet() - { - const string stringValues = "[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.1]"; - CompareMultipleRuns( - "new HashSet(.ConvertAll(x => double.Parse(x)))", () => new HashSet(SplitList(stringValues).ConvertAll(x => double.Parse(x))), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) - ); - } - - [Test] - public void Compare_StringStringMap() - { - const string mapValues = "{A:1,B:2,C:3,D:4,E:5,F:6,G:7,H:8,I:9,J:0}"; - var map = new Dictionary(); - CompareMultipleRuns( - "mapValues.Split(',').ConvertAll", () => SplitList(mapValues).ConvertAll(x => x.Split(':')).ForEach(y => map[y[0].FromCsvField()] = y[1].FromCsvField()), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(mapValues) - ); - } - - [Test] - public void Compare_StringIntMap() - { - const string mapValues = "{A:1,B:2,C:3,D:4,E:5,F:6,G:7,H:8,I:9,J:0}"; - var map = new Dictionary(); - CompareMultipleRuns( - "mapValues.Split(',').ConvertAll", () => SplitList(mapValues).ConvertAll(x => x.Split(':')).ForEach(y => map[y[0].FromCsvField()] = int.Parse(y[1])), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(mapValues) - ); - } - - [Test] - public void Compare_StringInt_SortedDictionary() - { - const string mapValues = "{A:1,B:2,C:3,D:4,E:5,F:6,G:7,H:8,I:9,J:0}"; - var map = new SortedDictionary(); - CompareMultipleRuns( - "mapValues.Split(',').ConvertAll", () => SplitList(mapValues).ConvertAll(x => x.Split(':')).ForEach(y => map[y[0].FromCsvField()] = int.Parse(y[1])), - "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(mapValues) - ); - } - - [Test] - public void Compare_ByteArray() - { - var byteArrayValue = new byte[] { 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, }; - var byteArrayString = Convert.ToBase64String(byteArrayValue); - - CompareMultipleRuns( - "Encoding.Default.GetBytes", () => System.Text.Encoding.Default.GetBytes(byteArrayString), - "SCU.Parse", () => TypeSerializer.DeserializeFromString(byteArrayString) - ); - } - } + [Ignore("Benchmarks for deserializing basic .NET types")] + [TestFixture] + public class StringParsePerf + : PerfTestBase + { + public StringParsePerf() + { + this.MultipleIterations = new List { 10000 }; + } + + public List CreateList(Func createStringFn, int noOfTimes) + { + var list = new List(); + for (var i = 0; i < noOfTimes; i++) + { + list.Add(createStringFn(i)); + } + return list; + } + + [Test] + public void Compare_ints() + { + CompareMultipleRuns( + "int.Parse", () => int.Parse("1"), + "SCU.Parse", () => TypeSerializer.DeserializeFromString("1") + ); + } + + [Test] + public void Compare_longs() + { + CompareMultipleRuns( + "long.Parse", () => long.Parse("1"), + "SCU.Parse", () => TypeSerializer.DeserializeFromString("1") + ); + } + + [Test] + public void Compare_Guids() + { + CompareMultipleRuns( + "new Guid", () => new Guid("AC800C9C-B8BE-4829-868A-B43CFF7B2AFD"), + "SCU.Parse", () => TypeSerializer.DeserializeFromString("AC800C9C-B8BE-4829-868A-B43CFF7B2AFD") + ); + } + + [Test] + public void Compare_DateTime() + { + const string dateTimeStr = "2009-12-20T19:24:37.4379982Z"; + CompareMultipleRuns( + "DateTime.Parse", () => DateTime.Parse(dateTimeStr), + "SCU.Parse", () => TypeSerializer.DeserializeFromString(dateTimeStr) + ); + } + + private static string[] SplitList(string listStr) + { + return listStr.Substring(1, listStr.Length - 2).Split(','); + } + + [Test] + public void Compare_IntList() + { + const string intValues = "[0,1,2,3,4,5,6,7,8,9]"; + CompareMultipleRuns( + "intValues.Split(',').ConvertAll", () => SplitList(intValues).Map(int.Parse), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(intValues) + ); + } + + [Test] + public void Compare_LongList() + { + const string longValues = "[0,1,2,3,4,5,6,7,8,9]"; + CompareMultipleRuns( + "intValues.Split(',').ConvertAll", () => SplitList(longValues).Map(long.Parse), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(longValues) + ); + } + + [Test] + public void Compare_StringArray() + { + const string stringValues = "[a,b,c,d,e,f,g,h,i,j]"; + CompareMultipleRuns( + "TextExtensions.FromCsvFields", () => TextExtensions.FromCsvFields(stringValues.Split(',')), + "SCU.Parse", () => TypeSerializer.DeserializeFromString(stringValues) + ); + } + + [Test] + public void Compare_DoubleArray() + { + const string stringValues = "[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.1]"; + CompareMultipleRuns( + ".Split(',').ConvertAll(x => double.Parse(x))", () => SplitList(stringValues).Map(double.Parse), + "SCU.Parse", () => TypeSerializer.DeserializeFromString(stringValues) + ); + } + + [Test] + public void Compare_GuidArray() + { + const string stringValues = "[8F403A5E-CDFC-4C6F-B0EB-C055C1C8BA60,5673BAC7-BAC5-4B3F-9B69-4180E6227508,B0CA730F-14C9-4D00-AC7F-07E7DE8D566E,4E26AF94-6B13-4F89-B192-36C6ABE73DAE,08491B16-2270-4DF9-8AEE-A8861A791C50]"; + CompareMultipleRuns( + ".Split(',').ConvertAll(x => new Guid(x))", () => SplitList(stringValues).Map(x => new Guid(x)), + "SCU.Parse", () => TypeSerializer.DeserializeFromString(stringValues) + ); + } + + [Test] + public void Compare_StringList() + { + const string stringValues = "[a,b,c,d,e,f,g,h,i,j]"; + CompareMultipleRuns( + "stringValues.Split(',').FromCsvFields()", () => SplitList(stringValues).FromCsvFields(), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) + ); + } + + [Test] + public void Compare_DoubleList() + { + const string stringValues = "[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.1]"; + CompareMultipleRuns( + ".Split(',').ConvertAll(x => double.Parse(x))", () => SplitList(stringValues).Map(double.Parse), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) + ); + } + + [Test] + public void Compare_GuidList() + { + const string stringValues = "[8F403A5E-CDFC-4C6F-B0EB-C055C1C8BA60,5673BAC7-BAC5-4B3F-9B69-4180E6227508,B0CA730F-14C9-4D00-AC7F-07E7DE8D566E,4E26AF94-6B13-4F89-B192-36C6ABE73DAE,08491B16-2270-4DF9-8AEE-A8861A791C50]"; + CompareMultipleRuns( + ".Split(',').ConvertAll(x => new Guid(x))", () => SplitList(stringValues).Map(x => new Guid(x)), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) + ); + } + + [Test] + public void Compare_StringHashSet() + { + const string stringValues = "[a,b,c,d,e,f,g,h,i,j]"; + CompareMultipleRuns( + "new HashSet(.Split(',').FromCsvFields())", () => new HashSet(SplitList(stringValues).FromCsvFields()), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) + ); + } + + [Test] + public void Compare_IntHashSet() + { + const string stringValues = "[0,1,2,3,4,5,6,7,8,9]"; + CompareMultipleRuns( + "new HashSet(.Split(',').ConvertAll(x => int.Parse(x))", () => new HashSet(SplitList(stringValues).Map(int.Parse)), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) + ); + } + + [Test] + public void Compare_DoubleHashSet() + { + const string stringValues = "[1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,0.1]"; + CompareMultipleRuns( + "new HashSet(.ConvertAll(x => double.Parse(x)))", () => new HashSet(SplitList(stringValues).Map(double.Parse)), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(stringValues) + ); + } + + [Test] + public void Compare_StringStringMap() + { + const string mapValues = "{A:1,B:2,C:3,D:4,E:5,F:6,G:7,H:8,I:9,J:0}"; + var map = new Dictionary(); + CompareMultipleRuns( + "mapValues.Split(',').ConvertAll", () => SplitList(mapValues).Map(x => x.Split(':')).ForEach(y => map[y[0].FromCsvField()] = y[1].FromCsvField()), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(mapValues) + ); + } + + [Test] + public void Compare_StringIntMap() + { + const string mapValues = "{A:1,B:2,C:3,D:4,E:5,F:6,G:7,H:8,I:9,J:0}"; + var map = new Dictionary(); + CompareMultipleRuns( + "mapValues.Split(',').ConvertAll", () => SplitList(mapValues).Map(x => x.Split(':')).ForEach(y => map[y[0].FromCsvField()] = int.Parse(y[1])), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(mapValues) + ); + } + + [Test] + public void Compare_StringInt_SortedDictionary() + { + const string mapValues = "{A:1,B:2,C:3,D:4,E:5,F:6,G:7,H:8,I:9,J:0}"; + var map = new SortedDictionary(); + CompareMultipleRuns( + "mapValues.Split(',').ConvertAll", () => SplitList(mapValues).Map(x => x.Split(':')).ForEach(y => map[y[0].FromCsvField()] = int.Parse(y[1])), + "SCU.Parse>", () => TypeSerializer.DeserializeFromString>(mapValues) + ); + } + + [Test] + public void Compare_ByteArray() + { + var byteArrayValue = new byte[] { 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, }; + var byteArrayString = Convert.ToBase64String(byteArrayValue); + + CompareMultipleRuns( + "Encoding.Default.GetBytes", () => System.Text.Encoding.GetEncoding(0).GetBytes(byteArrayString), + "SCU.Parse", () => TypeSerializer.DeserializeFromString(byteArrayString) + ); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/TextSerializerComparisons.cs b/tests/ServiceStack.Common.Tests/Perf/TextSerializerComparisons.cs deleted file mode 100644 index 1001e32ad04..00000000000 --- a/tests/ServiceStack.Common.Tests/Perf/TextSerializerComparisons.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Collections.Generic; -using Northwind.Common.ComplexModel; -using NUnit.Framework; -using ServiceStack.Text; - -namespace ServiceStack.Common.Tests.Perf -{ - [Ignore("Benchmarks on the war of the two text serializers")] - [TestFixture] - public class TextSerializerComparisons - : PerfTestBase - { - public TextSerializerComparisons() - { - this.MultipleIterations = new List { 10000 }; - } - - private void CompareSerializers(T dto) - { - CompareMultipleRuns( - "TypeSerializer", () => TypeSerializer.SerializeToString(dto), - "TextSerializer", () => JsonSerializer.SerializeToString(dto) - ); - - var stringStr = TypeSerializer.SerializeToString(dto); - var textStr = JsonSerializer.SerializeToString(dto); - - //return; - - CompareMultipleRuns( - "TypeSerializer", () => TypeSerializer.DeserializeFromString(stringStr), - "JsonSerializer", () => JsonSerializer.DeserializeFromString(textStr) - ); - - var seraializedStringDto = TypeSerializer.DeserializeFromString(stringStr); - Assert.That(seraializedStringDto.Equals(dto), Is.True); - - JsonSerializer.DeserializeFromString(textStr); - //Assert.That(seraializedTextDto.Equals(dto), Is.True); - } - - [Test] - public void Compare_ArrayDtoWithOrders() - { - CompareSerializers(DtoFactory.ArrayDtoWithOrders); - } - - [Test] - public void Compare_CustomerDto() - { - CompareSerializers(DtoFactory.CustomerDto); - } - - [Test] - public void Compare_CustomerOrderArrayDto() - { - CompareSerializers(DtoFactory.CustomerOrderArrayDto); - } - - [Test] - public void Compare_CustomerOrderListDto() - { - CompareSerializers(DtoFactory.CustomerOrderListDto); - } - - [Test] - public void Compare_MultiCustomerProperties() - { - CompareSerializers(DtoFactory.MultiCustomerProperties); - } - - [Test] - public void Compare_MultiDtoWithOrders() - { - CompareSerializers(DtoFactory.MultiDtoWithOrders); - } - - [Test] - public void Compare_MultiOrderProperties() - { - CompareSerializers(DtoFactory.MultiOrderProperties); - } - - [Test] - public void Compare_OrderDto() - { - CompareSerializers(DtoFactory.OrderDto); - } - - [Test] - public void Compare_SupplierDto() - { - CompareSerializers(DtoFactory.SupplierDto); - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Perf/ToStringPerf.cs b/tests/ServiceStack.Common.Tests/Perf/ToStringPerf.cs index 7be58717771..d068569a190 100644 --- a/tests/ServiceStack.Common.Tests/Perf/ToStringPerf.cs +++ b/tests/ServiceStack.Common.Tests/Perf/ToStringPerf.cs @@ -7,300 +7,312 @@ namespace ServiceStack.Common.Tests.Perf { - [Ignore("Bencharks for serializing basic .NET types")] - [TestFixture] - public class ToStringPerf - : PerfTestBase - { - public ToStringPerf() - { - this.MultipleIterations = new List { 10000 }; - } + [Ignore("Bencharks for serializing basic .NET types")] + [TestFixture] + public class ToStringPerf + : PerfTestBase + { + public ToStringPerf() + { + this.MultipleIterations = new List { 10000 }; + } - [Test] - public void Compare_string() - { - CompareMultipleRuns( - "'test'.ToCsvField()", () => "test".ToCsvField(), - "SCU.ToString('test')", () => TypeSerializer.SerializeToString("test") - ); - } + [Test] + public void Compare_string() + { + CompareMultipleRuns( + "'test'.ToCsvField()", () => "test".ToCsvField(), + "SCU.ToString('test')", () => TypeSerializer.SerializeToString("test") + ); + } - [Test] - public void Compare_escaped_string() - { - CompareMultipleRuns( - "'t,e:st'.ToCsvField()", () => "t,e:st".ToCsvField(), - "SCU.ToString('t,e:st')", () => TypeSerializer.SerializeToString("t,e:st") - ); - } + [Test] + public void Compare_escaped_string() + { + CompareMultipleRuns( + "'t,e:st'.ToCsvField()", () => "t,e:st".ToCsvField(), + "SCU.ToString('t,e:st')", () => TypeSerializer.SerializeToString("t,e:st") + ); + } - [Test] - public void Compare_ints() - { - CompareMultipleRuns( - "1.ToString()", () => 1.ToString(), - "SCU.ToString(1)", () => TypeSerializer.SerializeToString(1) - ); - } + [Test] + public void Compare_ints() + { + CompareMultipleRuns( + "1.ToString()", () => 1.ToString(), + "SCU.ToString(1)", () => TypeSerializer.SerializeToString(1) + ); + } - [Test] - public void Compare_longs() - { - CompareMultipleRuns( - "1L.ToString()", () => 1L.ToString(), - "SCU.ToString(1L)", () => TypeSerializer.SerializeToString(1L) - ); - } + [Test] + public void Compare_longs() + { + CompareMultipleRuns( + "1L.ToString()", () => 1L.ToString(), + "SCU.ToString(1L)", () => TypeSerializer.SerializeToString(1L) + ); + } - [Test] - public void Compare_Guids() - { - var guid = new Guid("AC800C9C-B8BE-4829-868A-B43CFF7B2AFD"); - CompareMultipleRuns( - "guid.ToString()", () => guid.ToString(), - "SCU.ToString(guid)", () => TypeSerializer.SerializeToString(guid) - ); - } + [Test] + public void Compare_Guids() + { + var guid = new Guid("AC800C9C-B8BE-4829-868A-B43CFF7B2AFD"); + CompareMultipleRuns( + "guid.ToString()", () => guid.ToString(), + "SCU.ToString(guid)", () => TypeSerializer.SerializeToString(guid) + ); + } - [Test] - public void Compare_DateTime() - { - var now = DateTime.Now; - CompareMultipleRuns( - "now.ToString()", () => now.ToString(), - "SCU.ToString(now)", () => TypeSerializer.SerializeToString(now) - ); - } + [Test] + public void Compare_DateTime() + { + var now = DateTime.Now; + CompareMultipleRuns( + "now.ToString()", () => now.ToString(), + "SCU.ToString(now)", () => TypeSerializer.SerializeToString(now) + ); + } - [Test] - public void Compare_IntList() - { - var intList = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - CompareMultipleRuns( - "intList.ForEach(x => sb.Append(x.ToString()))", () => { - var sb = new StringBuilder(); - intList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); - sb.ToString(); - }, - "SCU.ToString(intList)", () => TypeSerializer.SerializeToString(intList) - ); - } + [Test] + public void Compare_IntList() + { + var intList = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + CompareMultipleRuns( + "intList.ForEach(x => sb.Append(x.ToString()))", () => + { + var sb = new StringBuilder(); + intList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); + sb.ToString(); + }, + "SCU.ToString(intList)", () => TypeSerializer.SerializeToString(intList) + ); + } - [Test] - public void Compare_LongList() - { - var longList = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - CompareMultipleRuns( - "longList.ForEach(x => sb.Append(x.ToString()))", () => { - var sb = new StringBuilder(); - longList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); - sb.ToString(); - }, - "SCU.ToString(longList)", () => TypeSerializer.SerializeToString(longList) - ); - } + [Test] + public void Compare_LongList() + { + var longList = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + CompareMultipleRuns( + "longList.ForEach(x => sb.Append(x.ToString()))", () => + { + var sb = new StringBuilder(); + longList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); + sb.ToString(); + }, + "SCU.ToString(longList)", () => TypeSerializer.SerializeToString(longList) + ); + } - [Test] - public void Compare_StringArray() - { - var stringArray = new[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; - CompareMultipleRuns( - "sb.Append(s.ToCsvField());", () => { - var sb = new StringBuilder(); - foreach (var s in stringArray) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(s.ToCsvField()); - } - sb.ToString(); - }, - "SCU.ToString(stringArray)", () => TypeSerializer.SerializeToString(stringArray) - ); - } + [Test] + public void Compare_StringArray() + { + var stringArray = new[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; + CompareMultipleRuns( + "sb.Append(s.ToCsvField());", () => + { + var sb = new StringBuilder(); + foreach (var s in stringArray) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(s.ToCsvField()); + } + sb.ToString(); + }, + "SCU.ToString(stringArray)", () => TypeSerializer.SerializeToString(stringArray) + ); + } - [Test] - public void Compare_StringList() - { - var stringList = new List { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; - CompareMultipleRuns( - "sb.Append(s.ToCsvField());", () => { - var sb = new StringBuilder(); - stringList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); - sb.ToString(); - }, - "SCU.ToString(stringList)", () => TypeSerializer.SerializeToString(stringList) - ); - } + [Test] + public void Compare_StringList() + { + var stringList = new List { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; + CompareMultipleRuns( + "sb.Append(s.ToCsvField());", () => + { + var sb = new StringBuilder(); + stringList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); + sb.ToString(); + }, + "SCU.ToString(stringList)", () => TypeSerializer.SerializeToString(stringList) + ); + } - [Test] - public void Compare_DoubleList() - { - var doubleList = new List { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 0.1 }; - CompareMultipleRuns( - "doubleList.ForEach(x => sb.Append(x.ToString()))", () => { - var sb = new StringBuilder(); - doubleList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); - sb.ToString(); - }, - "SCU.ToString(doubleList)", () => TypeSerializer.SerializeToString(doubleList) - ); - } + [Test] + public void Compare_DoubleList() + { + var doubleList = new List { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 0.1 }; + CompareMultipleRuns( + "doubleList.ForEach(x => sb.Append(x.ToString()))", () => + { + var sb = new StringBuilder(); + doubleList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); + sb.ToString(); + }, + "SCU.ToString(doubleList)", () => TypeSerializer.SerializeToString(doubleList) + ); + } - [Test] - public void Compare_GuidList() - { - var guidList = new List - { - new Guid("8F403A5E-CDFC-4C6F-B0EB-C055C1C8BA60"), - new Guid("5673BAC7-BAC5-4B3F-9B69-4180E6227508"), - new Guid("B0CA730F-14C9-4D00-AC7F-07E7DE8D566E"), - new Guid("4E26AF94-6B13-4F89-B192-36C6ABE73DAE"), - new Guid("08491B16-2270-4DF9-8AEE-A8861A791C50"), - }; - CompareMultipleRuns( - "guidList.ForEach(x => sb.Append(x.ToString()))", () => { - var sb = new StringBuilder(); - guidList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); - sb.ToString(); - }, - "SCU.ToString(guidList)", () => TypeSerializer.SerializeToString(guidList) - ); - } + [Test] + public void Compare_GuidList() + { + var guidList = new List + { + new Guid("8F403A5E-CDFC-4C6F-B0EB-C055C1C8BA60"), + new Guid("5673BAC7-BAC5-4B3F-9B69-4180E6227508"), + new Guid("B0CA730F-14C9-4D00-AC7F-07E7DE8D566E"), + new Guid("4E26AF94-6B13-4F89-B192-36C6ABE73DAE"), + new Guid("08491B16-2270-4DF9-8AEE-A8861A791C50"), + }; + CompareMultipleRuns( + "guidList.ForEach(x => sb.Append(x.ToString()))", () => + { + var sb = new StringBuilder(); + guidList.ForEach(x => { if (sb.Length > 0) sb.Append(","); sb.Append(x.ToString()); }); + sb.ToString(); + }, + "SCU.ToString(guidList)", () => TypeSerializer.SerializeToString(guidList) + ); + } - [Test] - public void Compare_StringHashSet() - { - var stringHashSet = new HashSet { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; - CompareMultipleRuns( - "sb.Append(s.ToCsvField());", () => { - var sb = new StringBuilder(); - foreach (var s in stringHashSet) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(s.ToCsvField()); - } - sb.ToString(); - }, - "SCU.ToString(stringHashSet)", () => TypeSerializer.SerializeToString(stringHashSet) - ); - } + [Test] + public void Compare_StringHashSet() + { + var stringHashSet = new HashSet { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; + CompareMultipleRuns( + "sb.Append(s.ToCsvField());", () => + { + var sb = new StringBuilder(); + foreach (var s in stringHashSet) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(s.ToCsvField()); + } + sb.ToString(); + }, + "SCU.ToString(stringHashSet)", () => TypeSerializer.SerializeToString(stringHashSet) + ); + } - [Test] - public void Compare_IntHashSet() - { - var intHashSet = new HashSet { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - CompareMultipleRuns( - "intList.ForEach(x => sb.Append(x.ToString()))", () => { - var sb = new StringBuilder(); - foreach (var s in intHashSet) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(s.ToString()); - } - sb.ToString(); - }, - "SCU.ToString(intHashSet)", () => TypeSerializer.SerializeToString(intHashSet) - ); - } + [Test] + public void Compare_IntHashSet() + { + var intHashSet = new HashSet { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + CompareMultipleRuns( + "intList.ForEach(x => sb.Append(x.ToString()))", () => + { + var sb = new StringBuilder(); + foreach (var s in intHashSet) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(s.ToString()); + } + sb.ToString(); + }, + "SCU.ToString(intHashSet)", () => TypeSerializer.SerializeToString(intHashSet) + ); + } - [Test] - public void Compare_DoubleHashSet() - { - var doubleHashSet = new HashSet { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 0.1 }; - CompareMultipleRuns( - "doubleList.ForEach(x => sb.Append(x.ToString()))", () => { - var sb = new StringBuilder(); - foreach (var s in doubleHashSet) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(s.ToString()); - } - sb.ToString(); - }, - "SCU.ToString(doubleHashSet)", () => TypeSerializer.SerializeToString(doubleHashSet) - ); - } + [Test] + public void Compare_DoubleHashSet() + { + var doubleHashSet = new HashSet { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 0.1 }; + CompareMultipleRuns( + "doubleList.ForEach(x => sb.Append(x.ToString()))", () => + { + var sb = new StringBuilder(); + foreach (var s in doubleHashSet) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(s.ToString()); + } + sb.ToString(); + }, + "SCU.ToString(doubleHashSet)", () => TypeSerializer.SerializeToString(doubleHashSet) + ); + } - [Test] - public void Compare_StringStringMap() - { - var map = new Dictionary { - {"A", "1"},{"B", "2"},{"C", "3"},{"D", "4"},{"E", "5"}, - {"F", "6"},{"G", "7"},{"H", "8"},{"I", "9"},{"j", "10"}, - }; - CompareMultipleRuns( - "sb.Append(kv.Key.ToCsvField()).Append(ParseStringMethods.KeyValueSeperator).", () => { - var sb = new StringBuilder(); - foreach (var kv in map) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(kv.Key.ToCsvField()) - .Append(JsWriter.MapKeySeperator) - .Append(kv.Value.ToCsvField()); - } - sb.ToString(); - }, - "SCU.ToString(map)", () => TypeSerializer.SerializeToString(map) - ); - } + [Test] + public void Compare_StringStringMap() + { + var map = new Dictionary { + {"A", "1"},{"B", "2"},{"C", "3"},{"D", "4"},{"E", "5"}, + {"F", "6"},{"G", "7"},{"H", "8"},{"I", "9"},{"j", "10"}, + }; + CompareMultipleRuns( + "sb.Append(kv.Key.ToCsvField()).Append(ParseStringMethods.KeyValueSeperator).", () => + { + var sb = new StringBuilder(); + foreach (var kv in map) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(kv.Key.ToCsvField()) + .Append(JsWriter.MapKeySeperator) + .Append(kv.Value.ToCsvField()); + } + sb.ToString(); + }, + "SCU.ToString(map)", () => TypeSerializer.SerializeToString(map) + ); + } - [Test] - public void Compare_StringIntMap() - { - var map = new Dictionary { - {"A", 1},{"B", 2},{"C", 3},{"D", 4},{"E", 5}, - {"F", 6},{"G", 7},{"H", 8},{"I", 9},{"j", 10}, - }; - CompareMultipleRuns( - ".Append(ParseStringMethods.KeyValueSeperator).Append(kv.Value.ToString())", () => { - var sb = new StringBuilder(); - foreach (var kv in map) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(kv.Key.ToCsvField()) - .Append(JsWriter.MapKeySeperator) - .Append(kv.Value.ToString()); - } - sb.ToString(); - }, - "SCU.ToString(map)", () => TypeSerializer.SerializeToString(map) - ); - } + [Test] + public void Compare_StringIntMap() + { + var map = new Dictionary { + {"A", 1},{"B", 2},{"C", 3},{"D", 4},{"E", 5}, + {"F", 6},{"G", 7},{"H", 8},{"I", 9},{"j", 10}, + }; + CompareMultipleRuns( + ".Append(ParseStringMethods.KeyValueSeperator).Append(kv.Value.ToString())", () => + { + var sb = new StringBuilder(); + foreach (var kv in map) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(kv.Key.ToCsvField()) + .Append(JsWriter.MapKeySeperator) + .Append(kv.Value.ToString()); + } + sb.ToString(); + }, + "SCU.ToString(map)", () => TypeSerializer.SerializeToString(map) + ); + } - [Test] - public void Compare_StringInt_SortedDictionary() - { - var map = new SortedDictionary{ - {"A", 1},{"B", 2},{"C", 3},{"D", 4},{"E", 5}, - {"F", 6},{"G", 7},{"H", 8},{"I", 9},{"j", 10}, - }; - CompareMultipleRuns( - ".Append(ParseStringMethods.KeyValueSeperator).Append(kv.Value.ToString())", () => { - var sb = new StringBuilder(); - foreach (var kv in map) - { - if (sb.Length > 0) sb.Append(","); - sb.Append(kv.Key.ToCsvField()) - .Append(JsWriter.MapKeySeperator) - .Append(kv.Value.ToString()); - } - sb.ToString(); - }, - "SCU.ToString(map)", () => TypeSerializer.SerializeToString(map) - ); - } + [Test] + public void Compare_StringInt_SortedDictionary() + { + var map = new SortedDictionary{ + {"A", 1},{"B", 2},{"C", 3},{"D", 4},{"E", 5}, + {"F", 6},{"G", 7},{"H", 8},{"I", 9},{"j", 10}, + }; + CompareMultipleRuns( + ".Append(ParseStringMethods.KeyValueSeperator).Append(kv.Value.ToString())", () => + { + var sb = new StringBuilder(); + foreach (var kv in map) + { + if (sb.Length > 0) sb.Append(","); + sb.Append(kv.Key.ToCsvField()) + .Append(JsWriter.MapKeySeperator) + .Append(kv.Value.ToString()); + } + sb.ToString(); + }, + "SCU.ToString(map)", () => TypeSerializer.SerializeToString(map) + ); + } - [Test] - public void Compare_ByteArray() - { - var byteArrayValue = new byte[] { 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, }; + [Test] + public void Compare_ByteArray() + { + var byteArrayValue = new byte[] { 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, 0, 65, 97, 255, }; - CompareMultipleRuns( - "Encoding.Default.GetString(byteArrayValue)", () => Encoding.Default.GetString(byteArrayValue), - "SCU.ToString(byteArrayValue)", () => TypeSerializer.SerializeToString(byteArrayValue) - ); - } + CompareMultipleRuns( + "Encoding.Default.GetString(byteArrayValue)", () => Encoding.GetEncoding(0).GetString(byteArrayValue), + "SCU.ToString(byteArrayValue)", () => TypeSerializer.SerializeToString(byteArrayValue) + ); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/PerfTestBase.cs b/tests/ServiceStack.Common.Tests/PerfTestBase.cs index d519ac0dbe8..b8722b53380 100644 --- a/tests/ServiceStack.Common.Tests/PerfTestBase.cs +++ b/tests/ServiceStack.Common.Tests/PerfTestBase.cs @@ -5,106 +5,106 @@ namespace ServiceStack.Common.Tests { - public class PerfTestBase - { - protected int DefaultIterations { get; set; } - protected List MultipleIterations { get; set; } - - public PerfTestBase() - { - this.DefaultIterations = 10000; - this.MultipleIterations = new List { 1000, 10000, 100000, 1000000 }; - } - - protected StringBuilder SbLog = new StringBuilder(); - - public void Log(string message, params object[] args) - { - Console.WriteLine(message, args); - - SbLog.AppendFormat(message, args); - SbLog.AppendLine(); - } - - protected void CompareMultipleRuns(string run1Name, Action run1Action, string run2Name, Action run2Action) - { - WarmUp(run1Action, run2Action); - foreach (var iteration in this.MultipleIterations) - { - Log("\n{0} times:", iteration); - CompareRuns(iteration, run1Name, run1Action, run2Name, run2Action); - } - } - - protected void CompareRuns(string run1Name, Action run1Action, string run2Name, Action run2Action) - { - CompareRuns(DefaultIterations, run1Name, run1Action, run2Name, run2Action); - } - - protected void CompareRuns(int iterations, string run1Name, Action run1Action, string run2Name, Action run2Action) - { - var run1 = RunAction(run1Action, iterations, run1Name); - var run2 = RunAction(run2Action, iterations, run2Name); - - var runDiff = run1.Ticks - run2.Ticks; - var run1IsSlower = runDiff > 0; - var slowerRun = run1IsSlower ? run1Name : run2Name; - var fasterRun = run1IsSlower ? run2Name : run1Name; - var runDiffTime = run1IsSlower ? runDiff : runDiff * -1; - var runDiffAvg = run1IsSlower ? run1.Ticks / (double)run2.Ticks : run2.Ticks / (double)run1.Ticks; - - Log("{0} was {1}ms or {2} times slower than {3}", - slowerRun, runDiffTime, Math.Round(runDiffAvg, 2), fasterRun); - } - - protected void WarmUp(params Action[] actions) - { - foreach (var action in actions) - { - action(); - GC.Collect(); - } - } - - protected void RunMultipleTimes(Action action, string actionName) - { - WarmUp(action); - foreach (var iteration in this.MultipleIterations) - { - Log("\n{0} times:", iteration); - RunAction(action, iteration, actionName ?? "Action"); - } - } - - protected TimeSpan RunAction(Action action, int iterations) - { - return RunAction(action, iterations, null); - } - - protected TimeSpan RunAction(Action action, int iterations, string actionName) - { - actionName = actionName ?? action.GetType().Name; - var ticksTaken = Measure(action, iterations); - var timeSpan = TimeSpan.FromSeconds(ticksTaken * 1d / Stopwatch.Frequency); - - Log("{0} took {1}ms ({2} ticks), avg: {3} ticks", actionName, timeSpan.TotalMilliseconds, timeSpan.Ticks, (timeSpan.Ticks / iterations)); - - return timeSpan; - } - - protected long Measure(Action action, decimal iterations) - { - GC.Collect(); - var begin = Stopwatch.GetTimestamp(); - - for (var i = 0; i < iterations; i++) - { - action(); - } - - var end = Stopwatch.GetTimestamp(); - - return (end - begin); - } - } + public class PerfTestBase + { + protected int DefaultIterations { get; set; } + protected List MultipleIterations { get; set; } + + public PerfTestBase() + { + this.DefaultIterations = 10000; + this.MultipleIterations = new List { 1000, 10000, 100000, 1000000 }; + } + + protected StringBuilder SbLog = new StringBuilder(); + + public void Log(string message, params object[] args) + { + Console.WriteLine(message, args); + + SbLog.AppendFormat(message, args); + SbLog.AppendLine(); + } + + protected void CompareMultipleRuns(string run1Name, Action run1Action, string run2Name, Action run2Action) + { + WarmUp(run1Action, run2Action); + foreach (var iteration in this.MultipleIterations) + { + Log("\n{0} times:", iteration); + CompareRuns(iteration, run1Name, run1Action, run2Name, run2Action); + } + } + + protected void CompareRuns(string run1Name, Action run1Action, string run2Name, Action run2Action) + { + CompareRuns(DefaultIterations, run1Name, run1Action, run2Name, run2Action); + } + + protected void CompareRuns(int iterations, string run1Name, Action run1Action, string run2Name, Action run2Action) + { + var run1 = RunAction(run1Action, iterations, run1Name); + var run2 = RunAction(run2Action, iterations, run2Name); + + var runDiff = run1.Ticks - run2.Ticks; + var run1IsSlower = runDiff > 0; + var slowerRun = run1IsSlower ? run1Name : run2Name; + var fasterRun = run1IsSlower ? run2Name : run1Name; + var runDiffTime = run1IsSlower ? runDiff : runDiff * -1; + var runDiffAvg = run1IsSlower ? run1.Ticks / (double)run2.Ticks : run2.Ticks / (double)run1.Ticks; + + Log("{0} was {1}ms or {2} times slower than {3}", + slowerRun, runDiffTime, Math.Round(runDiffAvg, 2), fasterRun); + } + + protected void WarmUp(params Action[] actions) + { + foreach (var action in actions) + { + action(); + GC.Collect(); + } + } + + protected void RunMultipleTimes(Action action, string actionName) + { + WarmUp(action); + foreach (var iteration in this.MultipleIterations) + { + Log("\n{0} times:", iteration); + RunAction(action, iteration, actionName ?? "Action"); + } + } + + protected TimeSpan RunAction(Action action, int iterations) + { + return RunAction(action, iterations, null); + } + + protected TimeSpan RunAction(Action action, int iterations, string actionName) + { + actionName = actionName ?? action.GetType().Name; + var ticksTaken = Measure(action, iterations); + var timeSpan = TimeSpan.FromSeconds(ticksTaken * 1d / Stopwatch.Frequency); + + Log("{0} took {1}ms ({2} ticks), avg: {3} ticks", actionName, timeSpan.TotalMilliseconds, timeSpan.Ticks, (timeSpan.Ticks / iterations)); + + return timeSpan; + } + + protected long Measure(Action action, decimal iterations) + { + GC.Collect(); + var begin = Stopwatch.GetTimestamp(); + + for (var i = 0; i < iterations; i++) + { + action(); + } + + var end = Stopwatch.GetTimestamp(); + + return (end - begin); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/PerfUtilsTests.cs b/tests/ServiceStack.Common.Tests/PerfUtilsTests.cs new file mode 100644 index 00000000000..7d666369837 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/PerfUtilsTests.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [TestFixture, Ignore("Benchmark")] + public class PerfUtilsTests + { + Random rand = new Random(); + + [Test] + public void Measure_unique_collections() + { + var set = new HashSet(); + var avgMicroSecs = PerfUtils.Measure( + () => set.Add(rand.Next(0, 1000)), runForMs:2000); + + "HashSet: {0}us".Print(avgMicroSecs); + + var list = new List(); + avgMicroSecs = PerfUtils.Measure( + () => { + int i = rand.Next(0, 1000); + if (!list.Contains(i)) + list.Add(i); + }, runForMs: 2000); + + "List: {0}us".Print(avgMicroSecs); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Common.Tests/Properties/AssemblyInfo.cs index 3c70899c6f1..0834a248a53 100644 --- a/tests/ServiceStack.Common.Tests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.Common.Tests/Properties/AssemblyInfo.cs @@ -10,8 +10,8 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Microsoft")] [assembly: AssemblyProduct("ServiceStack.Common.Tests")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCopyright("Copyright (c) Microsoft 2009")] +[assembly: AssemblyTrademark("Service Stack")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("6.0.0.0")] diff --git a/tests/ServiceStack.Common.Tests/Properties/Settings.Designer.cs b/tests/ServiceStack.Common.Tests/Properties/Settings.Designer.cs index f343767431a..8f514207da8 100644 --- a/tests/ServiceStack.Common.Tests/Properties/Settings.Designer.cs +++ b/tests/ServiceStack.Common.Tests/Properties/Settings.Designer.cs @@ -1,20 +1,21 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.17929 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ +#if !NETCORE namespace ServiceStack.Common.Tests.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { @@ -35,3 +36,4 @@ public string authConnectionString { } } } +#endif diff --git a/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs b/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs index 50bfd27b5d8..16e385c4717 100644 --- a/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs +++ b/tests/ServiceStack.Common.Tests/QueryStringSerializerTests.cs @@ -1,15 +1,13 @@ -using System.Collections.Generic; +#if !NETCORE +using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; using System.Web; -using Funq; using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Host; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Support.Mocks; namespace ServiceStack.Common.Tests { @@ -20,18 +18,20 @@ public class QueryStringSerializerTests public void Can_deserialize_TestRequest_QueryStringSerializer_output() { // Setup - var testAppHost = new TestAppHost(new Container(), typeof(TestService).Assembly); - var restPath = new RestPath(typeof(TestRequest), "/service", "GET"); - var restHandler = new RestHandler { RestPath = restPath }; + using (new BasicAppHost(typeof (TestService).Assembly).Init()) + { + var restPath = new RestPath(typeof(TestRequest), "/service", "GET"); + var restHandler = new RestHandler { RestPath = restPath }; - var requestString = "ListOfA={ListOfB:[{Property:prop1},{Property:prop2}]}"; - NameValueCollection queryString = HttpUtility.ParseQueryString(requestString); - var httpReq = new HttpRequestMock("service", "GET", "application/json", "service", queryString, new MemoryStream(), new NameValueCollection()); + var requestString = "ListOfA={ListOfB:[{Property:prop1},{Property:prop2}]}"; + NameValueCollection queryString = HttpUtility.ParseQueryString(requestString); + var httpReq = new MockHttpRequest("service", "GET", "application/json", "service", queryString, new MemoryStream(), new NameValueCollection()); - var request2 = (TestRequest)restHandler.CreateRequest(httpReq, "service"); + var request2 = (TestRequest)restHandler.CreateRequestAsync(httpReq, "service").Result; - Assert.That(request2.ListOfA.Count, Is.EqualTo(1)); - Assert.That(request2.ListOfA.First().ListOfB.Count, Is.EqualTo(2)); + Assert.That(request2.ListOfA.Count, Is.EqualTo(1)); + Assert.That(request2.ListOfA.First().ListOfB.Count, Is.EqualTo(2)); + } } [Test] @@ -42,7 +42,7 @@ public void QueryStringSerializer_TestRequest_output() Assert.That(str, Is.EqualTo("ListOfA={ListOfB:[{Property:prop1},{Property:prop2}]}")); } - public class TestService : ServiceInterface.Service + public class TestService : Service { public object Get(TestRequest request) { @@ -65,4 +65,5 @@ public class B public string Property { get; set; } } } -} \ No newline at end of file +} +#endif diff --git a/tests/ServiceStack.Common.Tests/RedisTypeTests.cs b/tests/ServiceStack.Common.Tests/RedisTypeTests.cs new file mode 100644 index 00000000000..febe5c0b54f --- /dev/null +++ b/tests/ServiceStack.Common.Tests/RedisTypeTests.cs @@ -0,0 +1,10 @@ +using NUnit.Framework; +using ServiceStack.Redis; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class RedisTypeTests + { + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Reflection/InvokerMethodTests.cs b/tests/ServiceStack.Common.Tests/Reflection/InvokerMethodTests.cs new file mode 100644 index 00000000000..79f178c9d5a --- /dev/null +++ b/tests/ServiceStack.Common.Tests/Reflection/InvokerMethodTests.cs @@ -0,0 +1,41 @@ +using NUnit.Framework; + +namespace ServiceStack.Common.Tests.Reflection +{ + class TransformDouble + { + public double Target { get; } + public TransformDouble(double target) => Target = target; + + public double Add(double value) => Target + value; + } + + public class InvokerMethodTests + { + [Test] + public void Can_use_MethodInvoker_to_call_Add_with_runtime_type() + { + var method = typeof(TransformDouble).GetMethod("Add"); + var invoker = method.GetInvoker(); + + var instance = new TransformDouble(1.0); + Assert.That(invoker(instance, 2.0), Is.EqualTo(3.0)); + + Assert.That(invoker(instance, 2), Is.EqualTo(3.0)); + Assert.That(invoker(instance, "2"), Is.EqualTo(3.0)); + } + + [Test] + public void Can_use_ObjectActivator_to_call_Add_with_runtime_type() + { + var ctor = typeof(TransformDouble).GetConstructors()[0]; + var activator = ctor.GetActivator(); + + Assert.That(((TransformDouble)activator(1.0)).Target, Is.EqualTo(1.0)); + + Assert.That(((TransformDouble)activator(1)).Target, Is.EqualTo(1.0)); + Assert.That(((TransformDouble)activator("1")).Target, Is.EqualTo(1.0)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Reflection/PropertyAccessorTests.cs b/tests/ServiceStack.Common.Tests/Reflection/PropertyAccessorTests.cs index 2a857239224..2b3ab090481 100644 --- a/tests/ServiceStack.Common.Tests/Reflection/PropertyAccessorTests.cs +++ b/tests/ServiceStack.Common.Tests/Reflection/PropertyAccessorTests.cs @@ -1,148 +1,149 @@ using NUnit.Framework; -using ServiceStack.Common.Reflection; using ServiceStack.Common.Tests.Models; namespace ServiceStack.Common.Tests.Reflection { - [TestFixture] - public class PropertyAccessorTests - { - [Test] - public void Can_access_ModelWithIdAndName() - { - var idAccessor = new PropertyAccessor("Id"); - var nameAccessor = new PropertyAccessor("Name"); - - var obj = new ModelWithIdAndName { Id = 1, Name = "A" }; - - Assert.That(idAccessor.GetPropertyFn()(obj), Is.EqualTo(1)); - Assert.That(nameAccessor.GetPropertyFn()(obj), Is.EqualTo("A")); - - idAccessor.SetPropertyFn()(obj, 2); - nameAccessor.SetPropertyFn()(obj, "B"); - - Assert.That(obj.Id, Is.EqualTo(2)); - Assert.That(obj.Name, Is.EqualTo("B")); - } - - [Test] - public void Can_access_ModelWithFieldsOfDifferentTypes() - { - var idAccessor = new PropertyAccessor("Id"); - var nameAccessor = new PropertyAccessor("Name"); - var longIdAccessor = new PropertyAccessor("LongId"); - var guidAccessor = new PropertyAccessor("Guid"); - var boolAccessor = new PropertyAccessor("Bool"); - var dateTimeAccessor = new PropertyAccessor("DateTime"); - - var original = ModelWithFieldsOfDifferentTypesFactory.Instance.CreateInstance(1); - - Assert.That(idAccessor.GetPropertyFn()(original), Is.EqualTo(original.Id)); - Assert.That(nameAccessor.GetPropertyFn()(original), Is.EqualTo(original.Name)); - Assert.That(longIdAccessor.GetPropertyFn()(original), Is.EqualTo(original.LongId)); - Assert.That(guidAccessor.GetPropertyFn()(original), Is.EqualTo(original.Guid)); - Assert.That(boolAccessor.GetPropertyFn()(original), Is.EqualTo(original.Bool)); - Assert.That(dateTimeAccessor.GetPropertyFn()(original), Is.EqualTo(original.DateTime)); - - var to = ModelWithFieldsOfDifferentTypesFactory.Instance.CreateInstance(2); - - idAccessor.SetPropertyFn()(original, to.Id); - nameAccessor.SetPropertyFn()(original, to.Name); - longIdAccessor.SetPropertyFn()(original, to.LongId); - guidAccessor.SetPropertyFn()(original, to.Guid); - boolAccessor.SetPropertyFn()(original, to.Bool); - dateTimeAccessor.SetPropertyFn()(original, to.DateTime); - - ModelWithFieldsOfDifferentTypesFactory.Instance.AssertIsEqual(original, to); - } - - [Test] - public void Can_access_ModelWithComplexTypes() - { - var idAccessor = new PropertyAccessor("Id"); - var stringListAccessor = new PropertyAccessor("StringList"); - var intListAccessor = new PropertyAccessor("IntList"); - var stringMapAccessor = new PropertyAccessor("StringMap"); - var intMapAccessor = new PropertyAccessor("IntMap"); - var childAccessor = new PropertyAccessor("Child"); - - var original = ModelWithComplexTypesFactory.Instance.CreateInstance(1); - - Assert.That(idAccessor.GetPropertyFn()(original), Is.EqualTo(original.Id)); - Assert.That(stringListAccessor.GetPropertyFn()(original), Is.EqualTo(original.StringList)); - Assert.That(intListAccessor.GetPropertyFn()(original), Is.EqualTo(original.IntList)); - Assert.That(stringMapAccessor.GetPropertyFn()(original), Is.EqualTo(original.StringMap)); - Assert.That(intMapAccessor.GetPropertyFn()(original), Is.EqualTo(original.IntMap)); - Assert.That(childAccessor.GetPropertyFn()(original), Is.EqualTo(original.Child)); - - var to = ModelWithComplexTypesFactory.Instance.CreateInstance(2); - - idAccessor.SetPropertyFn()(original, to.Id); - stringListAccessor.SetPropertyFn()(original, to.StringList); - intListAccessor.SetPropertyFn()(original, to.IntList); - stringMapAccessor.SetPropertyFn()(original, to.StringMap); - intMapAccessor.SetPropertyFn()(original, to.IntMap); - childAccessor.SetPropertyFn()(original, to.Child); - - ModelWithComplexTypesFactory.Instance.AssertIsEqual(original, to); - } - - [Test] - public void Can_access_ModelWithFieldsOfDifferentAndNullableTypes() - { - var idAccessor = new PropertyAccessor("Id"); - var idNAccessor = new PropertyAccessor("NId"); - var longIdAccessor = new PropertyAccessor("NLongId"); - var guidAccessor = new PropertyAccessor("NGuid"); - var boolAccessor = new PropertyAccessor("NBool"); - var dateTimeAccessor = new PropertyAccessor("NDateTime"); - var floatAccessor = new PropertyAccessor("NFloat"); - var doubleAccessor = new PropertyAccessor("NDouble"); - var decimalAccessor = new PropertyAccessor("NDecimal"); - var timespanAccessor = new PropertyAccessor("NTimeSpan"); - - var original = ModelWithFieldsOfNullableTypesFactory.Instance.CreateInstance(1); - - Assert.That(idAccessor.GetPropertyFn()(original), Is.EqualTo(original.Id)); - Assert.That(idNAccessor.GetPropertyFn()(original), Is.EqualTo(original.NId)); - Assert.That(longIdAccessor.GetPropertyFn()(original), Is.EqualTo(original.NLongId)); - Assert.That(guidAccessor.GetPropertyFn()(original), Is.EqualTo(original.NGuid)); - Assert.That(boolAccessor.GetPropertyFn()(original), Is.EqualTo(original.NBool)); - Assert.That(dateTimeAccessor.GetPropertyFn()(original), Is.EqualTo(original.NDateTime)); - Assert.That(floatAccessor.GetPropertyFn()(original), Is.EqualTo(original.NFloat)); - Assert.That(doubleAccessor.GetPropertyFn()(original), Is.EqualTo(original.NDouble)); - Assert.That(decimalAccessor.GetPropertyFn()(original), Is.EqualTo(original.NDecimal)); - Assert.That(timespanAccessor.GetPropertyFn()(original), Is.EqualTo(original.NTimeSpan)); - - var to = ModelWithFieldsOfNullableTypesFactory.Instance.CreateInstance(2); - - idAccessor.SetPropertyFn()(original, to.Id); - idNAccessor.SetPropertyFn()(original, to.NId); - longIdAccessor.SetPropertyFn()(original, to.NLongId); - guidAccessor.SetPropertyFn()(original, to.NGuid); - boolAccessor.SetPropertyFn()(original, to.NBool); - dateTimeAccessor.SetPropertyFn()(original, to.NDateTime); - floatAccessor.SetPropertyFn()(original, to.NFloat); - doubleAccessor.SetPropertyFn()(original, to.NDouble); - decimalAccessor.SetPropertyFn()(original, to.NDecimal); - timespanAccessor.SetPropertyFn()(original, to.NTimeSpan); - - ModelWithFieldsOfNullableTypesFactory.Instance.AssertIsEqual(original, to); - - //Can handle nulls - original = new ModelWithFieldsOfNullableTypes(); - - Assert.That(idAccessor.GetPropertyFn()(original), Is.EqualTo(original.Id)); - Assert.That(idNAccessor.GetPropertyFn()(original), Is.EqualTo(original.NId)); - Assert.That(longIdAccessor.GetPropertyFn()(original), Is.EqualTo(original.NLongId)); - Assert.That(guidAccessor.GetPropertyFn()(original), Is.EqualTo(original.NGuid)); - Assert.That(boolAccessor.GetPropertyFn()(original), Is.EqualTo(original.NBool)); - Assert.That(dateTimeAccessor.GetPropertyFn()(original), Is.EqualTo(original.NDateTime)); - Assert.That(floatAccessor.GetPropertyFn()(original), Is.EqualTo(original.NFloat)); - Assert.That(doubleAccessor.GetPropertyFn()(original), Is.EqualTo(original.NDouble)); - Assert.That(decimalAccessor.GetPropertyFn()(original), Is.EqualTo(original.NDecimal)); - Assert.That(timespanAccessor.GetPropertyFn()(original), Is.EqualTo(original.NTimeSpan)); - } - - } + [TestFixture] + public class PropertyAccessorTests + { + [Test] + public void Can_access_ModelWithIdAndName() + { + var accessor = TypeProperties.Instance; + + var obj = new ModelWithIdAndName { Id = 1, Name = "A" }; + + Assert.That(accessor.GetPublicGetter("Id")(obj), Is.EqualTo(1)); + Assert.That(accessor.GetPublicGetter("Name")(obj), Is.EqualTo("A")); + + accessor.GetPublicSetter("Id")(obj, 2); + accessor.GetPublicSetter("Name")(obj, "B"); + + Assert.That(obj.Id, Is.EqualTo(2)); + Assert.That(obj.Name, Is.EqualTo("B")); + } + + [Test] + public void Can_access_ModelWithFieldsOfDifferentTypes() + { + var idAccessor = TypeProperties.GetAccessor("Id"); + var nameAccessor = TypeProperties.GetAccessor("Name"); + var longIdAccessor = TypeProperties.GetAccessor("LongId"); + var guidAccessor = TypeProperties.GetAccessor("Guid"); + var boolAccessor = TypeProperties.GetAccessor("Bool"); + var doubleAccessor = TypeProperties.GetAccessor("Double"); + var dateTimeAccessor = TypeProperties.GetAccessor("DateTime"); + + var original = ModelWithFieldsOfDifferentTypesFactory.Instance.CreateInstance(1); + + Assert.That(idAccessor.PublicGetter(original), Is.EqualTo(original.Id)); + Assert.That(nameAccessor.PublicGetter(original), Is.EqualTo(original.Name)); + Assert.That(longIdAccessor.PublicGetter(original), Is.EqualTo(original.LongId)); + Assert.That(guidAccessor.PublicGetter(original), Is.EqualTo(original.Guid)); + Assert.That(boolAccessor.PublicGetter(original), Is.EqualTo(original.Bool)); + Assert.That(doubleAccessor.PublicGetter(original), Is.EqualTo(original.Double).Within(0.1)); + Assert.That(dateTimeAccessor.PublicGetter(original), Is.EqualTo(original.DateTime)); + + var to = ModelWithFieldsOfDifferentTypesFactory.Instance.CreateInstance(2); + + idAccessor.PublicSetter(original, to.Id); + nameAccessor.PublicSetter(original, to.Name); + longIdAccessor.PublicSetter(original, to.LongId); + guidAccessor.PublicSetter(original, to.Guid); + boolAccessor.PublicSetter(original, to.Bool); + doubleAccessor.PublicSetter(original, to.Double); + dateTimeAccessor.PublicSetter(original, to.DateTime); + + ModelWithFieldsOfDifferentTypesFactory.Instance.AssertIsEqual(original, to); + } + + [Test] + public void Can_access_ModelWithComplexTypes() + { + var idAccessor = TypeProperties.GetAccessor("Id"); + var stringListAccessor = TypeProperties.GetAccessor("StringList"); + var intListAccessor = TypeProperties.GetAccessor("IntList"); + var stringMapAccessor = TypeProperties.GetAccessor("StringMap"); + var intMapAccessor = TypeProperties.GetAccessor("IntMap"); + var childAccessor = TypeProperties.GetAccessor("Child"); + + var original = ModelWithComplexTypesFactory.Instance.CreateInstance(1); + + Assert.That(idAccessor.PublicGetter(original), Is.EqualTo(original.Id)); + Assert.That(stringListAccessor.PublicGetter(original), Is.EqualTo(original.StringList)); + Assert.That(intListAccessor.PublicGetter(original), Is.EqualTo(original.IntList)); + Assert.That(stringMapAccessor.PublicGetter(original), Is.EqualTo(original.StringMap)); + Assert.That(intMapAccessor.PublicGetter(original), Is.EqualTo(original.IntMap)); + Assert.That(childAccessor.PublicGetter(original), Is.EqualTo(original.Child)); + + var to = ModelWithComplexTypesFactory.Instance.CreateInstance(2); + + idAccessor.PublicSetter(original, to.Id); + stringListAccessor.PublicSetter(original, to.StringList); + intListAccessor.PublicSetter(original, to.IntList); + stringMapAccessor.PublicSetter(original, to.StringMap); + intMapAccessor.PublicSetter(original, to.IntMap); + childAccessor.PublicSetter(original, to.Child); + + ModelWithComplexTypesFactory.Instance.AssertIsEqual(original, to); + } + + [Test] + public void Can_access_ModelWithFieldsOfDifferentAndNullableTypes() + { + var idAccessor = TypeProperties.GetAccessor("Id"); + var idNAccessor = TypeProperties.GetAccessor("NId"); + var longIdAccessor = TypeProperties.GetAccessor("NLongId"); + var guidAccessor = TypeProperties.GetAccessor("NGuid"); + var boolAccessor = TypeProperties.GetAccessor("NBool"); + var dateTimeAccessor = TypeProperties.GetAccessor("NDateTime"); + var floatAccessor = TypeProperties.GetAccessor("NFloat"); + var doubleAccessor = TypeProperties.GetAccessor("NDouble"); + var decimalAccessor = TypeProperties.GetAccessor("NDecimal"); + var timespanAccessor = TypeProperties.GetAccessor("NTimeSpan"); + + var original = ModelWithFieldsOfNullableTypesFactory.Instance.CreateInstance(1); + + Assert.That(idAccessor.PublicGetter(original), Is.EqualTo(original.Id)); + Assert.That(idNAccessor.PublicGetter(original), Is.EqualTo(original.NId)); + Assert.That(longIdAccessor.PublicGetter(original), Is.EqualTo(original.NLongId)); + Assert.That(guidAccessor.PublicGetter(original), Is.EqualTo(original.NGuid)); + Assert.That(boolAccessor.PublicGetter(original), Is.EqualTo(original.NBool)); + Assert.That(dateTimeAccessor.PublicGetter(original), Is.EqualTo(original.NDateTime)); + Assert.That(floatAccessor.PublicGetter(original), Is.EqualTo(original.NFloat)); + Assert.That(doubleAccessor.PublicGetter(original), Is.EqualTo(original.NDouble)); + Assert.That(decimalAccessor.PublicGetter(original), Is.EqualTo(original.NDecimal)); + Assert.That(timespanAccessor.PublicGetter(original), Is.EqualTo(original.NTimeSpan)); + + var to = ModelWithFieldsOfNullableTypesFactory.Instance.CreateInstance(2); + + idAccessor.PublicSetter(original, to.Id); + idNAccessor.PublicSetter(original, to.NId); + longIdAccessor.PublicSetter(original, to.NLongId); + guidAccessor.PublicSetter(original, to.NGuid); + boolAccessor.PublicSetter(original, to.NBool); + dateTimeAccessor.PublicSetter(original, to.NDateTime); + floatAccessor.PublicSetter(original, to.NFloat); + doubleAccessor.PublicSetter(original, to.NDouble); + decimalAccessor.PublicSetter(original, to.NDecimal); + timespanAccessor.PublicSetter(original, to.NTimeSpan); + + ModelWithFieldsOfNullableTypesFactory.Instance.AssertIsEqual(original, to); + + //Can handle nulls + original = new ModelWithFieldsOfNullableTypes(); + + Assert.That(idAccessor.PublicGetter(original), Is.EqualTo(original.Id)); + Assert.That(idNAccessor.PublicGetter(original), Is.EqualTo(original.NId)); + Assert.That(longIdAccessor.PublicGetter(original), Is.EqualTo(original.NLongId)); + Assert.That(guidAccessor.PublicGetter(original), Is.EqualTo(original.NGuid)); + Assert.That(boolAccessor.PublicGetter(original), Is.EqualTo(original.NBool)); + Assert.That(dateTimeAccessor.PublicGetter(original), Is.EqualTo(original.NDateTime)); + Assert.That(floatAccessor.PublicGetter(original), Is.EqualTo(original.NFloat)); + Assert.That(doubleAccessor.PublicGetter(original), Is.EqualTo(original.NDouble)); + Assert.That(decimalAccessor.PublicGetter(original), Is.EqualTo(original.NDecimal)); + Assert.That(timespanAccessor.PublicGetter(original), Is.EqualTo(original.NTimeSpan)); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ReflectionExtensionsTests.cs b/tests/ServiceStack.Common.Tests/ReflectionExtensionsTests.cs index 4485ba04b43..1e6b73fb559 100644 --- a/tests/ServiceStack.Common.Tests/ReflectionExtensionsTests.cs +++ b/tests/ServiceStack.Common.Tests/ReflectionExtensionsTests.cs @@ -1,68 +1,70 @@ +using System; using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Text; namespace ServiceStack.Common.Tests { - public enum UserFileType - { - DefaultProfile, - OriginalProfile, - Profile75X75, - Profile66X66, - Profile63X63, - } - - public class TestClassA - { - public IList ToStringList { get; set; } - public ArrayOfString FromStringList { get; set; } - public IList FromUserFileTypes { get; set; } - } - - public class TestClassB - { - public ArrayOfString ToStringList { get; set; } - public IList FromStringList { get; set; } - public ArrayOfString FromUserFileTypes { get; set; } - } + public enum UserFileType + { + DefaultProfile, + OriginalProfile, + Profile75X75, + Profile66X66, + Profile63X63, + } + + public class TestClassA + { + public IList ToStringList { get; set; } + public ArrayOfString FromStringList { get; set; } + public IList FromUserFileTypes { get; set; } + } + + public class TestClassB + { + public ArrayOfString ToStringList { get; set; } + public IList FromStringList { get; set; } + public ArrayOfString FromUserFileTypes { get; set; } + } public class TestClassC { public IList FromStringList { get; protected set; } } - [TestFixture] - public class ReflectionExtensionsTests - { - [Test] - public void Can_translate_generic_lists() - { - var values = new[] { "A", "B", "C" }; - var testA = new TestClassA { - FromStringList = new ArrayOfString(values), - ToStringList = new List(values), - FromUserFileTypes = new List - { - UserFileType.DefaultProfile, UserFileType.OriginalProfile - }, - }; - - var fromTestA = testA.TranslateTo(); - - AssertAreEqual(testA, fromTestA); - - var userFileTypeValues = testA.FromUserFileTypes.ConvertAll(x => x.ToString()); - var testB = new TestClassB { - FromStringList = new List(values), - ToStringList = new ArrayOfString(values), - FromUserFileTypes = new ArrayOfString(userFileTypeValues), - }; - - var fromTestB = testB.TranslateTo(); - AssertAreEqual(fromTestB, testB); - } + [TestFixture] + public class ReflectionExtensionsTests + { + [Test] + public void Can_translate_generic_lists() + { + var values = new[] { "A", "B", "C" }; + var testA = new TestClassA + { + ToStringList = new List(values), + FromStringList = new ArrayOfString(values), + FromUserFileTypes = new List + { + UserFileType.DefaultProfile, UserFileType.OriginalProfile + }, + }; + + var fromTestA = testA.ConvertTo(); + + AssertAreEqual(testA, fromTestA); + + var userFileTypeValues = testA.FromUserFileTypes.Map(x => x.ToString()); + var testB = new TestClassB + { + ToStringList = new ArrayOfString(values), + FromStringList = new List(values), + FromUserFileTypes = new ArrayOfString(userFileTypeValues), + }; + + var fromTestB = testB.ConvertTo(); + AssertAreEqual(fromTestB, testB); + } [Test] public void Can_translate_generic_list_does_ignore_protected_setters() @@ -73,29 +75,82 @@ public void Can_translate_generic_list_does_ignore_protected_setters() ToStringList = new List(values), }; - var fromTestA = testA.TranslateTo(); + var fromTestA = testA.ConvertTo(); Assert.NotNull(fromTestA); Assert.IsNull(fromTestA.FromStringList); } - private static void AssertAreEqual(TestClassA testA, TestClassB testB) - { - Assert.That(testA, Is.Not.Null); - Assert.That(testB, Is.Not.Null); - - Assert.That(testA.FromStringList, Is.Not.Null); - Assert.That(testB.FromStringList, Is.Not.Null); - Assert.That(testA.FromStringList, - Is.EquivalentTo(new List(testB.FromStringList))); - - Assert.That(testA.ToStringList, Is.Not.Null); - Assert.That(testB.ToStringList, Is.Not.Null); - Assert.That(testA.ToStringList, Is.EquivalentTo(testB.ToStringList)); - - Assert.That(testA.FromUserFileTypes, Is.Not.Null); - Assert.That(testB.FromUserFileTypes, Is.Not.Null); - Assert.That(testA.FromUserFileTypes, - Is.EquivalentTo(testB.FromUserFileTypes.ConvertAll(x => x.ToEnum()))); - } - } + private static void AssertAreEqual(TestClassA testA, TestClassB testB) + { + Assert.That(testA, Is.Not.Null); + Assert.That(testB, Is.Not.Null); + + Assert.That(testA.FromStringList, Is.Not.Null); + Assert.That(testB.FromStringList, Is.Not.Null); + Assert.That(testA.FromStringList, + Is.EquivalentTo(new List(testB.FromStringList))); + + Assert.That(testA.ToStringList, Is.Not.Null); + Assert.That(testB.ToStringList, Is.Not.Null); + Assert.That(testA.ToStringList, Is.EquivalentTo(testB.ToStringList)); + + Assert.That(testA.FromUserFileTypes, Is.Not.Null); + Assert.That(testB.FromUserFileTypes, Is.Not.Null); + Assert.That(testA.FromUserFileTypes, + Is.EquivalentTo(testB.FromUserFileTypes.ConvertAll(x => x.ToEnum()))); + } + + [Test] + public void Does_get_generic_args() + { + var returnType = typeof(IReturn<>); + var argsCount = returnType.GetGenericArguments().Length; + Assert.That(argsCount, Is.EqualTo(1)); + + argsCount = typeof(ServiceStack.Messaging.Message<>).GetGenericArguments().Length; + Assert.That(argsCount, Is.EqualTo(1)); + } + +#if !NETCORE + [Test] + public void Can_cache_a_geneneric_tuple_activator() + { + var genericArgs = new[] + { + typeof(TestClassA), + typeof(TestClassB), + typeof(TestClassC), + }; + Type genericType = typeof(Tuple<,,>).GetCachedGenericType(genericArgs); + + var ci = genericType.GetConstructor(genericArgs); + + var activator = ci.GetActivator(); + + var tuple = (Tuple) + activator(new TestClassA(), new TestClassB(), new TestClassC()); + + tuple = (Tuple) + activator(new TestClassA(), new TestClassB(), new TestClassC()); + + Assert.That(tuple.Item1, Is.Not.Null); + Assert.That(tuple.Item2, Is.Not.Null); + Assert.That(tuple.Item3, Is.Not.Null); + } + + [Test] + public void Can_cache_generic_list_activator() + { + Type genericType = typeof(List<>).GetCachedGenericType(typeof(TestClassA)); + + var ci = genericType.GetConstructor(Type.EmptyTypes); + + var activator = ci.GetActivator(); + + var list = (List)activator(); + + Assert.That(list, Is.Not.Null); + } +#endif + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ReflectionUtilTests.cs b/tests/ServiceStack.Common.Tests/ReflectionUtilTests.cs index 33f1101a210..b2cd82cd62b 100644 --- a/tests/ServiceStack.Common.Tests/ReflectionUtilTests.cs +++ b/tests/ServiceStack.Common.Tests/ReflectionUtilTests.cs @@ -1,43 +1,43 @@ using System; -using System.ComponentModel.DataAnnotations; using System.Linq; using NUnit.Framework; using ServiceStack.Common.Tests.Models; -using ServiceStack.Common.Utils; using ServiceStack.DataAnnotations; using System.Collections.Generic; +using System.Threading.Tasks; +using ServiceStack.Reflection; using ServiceStack.Text; namespace ServiceStack.Common.Tests { - [TestFixture] - public class ReflectionUtilTests - { - public enum TestClassType - { - One = 1, - Two = 2, - Three = 3 - } - - public class TestClass2 - { - public TestClassType Type { get; set; } - } - - public class TestClass - { - [Required] - public string Member1 { get; set; } - - public string Member2 { get; set; } - - [Required] - public string Member3 { get; set; } - - [StringLength(1)] - public string Member4 { get; set; } - } + [TestFixture] + public class ReflectionUtilTests + { + public enum TestClassType + { + One = 1, + Two = 2, + Three = 3 + } + + public class TestClass2 + { + public TestClassType Type { get; set; } + } + + public class TestClass + { + [Required] + public string Member1 { get; set; } + + public string Member2 { get; set; } + + [Required] + public string Member3 { get; set; } + + [StringLength(1)] + public string Member4 { get; set; } + } public class DtoWithStringArray { @@ -83,39 +83,39 @@ public class Vortex [Test] public void Can_PopulateRecursiveDto() { - var obj = (RecursiveDto)ReflectionUtils.PopulateObject(new RecursiveDto()); - Assert.IsNotNullOrEmpty(obj.Name); + var obj = (RecursiveDto)AutoMappingUtils.PopulateWith(new RecursiveDto()); + Assert.That(obj.Name, Is.Not.Null); Assert.IsNotNull(obj.Child); - Assert.IsNotNullOrEmpty(obj.Child.Name); + Assert.That(obj.Child.Name, Is.Not.Null); } [Test] public void Can_PopulateArrayOfRecursiveDto() { - var obj = (DtoWithRecursiveArray)ReflectionUtils.PopulateObject(new DtoWithRecursiveArray()); + var obj = (DtoWithRecursiveArray)AutoMappingUtils.PopulateWith(new DtoWithRecursiveArray()); Assert.IsNotNull(obj.Paths); Assert.Greater(obj.Paths.Length, 0); Assert.IsNotNull(obj.Paths[0]); - Assert.IsNotNullOrEmpty(obj.Paths[0].Name); + Assert.That(obj.Paths[0].Name, Is.Not.Null); Assert.IsNotNull(obj.Paths[0].Child); - Assert.IsNotNullOrEmpty(obj.Paths[0].Child.Name); + Assert.That(obj.Paths[0].Child.Name, Is.Not.Null); } [Test] public void Can_PopulateRecursiveArrayDto() { - var obj = (RecursiveArrayDto)ReflectionUtils.PopulateObject(new RecursiveArrayDto()); - Assert.IsNotNullOrEmpty(obj.Name); + var obj = (RecursiveArrayDto)AutoMappingUtils.PopulateWith(new RecursiveArrayDto()); + Assert.That(obj.Name, Is.Not.Null); Assert.IsNotNull(obj.Nodes[0]); - Assert.IsNotNullOrEmpty(obj.Nodes[0].Name); + Assert.That(obj.Nodes[0].Name, Is.Not.Null); Assert.IsNotNull(obj.Nodes[0].Nodes); - Assert.IsNotNullOrEmpty(obj.Nodes[0].Nodes[0].Name); + Assert.That(obj.Nodes[0].Nodes[0].Name, Is.Not.Null); } [Test] public void Can_PopulateTheVortex() { - var obj = (MindTwister)ReflectionUtils.PopulateObject(new MindTwister()); + var obj = (MindTwister)AutoMappingUtils.PopulateWith(new MindTwister()); Console.WriteLine("Mindtwister = " + ServiceStack.Text.XmlSerializer.SerializeToString(obj)); // TypeSerializer and JsonSerializer blow up on this structure with a Null Reference Exception! Assert.IsNotNull(obj); Assert.IsNotNull(obj.Name); @@ -126,7 +126,7 @@ public void Can_PopulateTheVortex() [Test] public void Can_PopulateObjectWithStringArray() { - var obj = (DtoWithStringArray)ReflectionUtils.PopulateObject(new DtoWithStringArray()); + var obj = (DtoWithStringArray)AutoMappingUtils.PopulateWith(new DtoWithStringArray()); Assert.IsNotNull(obj.Data); Assert.Greater(obj.Data.Length, 0); Assert.IsNotNull(obj.Data[0]); @@ -135,107 +135,107 @@ public void Can_PopulateObjectWithStringArray() [Test] public void Can_PopulateObjectWithNonZeroEnumArray() { - var obj = (DtoWithEnumArray)ReflectionUtils.PopulateObject(new DtoWithEnumArray()); + var obj = (DtoWithEnumArray)AutoMappingUtils.PopulateWith(new DtoWithEnumArray()); Assert.IsNotNull(obj.Data); Assert.Greater(obj.Data.Length, 0); Assert.That(Enum.IsDefined(typeof(TestClassType), obj.Data[0]), "Values in created array should be valid for the enum"); } - [Test] - public void PopulateObject_UsesDefinedEnum() - { - var requestObj = (TestClass2)ReflectionUtils.PopulateObject(Activator.CreateInstance(typeof(TestClass2))); - Assert.True(Enum.IsDefined(typeof(TestClassType), requestObj.Type)); - } - - [Test] - public void PopulateObject_UsesDefinedEnum_OnNestedTypes() - { - var requestObj = (Dictionary)ReflectionUtils.CreateDefaultValue(typeof(Dictionary), new Dictionary()); - Assert.True(Enum.IsDefined(typeof(TestClassType), requestObj.First().Value.Type)); - } - - [Test] - public void GetTest() - { - var propertyAttributes = ReflectionUtils.GetPropertyAttributes(typeof(TestClass)); - var propertyNames = propertyAttributes.ToList().ConvertAll(x => x.Key.Name); - Assert.That(propertyNames, Is.EquivalentTo(new[] { "Member1", "Member3" })); - } - - [Test] - public void Populate_Same_Objects() - { - var toObj = ModelWithFieldsOfDifferentTypes.Create(1); - var fromObj = ModelWithFieldsOfDifferentTypes.Create(2); - - var obj3 = ReflectionUtils.PopulateObject(toObj, fromObj); - - Assert.IsTrue(obj3 == toObj); - Assert.That(obj3.Bool, Is.EqualTo(fromObj.Bool)); - Assert.That(obj3.DateTime, Is.EqualTo(fromObj.DateTime)); - Assert.That(obj3.Double, Is.EqualTo(fromObj.Double)); - Assert.That(obj3.Guid, Is.EqualTo(fromObj.Guid)); - Assert.That(obj3.Id, Is.EqualTo(fromObj.Id)); - Assert.That(obj3.LongId, Is.EqualTo(fromObj.LongId)); - Assert.That(obj3.Name, Is.EqualTo(fromObj.Name)); - } - - [Test] - public void Populate_Different_Objects_with_different_property_types() - { - var toObj = ModelWithFieldsOfDifferentTypes.Create(1); - var fromObj = ModelWithOnlyStringFields.Create("2"); - - var obj3 = ReflectionUtils.PopulateObject(toObj, fromObj); - - Assert.IsTrue(obj3 == toObj); - Assert.That(obj3.Id, Is.EqualTo(2)); - Assert.That(obj3.Name, Is.EqualTo(fromObj.Name)); - } - - [Test] - public void Populate_From_Properties_With_Attribute() - { - var originalToObj = ModelWithOnlyStringFields.Create("id-1"); - var toObj = ModelWithOnlyStringFields.Create("id-1"); - var fromObj = ModelWithOnlyStringFields.Create("id-2"); - - ReflectionUtils.PopulateFromPropertiesWithAttribute(toObj, fromObj, - typeof(IndexAttribute)); - - Assert.That(toObj.Id, Is.EqualTo(originalToObj.Id)); - Assert.That(toObj.AlbumId, Is.EqualTo(originalToObj.AlbumId)); - - //Properties with IndexAttribute - Assert.That(toObj.Name, Is.EqualTo(fromObj.Name)); - Assert.That(toObj.AlbumName, Is.EqualTo(fromObj.AlbumName)); - } - - [Test] - public void Populate_From_Properties_With_Non_Default_Values() - { - var toObj = ModelWithFieldsOfDifferentTypes.Create(1); - var fromObj = ModelWithFieldsOfDifferentTypes.Create(2); - - var originalToObj = ModelWithFieldsOfDifferentTypes.Create(1); - var originalGuid = toObj.Guid; - - fromObj.Name = null; - fromObj.Double = default(double); - fromObj.Guid = default(Guid); - - ReflectionUtils.PopulateWithNonDefaultValues(toObj, fromObj); - - Assert.That(toObj.Name, Is.EqualTo(originalToObj.Name)); - Assert.That(toObj.Double, Is.EqualTo(originalToObj.Double)); - Assert.That(toObj.Guid, Is.EqualTo(originalGuid)); - - Assert.That(toObj.Id, Is.EqualTo(fromObj.Id)); - Assert.That(toObj.LongId, Is.EqualTo(fromObj.LongId)); - Assert.That(toObj.Bool, Is.EqualTo(fromObj.Bool)); - Assert.That(toObj.DateTime, Is.EqualTo(fromObj.DateTime)); - } + [Test] + public void PopulateObject_UsesDefinedEnum() + { + var requestObj = (TestClass2)AutoMappingUtils.PopulateWith(Activator.CreateInstance(typeof(TestClass2))); + Assert.True(Enum.IsDefined(typeof(TestClassType), requestObj.Type)); + } + + [Test] + public void PopulateObject_UsesDefinedEnum_OnNestedTypes() + { + var requestObj = (Dictionary)AutoMappingUtils.CreateDefaultValue(typeof(Dictionary), new Dictionary()); + Assert.True(Enum.IsDefined(typeof(TestClassType), requestObj.First().Value.Type)); + } + + [Test] + public void GetTest() + { + var propertyAttributes = AutoMappingUtils.GetPropertyAttributes(typeof(TestClass)); + var propertyNames = propertyAttributes.ToList().ConvertAll(x => x.Key.Name); + Assert.That(propertyNames, Is.EquivalentTo(new[] { "Member1", "Member3" })); + } + + [Test] + public void Populate_Same_Objects() + { + var toObj = ModelWithFieldsOfDifferentTypes.Create(1); + var fromObj = ModelWithFieldsOfDifferentTypes.Create(2); + + var obj3 = AutoMappingUtils.PopulateWith(toObj, fromObj); + + Assert.IsTrue(obj3 == toObj); + Assert.That(obj3.Bool, Is.EqualTo(fromObj.Bool)); + Assert.That(obj3.DateTime, Is.EqualTo(fromObj.DateTime)); + Assert.That(obj3.Double, Is.EqualTo(fromObj.Double)); + Assert.That(obj3.Guid, Is.EqualTo(fromObj.Guid)); + Assert.That(obj3.Id, Is.EqualTo(fromObj.Id)); + Assert.That(obj3.LongId, Is.EqualTo(fromObj.LongId)); + Assert.That(obj3.Name, Is.EqualTo(fromObj.Name)); + } + + [Test] + public void Populate_Different_Objects_with_different_property_types() + { + var toObj = ModelWithFieldsOfDifferentTypes.Create(1); + var fromObj = ModelWithOnlyStringFields.Create("2"); + + var obj3 = AutoMappingUtils.PopulateWith(toObj, fromObj); + + Assert.IsTrue(obj3 == toObj); + Assert.That(obj3.Id, Is.EqualTo(2)); + Assert.That(obj3.Name, Is.EqualTo(fromObj.Name)); + } + + [Test] + public void Populate_From_Properties_With_Attribute() + { + var originalToObj = ModelWithOnlyStringFields.Create("id-1"); + var toObj = ModelWithOnlyStringFields.Create("id-1"); + var fromObj = ModelWithOnlyStringFields.Create("id-2"); + + AutoMappingUtils.PopulateFromPropertiesWithAttribute(toObj, fromObj, + typeof(IndexAttribute)); + + Assert.That(toObj.Id, Is.EqualTo(originalToObj.Id)); + Assert.That(toObj.AlbumId, Is.EqualTo(originalToObj.AlbumId)); + + //Properties with IndexAttribute + Assert.That(toObj.Name, Is.EqualTo(fromObj.Name)); + Assert.That(toObj.AlbumName, Is.EqualTo(fromObj.AlbumName)); + } + + [Test] + public void Populate_From_Properties_With_Non_Default_Values() + { + var toObj = ModelWithFieldsOfDifferentTypes.Create(1); + var fromObj = ModelWithFieldsOfDifferentTypes.Create(2); + + var originalToObj = ModelWithFieldsOfDifferentTypes.Create(1); + var originalGuid = toObj.Guid; + + fromObj.Name = null; + fromObj.Double = default(double); + fromObj.Guid = default(Guid); + + toObj.PopulateWithNonDefaultValues(fromObj); + + Assert.That(toObj.Name, Is.EqualTo(originalToObj.Name)); + Assert.That(toObj.Double, Is.EqualTo(originalToObj.Double)); + Assert.That(toObj.Guid, Is.EqualTo(originalGuid)); + + Assert.That(toObj.Id, Is.EqualTo(fromObj.Id)); + Assert.That(toObj.LongId, Is.EqualTo(fromObj.LongId)); + Assert.That(toObj.Bool, Is.EqualTo(fromObj.Bool)); + Assert.That(toObj.DateTime, Is.EqualTo(fromObj.DateTime)); + } [Test] public void Populate_From_Nullable_Properties_With_Non_Default_Values() @@ -250,7 +250,7 @@ public void Populate_From_Nullable_Properties_With_Non_Default_Values() fromObj.Guid = default(Guid); fromObj.Bool = default(bool); - ReflectionUtils.PopulateWithNonDefaultValues(toObj, fromObj); + toObj.PopulateWithNonDefaultValues(fromObj); Assert.That(toObj.Name, Is.EqualTo(originalToObj.Name)); @@ -262,28 +262,44 @@ public void Populate_From_Nullable_Properties_With_Non_Default_Values() Assert.That(toObj.DateTime, Is.EqualTo(fromObj.DateTime)); } - [Test] - public void Translate_Between_Models_of_differrent_types_and_nullables() - { - var fromObj = ModelWithFieldsOfDifferentTypes.CreateConstant(1); + [Test] + public void Translate_Between_Models_of_different_types_and_nullables() + { + var fromObj = ModelWithFieldsOfDifferentTypes.CreateConstant(1); - var toObj = fromObj.TranslateTo(); + var toObj = fromObj.ConvertTo(); - Console.WriteLine(toObj.Dump()); + Console.WriteLine(toObj.Dump()); - ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(fromObj, toObj); - } + ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(fromObj, toObj); + } + + [Test] + public void Translate_Between_Models_of_nullables_and_different_types() + { + var fromObj = ModelWithFieldsOfDifferentTypesAsNullables.CreateConstant(1); - [Test] - public void Translate_Between_Models_of_nullables_and_differrent_types() - { - var fromObj = ModelWithFieldsOfDifferentTypesAsNullables.CreateConstant(1); + var toObj = fromObj.ConvertTo(); - var toObj = fromObj.TranslateTo(); + Console.WriteLine(toObj.Dump()); - Console.WriteLine(toObj.Dump()); + ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(toObj, fromObj); + } - ModelWithFieldsOfDifferentTypesAsNullables.AssertIsEqual(toObj, fromObj); - } - } + [Test] + public void Can_get_result_of_Task() + { + var tcs = new TaskCompletionSource(); + var task = tcs.Task; + tcs.SetResult("foo"); + + var fn = TypeProperties.Get(task.GetType()).GetPublicGetter("Result"); + var value = fn(task); + Assert.That(value, Is.EqualTo("foo")); + + fn = TypeProperties.Get(task.GetType()).GetPublicGetter("Result"); + value = fn(task); + Assert.That(value, Is.EqualTo("foo")); + } + } } diff --git a/tests/ServiceStack.Common.Tests/RsaUtilTests.cs b/tests/ServiceStack.Common.Tests/RsaUtilTests.cs new file mode 100644 index 00000000000..ebeee90b078 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/RsaUtilTests.cs @@ -0,0 +1,146 @@ +using System; +using System.Security.Cryptography; +using System.Xml; +using System.Xml.Linq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class RsaUtilTests + { + const string PrivateKeyXml = @" +sO2GRzjw6Kx9d2+RzsaH+vWINhuB6+zIQ2KKH39ZvV19AMvxmhRyqyYoTYjm7v7P0vNlpqeYYPqDx2sba+rD9GwarBGhG1ZJ2gmB24rGxLJ7G0tATKLWULs558tOjcoS5bVTxoS1XmxVjUw47RiafMSpe0B61cceSadV9LEHkrs= +AQAB +

3JLEo1LdH+CVYQHvSNHcob8lkmEWT+pBWqsz90Hk9Fy75fVxTVgDYryvm/SAZoq4HiSDFK8vha6GtaJMXfdjIw==

+zVgzfOKGoXCttLgR7+aQJc47bQe05nE8QcDfmu1RJFMJGzPJokTd6kGjAqZZZIARb25h+q/RvirsaCaQ9j03iQ== +XRmd4goBx4i1xGJaq3PZGnRh2W0dS9Hmj+yfXIf1qabSsHduwWSa2TwnKz6CS8XVfPOQWFSxTE2kElpUvXzD3Q== +Bx5nqoyv3ijp3LoE5Sw5ExZzOPRrcRG75QuqtNRFW90FE8xX0ShSCSz9WboqnzFRaWuKOgaeXtleGL49iEvXAQ== +SgkSPIM/CXU//ndT+5XT+IaVeXQa8HMrIPhbvsKsq3v6D7p4yPwOEvMRsRZfFpzGrIO3iRsCBpob2nyHbr4qJw== +BS4/U1CQhU+fsOKcc2CO1MNhxKvThxP83TRCdR+mggv9wAs4vNlCbk6EuZh7op3lefjUjie0J4rOVwWE3QkXycDz4qH8FHkROmJTBMqITvy7D0xvOAP0KMBrKH6vs0Knc2qzIDkyaV+Ej1xMF6aawZWoXKd9eCCL4HhQoFGAf/E= +
"; + + const string PublicKeyXml = @" +sO2GRzjw6Kx9d2+RzsaH+vWINhuB6+zIQ2KKH39ZvV19AMvxmhRyqyYoTYjm7v7P0vNlpqeYYPqDx2sba+rD9GwarBGhG1ZJ2gmB24rGxLJ7G0tATKLWULs558tOjcoS5bVTxoS1XmxVjUw47RiafMSpe0B61cceSadV9LEHkrs= +AQAB +"; + + const string PublicKeyXmlWithSpaces = @" + +sO2GRzjw6Kx9d2+RzsaH+vWINhuB6+zIQ2KKH39ZvV19AMvxmhRyqyYoTYjm7v7P0vNlpqeYYPqDx2sba+rD9GwarBGhG1ZJ2gmB24rGxLJ7G0tATKLWULs558tOjcoS5bVTxoS1XmxVjUw47RiafMSpe0B61cceSadV9LEHkrs= + AQAB +"; + + [Test] + public void Export_PrivateKey_to_xml() + { + var privateKey = RsaUtils.CreatePrivateKeyParams(); + "PRIVATE KEY".Print(); + privateKey.ToPrivateKeyXml().Print(); + + "PUBLIC KEY".Print(); + privateKey.ToPublicKeyXml().Print(); + } + + [Test] +#if NETCORE + [Ignore("Operation not supported on .NET Core")] +#endif + public void Can_parse_private_key_xml() + { + var pk1 = PlatformRsaUtils.ExtractFromXml(PrivateKeyXml); + using (var rsa = RSA.Create()) + { + rsa.FromXml(PrivateKeyXml); + + var pk2 = rsa.ExportParameters(includePrivateParameters: true); + + Assert.That(pk1.Modulus, Is.EqualTo(pk2.Modulus)); + Assert.That(pk1.Exponent, Is.EqualTo(pk2.Exponent)); + Assert.That(pk1.P, Is.EqualTo(pk2.P)); + Assert.That(pk1.Q, Is.EqualTo(pk2.Q)); + Assert.That(pk1.DP, Is.EqualTo(pk2.DP)); + Assert.That(pk1.DQ, Is.EqualTo(pk2.DQ)); + Assert.That(pk1.InverseQ, Is.EqualTo(pk2.InverseQ)); + Assert.That(pk1.D, Is.EqualTo(pk2.D)); + } + } + + [Test] +#if NETCORE + [Ignore("Operation not supported on .NET Core")] +#endif + public void Can_parse_public_key_xml() + { + var pk1 = PlatformRsaUtils.ExtractFromXml(PublicKeyXml); + using (var rsa = RSA.Create()) + { + rsa.FromXml(PublicKeyXml); + + var pk2 = rsa.ExportParameters(includePrivateParameters: false); + + Assert.That(pk1.Modulus, Is.EqualTo(pk2.Modulus)); + Assert.That(pk1.Exponent, Is.EqualTo(pk2.Exponent)); + Assert.That(pk1.P, Is.EqualTo(pk2.P)); + Assert.That(pk1.Q, Is.EqualTo(pk2.Q)); + Assert.That(pk1.DP, Is.EqualTo(pk2.DP)); + Assert.That(pk1.DQ, Is.EqualTo(pk2.DQ)); + Assert.That(pk1.InverseQ, Is.EqualTo(pk2.InverseQ)); + Assert.That(pk1.D, Is.EqualTo(pk2.D)); + } + } + + [Test] + public void Can_parse_public_key_xml_with_different_whitespace() + { + var pk1 = PlatformRsaUtils.ExtractFromXml(PublicKeyXml); + var pk2 = PlatformRsaUtils.ExtractFromXml(PublicKeyXmlWithSpaces); + Assert.That(pk1.Modulus, Is.EqualTo(pk2.Modulus)); + Assert.That(pk1.Exponent, Is.EqualTo(pk2.Exponent)); + } + + private static RSAParameters ExtractRsaParameters(string xml) + { + var doc = XDocument.Parse(xml); + var csp = new RSAParameters(); + var node = ((XElement) doc.FirstNode).FirstNode; + do + { + var el = node as XElement; + if (el != null) + { + switch (el.Name.LocalName) + { + case "Modulus": + csp.Modulus = Convert.FromBase64String(el.Value); + break; + case "Exponent": + csp.Exponent = Convert.FromBase64String(el.Value); + break; + case "P": + csp.P = Convert.FromBase64String(el.Value); + break; + case "Q": + csp.Q = Convert.FromBase64String(el.Value); + break; + case "DP": + csp.DP = Convert.FromBase64String(el.Value); + break; + case "DQ": + csp.DQ = Convert.FromBase64String(el.Value); + break; + case "InverseQ": + csp.InverseQ = Convert.FromBase64String(el.Value); + break; + case "D": + csp.D = Convert.FromBase64String(el.Value); + break; + } + } + } while ((node = node.NextNode) != null); + + return csp; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ServiceClient.Web/HtmlServiceClient.cs b/tests/ServiceStack.Common.Tests/ServiceClient.Web/HtmlServiceClient.cs index 69314d34e3c..2aacd365ad0 100644 --- a/tests/ServiceStack.Common.Tests/ServiceClient.Web/HtmlServiceClient.cs +++ b/tests/ServiceStack.Common.Tests/ServiceClient.Web/HtmlServiceClient.cs @@ -1,12 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceModel.Serialization; -using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.Common.Tests.ServiceClient.Web { @@ -31,16 +25,16 @@ public override string Format public override string Accept { - get { return Common.Web.ContentType.Html; } + get { return MimeTypes.Html; } } public override string ContentType { // Only used by the base class when POST-ing. - get { return Common.Web.ContentType.FormUrlEncoded; } + get { return MimeTypes.FormUrlEncoded; } } - public override void SerializeToStream(IRequestContext requestContext, object request, Stream stream) + public override void SerializeToStream(IRequest req, object request, Stream stream) { var queryString = QueryStringSerializer.SerializeToString(request); stream.Write(queryString); diff --git a/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTester.cs b/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTester.cs index 40776f89a03..ad80b271a8a 100644 --- a/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTester.cs +++ b/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTester.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using ServiceStack.ServiceClient.Web; +using ServiceStack.Web; namespace ServiceStack.Common.Tests.ServiceClient.Web { @@ -10,7 +10,7 @@ public class ServiceClientBaseTester : ServiceClientBase { public override string ContentType { get { return String.Format("application/{0}", Format); } } - public override void SerializeToStream(ServiceHost.IRequestContext requestContext, object request, System.IO.Stream stream) + public override void SerializeToStream(IRequest req, object request, System.IO.Stream stream) { throw new NotImplementedException(); } @@ -20,7 +20,7 @@ public override T DeserializeFromStream(System.IO.Stream stream) throw new NotImplementedException(); } - public override ServiceHost.StreamDeserializerDelegate StreamDeserializer + public override StreamDeserializerDelegate StreamDeserializer { get { diff --git a/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTests.cs b/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTests.cs index d2aaebb5858..5a3ca4817e1 100644 --- a/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTests.cs +++ b/tests/ServiceStack.Common.Tests/ServiceClient.Web/ServiceClientBaseTests.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using NUnit.Framework; +using ServiceStack.Common.Tests.FluentValidation; namespace ServiceStack.Common.Tests.ServiceClient.Web { @@ -18,8 +20,8 @@ public void SetBaseUri_FormatLoaded_LoadedFormatUsedInSyncAndAsyncUri() serviceClientBaseTester.SetBaseUri(baseUri); String expectedBaseUri = baseUri; - String expectedSyncReplyBaseUri = baseUri + "/" + serviceClientBaseTester.Format + "/syncreply/"; - String expectedAsyncOneWayBaseUri = baseUri + "/" + serviceClientBaseTester.Format + "/asynconeway/"; + String expectedSyncReplyBaseUri = baseUri + "/" + serviceClientBaseTester.Format + "/reply/"; + String expectedAsyncOneWayBaseUri = baseUri + "/" + serviceClientBaseTester.Format + "/oneway/"; Assert.That(serviceClientBaseTester.BaseUri, Is.EqualTo(expectedBaseUri)); Assert.That(serviceClientBaseTester.SyncReplyBaseUri, Is.EqualTo(expectedSyncReplyBaseUri)); Assert.That(serviceClientBaseTester.AsyncOneWayBaseUri, Is.EqualTo(expectedAsyncOneWayBaseUri)); diff --git a/tests/ServiceStack.Common.Tests/ServiceClient.Web/UrlExtensionsTests.cs b/tests/ServiceStack.Common.Tests/ServiceClient.Web/UrlExtensionsTests.cs index 2ffd6202612..283f47bf15e 100644 --- a/tests/ServiceStack.Common.Tests/ServiceClient.Web/UrlExtensionsTests.cs +++ b/tests/ServiceStack.Common.Tests/ServiceClient.Web/UrlExtensionsTests.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; +using ServiceStack.Common.Tests.Models; +using ServiceStack.NativeTypes; +using ServiceStack.Testing; using ServiceStack.Text; namespace ServiceStack.Common.Tests.ServiceClient.Web @@ -25,5 +28,158 @@ public void FormatQueryParameterValue_DateTimeOffsetValue_ValueIsUrlEncoded() var jsv = dateTimeOffset.ToJsv(); Assert.AreEqual(Uri.EscapeDataString(jsv), formattedVariable); } + + [Test] + public void Can_get_operation_name() + { + Assert.That(typeof(Root).GetOperationName(), Is.EqualTo("Root")); + Assert.That(typeof(Root.Nested).GetOperationName(), Is.EqualTo("Root.Nested")); + } + + [Test] + public void Can_use_nested_classes_as_Request_DTOs() + { + using (var appHost = new BasicAppHost(typeof(NestedService).Assembly).Init()) + { + var root = (Root)appHost.ExecuteService(new Root { Id = 1 }); + Assert.That(root.Id, Is.EqualTo(1)); + + var nested = (Root.Nested)appHost.ExecuteService(new Root.Nested { Id = 2 }); + Assert.That(nested.Id, Is.EqualTo(2)); + } + } + + [Test] + public void Can_expand_generic_List() + { + var genericName = typeof(List).ExpandTypeName(); + + genericName.Print(); + + Assert.That(genericName, Is.EqualTo("List")); + } + + [Test] + public void Can_expand_generic_List_and_Dictionary() + { + //System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[Namespace.Poco, Assembly.Name, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] + + var genericName = typeof(Dictionary>).ExpandTypeName(); + + genericName.Print(); + + Assert.That(genericName, Is.EqualTo("Dictionary>")); + } + + [Test] + public void Can_parse_Single_Type() + { + var fullGenericTypeName = "Poco"; + + var textNode = fullGenericTypeName.ParseTypeIntoNodes(); + + Assert.That(textNode.Text, Is.EqualTo("Poco")); + Assert.That(textNode.Children.Count, Is.EqualTo(0)); + } + + [Test] + public void Can_parse_generic_List_of_Poco() + { + var fullGenericTypeName = "List"; + + var textNode = fullGenericTypeName.ParseTypeIntoNodes(); + + textNode.PrintDump(); + + Assert.That(textNode.Text, Is.EqualTo("List")); + Assert.That(textNode.Children.Count, Is.EqualTo(1)); + Assert.That(textNode.Children[0].Text, Is.EqualTo("Poco")); + } + + [Test] + public void Can_parse_generic_List_Dictionary_of_String_and_Poco() + { + var fullGenericTypeName = "List>"; + + var textNode = fullGenericTypeName.ParseTypeIntoNodes(); + + Assert.That(textNode.Text, Is.EqualTo("List")); + Assert.That(textNode.Children.Count, Is.EqualTo(1)); + + Assert.That(textNode.Children[0].Text, Is.EqualTo("Dictionary")); + Assert.That(textNode.Children[0].Children.Count, Is.EqualTo(2)); + Assert.That(textNode.Children[0].Children[0].Text, Is.EqualTo("String")); + Assert.That(textNode.Children[0].Children[1].Text, Is.EqualTo("Poco")); + } + + [Test] + public void Can_parse_generic_List_Dictionary_of_Dictionary_of_String_and_Poco() + { + var fullGenericTypeName = "List>>"; + + var textNode = fullGenericTypeName.ParseTypeIntoNodes(); + + Assert.That(textNode.Text, Is.EqualTo("List")); + Assert.That(textNode.Children.Count, Is.EqualTo(1)); + + Assert.That(textNode.Children[0].Text, Is.EqualTo("Dictionary")); + Assert.That(textNode.Children[0].Children.Count, Is.EqualTo(2)); + Assert.That(textNode.Children[0].Children[0].Text, Is.EqualTo("String")); + + Assert.That(textNode.Children[0].Children[1].Text, Is.EqualTo("Dictionary")); + Assert.That(textNode.Children[0].Children[1].Children.Count, Is.EqualTo(2)); + Assert.That(textNode.Children[0].Children[1].Children[0].Text, Is.EqualTo("String")); + Assert.That(textNode.Children[0].Children[1].Children[1].Text, Is.EqualTo("Poco")); + } + + [Test] + public void Can_SplitGenericArgs() + { + var args = StringUtils.SplitGenericArgs("String,Int64,Boolean"); + Assert.That(args, Is.EquivalentTo(new[] {"String", "Int64", "Boolean"})); + + args = StringUtils.SplitGenericArgs("List>>"); + Assert.That(args, Is.EquivalentTo(new[] { "List>>" })); + + args = StringUtils.SplitGenericArgs("String,List>>,Int64"); + Assert.That(args, Is.EquivalentTo(new[] { "String", "List>>", "Int64" })); + } + + [Test] + public void Can_strip_nullables() + { + Assert.That(MetadataExtensions.StripGenericType("Nullable", "Nullable"), + Is.EqualTo("Byte")); + Assert.That(MetadataExtensions.StripGenericType("Nullable[]", "Nullable"), + Is.EqualTo("Byte[]")); + Assert.That(MetadataExtensions.StripGenericType("List>[]", "Nullable"), + Is.EqualTo("List[]")); + Assert.That(MetadataExtensions.StripGenericType("List>>[]", "Nullable"), + Is.EqualTo("List>[]")); + } + + } + + public class Root + { + public int Id { get; set; } + + public class Nested + { + public int Id { get; set; } + } + } + + public class NestedService : Service + { + public object Any(Root request) + { + return request; + } + + public object Any(Root.Nested request) + { + return request; + } } } diff --git a/tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj b/tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj index 5d47191f628..3dcfa62e6a3 100644 --- a/tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj +++ b/tests/ServiceStack.Common.Tests/ServiceStack.Common.Tests.csproj @@ -1,276 +1,63 @@ - - + - Debug - AnyCPU - 9.0.30729 - 2.0 - {3FA9197A-462D-44CC-9AB3-61AF414D0B45} - Library - Properties - ServiceStack.Common.Tests + net472;net6.0 + portable ServiceStack.Common.Tests - v4.0 - 512 - - - 3.5 - - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - + ServiceStack.Common.Tests + false + false + false + false + false + false + false + false - - True - full - False - bin\Debug\ - TRACE;DEBUG;MONO - prompt - 4 - AllRules.ruleset - False - x86 - - - pdbonly - True - bin\Release\ - TRACE - prompt - 4 - x86 - AllRules.ruleset - - - True - bin\monotouch\ - TRACE;DEBUG;STATIC_ONLY NO_EXPRESSIONS - full - AnyCPU - prompt - 4 - False - AllRules.ruleset - - - True - bin\MonoTouch\ - TRACE;DEBUG;STATIC_ONLY NO_EXPRESSIONS - full - AnyCPU - prompt - 4 - False - AllRules.ruleset - - - - ..\..\lib\tests\Moq.dll - - - ..\..\lib\ServiceStack.Redis.dll - - - - 3.5 - - - - 3.5 - - - 3.0 - - - - - 3.5 - - - 3.5 - - - - - ..\..\lib\tests\nunit.framework.dll - - - ..\..\lib\ServiceStack.Text.dll - - - ..\..\lib\tests\Northwind.Common.dll - - - ..\..\lib\tests\Mono.Data.Sqlite.dll - - - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - - - ..\..\lib\ServiceStack.OrmLite.SqlServer.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + PreserveNewest + - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface - - - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} - ServiceStack - + + + + + + + + + + + + + + + + + - - - + + $(DefineConstants);NET45 + + + + + + + + - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - SQL Server 2008 Express - true - - - False - Windows Installer 3.1 - true - - - False - Windows Installer 4.5 - true - + + $(DefineConstants);NETCORE + + + + - - + SettingsSingleFileGenerator - Settings.Designer.cs - - - sqlite3.dll - PreserveNewest - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/SessionExtensionTests.cs b/tests/ServiceStack.Common.Tests/SessionExtensionTests.cs new file mode 100644 index 00000000000..ccab1aa1138 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/SessionExtensionTests.cs @@ -0,0 +1,74 @@ +#if !NETCORE +using System; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class SessionExtensionTests + { + [Test] + public void Does_CreateRandomSessionId_without_url_unfriendly_chars() + { + 1000.Times(i => + { + var sessionId = SessionExtensions.CreateRandomSessionId(); + Assert.That(sessionId, Does.Not.Contain("+")); + Assert.That(sessionId, Does.Not.Contain("/")); + }); + } + + [Test] + public void ToBase64UrlSafe_does_not_contain_unfriendly_chars() + { + var bytes = new byte[24]; + string lastSessionId = null; + + 1000.Times(i => + { + SessionExtensions.PopulateWithSecureRandomBytes(bytes); + + var sessionId = bytes.ToBase64UrlSafe(); + + Assert.That(sessionId, Does.Not.Contain("+")); + Assert.That(sessionId, Does.Not.Contain("/")); + + if (lastSessionId != null) + Assert.That(sessionId, Is.Not.EqualTo(lastSessionId)); + lastSessionId = sessionId; + }); + } + + [Test] + public void Does_CreateRandomBase62Id_16_byte_id_in_less_than_3_attempts_avg() + { + Assert.That(SessionExtensions.CreateRandomBase62Id(16).Length, Is.EqualTo(24)); + + int attempts = 0; + 1000.Times(i => + { + do + { + attempts++; + } while (SessionExtensions.CreateRandomBase64Id(16).IndexOfAny(new[] {'+', '/'}) >= 0); + }); + + attempts.Print(); + Assert.That(attempts, Is.LessThan(1000 * 3)); + } + + [Test] + public void CreateRandomBase64Id_contains_url_unfriendly_chars() + { + Assert.Throws(() => + 1000.Times(i => + { + var sessionId = SessionExtensions.CreateRandomBase64Id(); + if (sessionId.ContainsAny("+", "-")) + throw new ArgumentException("Url Unfriendly Chars found"); + })); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/SiteUtilsTests.cs b/tests/ServiceStack.Common.Tests/SiteUtilsTests.cs new file mode 100644 index 00000000000..b84cc4979a8 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/SiteUtilsTests.cs @@ -0,0 +1,44 @@ +using NUnit.Framework; + +namespace ServiceStack.Common.Tests +{ + public class SiteUtilsTests + { + [Test] + [TestCase("northwind.netcore.io:", "https://northwind.netcore.io/")] + [TestCase("techstacks.io", "https://techstacks.io")] + [TestCase("http:techstacks.io", "http://techstacks.io")] + [TestCase("http:techstacks.io:1000", "http://techstacks.io:1000")] + [TestCase("http:techstacks.io:1000:site1:site2", "http://techstacks.io:1000/site1/site2")] + [TestCase("http:techstacks.io:1000:site1%7Csite2", "http://techstacks.io:1000/site1|site2")] + [TestCase("techstacks.io:site1%7Csite2", "https://techstacks.io/site1|site2")] + [TestCase("http://techstacks.io:1000/site1/site2", "http://techstacks.io:1000/site1/site2")] + [TestCase("https://techstacks.io:1000/site1/site2", "https://techstacks.io:1000/site1/site2")] + [TestCase("techstacks.io:1000:site1:site2(a:1,b:\"c,d\",e:f)", "https://techstacks.io:1000/site1/site2(a:1,b:\"c,d\",e:f)")] + [TestCase("apps.servicestack.net/gists/techstacks.io/swift/FindTechnologies(VendorName:Google,Take:5,OrderByDesc:ViewCount,Fields:\"Name,ProductUrl,Tier,VendorName\")?use=xcode&name=MyApp", + "https://apps.servicestack.net/gists/techstacks.io/swift/FindTechnologies(VendorName:Google,Take:5,OrderByDesc:ViewCount,Fields:\"Name,ProductUrl,Tier,VendorName\")?use=xcode&name=MyApp")] + public void Can_resolve_url_from_slug(string slug, string expected) + { + var url = SiteUtils.UrlFromSlug(slug); + Assert.That(url, Is.EqualTo(expected)); + } + + [Test] + [TestCase("techstacks.io", "https://techstacks.io")] + [TestCase("http:techstacks.io", "http://techstacks.io")] + [TestCase("http:techstacks.io:1000", "http://techstacks.io:1000")] + [TestCase("http:techstacks.io:1000:site1:site2", "http://techstacks.io:1000/site1/site2")] + [TestCase("http:techstacks.io:1000:site1|site2", "http://techstacks.io:1000/site1|site2")] + [TestCase("techstacks.io:site1%7Csite2", "https://techstacks.io/site1%7Csite2")] + [TestCase("http:techstacks.io:1000:site1:site2", "http://techstacks.io:1000/site1/site2")] + [TestCase("techstacks.io:1000:site1:site2", "https://techstacks.io:1000/site1/site2")] + [TestCase("techstacks.io:1000:site1:site2(a:1,b:\"c,d\",e:f)", "https://techstacks.io:1000/site1/site2(a:1,b:\"c,d\",e:f)")] + [TestCase("apps.servicestack.net:gists:techstacks.io:swift:FindTechnologies(VendorName:Google,Take:5,OrderByDesc:ViewCount,Fields:\"Name,ProductUrl,Tier,VendorName\")?use=xcode&name=MyApp", + "https://apps.servicestack.net/gists/techstacks.io/swift/FindTechnologies(VendorName:Google,Take:5,OrderByDesc:ViewCount,Fields:\"Name,ProductUrl,Tier,VendorName\")?use=xcode&name=MyApp")] + public void Can_convert_url_to_slug(string expected, string url) + { + var slug = SiteUtils.UrlToSlug(url); + Assert.That(slug, Is.EqualTo(expected)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/StreamExtensionsTests.cs b/tests/ServiceStack.Common.Tests/StreamExtensionsTests.cs index 04c7f1f524f..fb7f81af213 100644 --- a/tests/ServiceStack.Common.Tests/StreamExtensionsTests.cs +++ b/tests/ServiceStack.Common.Tests/StreamExtensionsTests.cs @@ -1,76 +1,76 @@ using System.Runtime.Serialization; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceModel.Serialization; -using DataContractSerializer=ServiceStack.ServiceModel.Serialization.DataContractSerializer; +using ServiceStack.Common; +using ServiceStack.Serialization; +using DataContractSerializer = ServiceStack.Serialization.DataContractSerializer; namespace ServiceStack.Common.Tests { - [TestFixture] - public class StreamExtensionsTests - { - [DataContract] - public class SimpleDto - { - [DataMember] - public int Id { get; set; } + [TestFixture] + public class StreamExtensionsTests + { + [DataContract] + public class SimpleDto + { + [DataMember] + public int Id { get; set; } - [DataMember] - public string Name { get; set; } + [DataMember] + public string Name { get; set; } - public SimpleDto(int id, string name) - { - Id = id; - Name = name; - } - } + public SimpleDto(int id, string name) + { + Id = id; + Name = name; + } + } - [Test] - public void Can_compress_and_decompress_SimpleDto() - { - var simpleDto = new SimpleDto(1, "name"); + [Test] + public void Can_compress_and_decompress_SimpleDto() + { + var simpleDto = new SimpleDto(1, "name"); - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); - var simpleDtoZip = simpleDtoXml.Deflate(); + var simpleDtoZip = simpleDtoXml.Deflate(); - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - var deserializedSimpleDtoXml = simpleDtoZip.Inflate(); + var deserializedSimpleDtoXml = simpleDtoZip.Inflate(); - Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); + Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( - deserializedSimpleDtoXml); + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( + deserializedSimpleDtoXml); - Assert.That(deserializedSimpleDto, Is.Not.Null); + Assert.That(deserializedSimpleDto, Is.Not.Null); - Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); - Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); - } + Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); + Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); + } - [Test] - public void Can_compress_and_decompress_SimpleDto_with_Gzip() - { - var simpleDto = new SimpleDto(1, "name"); + [Test] + public void Can_compress_and_decompress_SimpleDto_with_Gzip() + { + var simpleDto = new SimpleDto(1, "name"); - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); - var simpleDtoZip = simpleDtoXml.GZip(); + var simpleDtoZip = simpleDtoXml.GZip(); - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - var deserializedSimpleDtoXml = simpleDtoZip.GUnzip(); + var deserializedSimpleDtoXml = simpleDtoZip.GUnzip(); - Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); + Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( - deserializedSimpleDtoXml); + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( + deserializedSimpleDtoXml); - Assert.That(deserializedSimpleDto, Is.Not.Null); + Assert.That(deserializedSimpleDto, Is.Not.Null); - Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); - Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); - } - } + Assert.That(deserializedSimpleDto.Id, Is.EqualTo(simpleDto.Id)); + Assert.That(deserializedSimpleDto.Name, Is.EqualTo(simpleDto.Name)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/StringExtensionTests.cs b/tests/ServiceStack.Common.Tests/StringExtensionTests.cs index c8592b33a6c..fe9f16ff5f1 100644 --- a/tests/ServiceStack.Common.Tests/StringExtensionTests.cs +++ b/tests/ServiceStack.Common.Tests/StringExtensionTests.cs @@ -4,104 +4,86 @@ using System.Web; using NUnit.Framework; using ServiceStack.Text; +#if NETCORE +using HttpUtility = System.Net.WebUtility; +#endif namespace ServiceStack.Common.Tests { - [TestFixture] - public class StringExtensionTests - { - [Test] - public void To_works_with_ValueTypes() - { - Assert.That(1.ToString().To(), Is.EqualTo(1)); - } - - [Test] - public void To_on_null_or_empty_string_returns_default_value_supplied() - { - const string nullString = null; - Assert.That("".To(1), Is.EqualTo(1)); - Assert.That("".To(default(int)), Is.EqualTo(default(int))); - Assert.That(nullString.To(1), Is.EqualTo(1)); - } - - [Test] - public void To_ValueType_on_null_or_empty_string_returns_default_value() - { - Assert.That("".To(), Is.EqualTo(default(int))); - } - - [Test] - public void To_UrlEncode() - { - const string url = "http://www.servicestack.net/a?b=c&d=f"; - var urlEncoded = url.UrlEncode(); - - Assert.That(urlEncoded, Is.EqualTo(HttpUtility.UrlEncode(url))); - } - - [Test] - public void To_UrlDecode() - { - const string url = "http://www.servicestack.net/a?b=c&d=f"; - var urlEncoded = url.UrlEncode(); - var decodedUrl = urlEncoded.UrlDecode(); - - Assert.That(decodedUrl, Is.EqualTo(url)); - } - - [Test] - public void UrlFormat_encodes_components() - { - const string url = "http://www.servicestack.net/a?b={0}&d={1}"; - const string arg1 = "as@if.com"; - const string arg2 = "&="; - - var urlFormat = url.UrlFormat(arg1, arg2); - var expectedUrlFormat = string.Format(url, arg1.UrlEncode(), arg2.UrlEncode()); - - Assert.That(urlFormat, Is.EqualTo(expectedUrlFormat)); - } - - [Test] - public void ErrorCode_to_English_format() - { - const string code = "EmailAddressIsInvalid"; - Assert.That(code.ToEnglish(), Is.EqualTo("Email address is invalid")); - } - - [Test] - public void Print_special_chars() - { - var specialChars = new List { '"', ':', ',', '%' }; - specialChars.ForEach(x => Console.WriteLine(x + " = " + ((int)x).ToString("x"))); - } - - [Test] - public void HexEscape_escapes_special_chars() - { - var specialChars = new List { '"', ':', ',', '%' }; - const string unescapedString = "\"1st 2:nd 3r,d 4th%"; - const string expectedString = "%221st 2%3and 3r%2cd 4th%25"; - Assert.That(unescapedString.HexEscape(specialChars.ToArray()), Is.EqualTo(expectedString)); - } - - [Test] - public void HexUnescape_unescapes_special_chars() - { - var specialChars = new List { '"', ':', ',', '%' }; - const string escapedString = "%221st 2%3and 3r%2cd 4th%25"; - const string expectedString = "\"1st 2:nd 3r,d 4th%"; - Assert.That(escapedString.HexUnescape(specialChars.ToArray()), Is.EqualTo(expectedString)); - } - - [Test] - public void SafeVarName_strips_illegal_chars() - { - Assert.That("with space".SafeVarName(), Is.EqualTo("with_space")); - Assert.That("with @+:\\illegals".SafeVarName(), Is.EqualTo("with_____illegals")); - Assert.That("UPPER_lower_0123456789".SafeVarName(), Is.EqualTo("UPPER_lower_0123456789")); - } + [TestFixture] + public class StringExtensionTests + { + [Test] + public void To_UrlEncode() + { + const string url = "http://www.servicestack.net/a?b=c&d=f"; + var urlEncoded = url.UrlEncode(); + + Assert.That(urlEncoded.ToUpper(), Is.EqualTo(HttpUtility.UrlEncode(url).ToUpper())); + } + + [Test] + public void To_UrlDecode() + { + const string url = "http://www.servicestack.net/a?b=c&d=f"; + var urlEncoded = url.UrlEncode(); + var decodedUrl = urlEncoded.UrlDecode(); + + Assert.That(decodedUrl, Is.EqualTo(url)); + } + + [Test] + public void UrlFormat_encodes_components() + { + const string url = "http://www.servicestack.net/a?b={0}&d={1}"; + const string arg1 = "as@if.com"; + const string arg2 = "&="; + + var urlFormat = url.UrlFormat(arg1, arg2); + var expectedUrlFormat = string.Format(url, arg1.UrlEncode(), arg2.UrlEncode()); + + Assert.That(urlFormat, Is.EqualTo(expectedUrlFormat)); + } + + [Test] + public void ErrorCode_to_English_format() + { + const string code = "EmailAddressIsInvalid"; + Assert.That(code.ToEnglish(), Is.EqualTo("Email address is invalid")); + } + + [Test] + public void Print_special_chars() + { + var specialChars = new List { '"', ':', ',', '%' }; + specialChars.ForEach(x => Console.WriteLine(x + " = " + ((int)x).ToString("x"))); + } + + [Test] + public void HexEscape_escapes_special_chars() + { + var specialChars = new List { '"', ':', ',', '%' }; + const string unescapedString = "\"1st 2:nd 3r,d 4th%"; + const string expectedString = "%221st 2%3and 3r%2cd 4th%25"; + Assert.That(unescapedString.HexEscape(specialChars.ToArray()), Is.EqualTo(expectedString)); + } + + [Test] + public void HexUnescape_unescapes_special_chars() + { + var specialChars = new List { '"', ':', ',', '%' }; + const string escapedString = "%221st 2%3and 3r%2cd 4th%25"; + const string expectedString = "\"1st 2:nd 3r,d 4th%"; + Assert.That(escapedString.HexUnescape(specialChars.ToArray()), Is.EqualTo(expectedString)); + } + + [Test] + public void SafeVarName_strips_illegal_chars() + { + Assert.That("with space".SafeVarName(), Is.EqualTo("with_space")); + Assert.That("with @+:\\illegals".SafeVarName(), Is.EqualTo("with_____illegals")); + Assert.That("UPPER_lower_0123456789".SafeVarName(), Is.EqualTo("UPPER_lower_0123456789")); + } [Test] public void Glob_finds_right_strings() @@ -110,13 +92,13 @@ public void Glob_finds_right_strings() var expected = input.Where(s => s.EndsWith("oo")).ToList(); var actual = input.Where(s => s.Glob("*oo")).ToList(); - + Assert.That(actual, Is.EquivalentTo(expected)); } - [Test] - public void Does_combine_paths() - { + [Test] + public void Does_combine_paths() + { Assert.That("/".CombineWith("/some/other/path"), Is.EqualTo("/some/other/path")); Assert.That("a".CombineWith("/some/other/path"), Is.EqualTo("a/some/other/path")); Assert.That("a/".CombineWith("/some/other/path"), Is.EqualTo("a/some/other/path")); @@ -127,7 +109,7 @@ public void Does_combine_paths() Assert.That("/a".CombineWith("/some/other/path/"), Is.EqualTo("/a/some/other/path/")); Assert.That("/a".CombineWith("/some/", "other", "/path/"), Is.EqualTo("/a/some/other/path/")); Assert.That("/a".CombineWith("some", "other", "path/"), Is.EqualTo("/a/some/other/path/")); - + Assert.That("".CombineWith("some", "other", "path/"), Is.EqualTo("some/other/path/")); } @@ -160,5 +142,149 @@ public void ToHttps_is_not_case_sensitive() { Assert.That("HTTP://HOST.EXAMPLE.COM".ToHttps(), Is.EqualTo("https://HOST.EXAMPLE.COM")); } - } + + [Test] + public void Can_parse_commands() + { + Assert.That("COUNT".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:]" })); + Assert.That("COUNT()".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:]" })); + Assert.That("COUNT(*)".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:*]" })); + Assert.That("COUNT(DISTINCT Name)".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:DISTINCT Name]" })); + Assert.That("COUNT('Name')".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:'Name']" })); + Assert.That("COUNT(\"Name\")".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:\"Name\"]" })); + Assert.That("COUNT('N,a(m\"e')".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:'N,a(m\"e']" })); + Assert.That("COUNT(*,'foo',1)".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:*|'foo'|1]" })); + Assert.That("COUNT( * , 'foo' , 1 )".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:*|'foo'|1]" })); + Assert.That("Count(*), Min(Age), Max(Age), Sum(Id)".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo( + new[] { "[Count:*]", "[Min:Age]", "[Max:Age]", "[Sum:Id]" })); + Assert.That("Count(*,\",\"), Min(Age,')'), Max(Age,1), Sum(Id,Foo,2.0)".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo( + new[] { "[Count:*|\",\"]", "[Min:Age|')']", "[Max:Age|1]", "[Sum:Id|Foo|2.0]" })); + + Assert.That("Field1,Field2".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[Field1:]", "[Field2:]" })); + } + + [Test] + public void Can_parse_commands_with_Aliases() + { + Assert.That("COUNT(*) Count".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:*] Count" })); + Assert.That("COUNT(DISTINCT LivingStatus) as UniqueStatus".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[COUNT:DISTINCT LivingStatus] as UniqueStatus" })); + Assert.That("MIN(Age) MinAge".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { "[MIN:Age] MinAge" })); + Assert.That("Count(*) count, Min(Age) min, Max(Age) max, Sum(Id) sum".ParseCommands().Map(x => x.ToDebugString()), Is.EquivalentTo(new[] { + "[Count:*] count", "[Min:Age] min", "[Max:Age] max", "[Sum:Id] sum" + })); + } + + [Test] + public void Does_clean_input() + { + Assert.That("a.b+c@&.com=|".SafeInput(), Is.EqualTo("a.b+c@d.com")); + Assert.That("/a/b.c".SafeInput(), Is.EqualTo("/a/b.c")); + Assert.That("1,000.00".SafeInput(), Is.EqualTo("1,000.00")); + Assert.That("a b c".SafeInput(), Is.EqualTo("a b c")); + } + + [Test] + public void Does_parse_complex_arguments() + { + Assert.That("add(1,add(2,3))".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[add:1|add(2,3)]" })); + Assert.That(" add ( 1, add(2,3) ) ".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[add:1|add(2,3)]" })); + Assert.That("cat('1',cat(\"2\",'3'))".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[cat:'1'|cat(\"2\",'3')]" })); + + Assert.That(" add ( 1, add(add(2,3),4) ) ".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[add:1|add(add(2,3),4)]" })); + } + + [Test] + public void Does_preserve_js_literal_string() + { + Assert.That("li({ id:'id-{name}', className:'cls'})".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[li:{ id:'id-{name}', className:'cls'}]" })); + } + + [Test] + public void Does_preserve_ternary_expression() + { + Assert.That("filter( true ? 'Y' : 'N' )".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[filter:true ? 'Y' : 'N']" })); + } + + [Test] + public void Does_parse_binding_expressions() + { + Assert.That("var".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var:]" })); + Assert.That("var2".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var2:]" })); + Assert.That("var.prop".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var.prop:]" })); + Assert.That("var.prop.p2.p3".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var.prop.p2.p3:]" })); + Assert.That("var.prop[key]".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var.prop[key]:]" })); + Assert.That("var.prop['key']".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var.prop['key']:]" })); + Assert.That("var.prop[\"key\"]".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[var.prop[\"key\"]:]" })); + + Assert.That("fn(var)".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var]" })); + Assert.That("fn(var.prop)".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop]" })); + Assert.That("fn(var.prop.p2.p3)".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop.p2.p3]" })); + Assert.That("fn(var.prop[key])".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop[key]]" })); + Assert.That("fn(var.prop['key'])".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop['key']]" })); + Assert.That("fn(var.prop[\"key\"])".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop[\"key\"]]" })); + + Assert.That("fn(var,var)".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var|var]" })); + Assert.That("fn(var.prop,var.prop)".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop|var.prop]" })); + Assert.That("fn(var.prop.p2.p3,var.prop.p2.p3)".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop.p2.p3|var.prop.p2.p3]" })); + Assert.That("fn(var.prop[key],var.prop[key])".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop[key]|var.prop[key]]" })); + Assert.That("fn(var.prop['key'],var.prop['key'])".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop['key']|var.prop['key']]" })); + Assert.That("fn(var.prop[\"key\"],var.prop[\"key\"])".ParseCommands().Map(x => x.ToDebugString()), Is.EqualTo(new[]{ "[fn:var.prop[\"key\"]|var.prop[\"key\"]]" })); + } + + [Test] + public void Can_parse_SELECT_Expression_with_concatenation() + { + var sql = "\"UserName\", \"Email\", \"FirstName\" AS \"GivenName\", \"LastName\" AS \"Surname\", \"FirstName\" || @1 || \"LastName\" AS FullName"; + + var commands = sql.ParseCommands(); + + var names = commands.Map(x => x.Original.ToString()); + Assert.That(names, Is.EquivalentTo(new[] { + "\"UserName\"", + "\"Email\"", + "\"FirstName\" AS \"GivenName\"", + "\"LastName\" AS \"Surname\"", + "\"FirstName\" || @1 || \"LastName\" AS FullName", + })); + + var aliasesOrNames = names.Map(x => x.LastRightPart("AS").Trim().StripQuotes() ); + aliasesOrNames.PrintDump(); + + Assert.That(aliasesOrNames, Is.EquivalentTo(new[] { + "UserName", + "Email", + "GivenName", + "Surname", + "FullName", + })); + } + + [Test] + public void Can_parse_SELECT_Expression_with_nested_functions() + { + var sql = "CONCAT(CONCAT(\"FirstName\", @1), \"LastName\") AS FullName, \"FirstName\" AS \"GivenName\", \"LastName\" AS \"Surname\", \"Email\", \"UserName\""; + + var commands = sql.ParseCommands(); + + var names = commands.Map(x => x.Original.ToString()); + Assert.That(names, Is.EquivalentTo(new[] { + "CONCAT(CONCAT(\"FirstName\", @1), \"LastName\") AS FullName", + "\"FirstName\" AS \"GivenName\"", + "\"LastName\" AS \"Surname\"", + "\"Email\"", + "\"UserName\"", + })); + + var aliasesOrNames = names.Map(x => x.LastRightPart("AS").Trim().StripQuotes() ); + aliasesOrNames.PrintDump(); + + Assert.That(aliasesOrNames, Is.EquivalentTo(new[] { + "FullName", + "GivenName", + "Surname", + "Email", + "UserName", + })); + } + } } diff --git a/tests/ServiceStack.Common.Tests/StringUtilsTests.cs b/tests/ServiceStack.Common.Tests/StringUtilsTests.cs new file mode 100644 index 00000000000..c101b741e6d --- /dev/null +++ b/tests/ServiceStack.Common.Tests/StringUtilsTests.cs @@ -0,0 +1,102 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System; +using System.Globalization; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.Common.Tests +{ + [TestFixture] + public class StringUtilsTests + { + [Test] + public void Does_replace_outside_of_quotes() + { + Assert.That("{it}".ReplaceOutsideOfQuotes("{", "{{", "}", "}}"), Is.EqualTo("{{it}}")); + Assert.That("{it} '{it}'".ReplaceOutsideOfQuotes("{", "{{", "}", "}}"), Is.EqualTo("{{it}} '{it}'")); + Assert.That("{it} `'{it}' {it}`".ReplaceOutsideOfQuotes("{", "{{", "}", "}}"), Is.EqualTo("{{it}} `'{it}' {it}`")); + Assert.That("{it} `'{it}' {it}` {it}".ReplaceOutsideOfQuotes("{", "{{", "}", "}}"), Is.EqualTo("{{it}} `'{it}' {it}` {{it}}")); + + Assert.That("{ '{0:00}' | fmt(it) }\n".ReplaceOutsideOfQuotes("{", "{{", "}", "}}"), Is.EqualTo("{{ '{0:00}' | fmt(it) }}\n")); + } + + [Test] + public void HtmlStrip_unescapes_all_html_character_codes_correctly() + { + foreach (var value in Enumerable.Range(ushort.MinValue, ushort.MaxValue).Select(i => (ushort)i)) + { + var expected = ((char)value).ToString(CultureInfo.InvariantCulture); + + var decimalNotation = $"&#{value};"; + var decimalActual = decimalNotation.StripHtml().ConvertHtmlCodes(); + Assert.AreEqual(expected, decimalActual); + + var hexNotation = $"&#x{value:X};"; + var hexActual = hexNotation.StripHtml().ConvertHtmlCodes(); + Assert.AreEqual(expected, hexActual); + } + + foreach (var htmlNotation in StringUtils.HtmlCharacterCodes) + { + var actual = htmlNotation.Key.StripHtml().ConvertHtmlCodes(); + var expected = htmlNotation.Value; + Assert.AreEqual(expected, actual); + } + } + + [Test] + public void HtmlStrip_fixes_actual_production_example() + { + var encoded = @"Du träumst von node.js und willst mithelfen einen Request in unter 50ms auszuliefern? PHP ist Deine Muttersprache und Dein Verstand schreit nach immer neuen Herausforderungen? Dann passt du zu uns. Bringe Deine Kompetenzen in ein Unternehmen ein, das Dir neben hervorragenden Arbeitsbedingungen wirklich etwas zu bieten hat: Perspektiven! +Werde Teil unseres Teams und gestalte aktiv die technische Zukunft der weltweit größten Online Hotelsuche mit. Arbeite mit neuesten Technologien in einem global aufgestellten Unternehmen. Nutze die Freiheit Bestehendes in Frage zu stellen, Deinen Horizont zu erweitern und Neues zu entwickeln."; + var expected = @"Du träumst von node.js und willst mithelfen einen Request in unter 50ms auszuliefern? PHP ist Deine Muttersprache und Dein Verstand schreit nach immer neuen Herausforderungen? Dann passt du zu uns. Bringe Deine Kompetenzen in ein Unternehmen ein, das Dir neben hervorragenden Arbeitsbedingungen wirklich etwas zu bieten hat: Perspektiven! +Werde Teil unseres Teams und gestalte aktiv die technische Zukunft der weltweit größten Online Hotelsuche mit. Arbeite mit neuesten Technologien in einem global aufgestellten Unternehmen. Nutze die Freiheit Bestehendes in Frage zu stellen, Deinen Horizont zu erweitern und Neues zu entwickeln."; + var actual = encoded.StripHtml().ConvertHtmlCodes(); + Assert.AreEqual(expected, actual); + } + + [Test] + public void Does_convert_snake_case_to_PascalCase() + { + Assert.That(StringUtils.SnakeCaseToPascalCase(""), Is.EqualTo("")); + Assert.That(StringUtils.SnakeCaseToPascalCase("a"), Is.EqualTo("A")); + Assert.That(StringUtils.SnakeCaseToPascalCase("a_b"), Is.EqualTo("AB")); + Assert.That(StringUtils.SnakeCaseToPascalCase("a1_b2"), Is.EqualTo("A1B2")); + Assert.That(StringUtils.SnakeCaseToPascalCase("aa_bb"), Is.EqualTo("AaBb")); + Assert.That(StringUtils.SnakeCaseToPascalCase("aaBb"), Is.EqualTo("AaBb")); + } + + [Test] + public void Does_split_fields() + { + Assert.That(StringUtils.SplitVarNames(""), Is.EqualTo(new string[0])); + Assert.That(StringUtils.SplitVarNames("A"), Is.EqualTo(new[]{ "A"})); + Assert.That(StringUtils.SplitVarNames("A,B,C"), Is.EqualTo(new[]{ "A","B","C" })); + Assert.That(StringUtils.SplitVarNames("A, B , C"), Is.EqualTo(new[]{ "A","B","C" })); + Assert.That(StringUtils.SplitVarNames("A, B , C, "), Is.EqualTo(new[]{ "A","B","C" })); + } + + [Test] + public void Can_parse_base_datauri() + { + var utf8Bytes = "abc".ToUtf8Bytes(); + var dataUri = "data:image/jpg;base64," + Convert.ToBase64String(utf8Bytes); + var content = StaticContent.CreateFromDataUri(dataUri); + Assert.That(content.MimeType, Is.EqualTo("image/jpg")); + Assert.That(content.Data.ToArray(), Is.EqualTo(utf8Bytes)); + } + + [Test] + public void Can_parse_svg_datauri() + { + var dataUri = Svg.GetDataUri(Svg.Icons.Male); + var content = StaticContent.CreateFromDataUri(dataUri); + Assert.That(content.MimeType, Is.EqualTo("image/svg+xml")); + Assert.That(content.Data.FromUtf8().ToString(), Is.EqualTo(Svg.GetImage(Svg.Icons.Male))); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/TestBase.cs b/tests/ServiceStack.Common.Tests/TestBase.cs new file mode 100644 index 00000000000..47f08e19fee --- /dev/null +++ b/tests/ServiceStack.Common.Tests/TestBase.cs @@ -0,0 +1,751 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; +using ServiceStack.Messaging; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.Common.Tests +{ + public abstract class TestBase + { + protected ServiceStackHost AppHost { get; set; } + + protected bool HasConfigured { get; set; } + + protected TestBase(params Assembly[] serviceAssemblies) + : this(null, serviceAssemblies) { } + + protected TestBase(string serviceClientBaseUri, params Assembly[] serviceAssemblies) + { + if (serviceAssemblies.Length == 0) + serviceAssemblies = new[] { GetType().Assembly }; + + ServiceClientBaseUri = serviceClientBaseUri; + ServiceAssemblies = serviceAssemblies; + + this.AppHost = new BasicAppHost(serviceAssemblies) + { + ConfigureAppHost = host => + { + host.CatchAllHandlers.Add(new PredefinedRoutesFeature().ProcessRequest); + host.CatchAllHandlers.Add(new MetadataFeature().ProcessRequest); + } + }.Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + this.AppHost.Dispose(); + } + + protected abstract void Configure(Funq.Container container); + + protected Funq.Container Container => HostContext.Container; + + protected IServiceRoutes Routes => HostContext.AppHost.Routes; + + //All integration tests call the Webservices hosted at the following location: + protected string ServiceClientBaseUri { get; set; } + protected Assembly[] ServiceAssemblies { get; set; } + + public virtual void OnBeforeTestFixture() + { + OnConfigure(); + } + + protected virtual void OnConfigure() + { + if (HasConfigured) return; + + HasConfigured = true; + Configure(Container); + } + + public virtual void OnBeforeEachTest() + { + OnConfigure(); + } + + protected virtual IServiceClient CreateNewServiceClient() + { + return new DirectServiceClient(this, AppHost.ServiceController); + } + + protected virtual IRestClient CreateNewRestClient() + { + return new DirectServiceClient(this, AppHost.ServiceController); + } + + protected virtual IRestClientAsync CreateNewRestClientAsync() + { + return new DirectServiceClient(this, AppHost.ServiceController); + } + + public class DirectServiceClient : IServiceClient, IRestClient + { + private readonly TestBase parent; + ServiceController ServiceManager { get; set; } + + public DirectServiceClient(TestBase parent, ServiceController serviceManager) + { + this.parent = parent; + this.ServiceManager = serviceManager; + } + + public void SendOneWay(object requestDto) + { + ServiceManager.Execute(requestDto); + } + + public void SendOneWay(string relativeOrAbsoluteUri, object requestDto) + { + ServiceManager.Execute(requestDto); + } + + public void SendAllOneWay(IEnumerable requests) + { + throw new NotImplementedException(); + } + + public TResponse Get(IReturn requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Get(object requestDto) + { + throw new NotImplementedException(); + } + + public void AddHeader(string name, string value) + { + throw new NotImplementedException(); + } + + public void ClearCookies() + { + } + + public Dictionary GetCookieValues() + { + return new Dictionary(); + } + + public void SetCookie(string name, string value, TimeSpan? expiresIn = null) + { + throw new NotImplementedException(); + } + + public void Get(IReturnVoid request) + { + throw new NotImplementedException(); + } + + public TResponse Get(string relativeOrAbsoluteUrl) + { + return parent.ExecutePath(HttpMethods.Get, new UrlParts(relativeOrAbsoluteUrl), null); + } + + public IEnumerable GetLazy(IReturn> queryDto) + { + throw new NotImplementedException(); + } + + public TResponse Delete(IReturn request) + { + throw new NotImplementedException(); + } + + public TResponse Delete(object request) + { + throw new NotImplementedException(); + } + + public void Delete(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Delete(string relativeOrAbsoluteUrl) + { + return parent.ExecutePath(HttpMethods.Delete, new UrlParts(relativeOrAbsoluteUrl), null); + } + + public TResponse Post(IReturn requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Post(object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Post(string relativeOrAbsoluteUrl, object request) + { + throw new NotImplementedException(); + } + + public void Post(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Post(object request, string relativeOrAbsoluteUrl) + { + return parent.ExecutePath(HttpMethods.Post, new UrlParts(relativeOrAbsoluteUrl), request); + } + + public TResponse Put(IReturn requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Put(object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Put(string relativeOrAbsoluteUrl, object requestDto) + { + throw new NotImplementedException(); + } + + public void Put(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Put(object requestDto, string relativeOrAbsoluteUrl) + { + return parent.ExecutePath(HttpMethods.Put, new UrlParts(relativeOrAbsoluteUrl), requestDto); + } + + public TResponse Patch(IReturn requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Patch(object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Patch(string relativeOrAbsoluteUrl, object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Send(string httpMethod, string relativeOrAbsoluteUrl, object request) + { + throw new NotImplementedException(); + } + + public void Patch(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Patch(object requestDto, string relativeOrAbsoluteUrl) + { + return parent.ExecutePath(HttpMethods.Patch, new UrlParts(relativeOrAbsoluteUrl), requestDto); + } + + public TResponse PostFile(string relativeOrAbsoluteUrl, FileInfo fileToUpload, string mimeType) + { + throw new NotImplementedException(); + } + + public void CustomMethod(string httpVerb, IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse CustomMethod(string httpVerb, IReturn requestDto) + { + throw new NotImplementedException(); + } + + public TResponse CustomMethod(string httpVerb, object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse PostFile(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, string mimeType) + { + throw new NotImplementedException(); + } + + public TResponse PostFileWithRequest( + Stream fileToUpload, string fileName, object request, string fieldName = "upload") + { + throw new NotImplementedException(); + } + + private static void HandleException(Exception exception, Action onError) + { + var response = (TResponse)typeof(TResponse).CreateInstance(); + if (response is IHasResponseStatus hasResponseStatus) + { + hasResponseStatus.ResponseStatus = new ResponseStatus { + ErrorCode = exception.GetType().Name, + Message = exception.Message, + StackTrace = exception.StackTrace, + }; + } + var webServiceEx = new WebServiceException(exception.Message, exception); + onError?.Invoke(response, webServiceEx); + } + + public void SetCredentials(string userName, string password) + { + throw new NotImplementedException(); + } + + public Task GetAsync(string relativeOrAbsoluteUrl, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task DeleteAsync(string relativeOrAbsoluteUrl, CancellationToken token = default) + { + var tcs = new TaskCompletionSource(); + try + { + var response = parent.ExecutePath(HttpMethods.Delete, new UrlParts(relativeOrAbsoluteUrl), default(TResponse)); + tcs.SetResult(response); + } + catch (Exception ex) + { + HandleException(ex, (TResponse r, Exception rex) => tcs.SetException(rex)); + } + return tcs.Task; + } + + public Task PostAsync(string relativeOrAbsoluteUrl, object request, CancellationToken token = default) + { + var tcs = new TaskCompletionSource(); + try + { + var response = parent.ExecutePath(HttpMethods.Post, new UrlParts(relativeOrAbsoluteUrl), request); + tcs.SetResult(response); + } + catch (Exception ex) + { + HandleException(ex, (TResponse r, Exception rex) => tcs.SetException(rex)); + } + return tcs.Task; + } + + public Task PutAsync(string relativeOrAbsoluteUrl, object request, CancellationToken token = default) + { + var tcs = new TaskCompletionSource(); + try + { + var response = parent.ExecutePath(HttpMethods.Put, new UrlParts(relativeOrAbsoluteUrl), request); + tcs.SetResult(response); + } + catch (Exception ex) + { + HandleException(ex, (TResponse r, Exception rex) => tcs.SetException(rex)); + } + return tcs.Task; + } + + public Task CustomMethodAsync(string httpVerb, string relativeOrAbsoluteUrl, object request, + CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task SendAsync(string httpMethod, string absoluteUrl, object request, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public void CancelAsync() + { + throw new NotImplementedException(); + } + + public void Dispose() { } + public TResponse PostFileWithRequest(string relativeOrAbsoluteUrl, FileInfo fileToUpload, object request, string fieldName = "upload") + { + throw new NotImplementedException(); + } + + public TResponse PostFileWithRequest(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, object request, string fieldName = "upload") + { + throw new NotImplementedException(); + } + + public TResponse PostFilesWithRequest(object request, IEnumerable files) + { + throw new NotImplementedException(); + } + + public TResponse PostFilesWithRequest(string relativeOrAbsoluteUrl, object request, IEnumerable files) + { + throw new NotImplementedException(); + } + + public int Version { get; set; } + public string SessionId { get; set; } + + public TResponse Send(object request) + { + var message = MessageFactory.Create(request); + var response = ServiceManager.ExecuteMessage(message); + if (response is IHttpResult httpResult) + { + if (httpResult.StatusCode >= HttpStatusCode.BadRequest) + { + var webEx = new WebServiceException(httpResult.StatusDescription) + { + ResponseDto = httpResult.Response, + StatusCode = httpResult.Status, + }; + throw webEx; + } + return (TResponse)httpResult.Response; + } + + var responseStatus = response.GetResponseStatus(); + var isError = responseStatus?.ErrorCode != null; + if (isError) + { + var webEx = new WebServiceException(responseStatus.Message) + { + ResponseDto = response, + StatusCode = responseStatus.Errors != null && responseStatus.Errors.Count > 0 + ? 400 + : 500, + }; + throw webEx; + } + + return (TResponse)response; + } + + public List SendAll(IEnumerable requests) + { + throw new NotImplementedException(); + } + + public void Publish(object requestDto) + { + SendOneWay(requestDto); + } + + public void PublishAll(IEnumerable requestDtos) + { + throw new NotImplementedException(); + } + + public Task SendAsync(object requestDto, CancellationToken token = default) + { + var tcs = new TaskCompletionSource(); + try + { + var response = (TResponse)ServiceManager.Execute(requestDto); + tcs.SetResult(response); + } + catch (Exception ex) + { + HandleException(ex, (TResponse r, Exception rex) => tcs.SetException(rex)); + } + return tcs.Task; + } + + public Task> SendAllAsync(IEnumerable requests, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PublishAsync(object requestDto, CancellationToken token = default) + { + return SendAsync(requestDto, token); + } + + public Task PublishAllAsync(IEnumerable requestDtos, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public string BearerToken { get; set; } + public Task GetAsync(IReturn requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task GetAsync(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task GetAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task DeleteAsync(IReturn requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task DeleteAsync(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task DeleteAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PostAsync(IReturn requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PostAsync(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PostAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PutAsync(IReturn requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PutAsync(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PutAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PatchAsync(IReturn requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PatchAsync(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PatchAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task CustomMethodAsync(string httpVerb, IReturn requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task CustomMethodAsync(string httpVerb, object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task CustomMethodAsync(string httpVerb, IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + } + + public object ExecutePath(string pathInfo) + { + return ExecutePath(HttpMethods.Get, pathInfo); + } + + private class UrlParts + { + public UrlParts(string pathInfo) + { + this.PathInfo = pathInfo.UrlDecode(); + var qsIndex = pathInfo.IndexOf("?", StringComparison.Ordinal); + if (qsIndex != -1) + { + var qs = pathInfo.Substring(qsIndex + 1); + this.PathInfo = pathInfo.Substring(0, qsIndex); + var kvps = qs.Split('&'); + + this.QueryString = new Dictionary(); + foreach (var kvp in kvps) + { + var parts = kvp.Split('='); + this.QueryString[parts[0]] = parts.Length > 1 ? parts[1] : null; + } + } + } + + public string PathInfo { get; private set; } + public Dictionary QueryString { get; private set; } + } + + public object ExecutePath(string httpMethod, string pathInfo) + { + var urlParts = new UrlParts(pathInfo); + return ExecutePath(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, null); + } + + private TResponse ExecutePath(string httpMethod, UrlParts urlParts, object requestDto) + { + return (TResponse)ExecutePath(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, requestDto); + } + + public TResponse ExecutePath(string httpMethod, string pathInfo, object requestDto) + { + var urlParts = new UrlParts(pathInfo); + return (TResponse)ExecutePath(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, requestDto); + } + + public object ExecutePath( + string httpMethod, + string pathInfo, + Dictionary queryString, + Dictionary formData, + T requestBody) + { + var isDefault = Equals(requestBody, default(T)); + var json = !isDefault ? JsonSerializer.SerializeToString(requestBody) : null; + return ExecutePath(httpMethod, pathInfo, queryString, formData, json); + } + + public object ExecutePath( + string httpMethod, + string pathInfo, + Dictionary queryString, + Dictionary formData, + string requestBody) + { + var contentType = (formData != null && formData.Count > 0) + ? MimeTypes.FormUrlEncoded + : requestBody != null ? MimeTypes.Json : null; + + var httpReq = new MockHttpRequest( + nameof(MockHttpRequest), + httpMethod, + contentType, + pathInfo, + queryString.ToNameValueCollection(), + requestBody == null ? null : Encoding.UTF8.GetBytes(requestBody).InMemoryStream(), + formData.ToNameValueCollection() + ); + + var httpHandler = (IRequestHttpHandler)GetHandler(httpReq); + httpReq.OperationName = httpHandler.RequestName; + + var request = httpHandler.CreateRequestAsync(httpReq, httpHandler.RequestName).Result; + object response; + try + { + response = httpHandler.GetResponseAsync(httpReq, request).Result; + } + catch (Exception ex) + { + response = DtoUtils.CreateErrorResponse(request, ex); + } + + if (response is IHttpResult httpRes) + { + if (httpRes is IHttpError httpError) + { + throw new WebServiceException(httpError.Message) { + StatusCode = httpError.Status, + ResponseDto = httpError.Response + }; + } + var hasResponseStatus = httpRes.Response as IHasResponseStatus; + var status = hasResponseStatus?.ResponseStatus; + if (status != null && !status.ErrorCode.IsNullOrEmpty()) + { + throw new WebServiceException(status.Message) { + StatusCode = (int)HttpStatusCode.InternalServerError, + ResponseDto = httpRes.Response, + }; + } + + return httpRes.Response; + } + + return response; + } + + public T GetRequest(string pathInfo) + { + return (T) GetRequest(pathInfo); + } + + public object GetRequest(string pathInfo) + { + var urlParts = new UrlParts(pathInfo); + return GetRequest(HttpMethods.Get, urlParts.PathInfo, urlParts.QueryString, null, null); + } + + public object GetRequest(string httpMethod, string pathInfo) + { + var urlParts = new UrlParts(pathInfo); + return GetRequest(httpMethod, urlParts.PathInfo, urlParts.QueryString, null, null); + } + + public object GetRequest( + string httpMethod, + string pathInfo, + Dictionary queryString, + Dictionary formData, + string requestBody) + { + var contentType = (formData != null && formData.Count > 0) + ? MimeTypes.FormUrlEncoded + : requestBody != null ? MimeTypes.Json : null; + + var httpReq = new MockHttpRequest( + nameof(MockHttpRequest), + httpMethod, + contentType, + pathInfo, + queryString.ToNameValueCollection(), + requestBody == null ? null : Encoding.UTF8.GetBytes(requestBody).InMemoryStream(), + formData.ToNameValueCollection() + ); + + var httpHandler = (IRequestHttpHandler)GetHandler(httpReq); + httpReq.OperationName = httpHandler.RequestName; + + var request = httpHandler.CreateRequestAsync(httpReq, httpHandler.RequestName).Result; + return request; + } + + private static ServiceStackHandlerBase GetHandler(IHttpRequest httpReq) + { + var httpHandler = HttpHandlerFactory.GetHandlerForPathInfo(httpReq, null) as ServiceStackHandlerBase; + if (httpHandler == null) + throw new NotSupportedException(httpReq.PathInfo); + return httpHandler; + } + } + +} diff --git a/tests/ServiceStack.Common.Tests/TestUtils.cs b/tests/ServiceStack.Common.Tests/TestUtils.cs new file mode 100644 index 00000000000..fd220fefb49 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/TestUtils.cs @@ -0,0 +1,13 @@ +using System.Text.RegularExpressions; + +namespace ServiceStack.Common.Tests +{ + public static class TestUtils + { + public static string NormalizeNewLines(this string text) => text.Trim().Replace("\r", ""); + public static string RemoveNewLines(this string text) => text.Trim().Replace("\r", "").Replace("\n", ""); + + static readonly Regex whitespace = new Regex(@"\s+", RegexOptions.Compiled); + public static string RemoveAllWhitespace(this string text) => whitespace.Replace(text, ""); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/TestsConfig.cs b/tests/ServiceStack.Common.Tests/TestsConfig.cs new file mode 100644 index 00000000000..d72d7091671 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/TestsConfig.cs @@ -0,0 +1,23 @@ +using System; +using Amazon.DynamoDBv2; + +namespace ServiceStack.Common.Tests +{ + public class TestsConfig + { + public static readonly string RabbitMqHost = Environment.GetEnvironmentVariable("CI_RABBITMQ") ?? "localhost"; + + public static readonly string SqlServerConnString = Environment.GetEnvironmentVariable("MSSQL_CONNECTION") ?? "Server=localhost;Database=test;User Id=test;Password=test;"; + public static readonly string PostgreSqlConnString = Environment.GetEnvironmentVariable("PGSQL_CONNECTION") ?? "Server=localhost;Port=5432;User Id=test;Password=test;Database=test;Pooling=true;MinPoolSize=0;MaxPoolSize=200"; + + public static AmazonDynamoDBClient CreateDynamoDBClient() + { + var dynamoClient = new AmazonDynamoDBClient("keyId", "key", new AmazonDynamoDBConfig + { + ServiceURL = Environment.GetEnvironmentVariable("CI_DYNAMODB") ?? "http://localhost:8000", + }); + + return dynamoClient; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/Text/AdhocJsTests.cs b/tests/ServiceStack.Common.Tests/Text/AdhocJsTests.cs index a9a4cec13b0..b09362202f4 100644 --- a/tests/ServiceStack.Common.Tests/Text/AdhocJsTests.cs +++ b/tests/ServiceStack.Common.Tests/Text/AdhocJsTests.cs @@ -13,7 +13,7 @@ public enum EnumValues } [TestFixture] - public class AdhocJsTests + public class AdhocJsTests { [Test] public void Can_Deserialize() @@ -43,7 +43,7 @@ public void Can_Serialize_Array_of_chars() [Test] public void Can_Serialize_Array_with_nulls() { - using (JsConfig.With(includeNullValues:true)) + using (JsConfig.With(new Config { IncludeNullValues = true })) { var t = new { Name = "MyName", @@ -73,7 +73,6 @@ public void Deserialize_array_with_null_elements() { var json = "[{\"Value\": \"a\"},null,{\"Value\": \"b\"}]"; var o = JsonSerializer.DeserializeFromString(json); - o.PrintDump(); } } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs b/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs index 23e03041f37..bfb8d3a7c88 100644 --- a/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs +++ b/tests/ServiceStack.Common.Tests/UrlExtensionTests.cs @@ -1,8 +1,6 @@ using System; using System.Runtime.Serialization; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; using ServiceStack.Text; namespace ServiceStack.Common.Tests @@ -13,16 +11,28 @@ public class JustId : IReturn public long Id { get; set; } } + public class FluentJustId : IReturn + { + public long Id { get; set; } + } + + [FallbackRoute("/route/{Id}")] + public class FallbackJustId : IReturn + { + public long Id { get; set; } + public string Name { get; set; } + } + [Route("/route/{Id}")] - public class FieldId : IReturn - { - public readonly long Id; + public class FieldId : IReturn + { + public readonly long Id; - public FieldId(long id) - { - Id = id; - } - } + public FieldId(long id) + { + Id = id; + } + } [Route("/route/{Ids}")] public class ArrayIds : IReturn @@ -71,26 +81,42 @@ public class RequestWithNamedDataMembers : IReturn public string Excluded { get; set; } } - public enum Gender - { - None = 0, - Male, - Female - } + public enum Gender + { + None = 0, + Male, + Female + } - [Route("/route/{Id}")] - public class RequestWithValueTypes : IReturn - { - public long Id { get; set; } + [Route("/route/{Id}")] + public class RequestWithValueTypes : IReturn + { + public long Id { get; set; } - public Gender Gender1 { get; set; } + public Gender Gender1 { get; set; } + + public Gender? Gender2 { get; set; } + } - public Gender? Gender2 { get; set; } - } + [Route("/thing/{Id}/point", "POST")] + [DataContract] + public class IdWithAlias : IReturn + { + [DataMember(Name = "id")] + public int Id { get; set; } + } [TestFixture] public class UrlExtensionTests { +#if !NETCORE + [Test] + public void GetLeftAuthority_equals_GetUriPartialAuthority() + { + var uri = new Uri("http://www.domain.org:8080/path/info?query=string"); + Assert.That(uri.GetLeftAuthority(), Is.EqualTo(uri.GetLeftPart(UriPartial.Authority))); + } +#endif [Test] public void Can_create_url_with_JustId() { @@ -98,18 +124,42 @@ public void Can_create_url_with_JustId() Assert.That(url, Is.EqualTo("/route/1")); } - [Test] - public void Can_create_url_with_FieldId() - { - using (JsConfig.BeginScope()) - { - JsConfig.IncludePublicFields = true; - var url = new FieldId(1).ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/1")); + [Test] + public void Can_create_url_with_FluentJustId() + { + typeof(FluentJustId) + .AddAttributes(new RouteAttribute("/route/{Id}")); - } - } + var url = new FluentJustId { Id = 1 }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1")); + } + [Test] + public void Can_create_url_with_FallbackJustId() + { + var url = new FallbackJustId { Id = 1 }.ToGetUrl(); + Assert.That(url, Is.EqualTo("/route/1")); + + url = new FallbackJustId { Id = 1, Name = "foo" }.ToGetUrl(); + Assert.That(url, Is.EqualTo("/route/1?name=foo")); + } + + [Test] + public void Can_create_url_with_FieldId() + { + using (JsConfig.With(new ServiceStack.Text.Config { IncludePublicFields = true })) + { + var url = new FieldId(1).ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1")); + } + } + + [Test] + public void Can_create_POST_url_with_IdWithAlias() + { + var url = new IdWithAlias { Id = 1 }.ToPostUrl(); + Assert.That(url, Is.EqualTo("/thing/1/point")); + } [Test] public void Can_create_url_with_ArrayIds() @@ -139,40 +189,40 @@ public void Use_data_member_names_on_querystring() Assert.That(url, Is.EqualTo("/route/1?inc=Yes")); } - [Test] - public void Cannot_use_default_for_non_nullable_value_types_on_querystring() - { - var url = new RequestWithValueTypes {Id = 1, Gender1 = Gender.None}.ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/1")); - } - - [Test] - public void Can_use_non_default_for_non_nullable_value_types_on_querystring() - { - var url = new RequestWithValueTypes { Id = 1, Gender1 = Gender.Male }.ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/1?gender1=Male")); - } - - [Test] - public void Can_use_default_for_nullable_value_types_on_querystring() - { - var url = new RequestWithValueTypes { Id = 1, Gender2 = Gender.None }.ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/1?gender2=None")); - } - - [Test] - public void Cannot_use_null_for_nullable_value_types_on_querystring() - { - var url = new RequestWithValueTypes { Id = 1, Gender2 = null }.ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/1")); - } - - [Test] - public void Can_use_non_default_for_nullable_value_types_on_querystring() - { - var url = new RequestWithValueTypes { Id = 1, Gender2 = Gender.Male }.ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/1?gender2=Male")); - } + [Test] + public void Cannot_use_default_for_non_nullable_value_types_on_querystring() + { + var url = new RequestWithValueTypes { Id = 1, Gender1 = Gender.None }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1")); + } + + [Test] + public void Can_use_non_default_for_non_nullable_value_types_on_querystring() + { + var url = new RequestWithValueTypes { Id = 1, Gender1 = Gender.Male }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1?gender1=Male")); + } + + [Test] + public void Can_use_default_for_nullable_value_types_on_querystring() + { + var url = new RequestWithValueTypes { Id = 1, Gender2 = Gender.None }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1?gender2=None")); + } + + [Test] + public void Cannot_use_null_for_nullable_value_types_on_querystring() + { + var url = new RequestWithValueTypes { Id = 1, Gender2 = null }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1")); + } + + [Test] + public void Can_use_non_default_for_nullable_value_types_on_querystring() + { + var url = new RequestWithValueTypes { Id = 1, Gender2 = Gender.Male }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/1?gender2=Male")); + } [Test] public void Can_combine_Uris_with_toUrl() @@ -183,12 +233,12 @@ public void Can_combine_Uris_with_toUrl() Assert.That(new Uri(serviceEndpoint, actionUrl).ToString(), Is.EqualTo("http://localhost/api/route/1")); } - [Test] - public void Can_use_default_for_non_nullable_value_types_on_path() - { - var url = new RequestWithValueTypes { Id = 0 }.ToUrl("GET"); - Assert.That(url, Is.EqualTo("/route/0")); - } + [Test] + public void Can_use_default_for_non_nullable_value_types_on_path() + { + var url = new RequestWithValueTypes { Id = 0 }.ToUrl("GET"); + Assert.That(url, Is.EqualTo("/route/0")); + } [Route("/images/{ImagePath*}")] public class WildCardPath : IReturn @@ -224,5 +274,24 @@ public void Show_what_uri_escaping_encodes() Assert.That(Uri.EscapeDataString(data), Is.EqualTo("amp%26mod%25space%20comma%2Cdot.colon%3Asemicolon%3Bslash%2F")); } + [Test] + public void Can_generate_OneWay_path() + { + var url = new JustId { Id = 1 }.ToOneWayUrl(); + Assert.That(url, Is.EqualTo("/json/oneway/JustId?id=1")); + + url = new JustId { Id = 1 }.ToOneWayUrl(format: "xml"); + Assert.That(url, Is.EqualTo("/xml/oneway/JustId?id=1")); + } + + [Test] + public void Can_generate_Reply_path() + { + var url = new JustId { Id = 1 }.ToReplyUrl(); + Assert.That(url, Is.EqualTo("/json/reply/JustId?id=1")); + + url = new JustId { Id = 1 }.ToReplyUrl(format: "xml"); + Assert.That(url, Is.EqualTo("/xml/reply/JustId?id=1")); + } } } \ No newline at end of file diff --git a/tests/ServiceStack.Common.Tests/ValidationTests.cs b/tests/ServiceStack.Common.Tests/ValidationTests.cs new file mode 100644 index 00000000000..e26fc3e0c61 --- /dev/null +++ b/tests/ServiceStack.Common.Tests/ValidationTests.cs @@ -0,0 +1,98 @@ +#if !NETCORE +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Messaging; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.Common.Tests +{ + internal class DtoARequestValidator : AbstractValidator + { + internal readonly IDtoBValidator dtoBValidator; + + public DtoARequestValidator(IDtoBValidator dtoBValidator) + { + this.dtoBValidator = dtoBValidator; + RuleFor(dto => dto.FieldA).NotEmpty(); + RuleForEach(dto => dto.Items).SetValidator(dtoBValidator); + } + } + + internal class DtoBValidator : AbstractValidator, IDtoBValidator + { + public DtoBValidator() + { + RuleFor(dto => dto.FieldB).NotEmpty(); + } + } + + public class DtoA : IReturn + { + public string FieldA { get; set; } + public List Items { get; set; } + } + + public class DtoAResponse + { + public string FieldA { get; set; } + public List Items { get; set; } + } + + public class DtoB + { + public string FieldB { get; set; } + } + + internal interface IDtoBValidator : IValidator {} + + public class DtoAService : Service + { + public object Any(DtoA request) + { + return request.ConvertTo(); + } + } + + [TestFixture] + public class ValidationTests + { + [Test] + public void Can_register_IDtoBValidator_separately() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => { + host.RegisterService(); + host.Plugins.Add(new ValidationFeature()); + }, + ConfigureContainer = c => { + c.RegisterAs(); + c.RegisterValidators(typeof(DtoARequestValidator).Assembly); + } + }.Init()) + { + var dtoAValidator = (DtoARequestValidator)appHost.TryResolve>(); + Assert.That(dtoAValidator, Is.Not.Null); + Assert.That(dtoAValidator.dtoBValidator, Is.Not.Null); + Assert.That(appHost.TryResolve>(), Is.Not.Null); + Assert.That(appHost.TryResolve(), Is.Not.Null); + + var result = dtoAValidator.Validate(new DtoA()); + Assert.That(result.IsValid, Is.False); + Assert.That(result.Errors.Count, Is.EqualTo(1)); + + result = dtoAValidator.Validate(new DtoA { FieldA = "foo", Items = new[] { new DtoB() }.ToList() }); + Assert.That(result.IsValid, Is.False); + Assert.That(result.Errors.Count, Is.EqualTo(1)); + + result = dtoAValidator.Validate(new DtoA { FieldA = "foo", Items = new[] { new DtoB { FieldB = "bar" } }.ToList() }); + Assert.That(result.IsValid, Is.True); + } + } + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/Xlinq/XlinqExtensionsTests.cs b/tests/ServiceStack.Common.Tests/Xlinq/XlinqExtensionsTests.cs index c0d36f0912a..737ac5c5b9c 100644 --- a/tests/ServiceStack.Common.Tests/Xlinq/XlinqExtensionsTests.cs +++ b/tests/ServiceStack.Common.Tests/Xlinq/XlinqExtensionsTests.cs @@ -1,74 +1,76 @@ +#if !NETCORE using System; using System.Xml.Linq; using NUnit.Framework; using ServiceStack.DataAnnotations; -using ServiceStack.DesignPatterns.Model; +using ServiceStack.Model; using ServiceStack.OrmLite; using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceModel; using ServiceStack.Text; namespace ServiceStack.Common.Tests.Xlinq { - [TestFixture] - public class XlinqExtensionsTests - { - string xml = "" - + "" - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + ""; + [TestFixture] + public class XlinqExtensionsTests + { + string xml = "" + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; - public class XmlData : IHasId - { - [AutoIncrement] - public int Id { get; set; } - public string Day { get; set; } - public string Name { get; set; } - public int Time { get; set; } - public int Amount { get; set; } - public decimal Price { get; set; } - } + public class XmlData : IHasId + { + [AutoIncrement] + public int Id { get; set; } + public string Day { get; set; } + public string Name { get; set; } + public int Time { get; set; } + public int Amount { get; set; } + public decimal Price { get; set; } + } - [Test] - public void Insert_data_from_xml_into_db() - { - //OrmLiteConfig.DialectProvider = SqlServerOrmLiteDialectProvider.Instance; - OrmLiteConfig.DialectProvider = SqliteOrmLiteDialectProvider.Instance; + [Test] + public void Insert_data_from_xml_into_db() + { + //OrmLiteConfig.DialectProvider = SqlServerOrmLiteDialectProvider.Instance; + OrmLiteConfig.DialectProvider = SqliteOrmLiteDialectProvider.Instance; - var element2 = XElement.Parse(xml).AnyElement("Body").AnyElement("Element1").AnyElement("Element2"); + var element2 = XElement.Parse(xml).AnyElement("Body").AnyElement("Element1").AnyElement("Element2"); - using (var db = ":memory:".OpenDbConnection()) - { - db.CreateTable(true); - foreach (var element3 in element2.AllElements("Element3")) - { - var xmlData = new XmlData { - Day = element2.AnyAttribute("day").Value, - Name = element3.AnyAttribute("name").Value, - Time = int.Parse(element3.FirstElement().AnyAttribute("time").Value), - Amount = int.Parse(element3.FirstElement().FirstElement().AnyAttribute("amount").Value), - Price = decimal.Parse(element3.FirstElement().FirstElement().AnyAttribute("price").Value), - }; - db.Insert(xmlData); - } - db.Select().ForEach(x => Console.WriteLine(TypeSerializer.SerializeToString(x))); - } - } + using (var db = ":memory:".OpenDbConnection()) + { + db.CreateTable(true); + foreach (var element3 in element2.AllElements("Element3")) + { + var xmlData = new XmlData + { + Day = element2.AnyAttribute("day").Value, + Name = element3.AnyAttribute("name").Value, + Time = int.Parse(element3.FirstElement().AnyAttribute("time").Value), + Amount = int.Parse(element3.FirstElement().FirstElement().AnyAttribute("amount").Value), + Price = decimal.Parse(element3.FirstElement().FirstElement().AnyAttribute("price").Value), + }; + db.Insert(xmlData); + } + db.Select().ForEach(x => Console.WriteLine(TypeSerializer.SerializeToString(x))); + } + } - } -} \ No newline at end of file + } +} +#endif diff --git a/tests/ServiceStack.Common.Tests/app.config b/tests/ServiceStack.Common.Tests/app.config deleted file mode 100644 index e8b1a7a7002..00000000000 --- a/tests/ServiceStack.Common.Tests/app.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/tests/ServiceStack.Common.Tests/ci.app.config b/tests/ServiceStack.Common.Tests/ci.app.config deleted file mode 100644 index 26173945e37..00000000000 --- a/tests/ServiceStack.Common.Tests/ci.app.config +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/ServiceStack.Extensions.Tests/AutoQueryCrudModels.cs b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudModels.cs new file mode 100644 index 00000000000..000b1e90b3b --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudModels.cs @@ -0,0 +1,761 @@ +#if AUTOQUERY_CRUD +using System; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using ServiceStack.DataAnnotations; + +namespace ServiceStack.Extensions.Tests +{ + [DataContract] + public abstract class RockstarBase + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + [DataMember(Order = 5)] + public DateTime? DateDied { get; set; } + [DataMember(Order = 6)] + public LivingStatus LivingStatus { get; set; } + } + + [Alias(nameof(Rockstar))] + [DataContract] + public class RockstarAuto : RockstarBase + { + [AutoIncrement] + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class RockstarAutoGuid : RockstarBase + { + [AutoId] + [DataMember(Order = 1)] + public Guid Id { get; set; } + } + + [DataContract] + public class RockstarAudit : RockstarBase + { + [AutoIncrement] + [DataMember(Order = 1)] + public int Id { get; set; } + + [DataMember(Order = 2)] + public DateTime CreatedDate { get; set; } + [DataMember(Order = 3)] + public string CreatedBy { get; set; } + [DataMember(Order = 4)] + public string CreatedInfo { get; set; } + [DataMember(Order = 5)] + public DateTime ModifiedDate { get; set; } + [DataMember(Order = 6)] + public string ModifiedBy { get; set; } + [DataMember(Order = 7)] + public string ModifiedInfo { get; set; } + } + + public interface IAudit + { + DateTime CreatedDate { get; set; } + string CreatedBy { get; set; } + string CreatedInfo { get; set; } + DateTime ModifiedDate { get; set; } + string ModifiedBy { get; set; } + string ModifiedInfo { get; set; } + DateTime? SoftDeletedDate { get; set; } + string SoftDeletedBy { get; set; } + string SoftDeletedInfo { get; set; } + } + + public interface IAuditTenant : IAudit + { + int TenantId { get; set; } + } + + [DataContract] + public abstract class AuditBase : IAudit + { + [DataMember(Order = 1)] + public DateTime CreatedDate { get; set; } + + [Required] + [DataMember(Order = 2)] + public string CreatedBy { get; set; } + + [Required] + [DataMember(Order = 3)] + public string CreatedInfo { get; set; } + + [DataMember(Order = 4)] + public DateTime ModifiedDate { get; set; } + + [Required] + [DataMember(Order = 5)] + public string ModifiedBy { get; set; } + + [Required] + [DataMember(Order = 6)] + public string ModifiedInfo { get; set; } + + [Index] //Check if Deleted + [DataMember(Order = 7)] + public DateTime? SoftDeletedDate { get; set; } + + [DataMember(Order = 8)] + public string SoftDeletedBy { get; set; } + [DataMember(Order = 9)] + public string SoftDeletedInfo { get; set; } + } + + [DataContract] + public class RockstarAuditTenant : AuditBase + { + [Index] + [DataMember(Order = 1)] + public int TenantId { get; set; } + + [AutoIncrement] + [DataMember(Order = 2)] + public int Id { get; set; } + + [DataMember(Order = 3)] + public string FirstName { get; set; } + [DataMember(Order = 4)] + public string LastName { get; set; } + [DataMember(Order = 5)] + public int? Age { get; set; } + [DataMember(Order = 6)] + public DateTime DateOfBirth { get; set; } + [DataMember(Order = 7)] + public DateTime? DateDied { get; set; } + [DataMember(Order = 8)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class RockstarVersion : RockstarBase + { + [AutoIncrement] + [DataMember(Order = 1)] + public int Id { get; set; } + + [DataMember(Order = 2)] + public ulong RowVersion { get; set; } + } + + [DataContract] + public class CreateRockstar : RockstarBase, ICreateDb, IReturn { } + + [DataContract] + public class CreateRockstarResponse + { + [DataMember(Order = 1)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class CreateRockstarWithReturn : RockstarBase, ICreateDb, + IReturn { } + + [DataContract] + public class CreateRockstarWithVoidReturn : RockstarBase, ICreateDb, IReturnVoid { } + + [DataContract] + public class CreateRockstarWithAutoGuid : RockstarBase, ICreateDb, + IReturn { } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(RockstarAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public class CreateRockstarAudit : RockstarBase, ICreateDb, IReturn { } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public abstract class CreateAuditBase : ICreateDb, IReturn { } + + [AutoPopulate(nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public abstract class CreateAuditTenantBase : CreateAuditBase { } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public abstract class UpdateAuditBase : IUpdateDb
, IReturn { } + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public abstract class UpdateAuditTenantBase : UpdateAuditBase { } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public abstract class PatchAuditBase : IPatchDb
, IReturn { } + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public abstract class PatchAuditTenantBase : PatchAuditBase { } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.SoftDeletedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.SoftDeletedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.SoftDeletedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public abstract class SoftDeleteAuditBase : IUpdateDb
, IReturn { } + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public abstract class SoftDeleteAuditTenantBase : SoftDeleteAuditBase { } + + [ValidateRequest("IsAuthenticated")] + [AutoFilter(QueryTerm.Ensure, nameof(IAudit.SoftDeletedDate), Template = SqlTemplate.IsNull)] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public abstract class QueryDbTenant : QueryDb { } + + [DataContract] + public class CreateRockstarAuditTenant : CreateAuditTenantBase, IHasBearerToken + { + [DataMember(Order = 1)] + public string BearerToken { get; set; } //Authenticate MQ Requests + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public string LastName { get; set; } + [DataMember(Order = 4)] + public int? Age { get; set; } + [DataMember(Order = 5)] + public DateTime DateOfBirth { get; set; } + [DataMember(Order = 6)] + public DateTime? DateDied { get; set; } + [DataMember(Order = 7)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class UpdateRockstarAuditTenant : UpdateAuditTenantBase, IHasBearerToken + { + [DataMember(Order = 1)] + public string BearerToken { get; set; } //Authenticate MQ Requests + [DataMember(Order = 2)] + public int Id { get; set; } + [DataMember(Order = 3)] + public string FirstName { get; set; } + [DataMember(Order = 4)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class PatchRockstarAuditTenant : PatchAuditTenantBase, IHasBearerToken + { + [DataMember(Order = 1)] + public string BearerToken { get; set; } //Authenticate MQ Requests + [DataMember(Order = 2)] + public int Id { get; set; } + [DataMember(Order = 3)] + public string FirstName { get; set; } + [DataMember(Order = 4)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class CreateRockstarAuditTenantGateway : IReturn, IPost + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + [DataMember(Order = 5)] + public DateTime? DateDied { get; set; } + [DataMember(Order = 6)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class UpdateRockstarAuditTenantGateway : IReturn, IPut + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class PatchRockstarAuditTenantGateway : IReturn, IPatch + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class RealDeleteAuditTenantGateway : IReturn, IDelete + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class SoftDeleteAuditTenant : SoftDeleteAuditTenantBase + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [Authenticate] + [DataContract] + public class CreateRockstarAuditTenantMq : IReturnVoid + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + [DataMember(Order = 5)] + public DateTime? DateDied { get; set; } + [DataMember(Order = 6)] + public LivingStatus LivingStatus { get; set; } + } + + [Authenticate] + [DataContract] + public class UpdateRockstarAuditTenantMq : IPut, IReturnVoid + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class PatchRockstarAuditTenantMq : IPatch, IReturnVoid + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class RealDeleteAuditTenantMq : IDelete, IReturnVoid + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public class CreateRockstarAuditMqToken : RockstarBase, ICreateDb, IReturn, IHasBearerToken + { + [DataMember(Order = 1)] + public string BearerToken { get; set; } + } + + + [Authenticate] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public class RealDeleteAuditTenant : IDeleteDb, IReturn, IHasBearerToken + { + [DataMember(Order = 1)] + public string BearerToken { get; set; } //Authenticate MQ Requests + [DataMember(Order = 2)] + public int Id { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryRockstarAudit : QueryDbTenant + { + [DataMember(Order = 1)] + public int? Id { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [AutoFilter(QueryTerm.Ensure, nameof(AuditBase.SoftDeletedDate), SqlTemplate.IsNull)] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + [DataContract] + public class QueryRockstarAuditSubOr : QueryDb + { + [DataMember(Order = 1)] + public string FirstNameStartsWith { get; set; } + [DataMember(Order = 2)] + public int? AgeOlderThan { get; set; } + } + + [DataContract] + public class CreateRockstarVersion : RockstarBase, ICreateDb, + IReturn { } + + [DataContract] + public class RockstarWithIdResponse + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class RockstarWithIdAndCountResponse + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public int Count { get; set; } + [DataMember(Order = 3)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class RockstarWithIdAndRowVersionResponse + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public uint RowVersion { get; set; } + [DataMember(Order = 3)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class RockstarWithIdAndResultResponse + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public RockstarAuto Result { get; set; } + [DataMember(Order = 3)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class CreateRockstarWithReturnGuidResponse + { + [DataMember(Order = 1)] + public Guid Id { get; set; } + [DataMember(Order = 2)] + public RockstarAutoGuid Result { get; set; } + [DataMember(Order = 3)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class CreateRockstarAdhocNonDefaults : ICreateDb, IReturn + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + + [AutoDefault(Value = 21)] + [DataMember(Order = 3)] + public int? Age { get; set; } + + [AutoDefault(Expression = "date(2001,1,1)")] + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + + [AutoDefault(Eval = "utcNow")] + [DataMember(Order = 5)] + public DateTime? DateDied { get; set; } + + [AutoDefault(Value = global::ServiceStack.Extensions.Tests.LivingStatus.Dead)] + [DataMember(Order = 6)] + public LivingStatus? LivingStatus { get; set; } + } + + [DataContract] + public class CreateRockstarAutoMap : ICreateDb, IReturn + { + [AutoMap(nameof(RockstarAuto.FirstName))] + [DataMember(Order = 1)] + public string MapFirstName { get; set; } + + [AutoMap(nameof(RockstarAuto.LastName))] + [DataMember(Order = 2)] + public string MapLastName { get; set; } + + [AutoMap(nameof(RockstarAuto.Age))] + [AutoDefault(Value = 21)] + [DataMember(Order = 3)] + public int? MapAge { get; set; } + + [AutoMap(nameof(RockstarAuto.DateOfBirth))] + [AutoDefault(Expression = "date(2001,1,1)")] + [DataMember(Order = 4)] + public DateTime MapDateOfBirth { get; set; } + + [AutoMap(nameof(RockstarAuto.DateDied))] + [AutoDefault(Eval = "utcNow")] + [DataMember(Order = 5)] + public DateTime? MapDateDied { get; set; } + + [AutoMap(nameof(RockstarAuto.LivingStatus))] + [AutoDefault(Value = LivingStatus.Dead)] + [DataMember(Order = 6)] + public LivingStatus? MapLivingStatus { get; set; } + } + + [DataContract] + public class UpdateRockstar : RockstarBase, IUpdateDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [DataContract] + public class UpdateRockstarAudit : RockstarBase, IPatchDb, IReturn + { + [DataMember(Order = 1)] + // [DataMember(Order = 11)] + public int Id { get; set; } + + // [DataMember(Order = 2)] + // [DataMember(Order = 12)] + // public new string FirstName { get; set; } + + //1. Commenting out property resolves issue + //2. When using 1,2 index throws Grpc.Core.RpcException: Status(StatusCode=Unknown, Detail="Exception was thrown by handler.") + //3. When Index changed to 11,12 causes empty DTO to be sent + // [DataMember(Order = 13)] + // public new LivingStatus? LivingStatus { get; set; } //overridden property + } + + [Authenticate] + [DataContract] + public class DeleteRockstarAudit : IDeleteDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class UpdateRockstarVersion : RockstarBase, IPatchDb, + IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public ulong RowVersion { get; set; } + } + + [DataContract] + public class PatchRockstar : RockstarBase, IPatchDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class UpdateRockstarAdhocNonDefaults : IUpdateDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + + [AutoUpdate(AutoUpdateStyle.NonDefaults)] + [DataMember(Order = 2)] + public string FirstName { get; set; } + + [DataMember(Order = 3)] + public string LastName { get; set; } + + [AutoDefault(Value = 21)] + [DataMember(Order = 4)] + public int? Age { get; set; } + + [AutoDefault(Expression = "date(2001,1,1)")] + [DataMember(Order = 5)] + public DateTime DateOfBirth { get; set; } + + [AutoDefault(Eval = "utcNow")] + [DataMember(Order = 6)] + public DateTime? DateDied { get; set; } + + [AutoUpdate(AutoUpdateStyle.NonDefaults), AutoDefault(Value = LivingStatus.Dead)] + [DataMember(Order = 7)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class DeleteRockstar : IDeleteDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class DeleteRockstarFilters : IDeleteDb, IReturn + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + } + + [DataContract] + public class DeleteRockstarCountResponse + { + [DataMember(Order = 1)] + public int Count { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class CreateNamedRockstar : RockstarBase, ICreateDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class UpdateNamedRockstar : RockstarBase, IUpdateDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + //[ConnectionInfo] on AutoCrudConnectionInfoServices + [DataContract] + public class CreateConnectionInfoRockstar : RockstarBase, ICreateDb, + IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + [DataContract] + public class UpdateConnectionInfoRockstar : RockstarBase, IUpdateDb, + IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + } + + + [DataContract] + public class Booking : ServiceStack.AuditBase + { + [AutoIncrement] + [DataMember(Order = 1)] public int Id { get; set; } + [DataMember(Order = 2)] public RoomType RoomType { get; set; } + [DataMember(Order = 3)] public int RoomNumber { get; set; } + [DataMember(Order = 4)] public DateTime BookingStartDate { get; set; } + [DataMember(Order = 5)] public DateTime? BookingEndDate { get; set; } + [DataMember(Order = 6)] public string Notes { get; set; } + [DataMember(Order = 7)] public bool? Cancelled { get; set; } + [DataMember(Order = 8)] public decimal Cost { get; set; } + } + + public enum RoomType + { + Single, + Double, + Queen, + Twin, + Suite, + } + + [DataContract] + [AutoApply(Behavior.AuditQuery)] + public class QueryBookings : QueryDb + { + [DataMember(Order = 1)] public int[] Ids { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditCreate)] + public class CreateBooking + : ICreateDb, IReturn + { + [ApiAllowableValues(typeof(RoomType))] + [DataMember(Order = 1)] public RoomType RoomType { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 2)] public int RoomNumber { get; set; } + [DataMember(Order = 3)] public DateTime BookingStartDate { get; set; } + [DataMember(Order = 4)] public DateTime? BookingEndDate { get; set; } + [DataMember(Order = 5)] public string Notes { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 6)] public decimal Cost { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditModify)] + public class UpdateBooking + : IPatchDb, IReturn + { + [DataMember(Order = 1)] public int Id { get; set; } + [ApiAllowableValues(typeof(RoomType))] + [DataMember(Order = 2)] public RoomType? RoomType { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 3)] public int? RoomNumber { get; set; } + [DataMember(Order = 4)] public DateTime? BookingStartDate { get; set; } + [DataMember(Order = 5)] public DateTime? BookingEndDate { get; set; } + [DataMember(Order = 6)] public string Notes { get; set; } + [DataMember(Order = 7)] public bool? Cancelled { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 8)] public decimal? Cost { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditSoftDelete)] + public class DeleteBooking : IDeleteDb, IReturnVoid + { + [DataMember(Order = 1)] public int Id { get; set; } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.Validate.cs b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.Validate.cs new file mode 100644 index 00000000000..94d639708d6 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.Validate.cs @@ -0,0 +1,716 @@ +#if AUTOQUERY_CRUD +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.Model; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.Extensions.Tests +{ + public class NoRockstarAlbumReferences : TypeValidator + { + public NoRockstarAlbumReferences() + : base("HasForeignKeyReferences", "Has RockstarAlbum References") {} + + public override async Task IsValidAsync(object dto, IRequest request) + { + //Example of using compiled accessor delegates to access `Id` property + //var id = TypeProperties.Get(dto.GetType()).GetPublicGetter("Id")(dto).ConvertTo(); + + var id = ((IHasId)dto).Id; + using var db = HostContext.AppHost.GetDbConnection(request); + return !await db.ExistsAsync(x => x.RockstarId == id); + } + } + + public class MyValidators : ScriptMethods + { + public ITypeValidator NoRockstarAlbumReferences() => new NoRockstarAlbumReferences(); + } + + public partial class AutoQueryCrudTests + { + private bool UseDbSource = true; + + partial void OnConfigure(AutoQueryAppHost host, Container container) + { + host.ScriptContext.ScriptMethods.AddRange(new ScriptMethods[] { + new DbScriptsAsync(), + new MyValidators(), + }); + + host.ConfigurePlugin(feature => + { + feature.ConditionErrorCodes[ValidationConditions.IsOdd] = "NotOdd"; + feature.ErrorCodeMessages["NotOdd"] = "{PropertyName} must be odd"; + feature.ErrorCodeMessages["RuleMessage"] = "ErrorCodeMessages for RuleMessage"; + }); + + if (UseDbSource) + { + container.Register(c => + new OrmLiteValidationSource(c.Resolve(), host.GetMemoryCacheClient())); + } + else + { + container.Register(new MemoryValidationSource()); + } + + var validationSource = container.Resolve(); + validationSource.InitSchema(); + validationSource.SaveValidationRulesAsync(new List { + new() { Type = nameof(DynamicValidationRules), Validator = "IsAuthenticated" }, + new() { Type = nameof(DynamicValidationRules), Field = nameof(DynamicValidationRules.LastName), Validator = "NotNull" }, + new() { Type = nameof(DynamicValidationRules), Field = nameof(DynamicValidationRules.Age), Validator = "InclusiveBetween(13,100)" }, + }); + } + + private static void AssertErrorResponse(WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'First Name' must not be empty.")); + var status = ex.ResponseStatus; + Assert.That(status.Errors.Count, Is.EqualTo(3)); + + var fieldError = status.Errors.First(x => x.FieldName == nameof(RockstarBase.FirstName)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(fieldError.Message, Is.EqualTo("'First Name' must not be empty.")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(RockstarBase.Age)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(fieldError.Message, Is.EqualTo("'Age' must not be empty.")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(RockstarBase.LastName)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(fieldError.Message, Is.EqualTo("'Last Name' must not be empty.")); + } + + [Test] + public void Does_validate_when_no_Abstract_validator() + { + try + { + var response = client.Post(new NoAbstractValidator { + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + AssertErrorResponse(ex); + Console.WriteLine(ex); + } + + try + { + var response = client.Post(new NoAbstractValidator { + FirstName = "A", + LastName = "B", + Age = 12, + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'Age' must be between 13 and 100. You entered 12.")); + var status = ex.ResponseStatus; + Assert.That(status.Errors.Count, Is.EqualTo(1)); + } + + client.Post(new NoAbstractValidator { + FirstName = "A", + LastName = "B", + Age = 13, + DateOfBirth = new DateTime(2001,1,1), + }); + } + + [Test] + public void Does_validate_DynamicValidationRules_combined_with_IValidationSource_rules() + { + try + { + var anonClient = CreateClient(); + var response = anonClient.Post(new DynamicValidationRules { + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int) HttpStatusCode.Unauthorized)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + + var authClient = CreateAuthClient(); + try + { + var response = authClient.Post(new DynamicValidationRules { + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + AssertErrorResponse(ex); + Console.WriteLine(ex); + } + + try + { + var response = authClient.Post(new DynamicValidationRules { + FirstName = "A", + LastName = "B", + Age = 12, + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'Age' must be between 13 and 100. You entered 12.")); + var status = ex.ResponseStatus; + Assert.That(status.Errors.Count, Is.EqualTo(1)); + } + + authClient.Post(new DynamicValidationRules { + FirstName = "A", + LastName = "B", + Age = 13, + DateOfBirth = new DateTime(2001,1,1), + }); + } + + [Test] + public void Does_validate_combined_declarative_and_AbstractValidator() + { + try + { + var response = client.Post(new ValidateCreateRockstar()); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + AssertErrorResponse(ex); + Console.WriteLine(ex); + } + } + + [Test] + public void Does_validate_all_NotEmpty_Fields() + { + try + { + var response = client.Post(new EmptyValidators()); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Errors.Count, + Is.EqualTo(typeof(EmptyValidators).GetPublicProperties().Length)); + Assert.That(ex.ResponseStatus.Errors.All(x => x.ErrorCode == "NotEmpty")); + Console.WriteLine(ex); + } + } + + [Test] + public void Does_Validate_TriggerAllValidators() + { + try + { + var response = client.Post(new TriggerAllValidators { + CreditCard = "NotCreditCard", + Email = "NotEmail", + Empty = "NotEmpty", + Equal = "NotEqual", + ExclusiveBetween = 1, + GreaterThan = 1, + GreaterThanOrEqual = 1, + InclusiveBetween = 1, + Length = "Length", + LessThan = 20, + LessThanOrEqual = 20, + NotEmpty = "", + NotEqual = "NotEqual", + Null = "NotNull", + RegularExpression = "FOO", + ScalePrecision = 123.456m + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.AssertTriggerValidators(); + Console.WriteLine(ex); + } + } + + [Test] + public void Does_use_CustomErrorMessages() + { + try + { + var response = client.Post(new CustomValidationErrors()); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Console.WriteLine(ex); + var status = ex.ResponseStatus; + Assert.That(ex.ErrorCode, Is.EqualTo("ZERROR")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'Custom Error Code' must not be empty.")); + Assert.That(status.Errors.Count, Is.EqualTo(typeof(CustomValidationErrors).GetProperties().Length)); + + var fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.CustomErrorCode)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("ZERROR")); + Assert.That(fieldError.Message, Is.EqualTo("'Custom Error Code' must not be empty.")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.CustomErrorCodeAndMessage)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("ZERROR")); + Assert.That(fieldError.Message, Is.EqualTo("Custom Error Code And Message has to be between 1 and 2, you: 0")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.ErrorCodeRule)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("RuleMessage")); + Assert.That(fieldError.Message, Is.EqualTo("ErrorCodeMessages for RuleMessage")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.IsOddCondition)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotOdd")); + Assert.That(fieldError.Message, Is.EqualTo("Is Odd Condition must be odd")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.IsOddAndOverTwoDigitsCondition)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("RuleMessage")); + Assert.That(fieldError.Message, Is.EqualTo("ErrorCodeMessages for RuleMessage")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.IsOddOrOverTwoDigitsCondition)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("ScriptCondition")); + Assert.That(fieldError.Message, Is.EqualTo("The specified condition was not met for 'Is Odd Or Over Two Digits Condition'.")); + } + } + + [Test] + public void Can_satisfy_combined_conditions() + { + try + { + var response = client.Post(new CustomValidationErrors { + IsOddAndOverTwoDigitsCondition = 101 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Errors.Count, Is.EqualTo(typeof(CustomValidationErrors).GetProperties().Length - 1)); + Assert.That(ex.ResponseStatus.Errors.All(x => x.FieldName != nameof(CustomValidationErrors.IsOddAndOverTwoDigitsCondition))); + } + try + { + var response = client.Post(new CustomValidationErrors { + IsOddOrOverTwoDigitsCondition = 102 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Errors.Count, Is.EqualTo(typeof(CustomValidationErrors).GetProperties().Length - 1)); + Assert.That(ex.ResponseStatus.Errors.All(x => x.FieldName != nameof(CustomValidationErrors.IsOddOrOverTwoDigitsCondition))); + } + } + + [Test] + public void Does_OnlyValidatesRequest() + { + try + { + var response = client.Post(new OnlyValidatesRequest { + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.ErrorCode, Is.EqualTo("RuleMessage")); + Assert.That(ex.ErrorMessage, Is.EqualTo("ErrorCodeMessages for RuleMessage")); + Assert.That(ex.GetFieldErrors().Count, Is.EqualTo(0)); + } + + try + { + var response = client.Post(new OnlyValidatesRequest { + Test = 101 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(401)); + Assert.That(ex.ErrorCode, Is.EqualTo("AssertFailed2")); + Assert.That(ex.ErrorMessage, Is.EqualTo("2nd Assert Failed")); + Assert.That(ex.GetFieldErrors().Count, Is.EqualTo(0)); + } + + try + { + var response = client.Post(new OnlyValidatesRequest { + Test = 1001 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(ex.GetFieldErrors().Count, Is.EqualTo(1)); + } + } + + [Test] + public void Can_use_custom_Guid_Id_and_DateTimeOffset() + { + try + { + client.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var response = client.Post(new CreateBookmark { + Description = "Description", + Slug = "Slug", + Title = "Title", + Url = "Url", + }); + + Assert.That(response.Id, Is.Not.EqualTo(new Guid())); + Assert.That(response.Result.Id, Is.EqualTo(response.Id)); + Assert.That(response.Result.Description, Is.EqualTo("Description")); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + [Test] + public void Does_validate_TestAuthValidators() + { + try + { + var anonClient = CreateClient(); + anonClient.Post(new TestAuthValidators()); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(401)); + Assert.That(e.ErrorCode, Is.EqualTo("Unauthorized")); + Assert.That(e.ErrorMessage, Is.EqualTo("Not Authenticated")); + } + + try + { + var employeeClient = CreateClient(); + + employeeClient.Post(new Authenticate { + provider = "credentials", + UserName = "employee@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + employeeClient.Post(new TestAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(403)); + Assert.That(e.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(e.ErrorMessage, Is.EqualTo("Manager Role Required")); + } + + try + { + var managerClient = CreateClient(); + + managerClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + managerClient.Post(new TestAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + + try + { + var adminClient = CreateClient(); + + adminClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + adminClient.Post(new TestAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + } + + + [Test] + public void Does_validate_TestMultiAuthValidators() + { + try + { + var anonClient = CreateClient(); + anonClient.Post(new TestMultiAuthValidators()); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(401)); + Assert.That(e.ErrorCode, Is.EqualTo("Unauthorized")); + Assert.That(e.ErrorMessage, Is.EqualTo("Not Authenticated")); + } + + try + { + var employeeClient = CreateClient(); + + employeeClient.Post(new Authenticate { + provider = "credentials", + UserName = "employee@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + employeeClient.Post(new TestMultiAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(403)); + Assert.That(e.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(e.ErrorMessage, Is.EqualTo("Manager Role Required")); + } + + try + { + var managerClient = CreateClient(); + + managerClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + managerClient.Post(new TestMultiAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + + try + { + var adminClient = CreateClient(); + + adminClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + adminClient.Post(new TestMultiAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + } + + [Test] + public void Does_validate_TestIsAdmin() + { + var userNames = new[] { "employee@email.com", "manager" }; + foreach (var userName in userNames) + { + var userClient = CreateClient(); + if (userName != null) + { + try + { + var managerClient = CreateClient(); + + managerClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + managerClient.Post(new TestIsAdmin()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(403)); + Assert.That(e.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(e.ErrorMessage, Is.EqualTo("Admin Role Required")); + } + } + } + + try + { + var adminClient = CreateClient(); + + adminClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + adminClient.Post(new TestIsAdmin()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + } + + [Test] + public void Does_validate_TestDbCondition() + { + using var db = appHost.Resolve().OpenDbConnection(); + db.DropAndCreateTable(); + + try + { + db.Insert(new RockstarAlbum { Id = 1, Name = "An Album", Genre = "Pop", RockstarId = 1 }); + var response = client.Post(new TestDbCondition { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("HasForeignKeyReferences")); + } + + try + { + db.Delete(x => x.RockstarId == 1); + var response = client.Post(new TestDbCondition { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); //success! + } + } + + [Test] + public void Does_validate_TestDbValidator() + { + using var db = appHost.Resolve().OpenDbConnection(); + db.DropAndCreateTable(); + + try + { + db.Insert(new RockstarAlbum { Id = 1, Name = "An Album", Genre = "Pop", RockstarId = 1 }); + var response = client.Post(new TestDbValidator { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("HasForeignKeyReferences")); + } + + try + { + db.Delete(x => x.RockstarId == 1); + var response = client.Post(new TestDbValidator { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); //success! + } + } + } + + public static class ValidationUtils + { + public static void AssertTriggerValidators(this WebServiceException ex) + { + var errors = ex.ResponseStatus.Errors; + Assert.That(errors.First(x => x.FieldName == "CreditCard").ErrorCode, Is.EqualTo("CreditCard")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Empty").ErrorCode, Is.EqualTo("Empty")); + Assert.That(errors.First(x => x.FieldName == "Equal").ErrorCode, Is.EqualTo("Equal")); + Assert.That(errors.First(x => x.FieldName == "ExclusiveBetween").ErrorCode, Is.EqualTo("ExclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "GreaterThan").ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(errors.First(x => x.FieldName == "GreaterThanOrEqual").ErrorCode, Is.EqualTo("GreaterThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "InclusiveBetween").ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "Length").ErrorCode, Is.EqualTo("Length")); + Assert.That(errors.First(x => x.FieldName == "LessThan").ErrorCode, Is.EqualTo("LessThan")); + Assert.That(errors.First(x => x.FieldName == "LessThanOrEqual").ErrorCode, Is.EqualTo("LessThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "NotEmpty").ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors.First(x => x.FieldName == "NotEqual").ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errors.First(x => x.FieldName == "Null").ErrorCode, Is.EqualTo("Null")); + Assert.That(errors.First(x => x.FieldName == "RegularExpression").ErrorCode, Is.EqualTo("RegularExpression")); + Assert.That(errors.First(x => x.FieldName == "ScalePrecision").ErrorCode, Is.EqualTo("ScalePrecision")); + } + } + +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.ValidateModels.cs b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.ValidateModels.cs new file mode 100644 index 00000000000..a46457cb39b --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.ValidateModels.cs @@ -0,0 +1,360 @@ +#if AUTOQUERY_CRUD +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack.FluentValidation; +using ServiceStack.Model; + +namespace ServiceStack.Extensions.Tests +{ + public static class ValidationConditions + { + public const string IsOdd = "it.isOdd()"; + public const string IsOver2Digits = "it.log10() > 2"; + } + + [DataContract] + public class ValidateCreateRockstar + : ICreateDb, IReturn + { + [Validate(nameof(ValidateScripts.NotNull))] + // [Validate("NotNull")] + [DataMember(Order = 1)] + public string FirstName { get; set; } + + //Added by Fluent Validator + [DataMember(Order = 2)] + public string LastName { get; set; } + + // [Validate("[" + nameof(ValidateScripts.NotNull) + "," + nameof(ValidateScripts.Length) + "(13,100)]")] e.g. Typed + // [Validate("[NotNull,Length(13,100)]")] + [ValidateNotNull] + [ValidateInclusiveBetween(13,100)] + [DataMember(Order = 3)] + public int? Age { get; set; } + + [Validate("NotEmpty(default('DateTime'))")] + //[Validate("NotEmpty")] equivalent to above thanks to: Validators.AppendDefaultValueOnEmptyValidators + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + + [DataMember(Order = 5)] + public DateTime? DateDied { get; set; } + + [DataMember(Order = 6)] + public LivingStatus LivingStatus { get; set; } + } + + public class ValidateCreateRockstarValidator : AbstractValidator + { + public ValidateCreateRockstarValidator() + { + RuleFor(x => x.LastName).NotNull(); + } + } + + [AutoPopulate(nameof(LivingStatus), Value = LivingStatus.Alive)] + [DataContract] + public class NoAbstractValidator + : ICreateDb, IReturn + { + [ValidateNotNull] + [DataMember(Order = 1)] + public string FirstName { get; set; } + + [ValidateNotNull] + [DataMember(Order = 2)] + public string LastName { get; set; } + + [ValidateNotNull,ValidateInclusiveBetween(13,100)] + [DataMember(Order = 3)] + public int? Age { get; set; } + + [ValidateNotEmpty] + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + + [DataMember(Order = 5)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class EmptyValidators + : ICreateDb, IReturn + { + // [Validate("NotEmpty(0)")] + [ValidateNotEmpty] + [DataMember(Order = 1)] + public int Int { get; set; } + [ValidateNotEmpty] + [DataMember(Order = 2)] + public int? NInt { get; set; } + [ValidateNotEmpty] + // [Validate("NotEmpty(default('System.TimeSpan'))")] + [DataMember(Order = 3)] + public TimeSpan TimeSpan { get; set; } + [ValidateNotEmpty] + [DataMember(Order = 4)] + public TimeSpan? NTimeSpan { get; set; } + [ValidateNotEmpty] + [DataMember(Order = 5)] + public string String { get; set; } + [ValidateNotEmpty] + [DataMember(Order = 6)] + public int[] IntArray { get; set; } + [ValidateNotEmpty] + [DataMember(Order = 7)] + public List StringList { get; set; } + } + + [DataContract] + public class TriggerAllValidators + : ICreateDb, IReturn + { + [ValidateCreditCard] + [DataMember(Order = 1)] + public string CreditCard { get; set; } + [ValidateEmail] + [DataMember(Order = 2)] + public string Email { get; set; } + [ValidateEmpty] + [DataMember(Order = 3)] + public string Empty { get; set; } + [ValidateEqual("Equal")] + [DataMember(Order = 4)] + public string Equal { get; set; } + [ValidateExclusiveBetween(10, 20)] + [DataMember(Order = 5)] + public int ExclusiveBetween { get; set; } + [ValidateGreaterThanOrEqual(10)] + [DataMember(Order = 6)] + public int GreaterThanOrEqual { get; set; } + [ValidateGreaterThan(10)] + [DataMember(Order = 7)] + public int GreaterThan { get; set; } + [ValidateInclusiveBetween(10, 20)] + [DataMember(Order = 8)] + public int InclusiveBetween { get; set; } + [ValidateExactLength(10)] + [DataMember(Order = 9)] + public string Length { get; set; } + [ValidateLessThanOrEqual(10)] + [DataMember(Order = 10)] + public int LessThanOrEqual { get; set; } + [ValidateLessThan(10)] + [DataMember(Order = 11)] + public int LessThan { get; set; } + [ValidateNotEmpty] + [DataMember(Order = 12)] + public string NotEmpty { get; set; } + [ValidateNotEqual("NotEqual")] + [DataMember(Order = 13)] + public string NotEqual { get; set; } + [ValidateNull] + [DataMember(Order = 14)] + public string Null { get; set; } + [ValidateRegularExpression("^[a-z]*$")] + [DataMember(Order = 15)] + public string RegularExpression { get; set; } + [ValidateScalePrecision(1,1)] + [DataMember(Order = 16)] + public decimal ScalePrecision { get; set; } + } + + [DataContract] + public class DynamicValidationRules + : ICreateDb, IReturn + { + [ValidateNotNull] + [DataMember(Order = 1)] + public string FirstName { get; set; } + + //[Validate("NotNull")] added in IValidationSource + [DataMember(Order = 2)] + public string LastName { get; set; } + + // [Validate("[NotNull,InclusiveBetween(13,100)]")] + [ValidateNotNull] + //[Validate("InclusiveBetween(13,100)")] added in IValidationSource + [DataMember(Order = 3)] + public int? Age { get; set; } + + [ValidateNotEmpty] + [DataMember(Order = 4)] + public DateTime DateOfBirth { get; set; } + + [DataMember(Order = 5)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class CustomValidationErrors + : ICreateDb, IReturn + { + // Just overrides ErrorCode + [ValidateNotNull(ErrorCode = "ZERROR")] + [DataMember(Order = 1)] + public string CustomErrorCode { get; set; } + + // Overrides both ErrorCode & Message + [ValidateInclusiveBetween(1,2, ErrorCode = "ZERROR", + Message = "{PropertyName} has to be between {From} and {To}, you: {PropertyValue}")] + [DataMember(Order = 2)] + public int CustomErrorCodeAndMessage { get; set; } + + // Overrides ErrorCode & uses Message from Validators + [ValidateNotNull(ErrorCode = "RuleMessage")] + [DataMember(Order = 3)] + public string ErrorCodeRule { get; set; } + + // Overrides ErrorCode & uses Message from Validators + [Validate(Condition = ValidationConditions.IsOdd)] + [DataMember(Order = 4)] + public int IsOddCondition { get; set; } + + // Combined typed conditions + Error code + [Validate(AllConditions = new[]{ ValidationConditions.IsOdd, ValidationConditions.IsOver2Digits }, ErrorCode = "RuleMessage")] + [DataMember(Order = 5)] + public int IsOddAndOverTwoDigitsCondition { get; set; } + + // Combined typed conditions + unknown error code + [Validate(AnyConditions = new[]{ ValidationConditions.IsOdd, ValidationConditions.IsOver2Digits })] + [DataMember(Order = 6)] + public int IsOddOrOverTwoDigitsCondition { get; set; } + } + + [ValidateRequest("HasRole('Manager')")] + [DataContract] + public class TestAuthValidators + : ICreateDb, IReturn + { + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + [DataMember(Order = 1)] + public string NotNull { get; set; } + } + + [ValidateIsAuthenticated, ValidateHasRole("Manager")] + [DataContract] + public class TestMultiAuthValidators + : ICreateDb, IReturn + { + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + [DataMember(Order = 1)] + public string NotNull { get; set; } + } + + [ValidateIsAdmin] + [DataContract] + public class TestIsAdmin + : ICreateDb, IReturn + { + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + [DataMember(Order = 1)] + public string NotNull { get; set; } + } + + [ValidateRequest(Condition = "!dbExistsSync('SELECT * FROM RockstarAlbum WHERE RockstarId = @Id', { dto.Id })", + ErrorCode = "HasForeignKeyReferences")] + [DataContract] + public class TestDbCondition + : ICreateDb, IReturn + { + [DataMember(Order = 1)] + public int Id { get; set; } + + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + [DataMember(Order = 2)] + public string NotNull { get; set; } + } + + [ValidateRequest("NoRockstarAlbumReferences")] + [DataContract] + public class TestDbValidator + : ICreateDb, IReturn, IHasId + { + [DataMember(Order = 1)] + public int Id { get; set; } + + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + [DataMember(Order = 2)] + public string NotNull { get; set; } + } + + [ValidateRequest(Conditions = new[]{ "it.Test.isOdd()", "it.Test.log10() > 2" }, ErrorCode = "RuleMessage")] + [ValidateRequest(Condition = "it.Test.log10() > 3", ErrorCode = "AssertFailed2", Message = "2nd Assert Failed", StatusCode = 401)] + [DataContract] + public class OnlyValidatesRequest + : ICreateDb, IReturn + { + // Combined typed conditions + Error code + [DataMember(Order = 1)] + public int Test { get; set; } + + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + [DataMember(Order = 2)] + public string NotNull { get; set; } + } + + + [DataContract] + public class DaoBase + { + [DataMember(Order = 1)] + public virtual Guid Id { get; set; } + [DataMember(Order = 2)] + public virtual DateTime CreateDate { get; set; } + [DataMember(Order = 3)] + public virtual string CreatedBy { get; set; } + [DataMember(Order = 4)] + public virtual DateTime ModifiedDate { get; set; } + [DataMember(Order = 5)] + public virtual string ModifiedBy { get; set; } + } + + [DataContract] + public class Bookmark : DaoBase + { + [DataMember(Order = 1)] + public string Slug { get; set; } + [DataMember(Order = 2)] + public string Title { get; set; } + [DataMember(Order = 3)] + public string Description { get; set; } + [DataMember(Order = 4)] + public string Url { get; set; } + } + + [DataContract] + public class QueryBookmarks : QueryDb { } + + // custom script methods + [AutoPopulate(nameof(Bookmark.Id), Eval = "nguid")] + [AutoPopulate(nameof(Bookmark.CreatedBy), Eval = "userAuthId")] + [AutoPopulate(nameof(Bookmark.CreateDate), Eval = "utcNow")] + [AutoPopulate(nameof(Bookmark.ModifiedBy), Eval = "userAuthId")] + [AutoPopulate(nameof(Bookmark.ModifiedDate), Eval = "utcNow")] + [DataContract] + public class CreateBookmark : ICreateDb, IReturn + { + [DataMember(Order = 1)] + public string Slug { get; set; } + [DataMember(Order = 2)] + public string Title { get; set; } + [DataMember(Order = 3)] + public string Description { get; set; } + [DataMember(Order = 4)] + public string Url { get; set; } + } + + [DataContract] + public class CreateBookmarkResponse + { + [DataMember(Order = 1)] + public Guid Id { get; set; } + [DataMember(Order = 2)] + public Bookmark Result { get; set; } + [DataMember(Order = 3)] + public ResponseStatus ResponseStatus { get; set; } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.cs b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.cs new file mode 100644 index 00000000000..8c69fe7857e --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/AutoQueryCrudTests.cs @@ -0,0 +1,1282 @@ +#if AUTOQUERY_CRUD +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.Messaging; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.Extensions.Tests +{ + public class AutoCrudGatewayServices : Service + { + public async Task Any(CreateRockstarAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public async Task Any(UpdateRockstarAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public async Task Any(PatchRockstarAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public async Task Any(RealDeleteAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public void Any(CreateRockstarAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + Request.PopulateRequestDtoIfAuthenticated(mqRequest); + PublishMessage(mqRequest); + } + + public void Any(UpdateRockstarAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + Request.PopulateRequestDtoIfAuthenticated(mqRequest); + PublishMessage(mqRequest); + } + + public void Any(PatchRockstarAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + Request.PopulateRequestDtoIfAuthenticated(mqRequest); + PublishMessage(mqRequest); + } + + public void Any(RealDeleteAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + Request.PopulateRequestDtoIfAuthenticated(mqRequest); + PublishMessage(mqRequest); + } + } + + [ConnectionInfo(NamedConnection = AutoQueryAppHost.SqlServerNamedConnection)] + public class AutoCrudConnectionInfoServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + public Task Any(CreateConnectionInfoRockstar request) => + AutoQuery.CreateAsync(request, Request); + + public Task Any(UpdateConnectionInfoRockstar request) => + AutoQuery.UpdateAsync(request, Request); + } + + public partial class AutoQueryCrudTests + { + private readonly ServiceStackHost appHost; + public GrpcServiceClient client; + + private static readonly int TotalRockstars = AutoQueryAppHost.SeedRockstars.Length; + private static readonly int TotalAlbums = AutoQueryAppHost.SeedAlbums.Length; + private const string TenantId = nameof(TenantId); + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + public static string JwtUserToken = null; + + partial void OnConfigure(AutoQueryAppHost host, Funq.Container container); + + public AutoQueryCrudTests() + { + appHost = new AutoQueryAppHost { + ConfigureFn = (host,container) => { + + container.AddSingleton(c => + new OrmLiteCrudEvents(c.Resolve()) { + NamedConnections = { AutoQueryAppHost.SqlServerNamedConnection } + }.Reset() //Drop and re-create AutoCrudEvent Table + ); + container.Resolve().InitSchema(); + + container.AddSingleton(c => + new InMemoryAuthRepository()); + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(host.AppSettings), + new JwtAuthProvider(host.AppSettings) { + RequireSecureConnection = false, + AuthKey = AuthKey, + CreatePayloadFilter = (obj, session) => { + obj[nameof(AuthUserSession.City)] = ((AuthUserSession)session).City; + } + }, + })); + + var jwtProvider = host.GetPlugin().AuthProviders.OfType().First(); + JwtUserToken = jwtProvider.CreateJwtBearerToken(new AuthUserSession { + Id = SessionExtensions.CreateRandomSessionId(), + UserName = "jwtuser", + FirstName = "JWT", + LastName = "User", + DisplayName = "JWT User", + City = "Japan", + }); + + var authRepo = container.Resolve(); + authRepo.InitSchema(); + + authRepo.CreateUserAuth(new UserAuth { + Id = 1, + Email = "admin@email.com", + DisplayName = "Admin User", + City = "London", + Roles = new List { + RoleNames.Admin + } + }, "p@55wOrd"); + + authRepo.CreateUserAuth(new UserAuth { + Id = 2, + UserName = "manager", + DisplayName = "The Manager", + City = "Perth", + Roles = new List { + "Employee", + "Manager", + } + }, "p@55wOrd"); + + authRepo.CreateUserAuth(new UserAuth { + Id = 3, + Email = "employee@email.com", + DisplayName = "An Employee", + City = "Manhattan", + Roles = new List { + "Employee", + } + }, "p@55wOrd"); + + void AddTenantId(IRequest req, IResponse res, object dto) + { + var userSession = req.SessionAs(); + if (userSession.IsAuthenticated) + { + req.SetItem(TenantId, userSession.City switch { + "London" => 10, + "Perth" => 10, + _ => 20, + }); + } + } + + host.GlobalRequestFilters.Add(AddTenantId); + host.GlobalMessageRequestFilters.Add(AddTenantId); + + container.AddSingleton(c => new BackgroundMqService()); + var mqService = container.Resolve(); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + host.AfterInitCallbacks.Add(_ => mqService.Start()); + + OnConfigure(host, container); + } + } + .Init() + .Start(TestsConfig.ListeningOn); + + using var db = appHost.TryResolve().OpenDbConnection(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + + AutoMapping.RegisterPopulator((Dictionary target, CreateRockstarWithAutoGuid source) => { + if (source.FirstName == "Created") + { + target[nameof(source.LivingStatus)] = LivingStatus.Dead; + } + }); + + client = CreateClient(); + } + + private static GrpcServiceClient CreateClient() => TestsConfig.GetInsecureClient(); + + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost.Dispose(); + + public List Rockstars => AutoQueryAppHost.SeedRockstars.ToList(); + + public List PagingTests => AutoQueryAppHost.SeedPagingTest.ToList(); + + private static GrpcServiceClient CreateAuthClient() + { + var authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + return authClient; + } + + [Test] + public void Can_CreateRockstar() + { + var request = new CreateRockstar { + FirstName = "Return", + LastName = "Empty", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.Single(x => x.LastName == "Empty"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Return")); + } + + [Test] + public void Can_CreateRockstarWithReturn() + { + var request = new CreateRockstarWithReturn { + FirstName = "Return", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,2,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + Assert.That(response.Id, Is.GreaterThan(0)); + var newRockstar = response.Result; + Assert.That(newRockstar.LastName, Is.EqualTo("Result")); + } + + [Test] + public void Can_CreateRockstarWithVoidReturn() + { + var request = new CreateRockstarWithVoidReturn { + FirstName = "Return", + LastName = "Void", + Age = 20, + DateOfBirth = new DateTime(2001,3,1), + LivingStatus = LivingStatus.Alive, + }; + + client.Post(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.Single(x => x.LastName == "Void"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Return")); + } + + [Test] + public void Can_CreateRockstarWithAutoGuid() + { + var request = new CreateRockstarWithAutoGuid { + FirstName = "Create", + LastName = "AutoId", + Age = 20, + DateOfBirth = new DateTime(2001,4,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + Assert.That(response.Id, Is.Not.Null); + var newRockstar = response.Result; + Assert.That(newRockstar.Id, Is.EqualTo(response.Id)); + Assert.That(newRockstar.LastName, Is.EqualTo("AutoId")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + } + + [Test] + public void Can_CreateRockstarWithAutoGuid_with_Custom_Mapping() + { + var request = new CreateRockstarWithAutoGuid { + FirstName = "Created", + LastName = "AutoId", + Age = 20, + DateOfBirth = new DateTime(2001,5,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + Assert.That(response.Id, Is.Not.Null); + var newRockstar = response.Result; + Assert.That(newRockstar.Id, Is.EqualTo(response.Id)); + Assert.That(newRockstar.LastName, Is.EqualTo("AutoId")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Dead)); //overridden by RegisterPopulator + } + + [Test] + public void Can_UpdateRockstar() + { + var createResponse = client.Post(new CreateRockstarWithReturn { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }); + + var request = new UpdateRockstar { + Id = createResponse.Id, + LastName = "UpdateResult", + }; + + var response = client.Put(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.FirstName, Is.Null); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateResult")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + } + + [Test] + public void Can_PatchRockstar() + { + var createRequest = new CreateRockstarWithReturn { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }; + var createResponse = client.Post(createRequest); + + var request = new PatchRockstar { + Id = createResponse.Id, + LastName = "UpdateResult", + }; + + var response = client.Patch(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateResult")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(newRockstar.Age, Is.EqualTo(createRequest.Age)); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + } + + [Test] + public void Can_UpdateRockstarAdhocNonDefaults() + { + var createRequest = new CreateRockstarWithReturn { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }; + var createResponse = client.Post(createRequest); + + var request = new UpdateRockstarAdhocNonDefaults { + Id = createResponse.Id, + LastName = "UpdateResult", + }; + + using (JsConfig.With(new Text.Config { AssumeUtc = true })) + { + var response = client.Put(request); + } + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateResult")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); //[AutoUpdate(AutoUpdateStyle.NonDefaults)] + Assert.That(newRockstar.Age, Is.EqualTo(21)); //[AutoDefault(Value = 21)] + //[AutoDefault(Eval = "date(2001,1,1)")] + Assert.That(newRockstar.DateOfBirth, Is.EqualTo(new DateTime(2001,1,1))); + Assert.That(newRockstar.DateDied.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + //[AutoUpdate(AutoUpdateStyle.NonDefaults), AutoDefault(Value = LivingStatus.Dead)] + Assert.That(newRockstar.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + } + + [Test] + public void Does_throw_when_no_rows_updated() + { + try + { + client.Put(new UpdateRockstar { + Id = 100, + LastName = "UpdateRockstar", + }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(OptimisticConcurrencyException))); + } + } + + [Test] + public void Can_Delete_CreateRockstarWithReturn() + { + var request = new CreateRockstarWithReturn { + FirstName = "Delete", + LastName = "Rockstar", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(request); + + using var db = appHost.GetDbConnection(); + + var newRockstar = db.Single(x => x.Id == createResponse.Id); + Assert.That(newRockstar, Is.Not.Null); + + var response = client.Delete(new DeleteRockstar { + Id = createResponse.Id + }); + + newRockstar = db.Single(x => x.Id == createResponse.Id); + Assert.That(newRockstar, Is.Null); + } + + [Test] + public void Does_throw_for_Delete_without_filters() + { + var request = new CreateRockstarWithReturn { + FirstName = "Delete", + LastName = "Rockstar", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(request); + + try + { + var response = client.Delete(new DeleteRockstar()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(NotSupportedException))); + } + } + + [Test] + public void Can_delete_with_multiple_non_PrimaryKey_filters() + { + var requests = 5.Times(i => new CreateRockstarWithReturn { + FirstName = "Delete", + LastName = "Filter" + i, + Age = 23, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }); + + requests.Each(x => client.Post(x)); + + try + { + client.Delete(new DeleteRockstarFilters()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(NotSupportedException))); + } + + using var db = appHost.GetDbConnection(); + + var response = client.Delete(new DeleteRockstarFilters { Age = 23, LastName = "Filter1" }); + Assert.That(response.Count, Is.EqualTo(1)); + var remaining = db.Select(x => x.Age == 23); + Assert.That(remaining.Count, Is.EqualTo(5 - 1)); + + response = client.Delete(new DeleteRockstarFilters { Age = 23 }); + Assert.That(response.Count, Is.EqualTo(4)); + remaining = db.Select(x => x.Age == 23); + Assert.That(remaining.Count, Is.EqualTo(0)); + } + + [Test] + public void Can_CreateRockstarAdhocNonDefaults() + { + var createRequest = new CreateRockstarAdhocNonDefaults { + FirstName = "Create", + LastName = "Defaults", + }; + + using var jsScope = JsConfig.With(new Text.Config { AssumeUtc = true }); + var createResponse = client.Post(createRequest); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("Defaults")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(newRockstar.Age, Is.EqualTo(21)); //[AutoDefault(Value = 21)] + //[AutoDefault(Eval = "date(2001,1,1)")] + Assert.That(newRockstar.DateOfBirth, Is.EqualTo(new DateTime(2001,1,1))); + Assert.That(newRockstar.DateDied.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + //[AutoDefault(Value = global::ServiceStack.WebHost.Endpoints.Tests.LivingStatus.Dead)] + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + } + + [Test] + public void Can_CreateRockstarAutoMap() + { + var createRequest = new CreateRockstarAutoMap { + MapFirstName = "Map", + MapLastName = "Defaults", + MapDateOfBirth = new DateTime(2002,2,2), + MapLivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(createRequest); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("Defaults")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.MapFirstName)); + Assert.That(newRockstar.Age, Is.EqualTo(21)); //[AutoDefault(Value = 21)] + //[AutoDefault(Eval = "date(2001,1,1)")] + Assert.That(newRockstar.DateOfBirth.Date, Is.EqualTo(new DateTime(2002,2,2).Date)); + Assert.That(newRockstar.DateDied.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + //[AutoDefault(Value = LivingStatus.Alive)] + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + } + + [Test] + public void Can_CreateRockstarAudit() + { + var authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var createResponse = authClient.Post(new CreateRockstarAudit { + FirstName = "Create", + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.FirstName, Is.EqualTo("Create")); + Assert.That(newRockstar.LastName, Is.EqualTo("Audit")); + Assert.That(newRockstar.Age, Is.EqualTo(20)); + Assert.That(newRockstar.DateOfBirth.Date, Is.EqualTo(new DateTime(2002,2,2).Date)); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("Admin User (London)")); + + authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + authClient.Patch(new UpdateRockstarAudit { + Id = createResponse.Id, + FirstName = "Updated", + // LivingStatus = LivingStatus.Alive, + }); + + newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.FirstName, Is.EqualTo("Updated")); + // Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("manager")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("The Manager (Perth)")); + + authClient.Delete(new DeleteRockstarAudit { + Id = createResponse.Id, + }); + + newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar, Is.Null); + } + + [Test] + public async Task Can_CreateRockstarAuditTenant_with_Events() + { + var dbEvents = (OrmLiteCrudEvents) appHost.Resolve(); + dbEvents.Clear(); + + var authClient = CreateAuthClient(); + var id = CreateAndSoftDeleteRockstarAuditTenant(authClient); + + using var db = appHost.GetDbConnection(); + + void assertState(RockstarAuditTenant result) + { + Assert.That(result.Id, Is.EqualTo(id)); + Assert.That(result.FirstName, Is.EqualTo("Updated & Patched")); + Assert.That(result.LastName, Is.EqualTo("Audit")); + Assert.That(result.Age, Is.EqualTo(20)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(new DateTime(2002, 2, 2).Date)); + Assert.That(result.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + + Assert.That(result.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(result.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(result.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.ModifiedBy, Is.EqualTo("manager")); + Assert.That(result.ModifiedInfo, Is.EqualTo("The Manager (Perth)")); + } + + var crudEvents = db.Select(); + // events.PrintDump(); + Assert.That(crudEvents.Count, Is.EqualTo(4)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(CreateRockstarAuditTenant)), Is.EqualTo(1)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(UpdateRockstarAuditTenant)), Is.EqualTo(1)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(PatchRockstarAuditTenant)), Is.EqualTo(1)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(SoftDeleteAuditTenant)), Is.EqualTo(1)); + + var newRockstar = db.SingleById(id); + assertState(newRockstar); + + db.DeleteById(id); + Assert.That(db.SingleById(id), Is.Null); + + // OrmLiteUtils.PrintSql(); + + var eventsPlayer = new CrudEventsExecutor(appHost); + foreach (var crudEvent in dbEvents.GetEvents(db)) + { + await eventsPlayer.ExecuteAsync(crudEvent); + } + + crudEvents = db.Select(); + Assert.That(crudEvents.Count, Is.EqualTo(4)); // Should not be any new events created by executor + + newRockstar = db.SingleById(id); //uses the same Id + assertState(newRockstar); // State should be the same + } + + [Test] + public void Can_CreateRockstarAuditTenant() + { + var authClient = CreateAuthClient(); + CreateAndSoftDeleteRockstarAuditTenant(authClient); + } + + private int CreateAndSoftDeleteRockstarAuditTenant(GrpcServiceClient authClient) + { + using var db = appHost.GetDbConnection(); + db.DeleteAll(); + + var createRequest = new CreateRockstarAuditTenant { + FirstName = "Create", + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002, 2, 2), + LivingStatus = LivingStatus.Dead, + }; + var createResponse = authClient.Post(createRequest); + var id = createResponse.Id; + Assert.That(id, Is.GreaterThan(0)); + var result = createResponse.Result; + + Assert.That(result.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + + var newRockstar = db.SingleById(id); + Assert.That(newRockstar.TenantId, Is.EqualTo(10)); //admin.City London => 10 + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(newRockstar.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(newRockstar.Age, Is.EqualTo(createRequest.Age)); + Assert.That(newRockstar.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("Admin User (London)")); + + Assert.That(authClient.Get(new QueryRockstarAudit {Id = id}).Results.Count, + Is.EqualTo(1)); + + authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + var updateRequest = new UpdateRockstarAuditTenant { + Id = id, + FirstName = "Updated", + LivingStatus = LivingStatus.Alive, + }; + var updateResponse = authClient.Put(updateRequest); + + void assertUpdated(RockstarAuto result) + { + Assert.That(result.FirstName, Does.StartWith(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + } + + Assert.That(updateResponse.Id, Is.EqualTo(id)); + assertUpdated(updateResponse.Result); + + newRockstar = db.SingleById(id); + Assert.That(newRockstar.FirstName, Is.EqualTo("Updated")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("manager")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("The Manager (Perth)")); + + Assert.That(authClient.Get(new QueryRockstarAuditSubOr { + FirstNameStartsWith = "Up", + AgeOlderThan = 18, + }).Results.Count, + Is.EqualTo(1)); + + var patchRequest = new PatchRockstarAuditTenant { + Id = id, + FirstName = updateRequest.FirstName + " & Patched" + }; + var patchResponse = authClient.Patch(patchRequest); + Assert.That(patchResponse.Result.FirstName, Is.EqualTo("Updated & Patched")); + assertUpdated(patchResponse.Result); + + var softDeleteResponse = authClient.Put(new SoftDeleteAuditTenant { + Id = id, + }); + + Assert.That(softDeleteResponse.Id, Is.EqualTo(id)); + assertUpdated(softDeleteResponse.Result); + + newRockstar = db.SingleById(id); + Assert.That(newRockstar.SoftDeletedDate.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.SoftDeletedBy, Is.EqualTo("manager")); + Assert.That(newRockstar.SoftDeletedInfo, Is.EqualTo("The Manager (Perth)")); + + Assert.That(authClient.Get(new QueryRockstarAudit { Id = id }).Results?.Count ?? 0, + Is.EqualTo(0)); + + Assert.That(authClient.Get(new QueryRockstarAuditSubOr { + FirstNameStartsWith = "Up", + AgeOlderThan = 18, + }).Results?.Count ?? 0, + Is.EqualTo(0)); + + return id; + } + + [Test] + public void Can_CreateRockstarAuditTenant_with_RealDelete() + { + var authClient = CreateAuthClient(); + var id = CreateAndSoftDeleteRockstarAuditTenant(authClient); + + using var db = appHost.GetDbConnection(); + + var realDeleteResponse = authClient.Delete(new RealDeleteAuditTenant { + Id = id, + Age = 99 //non matching filter + }); + Assert.That(realDeleteResponse.Id, Is.EqualTo(id)); + Assert.That(realDeleteResponse.Count, Is.EqualTo(0)); + var newRockstar = db.SingleById(id); + Assert.That(newRockstar, Is.Not.Null); + + realDeleteResponse = authClient.Delete(new RealDeleteAuditTenant { + Id = id, + }); + Assert.That(realDeleteResponse.Id, Is.EqualTo(id)); + Assert.That(realDeleteResponse.Count, Is.EqualTo(1)); + newRockstar = db.SingleById(id); + Assert.That(newRockstar, Is.Null); + } + + [Test] + public void Can_CreateRockstarAuditTenantGateway_Gateway() + { + var authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var createRequest = new CreateRockstarAuditTenantGateway { + FirstName = "CreateGateway", + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + var createResponse = authClient.Post(createRequest); + Assert.That(createResponse.Id, Is.GreaterThan(0)); + var result = createResponse.Result; + + var updateRequest = new UpdateRockstarAuditTenantGateway { + Id = createResponse.Id, + FirstName = "UpdatedGateway", + LivingStatus = LivingStatus.Alive, + }; + var updateResponse = authClient.Put(updateRequest); + result = updateResponse.Result; + + Assert.That(updateResponse.Id, Is.EqualTo(createResponse.Id)); + Assert.That(result.FirstName, Is.EqualTo(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + + var patchRequest = new PatchRockstarAuditTenantGateway { + Id = createResponse.Id, + FirstName = "PatchedGateway", + LivingStatus = LivingStatus.Alive, + }; + var patchResponse = authClient.Patch(patchRequest); + result = patchResponse.Result; + + Assert.That(updateResponse.Id, Is.EqualTo(createResponse.Id)); + Assert.That(result.FirstName, Is.EqualTo(patchRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(patchRequest.LivingStatus)); + + var deleteRequest = authClient.Delete(new RealDeleteAuditTenantGateway { + Id = createResponse.Id, + }); + Assert.That(deleteRequest.Id, Is.EqualTo(createResponse.Id)); + } + + [Test] + public void Can_CreateRockstarAuditTenantMq() + { + var authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + }); + + var createRequest = new CreateRockstarAuditTenantMq { + FirstName = nameof(CreateRockstarAuditTenantMq), + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + authClient.Post(createRequest); + + using var db = appHost.GetDbConnection(); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(CreateRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + var result = db.Single(x => x.FirstName == nameof(CreateRockstarAuditTenantMq)); + + var updateRequest = new UpdateRockstarAuditTenantMq { + Id = result.Id, + FirstName = nameof(UpdateRockstarAuditTenantMq), + LivingStatus = LivingStatus.Alive, + }; + authClient.Put(updateRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(UpdateRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(UpdateRockstarAuditTenantMq)); + + Assert.That(result.FirstName, Is.EqualTo(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + + var patchRequest = new PatchRockstarAuditTenantMq { + Id = result.Id, + FirstName = nameof(PatchRockstarAuditTenantMq), + LivingStatus = LivingStatus.Alive, + }; + authClient.Patch(patchRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)); + + Assert.That(result.FirstName, Is.EqualTo(patchRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(patchRequest.LivingStatus)); + + authClient.Delete(new RealDeleteAuditTenantMq { + Id = result.Id, + }); + + ExecUtils.RetryUntilTrue(() => + !db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + + Assert.That(db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), Is.False); + } + + [Test] + public void Can_CreateRockstarAuditTenant_Send() + { + var authClient = CreateClient(); + var authResponse = authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var createRequest = new CreateRockstarAuditTenant { + FirstName = nameof(CreateRockstarAuditTenant), + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + authClient.Send(createRequest); + + using var db = appHost.GetDbConnection(); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(CreateRockstarAuditTenant)), + TimeSpan.FromSeconds(2)); + var result = db.Single(x => x.FirstName == nameof(CreateRockstarAuditTenant)); + + var updateRequest = new UpdateRockstarAuditTenant { + Id = result.Id, + FirstName = nameof(UpdateRockstarAuditTenant), + LivingStatus = LivingStatus.Alive, + }; + authClient.Send(updateRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(UpdateRockstarAuditTenant)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(UpdateRockstarAuditTenant)); + + Assert.That(result.FirstName, Is.EqualTo(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + + var patchRequest = new PatchRockstarAuditTenant { + Id = result.Id, + FirstName = nameof(PatchRockstarAuditTenant), + LivingStatus = LivingStatus.Alive, + }; + authClient.Send(patchRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenant)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(PatchRockstarAuditTenant)); + + Assert.That(result.FirstName, Is.EqualTo(patchRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(patchRequest.LivingStatus)); + + authClient.Delete(new RealDeleteAuditTenant { + Id = result.Id, + }); + + ExecUtils.RetryUntilTrue(() => + !db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + + Assert.That(db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), Is.False); + } + + [Test] + public void Can_CreateRockstarAuditMqToken_OneWay() + { + var createRequest = new CreateRockstarAuditMqToken { + BearerToken = JwtUserToken, + FirstName = nameof(CreateRockstarAuditMqToken), + LastName = "JWT", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + client.Send(createRequest); + + using var db = appHost.GetDbConnection(); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(CreateRockstarAuditMqToken)), + TimeSpan.FromSeconds(2)); + + var result = db.Single(x => x.FirstName == nameof(CreateRockstarAuditMqToken)); + Assert.That(result.Id, Is.GreaterThan(0)); + Assert.That(result.FirstName, Is.EqualTo(nameof(CreateRockstarAuditMqToken))); + Assert.That(result.LastName, Is.EqualTo("JWT")); + Assert.That(result.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + Assert.That(result.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.CreatedBy, Is.EqualTo("jwtuser")); + Assert.That(result.CreatedInfo, Is.EqualTo("JWT User (Japan)")); + Assert.That(result.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.ModifiedBy, Is.EqualTo("jwtuser")); + Assert.That(result.ModifiedInfo, Is.EqualTo("JWT User (Japan)")); + } + + [Test] + public void Can_UpdateRockstarVersion() + { + var createResponse = client.Post(new CreateRockstarVersion { + FirstName = "Create", + LastName = "Version", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }); + + try + { + client.Patch(new UpdateRockstarVersion { + Id = createResponse.Id, + LastName = "UpdateVersion2", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(OptimisticConcurrencyException))); + } + + var response = client.Patch(new UpdateRockstarVersion { + Id = createResponse.Id, + LastName = "UpdateVersion3", + RowVersion = createResponse.RowVersion, + }); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.RowVersion, Is.Not.EqualTo(default(uint))); + Assert.That(newRockstar.FirstName, Is.EqualTo("Create")); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateVersion3")); + + try + { + client.Patch(new UpdateRockstarVersion { + Id = createResponse.Id, + LastName = "UpdateVersion4", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(OptimisticConcurrencyException))); + } + } + + [Test] + public void Can_NamedConnection_AutoCrud_Services() + { + var createRequest = new CreateNamedRockstar { + Id = 10, + FirstName = "Named", + LastName = "SqlServer", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(createRequest); + Assert.That(createResponse.Id, Is.EqualTo(10)); + Assert.That(createResponse.Result, Is.Not.Null); + + using var db = appHost.Resolve() + .OpenDbConnection(AutoQueryAppHost.SqlServerNamedConnection); + + var newRockstar = db.Single(x => x.LastName == "SqlServer"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Named")); + + var updateRequest = new UpdateNamedRockstar { + Id = 10, + FirstName = "Updated", + Age = 21, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Dead, + }; + + var updateResponse = client.Put(updateRequest); + + Assert.That(updateResponse.Id, Is.EqualTo(10)); + Assert.That(updateResponse.Result.FirstName, Is.EqualTo("Updated")); + Assert.That(updateResponse.Result.Age, Is.EqualTo(21)); + Assert.That(updateResponse.Result.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + } + + [Test] + public void Can_ConnectionInfo_AutoCrud_Services() + { + var createRequest = new CreateConnectionInfoRockstar { + Id = 11, + FirstName = "Named", + LastName = "SqlServer", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(createRequest); + Assert.That(createResponse.Id, Is.EqualTo(11)); + Assert.That(createResponse.Result, Is.Not.Null); + + using var db = appHost.Resolve() + .OpenDbConnection(AutoQueryAppHost.SqlServerNamedConnection); + + var newRockstar = db.Single(x => x.LastName == "SqlServer"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Named")); + + var updateRequest = new UpdateConnectionInfoRockstar { + Id = 11, + FirstName = "Updated", + Age = 21, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Dead, + }; + + var updateResponse = client.Put(updateRequest); + + Assert.That(updateResponse.Id, Is.EqualTo(11)); + Assert.That(updateResponse.Result.FirstName, Is.EqualTo("Updated")); + Assert.That(updateResponse.Result.Age, Is.EqualTo(21)); + Assert.That(updateResponse.Result.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + } + + [Test] + public void Does_apply_Audit_behavior() + { + var authClient = CreateClient(); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var booking1Id = authClient.Post(new CreateBooking { + RoomNumber = 1, + BookingStartDate = DateTime.Today.AddDays(1), + BookingEndDate = DateTime.Today.AddDays(5), + Cost = 100, + }).Id.ToInt(); + var booking2Id = authClient.Post(new CreateBooking { + RoomNumber = 2, + BookingStartDate = DateTime.Today.AddDays(2), + BookingEndDate = DateTime.Today.AddDays(6), + Cost = 200, + }).Id.ToInt(); + + var bookings = client.Get(new QueryBookings { + Ids = new []{ booking1Id, booking2Id } + }); + + // bookings.PrintDump(); + Assert.That(bookings.Results.Count, Is.EqualTo(2)); + + Assert.That(bookings.Results.All(x => x.CreatedBy != null)); + Assert.That(bookings.Results.All(x => x.CreatedDate >= DateTime.UtcNow.Date)); + Assert.That(bookings.Results.All(x => x.ModifiedBy != null)); + Assert.That(bookings.Results.All(x => x.ModifiedDate >= DateTime.UtcNow.Date)); + Assert.That(bookings.Results.All(x => x.ModifiedDate == x.CreatedDate)); + + authClient.Patch(new UpdateBooking { + Id = booking1Id, + Cancelled = true, + Notes = "Missed Flight", + }); + var booking1 = client.Get(new QueryBookings { + Ids = new[] { booking1Id } + }).Results[0]; + Assert.That(booking1.Cancelled, Is.True); + Assert.That(booking1.Notes, Is.EqualTo("Missed Flight")); + Assert.That(booking1.ModifiedDate, Is.Not.EqualTo(booking1.CreatedDate)); + + authClient.Delete(new DeleteBooking { + Id = booking2Id, + }); + var booking2 = client.Get(new QueryBookings { + Ids = new[] { booking2Id } + }).Results?.FirstOrDefault(); + Assert.That(booking2, Is.Null); + + using var db = appHost.Resolve().OpenDbConnection(); + booking2 = db.SingleById(booking2Id); + // booking2.PrintDump(); + Assert.That(booking2, Is.Not.Null); + Assert.That(booking2.DeletedBy, Is.Not.Null); + Assert.That(booking2.DeletedDate, Is.Not.Null); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/GrpcAuthTests.cs b/tests/ServiceStack.Extensions.Tests/GrpcAuthTests.cs new file mode 100644 index 00000000000..2ee29b39f3d --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/GrpcAuthTests.cs @@ -0,0 +1,398 @@ +using System; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Auth; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.Extensions.Tests +{ + [DataContract] + public class HelloJwt : IReturn, IHasBearerToken + { + [DataMember(Order = 1)] + public string Name { get; set; } + [DataMember(Order = 2)] + public string BearerToken { get; set; } + } + [DataContract] + public class HelloJwtResponse + { + [DataMember(Order = 1)] + public string Result { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class Secured : IReturn + { + [DataMember(Order = 1)] + public string Name { get; set; } + } + + [DataContract] + public class SecuredResponse + { + [DataMember(Order = 1)] + public string Result { get; set; } + + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [Authenticate] + public class AuthServices : Service + { + public object Any(HelloJwt request) + { + return new HelloJwtResponse { Result = $"Hello, {request.Name}" }; + } + + public object Post(Secured request) + { + return new SecuredResponse { Result = $"Hello, {request.Name}" }; + } + } + + [DataContract] + public class RequiresAuth : IReturn, IHasBearerToken + { + [DataMember(Order = 1)] + public string Name { get; set; } + [DataMember(Order = 2)] + public string BearerToken { get; set; } + } + + [Authenticate] + public class RequiresAuthService : Service + { + public static ApiKey LastApiKey; + + public object Any(RequiresAuth request) + { + LastApiKey = base.Request.GetApiKey(); + return request; + } + } + + public class GrpcAuthTests + { + public static readonly byte[] AuthKey = AesUtils.CreateKey(); + public const string Username = "mythz"; + public const string Password = "p@55word"; + + private static IManageApiKeys apiRepo; + private const string userId = "1"; + private static ApiKey liveKey; + private static ApiKey testKey; + + public class AppHost : AppSelfHostBase + { + public static ApiKey LastApiKey; + public AppHost() + : base(nameof(GrpcTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + Plugins.Add(new GrpcFeature(App)); + + container.Register(new InMemoryAuthRepository()); + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + new JwtAuthProvider + { + AuthKey = AuthKey, + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + IncludeJwtInConvertSessionToTokenResponse = true, + }, + new ApiKeyAuthProvider(AppSettings) { RequireSecureConnection = false }, + })); + + Plugins.Add(new RegistrationFeature()); + + GlobalRequestFilters.Add((req, res, dto) => + { + LastApiKey = req.GetApiKey(); + }); + + AfterInitCallbacks.Add(host => { + + var authRepo = GetAuthRepository(); + (authRepo as InMemoryAuthRepository).Clear(); + authRepo.CreateUserAuth(new UserAuth + { + Id = userId.ToInt(), + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + + apiRepo = (IManageApiKeys)container.Resolve(); + var apiKeyProvider = (ApiKeyAuthProvider)AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name); + var apiKeys = apiKeyProvider.GenerateNewApiKeys(userId); + using (authRepo as IDisposable) + { + apiRepo.StoreAll(apiKeys); + } + liveKey = apiKeys.First(x => x.Environment == "live"); + testKey = apiKeys.First(x => x.Environment == "test"); + }); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + } + } + + private readonly ServiceStackHost appHost; + public GrpcAuthTests() + { + appHost = new AppHost() + .Init() + .Start(TestsConfig.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private static string CreateExpiredToken() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name); + jwtProvider.CreatePayloadFilter = (jwtPayload, session) => + jwtPayload["exp"] = DateTime.UtcNow.AddSeconds(-1).ToUnixTime().ToString(); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + jwtProvider.CreatePayloadFilter = null; + return token; + } + + private async Task GetRefreshToken() + { + var authClient = GetClient(); + var response = await authClient.SendAsync(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + return response.RefreshToken; + } + + private static GrpcServiceClient GetClient() => TestsConfig.GetInsecureClient(); + + protected virtual async Task GetClientWithRefreshToken(string refreshToken = null, string accessToken = null) + { + if (refreshToken == null) + { + refreshToken = await GetRefreshToken(); + } + + var client = GetClient(); + client.RefreshToken = refreshToken; + client.BearerToken = accessToken; + return client; + } + + protected virtual GrpcServiceClient GetClientWithBasicAuthCredentials() + { + var client = GetClient(); + client.SetCredentials(Username, Password); + return client; + } + + [Test] + public async Task Can_not_access_Secured_without_Auth() + { + var client = GetClient(); + + try + { + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.Message.Print(); + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + } + + [Test] + public async Task Can_access_Secured_using_BasicAuth() + { + var client = GetClientWithBasicAuthCredentials(); + + var request = new Secured { Name = "test" }; + + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = await client.PostAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public async Task Can_ConvertSessionToToken() + { + var authClient = GetClient(); + var authResponse = await authClient.SendAsync(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + Assert.That(authResponse.SessionId, Is.Not.Null); + Assert.That(authResponse.UserName, Is.EqualTo(Username)); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + authClient.SessionId = authResponse.SessionId; + + var response = await authClient.SendAsync(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + + authClient.BearerToken = (await authClient.SendAsync(new ConvertSessionToToken())).AccessToken; + Assert.That(authClient.BearerToken, Is.Not.Null); + + authClient.SessionId = null; + + response = await authClient.SendAsync(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + } + + [Test] + public async Task Invalid_RefreshToken_throws_RefreshTokenException() + { + var client = await GetClientWithRefreshToken("Invalid.Refresh.Token"); + try + { + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.Fail("Should throw"); + } + catch (RefreshTokenException ex) + { + ex.Message.Print(); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + } + } + + [Test] + public async Task Can_Auto_reconnect_with_just_RefreshToken() + { + var client = await GetClientWithRefreshToken(); + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public async Task Can_Auto_reconnect_with_RefreshToken_after_expired_token() + { + var client = await GetClientWithRefreshToken(await GetRefreshToken(), CreateExpiredToken()); + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public async Task Does_return_token_on_subsequent_BasicAuth_Authentication_requests() + { + var client = GetClientWithBasicAuthCredentials(); + + var response = await client.PostAsync(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + + response = await client.PostAsync(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + } + + [Test] + public async Task Can_Authenticate_with_ApiKey() + { + AppHost.LastApiKey = null; + RequiresAuthService.LastApiKey = null; + + var client = GetClient(); + client.BearerToken = liveKey.Id; + + var request = new RequiresAuth { Name = "foo" }; + var response = await client.SendAsync(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + Assert.That(RequiresAuthService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + + client.BearerToken = testKey.Id; + var testResponse = await client.SendAsync(new Secured { Name = "test" }); + Assert.That(testResponse.Result, Is.EqualTo("Hello, test")); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(testKey.Id)); + } + + [Test] + public async Task Does_allow_ApiKey_in_IHasBearerToken_RequestDto() + { + AppHost.LastApiKey = null; + RequiresAuthService.LastApiKey = null; + + var client = GetClient(); + + var request = new RequiresAuth { BearerToken = liveKey.Id, Name = "foo" }; + var response = await client.SendAsync(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + Assert.That(RequiresAuthService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/GrpcAutoQueryTests.cs b/tests/ServiceStack.Extensions.Tests/GrpcAutoQueryTests.cs new file mode 100644 index 00000000000..3d769f80a94 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/GrpcAutoQueryTests.cs @@ -0,0 +1,1933 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf; +using ProtoBuf.Grpc.Client; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.Logging; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.Extensions.Tests +{ + [DataContract] + public class Rockstar + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public string LastName { get; set; } + [DataMember(Order = 4)] + public int? Age { get; set; } + [DataMember(Order = 5)] + public DateTime DateOfBirth { get; set; } + [DataMember(Order = 6)] + public DateTime? DateDied { get; set; } + [DataMember(Order = 7)] + public LivingStatus LivingStatus { get; set; } + } + + public enum LivingStatus + { + Alive, + Dead + } + + [DataContract] + public class PagingTest + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string Name { get; set; } + [DataMember(Order = 3)] + public int Value { get; set; } + } + + + [Alias("Rockstar")] + [NamedConnection("SqlServer")] + [DataContract] + public class NamedRockstar : Rockstar { } + + [Route("/query/namedrockstars")] + [DataContract] + public class QueryNamedRockstars : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [Route("/query/rockstars")] + [DataContract, Id(10), Tag(Keywords.Dynamic)] + public class QueryRockstars : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [Route("/query/rockstaralbums")] + [DataContract] + public class QueryRockstarAlbums : QueryDb + { + [DataMember(Order = 1)] + public int? Id { get; set; } + [DataMember(Order = 2)] + public int? RockstarId { get; set; } + [DataMember(Order = 3)] + public string Name { get; set; } + [DataMember(Order = 4)] + public string Genre { get; set; } + [DataMember(Order = 5)] + public int[] IdBetween { get; set; } + } + + [Route("/query/pagingtest")] + [DataContract] + public class QueryPagingTest : QueryDb + { + [DataMember(Order = 1)] + public int? Id { get; set; } + [DataMember(Order = 2)] + public string Name { get; set; } + [DataMember(Order = 3)] + public int? Value { get; set; } + } + + [DataContract] + public class QueryRockstarsConventions : QueryDb + { + [DataMember(Order = 1)] + public DateTime? DateOfBirthGreaterThan { get; set; } + [DataMember(Order = 2)] + public DateTime? DateDiedLessThan { get; set; } + [DataMember(Order = 3)] + public int[] Ids { get; set; } + [DataMember(Order = 4)] + public int? AgeOlderThan { get; set; } + [DataMember(Order = 5)] + public int? AgeGreaterThanOrEqualTo { get; set; } + [DataMember(Order = 6)] + public int? AgeGreaterThan { get; set; } + [DataMember(Order = 7)] + public int? GreaterThanAge { get; set; } + [DataMember(Order = 8)] + public string FirstNameStartsWith { get; set; } + [DataMember(Order = 9)] + public string LastNameEndsWith { get; set; } + [DataMember(Order = 10)] + public string LastNameContains { get; set; } + [DataMember(Order = 11)] + public string RockstarAlbumNameContains { get; set; } + [DataMember(Order = 12)] + public int? RockstarIdAfter { get; set; } + [DataMember(Order = 13)] + public int? RockstarIdOnOrAfter { get; set; } + } + + [DataContract] + public class QueryCustomRockstars : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [Route("/customrockstars")] + [DataContract] + public class QueryJoinedRockstarAlbums : QueryDb, IJoin + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string RockstarAlbumName { get; set; } + } + + [DataContract] + public class QueryRockstarAlbumsImplicit : QueryDb, IJoin + { + } + + [DataContract] + public class QueryRockstarAlbumsLeftJoin : QueryDb, ILeftJoin + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string AlbumName { get; set; } + [DataMember(Order = 3)] + public int? IdNotEqualTo { get; set; } + } + + [DataContract] + public class QueryRockstarAlbumsCustomLeftJoin : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string AlbumName { get; set; } + [DataMember(Order = 3)] + public int? IdNotEqualTo { get; set; } + } + + [DataContract] + public class QueryMultiJoinRockstar : QueryDb, + IJoin, + IJoin + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string RockstarAlbumName { get; set; } + [DataMember(Order = 3)] + public string RockstarGenreName { get; set; } + } + + [DataContract] + public class QueryOverridedRockstars : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryOverridedCustomRockstars : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryCaseInsensitiveOrderBy : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryFieldRockstars : QueryDb + { + [DataMember(Order = 1)] + public string FirstName { get; set; } //default to 'AND FirstName = {Value}' + + [DataMember(Order = 2)] + public string[] FirstNames { get; set; } //Collections default to 'FirstName IN ({Values}) + + [QueryDbField(Operand = ">=")] + [DataMember(Order = 3)] + public int? Age { get; set; } + + [QueryDbField(Template = "UPPER({Field}) LIKE UPPER({Value})", Field = "FirstName")] + [DataMember(Order = 4)] + public string FirstNameCaseInsensitive { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value}", Field = "FirstName", ValueFormat = "{0}%")] + [DataMember(Order = 5)] + public string FirstNameStartsWith { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value}", Field = "LastName", ValueFormat = "%{0}")] + [DataMember(Order = 6)] + public string LastNameEndsWith { get; set; } + + [QueryDbField(Template = "{Field} BETWEEN {Value1} AND {Value2}", Field = "FirstName")] + [DataMember(Order = 7)] + public string[] FirstNameBetween { get; set; } + + [QueryDbField(Term = QueryTerm.Or, Template = "UPPER({Field}) LIKE UPPER({Value})", Field = "LastName")] + [DataMember(Order = 8)] + public string OrLastName { get; set; } + } + + [DataContract] + public class QueryRockstarAlias : QueryDb, + IJoin + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string RockstarAlbumName { get; set; } + } + + [DataContract] + public class RockstarAlias + { + [DataMember(Order = 1)] + [Alias("Id")] + public int RockstarId { get; set; } + + [DataMember(Order = 2)] + public string FirstName { get; set; } + + [DataMember(Order = 3)] + [Alias("LastName")] + public string Surname { get; set; } + + [DataMember(Name = "album", Order = 4)] + public string RockstarAlbumName { get; set; } + } + + [DataContract] + public class QueryFieldRockstarsDynamic : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryRockstarsFilter : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryCustomRockstarsFilter : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + public interface IFilterRockstars { } + [DataContract] + public class QueryRockstarsIFilter : QueryDb, IFilterRockstars + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [Route("/OrRockstars")] + [DataContract] + public class QueryOrRockstars : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + } + + [DataContract] + public class QueryRockstarsImplicit : QueryDb {} + + [Route("/OrRockstarsFields")] + [DataContract] + public class QueryOrRockstarsFields : QueryDb + { + [QueryDbField(Term = QueryTerm.Or)] + [DataMember(Order = 1)] + public string FirstName { get; set; } + + [QueryDbField(Term = QueryTerm.Or)] + [DataMember(Order = 2)] + public string LastName { get; set; } + } + + [DataContract] + public class QueryFieldsImplicitConventions : QueryDb + { + [QueryDbField(Term = QueryTerm.Or)] + [DataMember(Order = 1)] + public string FirstNameContains { get; set; } + + [QueryDbField(Term = QueryTerm.Or)] + [DataMember(Order = 2)] + public string LastNameEndsWith { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [DataContract] + public class QueryGetRockstars : QueryDb + { + [DataMember(Order = 1)] + public int[] Ids { get; set; } + [DataMember(Order = 2)] + public List Ages { get; set; } + [DataMember(Order = 3)] + public List FirstNames { get; set; } + [DataMember(Order = 4)] + public int[] IdsBetween { get; set; } + } + + [DataContract] + public class QueryRockstarFilters : QueryDb + { + [DataMember(Order = 1)] + public int[] Ids { get; set; } + [DataMember(Order = 2)] + public List Ages { get; set; } + [DataMember(Order = 3)] + public List FirstNames { get; set; } + [DataMember(Order = 4)] + public int[] IdsBetween { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [DataContract] + public class QueryGetRockstarsDynamic : QueryDb {} + +// [References(typeof(RockstarAlbumGenreGlobalIndex))] + [DataContract] + public class RockstarAlbum + { + [AutoIncrement] + [DataMember(Order = 1)] + public int Id { get; set; } + [References(typeof(Rockstar))] + [DataMember(Order = 2)] + public int RockstarId { get; set; } + [DataMember(Order = 3)] + public string Name { get; set; } + [Index] + [DataMember(Order = 4)] + public string Genre { get; set; } + } + + [DataContract] + public class RockstarGenre + { + [AutoIncrement] + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public int RockstarId { get; set; } + [DataMember(Order = 3)] + public string Name { get; set; } + } + + [DataContract] + public class CustomRockstar + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + [DataMember(Order = 4)] + public string RockstarAlbumName { get; set; } + [DataMember(Order = 5)] + public string RockstarGenreName { get; set; } + } + + [DataContract] + public class QueryCustomRockstarsSchema : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [Schema("dbo")] + [DataContract] + public class CustomRockstarSchema + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public string LastName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + [DataMember(Order = 4)] + public string RockstarAlbumName { get; set; } + [DataMember(Order = 5)] + public string RockstarGenreName { get; set; } + } + + [Route("/movies/search")] + [QueryDb(QueryTerm.And)] //Default + [DataContract] + public class SearchMovies : QueryDb {} + + [Route("/movies")] + [QueryDb(QueryTerm.Or)] + [DataContract] + public class QueryMovies : QueryDb + { + [DataMember(Order = 1)] + public int[] Ids { get; set; } + [DataMember(Order = 2)] + public string[] ImdbIds { get; set; } + [DataMember(Order = 3)] + public string[] Ratings { get; set; } + } + +// [References(typeof(MovieTitleIndex))] + [DataContract] + public class Movie + { + [AutoIncrement] + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string ImdbId { get; set; } + [DataMember(Order = 3)] + public string Title { get; set; } + [DataMember(Order = 4)] + public string Rating { get; set; } + [DataMember(Order = 5)] + public decimal Score { get; set; } + [DataMember(Order = 6)] + public string Director { get; set; } + [DataMember(Order = 7)] + public DateTime ReleaseDate { get; set; } + [DataMember(Order = 8)] + public string TagLine { get; set; } + [DataMember(Order = 9)] + public List Genres { get; set; } + } + + [DataContract] + public class StreamMovies : QueryDb + { + [DataMember(Order = 1)] + public string[] Ratings { get; set; } + } + + [DataContract] + public class QueryUnknownRockstars : QueryDb + { + [DataMember(Order = 1)] + public int UnknownInt { get; set; } + [DataMember(Order = 2)] + public string UnknownProperty { get; set; } + } + + [Route("/query/rockstar-references")] + [DataContract] + public class QueryRockstarsWithReferences : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryCustomRockstarsReferences : QueryDb + { + [DataMember(Order = 1)] + public int? Age { get; set; } + } + + [Alias("Rockstar")] + [DataContract] + public class RockstarReference + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public string LastName { get; set; } + [DataMember(Order = 4)] + public int? Age { get; set; } + + [Reference] + [DataMember(Order = 5)] + public List Albums { get; set; } + } + + [Route("/query/all-fields")] + [DataContract] + public class QueryAllFields : QueryDb + { + [DataMember(Order = 1)] + public virtual Guid? Guid { get; set; } + } + + [DataContract] + public class AllFields + { + [DataMember(Order = 1)] + public virtual int Id { get; set; } + [DataMember(Order = 2)] + public virtual int? NullableId { get; set; } + [DataMember(Order = 3)] + public virtual byte Byte { get; set; } + [DataMember(Order = 4)] + public virtual short Short { get; set; } + [DataMember(Order = 5)] + public virtual int Int { get; set; } + [DataMember(Order = 6)] + public virtual long Long { get; set; } + [DataMember(Order = 7)] + public virtual ushort UShort { get; set; } + [DataMember(Order = 8)] + public virtual uint UInt { get; set; } + [DataMember(Order = 9)] + public virtual ulong ULong { get; set; } + [DataMember(Order = 10)] + public virtual float Float { get; set; } + [DataMember(Order = 11)] + public virtual double Double { get; set; } + [DataMember(Order = 12)] + public virtual decimal Decimal { get; set; } + [DataMember(Order = 13)] + public virtual string String { get; set; } + [DataMember(Order = 14)] + public virtual DateTime DateTime { get; set; } + [DataMember(Order = 15)] + public virtual TimeSpan TimeSpan { get; set; } + [DataMember(Order = 16)] + public virtual Guid Guid { get; set; } + [DataMember(Order = 17)] + public virtual DateTime? NullableDateTime { get; set; } + [DataMember(Order = 18)] + public virtual TimeSpan? NullableTimeSpan { get; set; } + [DataMember(Order = 19)] + public virtual Guid? NullableGuid { get; set; } + [DataMember(Order = 20)] + public HttpStatusCode Enum { get; set; } + [DataMember(Order = 21)] + public HttpStatusCode? NullableEnum { get; set; } + } + + [EnumAsInt] + public enum SomeEnumAsInt + { + Value0 = 0, + Value1 = 1, + Value2 = 2, + Value3 = 3, + } + + public enum SomeEnum + { + // Enum values must be unique globally + // https://stackoverflow.com/questions/13802844/protobuf-net-into-proto-generates-enum-conflicts + [ProtoEnum(Name="SomeEnum_Value0")] + Value0 = 0, + [ProtoEnum(Name="SomeEnum_Value1")] + Value1 = 1, + [ProtoEnum(Name="SomeEnum_Value2")] + Value2 = 2, + [ProtoEnum(Name="SomeEnum_Value3")] + Value3 = 3 + } + + [DataContract] + public class TypeWithEnum + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string Name { get; set; } + [DataMember(Order = 3)] + public SomeEnum SomeEnum { get; set; } + [DataMember(Order = 4)] + public SomeEnumAsInt SomeEnumAsInt { get; set; } + [DataMember(Order = 5)] + public SomeEnum? NSomeEnum { get; set; } + [DataMember(Order = 6)] + public SomeEnumAsInt? NSomeEnumAsInt { get; set; } + } + + [Route("/query-enums")] + [DataContract] + public class QueryTypeWithEnums : QueryDb {} + + [DataContract] + public class Adhoc + { + [DataMember(Order = 1)] + public int Id { get; set; } + + [DataMember(Name = "first_name", Order = 2)] + public string FirstName { get; set; } + + [DataMember(Order = 3)] + public string LastName { get; set; } + } + + [DataContract] + [Route("/adhoc-rockstars")] + public class QueryAdhocRockstars : QueryDb + { + [DataMember(Name = "first_name", Order = 1)] + public string FirstName { get; set; } + } + + [DataContract] + [Route("/adhoc")] + public class QueryAdhoc : QueryDb {} + + public class AutoQueryService : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + //Override with custom impl + public object Get(QueryOverridedRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams()); + q.Take(1); + return AutoQuery.Execute(dto, q); + } + + public object Get(QueryOverridedCustomRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams()); + q.Take(1); + return AutoQuery.Execute(dto, q); + } + + public object Get(QueryCaseInsensitiveOrderBy dto) + { + var q = AutoQuery.CreateQuery(dto, Request); + if (q.OrderByExpression != null) + q.OrderByExpression += " COLLATE NOCASE"; + + return AutoQuery.Execute(dto, q); + } + + public object Get(StreamMovies dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams()); + q.Take(2); + return AutoQuery.Execute(dto, q); + } + + public object Get(QueryCustomRockstarsReferences request) + { + var q = AutoQuery.CreateQuery(request, Request.GetRequestParams()); + var response = new QueryResponse + { + Offset = q.Offset.GetValueOrDefault(0), + Results = Db.LoadSelect(q, include:new string[0]), + Total = (int)Db.Count(q), + }; + return response; + } + + public object Get(QueryRockstarAlbumsCustomLeftJoin query) + { + var q = AutoQuery.CreateQuery(query, Request) + .LeftJoin((r, a) => r.Id == a.RockstarId); + return AutoQuery.Execute(query, q); + } + } + + public interface IChangeDb + { + string NamedConnection { get; set; } + string ConnectionString { get; set; } + string ProviderName { get; set; } + } + + [Route("/querychangedb")] + [DataContract] + public class QueryChangeDb : QueryDb, IChangeDb + { + [DataMember(Order = 1)] + public string NamedConnection { get; set; } + [DataMember(Order = 2)] + public string ConnectionString { get; set; } + [DataMember(Order = 3)] + public string ProviderName { get; set; } + } + + [Route("/changedb")] + [DataContract] + public class ChangeDb : IReturn, IChangeDb + { + [DataMember(Order = 1)] + public string NamedConnection { get; set; } + [DataMember(Order = 2)] + public string ConnectionString { get; set; } + [DataMember(Order = 3)] + public string ProviderName { get; set; } + } + + [DataContract] + public class ChangeDbResponse + { + [DataMember(Order = 1)] + public List Results { get; set; } + } + + [DataContract] + public class DynamicDbServices : Service + { + public object Get(ChangeDb request) + { + return new ChangeDbResponse { Results = Db.Select() }; + } + } + + [DataContract] + public class ChangeConnectionInfo : IReturn { } + [DataContract] + public class QueryChangeConnectionInfo : QueryDb { } + + [ConnectionInfo(NamedConnection = AutoQueryAppHost.SqlServerNamedConnection)] + [DataContract] + public class NamedConnectionServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + public object Get(ChangeConnectionInfo request) + { + return new ChangeDbResponse { Results = Db.Select() }; + } + + public object Get(QueryChangeConnectionInfo query) + { + return AutoQuery.Execute(query, AutoQuery.CreateQuery(query, Request), Request); + } + } + + [Alias(nameof(Rockstar))] + [DataContract] + public class CustomSelectRockstar + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public string LastName { get; set; } + [CustomSelect("Age * 2")] + [DataMember(Order = 4)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryJoinedRockstarAlbumsCustomSelect : QueryDb, + IJoin + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string RockstarAlbumName { get; set; } + } + + [DataContract] + public class CustomSelectRockstarResponse + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string FirstName { get; set; } + [DataMember(Order = 3)] + public int? Age { get; set; } + } + + [DataContract] + public class QueryJoinedRockstarAlbumsCustomSelectResponse : QueryDb, + IJoin + { + [DataMember(Order = 1)] + public int? Age { get; set; } + [DataMember(Order = 2)] + public string RockstarAlbumName { get; set; } + } + + public class TestsConfig + { + public static readonly int Port = 20000; + public static readonly string BaseUri = Environment.GetEnvironmentVariable("CI_BASEURI") ?? $"http://localhost:{Port}"; + public static readonly string AbsoluteBaseUri = BaseUri + "/"; + + public static readonly string HostNameBaseUrl = $"http://DESKTOP-BCS76J0:{Port}/"; //Allow fiddler + public static readonly string AnyHostBaseUrl = $"http://*:{Port}/"; //Allow capturing by fiddler + + public static readonly string ListeningOn = BaseUri + "/"; + public static readonly string RabbitMQConnString = Environment.GetEnvironmentVariable("CI_RABBITMQ") ?? "localhost"; + public static readonly string SqlServerConnString = Environment.GetEnvironmentVariable("MSSQL_CONNECTION") ?? "Server=localhost;Database=test;User Id=test;Password=test;"; + public static readonly string PostgreSqlConnString = Environment.GetEnvironmentVariable("PGSQL_CONNECTION") ?? "Server=localhost;Port=5432;User Id=test;Password=test;Database=test;Pooling=true;MinPoolSize=0;MaxPoolSize=200"; + public static readonly string DynamoDbServiceURL = Environment.GetEnvironmentVariable("CI_DYNAMODB") ?? "http://localhost:8000"; + + public const string AspNetBaseUri = "http://localhost:50000/"; + public const string AspNetServiceStackBaseUri = AspNetBaseUri + "api"; + + public static GrpcServiceClient GetInsecureClient() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + var client = new GrpcServiceClient(BaseUri); + return client; + } + } + + public static class TestUtils + { + public static void AddRequiredConfig(this ScriptContext context) + { + context.ScriptMethods.AddRange(new ScriptMethods[] { + new DbScriptsAsync(), + new MyValidators(), + }); + } + } + + public class AutoQueryAppHost : AppSelfHostBase + { + public AutoQueryAppHost() + : base("AutoQuery", typeof(AutoQueryService).Assembly) { } + + public static readonly string SqlServerConnString = TestsConfig.SqlServerConnString; + public const string SqlServerNamedConnection = "SqlServer"; + public const string SqlServerProvider = "SqlServer2012"; + + public static string SqliteFileConnString = "~/App_Data/autoquery.sqlite".MapProjectPath(); + + public Action ConfigureFn { get; set; } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public Action ConfigureGrpc { get; set; } + + public override void Configure(Container container) + { + var grpcFeature = new GrpcFeature(App); + ConfigureGrpc?.Invoke(grpcFeature); + Plugins.Add(grpcFeature); + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + + dbFactory.RegisterConnection(SqlServerNamedConnection, SqlServerConnString, SqlServer2012Dialect.Provider); + dbFactory.RegisterDialectProvider(SqlServerProvider, SqlServer2012Dialect.Provider); + + using (var db = dbFactory.OpenDbConnection(SqlServerNamedConnection)) + { + db.DropTable(); + db.DropAndCreateTable(); + + db.Insert(new NamedRockstar { + Id = 1, + FirstName = "Microsoft", + LastName = "SQL Server", + Age = 27, + DateOfBirth = new DateTime(1989,1,1), + LivingStatus = LivingStatus.Alive, + }); + } + + using (var db = dbFactory.OpenDbConnectionString(SqliteFileConnString)) + { + db.DropTable(); + db.DropAndCreateTable(); + db.Insert(new Rockstar { + Id = 1, + FirstName = "Sqlite", + LastName = "File DB", + Age = 16, + DateOfBirth = new DateTime(2000, 8, 1), + LivingStatus = LivingStatus.Alive, + }); + } + + RegisterTypedRequestFilter((req, res, dto) => + req.Items[Keywords.DbInfo] = dto.ConvertTo()); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Database=test;User Id=test;Password=test;", + // SqlServerDialect.Provider)); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Database=test;User Id=test;Password=test;", + // SqlServer2012Dialect.Provider)); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Database=test;UID=root;Password=test", + // MySqlDialect.Provider)); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Port=5432;User Id=test;Password=test;Database=test;Pooling=true;MinPoolSize=0;MaxPoolSize=200", + // PostgreSqlDialect.Provider)); + + using (var db = container.Resolve().Open()) + { + db.DropTable(); + db.DropTable(); + db.CreateTable(); + db.CreateTable(); + + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + + db.InsertAll(SeedRockstars); + db.InsertAll(SeedAlbums); + db.InsertAll(SeedGenres); + db.InsertAll(SeedMovies); + db.InsertAll(SeedPagingTest); + + db.DropAndCreateTable(); + db.Insert(new AllFields + { + Id = 1, + NullableId = 2, + Byte = 3, + DateTime = new DateTime(2001, 01, 01), + NullableDateTime = new DateTime(2002, 02, 02), + Decimal = 4, + Double = 5.5, + Float = 6.6f, + Guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"), + NullableGuid = new Guid("7A2FDDD8-4BB0-4735-8230-A6AC79088489"), + Long = 7, + Short = 8, + String = "string", + TimeSpan = TimeSpan.FromHours(1), + NullableTimeSpan = TimeSpan.FromDays(1), + UInt = 9, + ULong = 10, + UShort = 11, + Enum = HttpStatusCode.MethodNotAllowed, + NullableEnum = HttpStatusCode.MethodNotAllowed, + }); + + db.DropAndCreateTable(); + db.InsertAll(SeedRockstars.Map(x => new Adhoc + { + Id = x.Id, + FirstName = x.FirstName, + LastName = x.LastName + })); + + db.CreateTable(); + + db.Insert(new TypeWithEnum { Id = 1, Name = "Value1", SomeEnum = SomeEnum.Value1, NSomeEnum = SomeEnum.Value1, SomeEnumAsInt = SomeEnumAsInt.Value1, NSomeEnumAsInt = SomeEnumAsInt.Value1 }); + db.Insert(new TypeWithEnum { Id = 2, Name = "Value2", SomeEnum = SomeEnum.Value2, NSomeEnum = SomeEnum.Value2, SomeEnumAsInt = SomeEnumAsInt.Value2, NSomeEnumAsInt = SomeEnumAsInt.Value2 }); + db.Insert(new TypeWithEnum { Id = 3, Name = "Value3", SomeEnum = SomeEnum.Value3, NSomeEnum = SomeEnum.Value3, SomeEnumAsInt = SomeEnumAsInt.Value3, NSomeEnumAsInt = SomeEnumAsInt.Value3 }); + } + + var autoQuery = new AutoQueryFeature + { + MaxLimit = 100, + EnableRawSqlFilters = true, + ResponseFilters = { + ctx => { + var executedCmds = new List(); + var supportedFns = new Dictionary>(StringComparer.OrdinalIgnoreCase) + { + {"ADD", (a,b) => a + b }, + {"MULTIPLY", (a,b) => a * b }, + {"DIVIDE", (a,b) => a / b }, + {"SUBTRACT", (a,b) => a - b }, + }; + foreach (var cmd in ctx.Commands) + { + if (!supportedFns.TryGetValue(cmd.Name, out var fn)) continue; + var label = !cmd.Suffix.IsNullOrWhiteSpace() ? cmd.Suffix.Trim().ToString() : cmd.ToString(); + ctx.Response.Meta[label] = fn(cmd.Args[0].ParseInt32(), cmd.Args[1].ParseInt32()).ToString(); + executedCmds.Add(cmd); + } + ctx.Commands.RemoveAll(executedCmds.Contains); + } + } + } + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName.EndsWith("son")) + ) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName.EndsWith("son")) + ) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName.EndsWith("son")) + ); + + Plugins.Add(autoQuery); + + ConfigureFn?.Invoke(this,container); + } + + public static Rockstar[] SeedRockstars = new[] { + new Rockstar { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1942, 11, 27), DateDied = new DateTime(1970, 09, 18), }, + new Rockstar { Id = 2, FirstName = "Jim", LastName = "Morrison", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1943, 12, 08), DateDied = new DateTime(1971, 07, 03), }, + new Rockstar { Id = 3, FirstName = "Kurt", LastName = "Cobain", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1967, 02, 20), DateDied = new DateTime(1994, 04, 05), }, + new Rockstar { Id = 4, FirstName = "Elvis", LastName = "Presley", Age = 42, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1935, 01, 08), DateDied = new DateTime(1977, 08, 16), }, + new Rockstar { Id = 5, FirstName = "David", LastName = "Grohl", Age = 44, LivingStatus = LivingStatus.Alive, DateOfBirth = new DateTime(1969, 01, 14), }, + new Rockstar { Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48, LivingStatus = LivingStatus.Alive, DateOfBirth = new DateTime(1964, 12, 23), }, + new Rockstar { Id = 7, FirstName = "Michael", LastName = "Jackson", Age = 50, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1958, 08, 29), DateDied = new DateTime(2009, 06, 05), }, + }; + + public static RockstarAlbum[] SeedAlbums = new[] { + new RockstarAlbum { Id = 1, RockstarId = 1, Name = "Electric Ladyland", Genre = "Funk" }, + new RockstarAlbum { Id = 2, RockstarId = 3, Name = "Bleach", Genre = "Grunge" }, + new RockstarAlbum { Id = 3, RockstarId = 3, Name = "Nevermind", Genre = "Grunge" }, + new RockstarAlbum { Id = 4, RockstarId = 3, Name = "In Utero", Genre = "Grunge" }, + new RockstarAlbum { Id = 5, RockstarId = 3, Name = "Incesticide", Genre = "Grunge" }, + new RockstarAlbum { Id = 6, RockstarId = 3, Name = "MTV Unplugged in New York", Genre = "Acoustic" }, + new RockstarAlbum { Id = 7, RockstarId = 5, Name = "Foo Fighters", Genre = "Grunge" }, + new RockstarAlbum { Id = 8, RockstarId = 6, Name = "Into the Wild", Genre = "Folk" }, + }; + + public static RockstarGenre[] SeedGenres = new[] { + new RockstarGenre { RockstarId = 1, Name = "Rock" }, + new RockstarGenre { RockstarId = 3, Name = "Grunge" }, + new RockstarGenre { RockstarId = 5, Name = "Alternative Rock" }, + new RockstarGenre { RockstarId = 6, Name = "Folk Rock" }, + }; + + public static Movie[] SeedMovies = new[] { + new Movie { ImdbId = "tt0111161", Title = "The Shawshank Redemption", Score = 9.2m, Director = "Frank Darabont", ReleaseDate = new DateTime(1995,2,17), TagLine = "Fear can hold you prisoner. Hope can set you free.", Genres = new List{"Crime","Drama"}, Rating = "R", }, + new Movie { ImdbId = "tt0068646", Title = "The Godfather", Score = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List {"Crime","Drama", "Thriller"}, Rating = "R", }, + new Movie { ImdbId = "tt1375666", Title = "Inception", Score = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List{"Action", "Mystery", "Sci-Fi", "Thriller"}, Rating = "PG-13", }, + new Movie { ImdbId = "tt0071562", Title = "The Godfather: Part II", Score = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List {"Crime","Drama", "Thriller"}, Rating = "R", }, + new Movie { ImdbId = "tt0060196", Title = "The Good, the Bad and the Ugly", Score = 9.0m, Director = "Sergio Leone", ReleaseDate = new DateTime(1967,12,29), TagLine = "They formed an alliance of hate to steal a fortune in dead man's gold", Genres = new List{"Adventure","Western"}, Rating = "R", }, + new Movie { ImdbId = "tt0114709", Title = "Toy Story", Score = 8.3m, Director = "John Lasseter", ReleaseDate = new DateTime(1995,11,22), TagLine = "A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy's room.", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "G", }, + new Movie { ImdbId = "tt2294629", Title = "Frozen", Score = 7.8m, Director = "Chris Buck", ReleaseDate = new DateTime(2013,11,27), TagLine = "Fearless optimist Anna teams up with Kristoff in an epic journey, encountering Everest-like conditions, and a hilarious snowman named Olaf", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "PG", }, + new Movie { ImdbId = "tt1453405", Title = "Monsters University", Score = 7.4m, Director = "Dan Scanlon", ReleaseDate = new DateTime(2013,06,21), TagLine = "A look at the relationship between Mike and Sulley during their days at Monsters University -- when they weren't necessarily the best of friends.", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "G", }, + new Movie { ImdbId = "tt0468569", Title = "The Dark Knight", Score = 9.0m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2008,07,18), TagLine = "When Batman, Gordon and Harvey Dent launch an assault on the mob, they let the clown out of the box, the Joker, bent on turning Gotham on itself and bringing any heroes down to his level.", Genres = new List{"Action","Crime","Drama"}, Rating = "PG-13", }, + new Movie { ImdbId = "tt0109830", Title = "Forrest Gump", Score = 8.8m, Director = "Robert Zemeckis", ReleaseDate = new DateTime(1996,07,06), TagLine = "Forrest Gump, while not intelligent, has accidentally been present at many historic moments, but his true love, Jenny Curran, eludes him.", Genres = new List{"Drama","Romance"}, Rating = "PG-13", }, + }; + + public static PagingTest[] SeedPagingTest = 250.Times(i => new PagingTest { Id = i, Name = "Name" + i, Value = i % 2 }).ToArray(); + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + } + } + + public class GrpcAutoQueryTests + { + private readonly ServiceStackHost appHost; + public IServiceClientAsync client; + + private static readonly int TotalRockstars = AutoQueryAppHost.SeedRockstars.Length; + private static readonly int TotalAlbums = AutoQueryAppHost.SeedAlbums.Length; + + public GrpcAutoQueryTests() + { + ConsoleLogFactory.Configure(); + appHost = new AutoQueryAppHost() + .Init() + .Start(TestsConfig.ListeningOn); + + GrpcClientFactory.AllowUnencryptedHttp2 = true; + client = new GrpcServiceClient(TestsConfig.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public List Rockstars => AutoQueryAppHost.SeedRockstars.ToList(); + + public List PagingTests => AutoQueryAppHost.SeedPagingTest.ToList(); + + [Test] + public async Task Can_execute_basic_query() + { + var response = await client.GetAsync(new QueryRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public async Task Can_execute_basic_query_NamedRockstar() + { + var response = await client.GetAsync(new QueryNamedRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("SQL Server")); + } + + [Test] + public async Task Can_execute_overridden_basic_query() + { + var response = await client.GetAsync(new QueryOverridedRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Can_execute_overridden_basic_query_with_case_insensitive_orderBy() + { + var response = await client.GetAsync(new QueryCaseInsensitiveOrderBy { Age = 27, OrderBy = "FirstName" }); + + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_AdhocRockstars_query() + { + var request = new QueryAdhocRockstars { FirstName = "Jimi", Include = "Total" }; + + Assert.That(request.ToGetUrl(), Is.EqualTo("/adhoc-rockstars?first_name=Jimi&include=Total")); + + var response = await client.GetAsync(request); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo(request.FirstName)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_on_overridden_CustomRockstar() + { + var response = await client.GetAsync(new QueryOverridedCustomRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Can_execute_basic_query_with_limits() + { + var response = await client.GetAsync(new QueryRockstars { Skip = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 2)); + + response = await client.GetAsync(new QueryRockstars { Take = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryRockstars { Skip = 2, Take = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition() + { + var response = await client.GetAsync(new QueryRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_implicitly() + { + var client = new GrpcServiceClient(TestsConfig.ListeningOn) { + RequestFilter = ctx => { + ctx.RequestHeaders.Add("query.Age", "27"); + ctx.RequestHeaders.Add("query.Include", "Total"); + } + }; + var response = await client.GetAsync(new QueryRockstarsImplicit()); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_on_CustomRockstar() + { + var response = await client.GetAsync(new QueryCustomRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_on_CustomRockstarSchema() + { + var response = await client.GetAsync(new QueryCustomRockstarsSchema { Age = 27, Include = "Total" }); + + response.PrintDump(); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results[0].FirstName, Is.Not.Null); + Assert.That(response.Results[0].LastName, Is.Not.Null); + Assert.That(response.Results[0].Age, Is.EqualTo(27)); + } + + [Test] + public async Task Can_execute_query_with_JOIN_on_RockstarAlbums() + { + var response = await client.GetAsync(new QueryJoinedRockstarAlbums { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", "Foo Fighters", "Into the Wild", + })); + + response = await client.GetAsync(new QueryJoinedRockstarAlbums { Age = 27, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(6)); + Assert.That(response.Results.Count, Is.EqualTo(6)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", + })); + + response = await client.GetAsync(new QueryJoinedRockstarAlbums { RockstarAlbumName = "Nevermind", Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + } + + [Test] + public async Task Can_execute_query_with_JOIN_on_RockstarAlbums_and_CustomSelectRockstar() + { + var response = await client.GetAsync(new QueryJoinedRockstarAlbumsCustomSelect { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var ages = response.Results.Select(x => x.Age); + Assert.That(ages.Contains(27 * 2)); + + var customRes = await client.GetAsync(new QueryJoinedRockstarAlbumsCustomSelectResponse { Include = "Total" }); + Assert.That(customRes.Total, Is.EqualTo(TotalAlbums)); + Assert.That(customRes.Results.Count, Is.EqualTo(TotalAlbums)); + ages = customRes.Results.Select(x => x.Age); + Assert.That(ages.Contains(27 * 2)); + } + + [Test] + public async Task Can_execute_query_with_multiple_JOINs_on_Rockstar_Albums_and_Genres() + { + var response = await client.GetAsync(new QueryMultiJoinRockstar { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", "Foo Fighters", "Into the Wild", + })); + + var genreNames = response.Results.Select(x => x.RockstarGenreName).Distinct(); + Assert.That(genreNames, Is.EquivalentTo(new[] { + "Rock", "Grunge", "Alternative Rock", "Folk Rock" + })); + + response = await client.GetAsync(new QueryMultiJoinRockstar { RockstarAlbumName = "Nevermind", Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + + response = await client.GetAsync(new QueryMultiJoinRockstar { RockstarGenreName = "Folk Rock", Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarGenreName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Folk Rock" })); + } + + [Test] + public async Task Can_execute_query_with_LEFTJOIN_on_RockstarAlbums() + { + var response = await client.GetAsync(new QueryRockstarAlbumsLeftJoin { IdNotEqualTo = 3, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalRockstars - 1)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 1)); + var albumNames = response.Results.Where(x => x.RockstarAlbumName != null).Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Foo Fighters", "Into the Wild" + })); + } + + [Test] + public async Task Can_execute_query_with_custom_LEFTJOIN_on_RockstarAlbums() + { + var response = await client.GetAsync(new QueryRockstarAlbumsCustomLeftJoin { IdNotEqualTo = 3, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalRockstars - 1)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 1)); + var albumNames = response.Results.Where(x => x.RockstarAlbumName != null).Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Foo Fighters", "Into the Wild" + })); + } + + [Test] + public async Task Can_execute_custom_QueryFields() + { + QueryResponse response; + response = await client.GetAsync(new QueryFieldRockstars { FirstName = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = await client.GetAsync(new QueryFieldRockstars { FirstNames = new[] { "Jim","Kurt" } }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryFieldRockstars { FirstNameCaseInsensitive = "jim" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = await client.GetAsync(new QueryFieldRockstars { FirstNameStartsWith = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryFieldRockstars { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryFieldRockstars { FirstNameBetween = new[] {"A","F"} }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryFieldRockstars + { + LastNameEndsWith = "son", + OrLastName = "Hendrix" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim", + OrLastName = "Presley" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryFieldRockstars { Age = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public async Task Can_execute_combination_of_QueryFields() + { + QueryResponse response; + + response = await client.GetAsync(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim", + LastNameEndsWith = "son", + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = await client.GetAsync(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim", + OrLastName = "Cobain", + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Does_escape_values() + { + QueryResponse response; + + response = await client.GetAsync(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim'\"", + }); + Assert.That(response.Results?.Count ?? 0, Is.EqualTo(0)); + } + + [Test] + public async Task Does_use_custom_model_to_select_columns() + { + var response = await client.GetAsync(new QueryRockstarAlias { RockstarAlbumName = "Nevermind" }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].RockstarId, Is.EqualTo(3)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Kurt")); + Assert.That(response.Results[0].RockstarAlbumName, Is.EqualTo("Nevermind")); + } + + [Test] + public async Task Does_allow_adding_attributes_dynamically() + { + typeof(QueryFieldRockstarsDynamic) + .GetProperty("Age") + .AddAttributes(new QueryDbFieldAttribute { Operand = ">=" }); + + var response = await client.GetAsync(new QueryFieldRockstarsDynamic { Age = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public async Task Does_execute_typed_QueryFilters() + { + // QueryFilter appends additional: x => x.LastName.EndsWith("son") + var response = await client.GetAsync(new QueryRockstarsFilter { Age = 27 }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + var custom = await client.GetAsync(new QueryCustomRockstarsFilter { Age = 27 }); + Assert.That(custom.Results.Count, Is.EqualTo(1)); + + response = await client.GetAsync(new QueryRockstarsIFilter { Age = 27 }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Can_execute_OR_QueryFilters() + { + var response = await client.GetAsync(new QueryOrRockstars { Age = 42, FirstName = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Does_retain_implicit_convention_when_not_overriding_template_or_ValueFormat() + { + var response = await client.GetAsync(new QueryFieldsImplicitConventions { FirstNameContains = "im" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryFieldsImplicitConventions { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Can_execute_OR_QueryFilters_Fields() + { + var response = await client.GetAsync(new QueryOrRockstarsFields + { + FirstName = "Jim", + LastName = "Vedder", + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Can_execute_Explicit_conventions() + { + var response = await client.GetAsync(new QueryRockstarsConventions { Ids = new[] {1, 2, 3} }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryRockstarsConventions { AgeOlderThan = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryRockstarsConventions { AgeGreaterThanOrEqualTo = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = await client.GetAsync(new QueryRockstarsConventions { AgeGreaterThan = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = await client.GetAsync(new QueryRockstarsConventions { GreaterThanAge = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryRockstarsConventions { FirstNameStartsWith = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = await client.GetAsync(new QueryRockstarsConventions { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = await client.GetAsync(new QueryRockstarsConventions { LastNameContains = "e" }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryRockstarsConventions { DateOfBirthGreaterThan = new DateTime(1960, 01, 01) }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = await client.GetAsync(new QueryRockstarsConventions { DateDiedLessThan = new DateTime(1980, 01, 01) }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_In_OR_Queries() + { + QueryResponse response; + response = await client.GetAsync(new QueryGetRockstars()); + Assert.That(response.Results?.Count ?? 0, Is.EqualTo(0)); + + response = await client.GetAsync(new QueryGetRockstars { Ids = new[] { 1, 2, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetAsync(new QueryGetRockstars { Ages = new[] { 42, 44 }.ToList() }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryGetRockstars { FirstNames = new[] { "Jim", "Kurt" }.ToList() }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetAsync(new QueryGetRockstars { IdsBetween = new[] { 1, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Does_ignore_empty_collection_filters_by_default() + { + QueryResponse response; + response = await client.GetAsync(new QueryRockstarFilters()); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryAppHost.SeedRockstars.Length)); + + response = await client.GetAsync(new QueryRockstarFilters + { + Ids = new int[] {}, + Ages = new List(), + FirstNames = new List(), + IdsBetween = new int[] {}, + }); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryAppHost.SeedRockstars.Length)); + } + + [Test] + public async Task Can_query_Movie_Ratings() + { + var response = await client.GetAsync(new QueryMovies { Ratings = new[] {"G","PG-13"} }); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + response = await client.GetAsync(new QueryMovies { + Ids = new[] { 1, 2 }, + ImdbIds = new[] { "tt0071562", "tt0060196" }, + Ratings = new[] { "G", "PG-13" } + }); + Assert.That(response.Results.Count, Is.EqualTo(9)); + } + + [Test] + public async Task Does_implicitly_OrderBy_PrimaryKey_when_limits_is_specified() + { + var movies = await client.GetAsync(new SearchMovies { Take = 100 }); + var ids = movies.Results.Map(x => x.Id); + var orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var rockstars = await client.GetAsync(new SearchMovies { Take = 100 }); + ids = rockstars.Results.Map(x => x.Id); + orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public async Task Can_OrderBy_queries() + { + var movies = await client.GetAsync(new SearchMovies { Take = 100, OrderBy = "ImdbId" }); + var ids = movies.Results.Map(x => x.ImdbId); + var orderedIds = ids.OrderBy(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetAsync(new SearchMovies { Take = 100, OrderBy = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetAsync(new SearchMovies { Take = 100, OrderByDesc = "ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = ids.OrderByDescending(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetAsync(new SearchMovies { Take = 100, OrderByDesc = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetAsync(new SearchMovies { Take = 100, OrderBy = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetAsync(new SearchMovies { Take = 100, OrderByDesc = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public async Task Does_not_query_Ignored_properties() + { + var response = await client.GetAsync(new QueryUnknownRockstars { + UnknownProperty = "Foo", + UnknownInt = 1, + Include = "Total" + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public async Task Can_Query_Rockstars_with_References() + { + var response = await client.GetAsync(new QueryRockstarsWithReferences { + Age = 27 + }); + + Assert.That(response.Results.Count, Is.EqualTo(3)); + + var jimi = response.Results.First(x => x.FirstName == "Jimi"); + Assert.That(jimi.Albums.Count, Is.EqualTo(1)); + Assert.That(jimi.Albums[0].Name, Is.EqualTo("Electric Ladyland")); + + var jim = response.Results.First(x => x.FirstName == "Jim"); + Assert.That(jim.Albums, Is.Null); + + var kurt = response.Results.First(x => x.FirstName == "Kurt"); + Assert.That(kurt.Albums.Count, Is.EqualTo(5)); + + response = await client.GetAsync(new QueryRockstarsWithReferences + { + Age = 27, + Fields = "Id,FirstName,Age" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.All(x => x.Albums == null)); + + response = await client.GetAsync(new QueryRockstarsWithReferences + { + Age = 27, + Fields = "Id,FirstName,Age,Albums" + }); + Assert.That(response.Results.Where(x => x.FirstName != "Jim").All(x => x.Albums != null)); + } + + [Test] + public async Task Can_Query_RockstarReference_without_References() + { + var response = await client.GetAsync(new QueryCustomRockstarsReferences + { + Age = 27 + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results.All(x => x.Albums == null)); + } + + [Test] + public async Task Can_Query_AllFields_Guid() + { + var guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"); + var response = await client.GetAsync(new QueryAllFields { + Guid = guid + }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + + Assert.That(response.Results[0].Guid, Is.EqualTo(guid)); + } + + [Test] + public async Task Does_populate_Total() + { + var response = await client.GetAsync(new QueryRockstars { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta, Is.Null); + + response = await client.GetAsync(new QueryRockstars { Include = "COUNT" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetAsync(new QueryRockstars { Include = "COUNT(*)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetAsync(new QueryRockstars { Include = "COUNT(DISTINCT LivingStatus), Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetAsync(new QueryRockstars { Include = "Count(*), Min(Age), Max(Age), Sum(Id)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetAsync(new QueryRockstars { Age = 27, Include = "Count(*), Min(Age), Max(Age), Sum(Id)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public async Task Can_Include_Aggregates_in_AutoQuery() + { + var response = await client.GetAsync(new QueryRockstars { Include = "COUNT" }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = await client.GetAsync(new QueryRockstars { Include = "COUNT(*)" }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = await client.GetAsync(new QueryRockstars { Include = "COUNT(DISTINCT LivingStatus)" }); + Assert.That(response.Meta["COUNT(DISTINCT LivingStatus)"], Is.EqualTo("2")); + + response = await client.GetAsync(new QueryRockstars { Include = "MIN(Age)" }); + Assert.That(response.Meta["MIN(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = await client.GetAsync(new QueryRockstars { Include = "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age)", OrderBy = "Id" }); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + Assert.That(double.Parse(response.Meta["Avg(Age)"]), Is.EqualTo(Rockstars.Average(x => x.Age)).Within(1d)); + //Not supported by Sqlite + //Assert.That(response.Meta["First(Id)"], Is.EqualTo(Rockstars.First().Id.ToString())); + //Assert.That(response.Meta["Last(Id)"], Is.EqualTo(Rockstars.Last().Id.ToString())); + + response = await client.GetAsync(new QueryRockstars { Age = 27, Include = "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age)", OrderBy = "Id" }); + var rockstars27 = Rockstars.Where(x => x.Age == 27).ToList(); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(rockstars27.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(rockstars27.Map(x => x.Id).Sum().ToString())); + Assert.That(double.Parse(response.Meta["Avg(Age)"]), Is.EqualTo(rockstars27.Average(x => x.Age)).Within(1d)); + //Not supported by Sqlite + //Assert.That(response.Meta["First(Id)"], Is.EqualTo(rockstars27.First().Id.ToString())); + //Assert.That(response.Meta["Last(Id)"], Is.EqualTo(rockstars27.Last().Id.ToString())); + } + + [Test] + public async Task Does_ignore_unknown_aggregate_commands() + { + var response = await client.GetAsync(new QueryRockstars { Include = "FOO(1), Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta, Is.Null); + + response = await client.GetAsync(new QueryRockstars { Include = "FOO(1), Min(Age), Bar('a') alias, Count(*), Baz(1,'foo')" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + } + + [Test] + public async Task Can_Include_Aggregates_in_AutoQuery_with_Aliases() + { + var response = await client.GetAsync(new QueryRockstars { Include = "COUNT(*) count" }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + + response = await client.GetAsync(new QueryRockstars { Include = "COUNT(DISTINCT LivingStatus) as uniquestatus" }); + Assert.That(response.Meta["uniquestatus"], Is.EqualTo("2")); + + response = await client.GetAsync(new QueryRockstars { Include = "MIN(Age) minage" }); + Assert.That(response.Meta["minage"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = await client.GetAsync(new QueryRockstars { Include = "Count(*) count, Min(Age) min, Max(Age) max, Sum(Id) sum" }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["min"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["max"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["sum"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + } + + [Test] + public async Task Can_execute_custom_aggregate_functions() + { + var response = await client.GetAsync(new QueryRockstars { + Include = "ADD(6,2), Multiply(6,2) SixTimesTwo, Subtract(6,2), divide(6,2) TheDivide" + }); + Assert.That(response.Meta["ADD(6,2)"], Is.EqualTo("8")); + Assert.That(response.Meta["SixTimesTwo"], Is.EqualTo("12")); + Assert.That(response.Meta["Subtract(6,2)"], Is.EqualTo("4")); + Assert.That(response.Meta["TheDivide"], Is.EqualTo("3")); + } + + [Test] + public async Task Sending_empty_ChangeDb_returns_default_info() + { + var response = await client.GetAsync(new ChangeDb()); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + + var aqResponse = await client.GetAsync(new QueryChangeDb()); + Assert.That(aqResponse.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public async Task Can_ChangeDb_with_Named_Connection() + { + var response = await client.GetAsync(new ChangeDb { NamedConnection = AutoQueryAppHost.SqlServerNamedConnection }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = await client.GetAsync(new QueryChangeDb { NamedConnection = AutoQueryAppHost.SqlServerNamedConnection }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public async Task Can_ChangeDb_with_ConnectionString() + { + var response = await client.GetAsync(new ChangeDb { ConnectionString = AutoQueryAppHost.SqliteFileConnString }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Sqlite")); + + var aqResponse = await client.GetAsync(new QueryChangeDb { ConnectionString = AutoQueryAppHost.SqliteFileConnString }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Sqlite")); + } + + [Test] + public async Task Can_ChangeDb_with_ConnectionString_and_Provider() + { + var response = await client.GetAsync(new ChangeDb + { + ConnectionString = AutoQueryAppHost.SqlServerConnString, + ProviderName = AutoQueryAppHost.SqlServerProvider, + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = await client.GetAsync(new QueryChangeDb + { + ConnectionString = AutoQueryAppHost.SqlServerConnString, + ProviderName = AutoQueryAppHost.SqlServerProvider, + }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public async Task Can_Change_Named_Connection_with_ConnectionInfoAttribute() + { + var response = await client.GetAsync(new ChangeConnectionInfo()); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = await client.GetAsync(new QueryChangeConnectionInfo()); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public async Task Does_return_MaxLimit_results() + { + QueryResponse response; + response = await client.GetAsync(new QueryPagingTest { Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = await client.GetAsync(new QueryPagingTest { Skip = 200, Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(PagingTests.Skip(200).Count())); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = await client.GetAsync(new QueryPagingTest { Value = 1, Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count(x => x.Value == 1))); + } + + [Test] + public async Task Can_query_on_ForeignKey_and_Index() + { + QueryResponse response; + response = await client.GetAsync(new QueryRockstarAlbums { RockstarId = 3, Include = "Total" }); //Hash + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Total, Is.EqualTo(5)); + + response = await client.GetAsync(new QueryRockstarAlbums { RockstarId = 3, Id = 3, Include = "Total" }); //Hash + Range + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Name, Is.EqualTo("Nevermind")); + + //Hash + Range BETWEEN + response = await client.GetAsync(new QueryRockstarAlbums + { + RockstarId = 3, + IdBetween = new[] { 2, 3 }, + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(2)); + + //Hash + Range BETWEEN + Filter + response = await client.GetAsync(new QueryRockstarAlbums + { + RockstarId = 3, + IdBetween = new[] { 2, 3 }, + Name = "Nevermind", + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Id, Is.EqualTo(3)); + + //Hash + LocalSecondaryIndex + response = await client.GetAsync(new QueryRockstarAlbums { RockstarId = 3, Genre = "Grunge", Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + Assert.That(response.Total, Is.EqualTo(4)); + + response.PrintDump(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/GrpcIntegrationTests.cs b/tests/ServiceStack.Extensions.Tests/GrpcIntegrationTests.cs new file mode 100644 index 00000000000..9039c6c596c --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/GrpcIntegrationTests.cs @@ -0,0 +1,75 @@ +using System; +using System.Runtime.Serialization; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Text; + +namespace ServiceStack.Extensions.Tests +{ + public class GrpcIntegrationTests + { + [Route("/hello")] + [Route("/hello/{Name}")] + [DataContract] + public partial class Hello + : IReturn + { + [DataMember(Order = 1)] + public virtual string Name { get; set; } + } + + [DataContract] + public partial class HelloResponse + { + [DataMember(Order = 1)] + public virtual string Result { get; set; } + + [DataMember(Order = 2)] + public virtual ResponseStatus ResponseStatus { get; set; } + } + + // [Test] // Integration Test + public async Task Can_call_external_secure_service_using_remote_certificate() + { + try + { + // File.WriteAllBytes("grpc.crt", "https://todoworld.servicestack.net/grpc.crt".GetBytesFromUrl()); + // var cert = new X509Certificate2("grpc.crt"); + var cert = new X509Certificate2("https://todoworld.servicestack.net/grpc.crt".GetBytesFromUrl()); + + var client = new GrpcServiceClient("https://todoworld.servicestack.net:50051", + cert, GrpcUtils.AllowSelfSignedCertificatesFrom("todoworld.servicestack.net")); + + var response = await client.GetAsync(new Hello {Name = "gRPC SSL C# 50051"}); + response.Result.Print(); + + client = new GrpcServiceClient("https://todoworld.servicestack.net:5051", + cert, GrpcUtils.AllowSelfSignedCertificatesFrom("todoworld.servicestack.net")); + + response = await client.GetAsync(new Hello {Name = "gRPC SSL C# 5051"}); + + response.Result.Print(); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + // [Test] // Integration Test + public async Task Can_call_external_plaintext_service() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + var client = new GrpcServiceClient("http://todoworld.servicestack.net:50054"); + var response = await client.GetAsync(new Hello {Name = "gRPC Text C# 50054"}); + response.Result.Print(); + + client = new GrpcServiceClient("http://todoworld.servicestack.net:5054"); + response = await client.GetAsync(new Hello {Name = "gRPC Text C# 5054"}); + response.Result.Print(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/GrpcServerEventsTests.cs b/tests/ServiceStack.Extensions.Tests/GrpcServerEventsTests.cs new file mode 100644 index 00000000000..28865b0b83b --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/GrpcServerEventsTests.cs @@ -0,0 +1,130 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Text; + +namespace ServiceStack.Extensions.Tests +{ + public class GrpcServerEventsTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(GrpcServerEventsTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new GrpcFeature(App)); + Plugins.Add(new ServerEventsFeature()); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) => services.AddServiceStackGrpc(); + + public override void Configure(IApplicationBuilder app) => app.UseRouting(); + } + + private readonly ServiceStackHost appHost; + public GrpcServerEventsTests() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + appHost = new AppHost() + .Init() + .Start(TestsConfig.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private static GrpcServiceClient GetClient() => new GrpcServiceClient(TestsConfig.BaseUri); + + [Test] + public async Task Can_subscribe_to_ServerEvents() + { + var client = GetClient(); + + void AssertMessage(StreamServerEventsResponse msg) + { + Assert.That(msg.EventId, Is.GreaterThan(0)); + Assert.That(msg.Channels, Is.EqualTo(new[] { "home" })); + Assert.That(msg.Json, Is.Not.Null); + Assert.That(msg.Op, Is.EqualTo("cmd")); + Assert.That(msg.UserId, Is.EqualTo("-1")); + Assert.That(msg.DisplayName, Is.Not.Null); + Assert.That(msg.ProfileUrl, Is.Not.Null); + Assert.That(msg.IsAuthenticated, Is.False); + } + + var i = 0; + await foreach (var msg in client.StreamAsync(new StreamServerEvents { Channels = new[] { "home" } })) + { + if (i == 0) + { + Assert.That(msg.Selector, Is.EqualTo("cmd.onConnect")); + Assert.That(msg.Id, Is.Not.Null); + Assert.That(msg.UnRegisterUrl, Is.Not.Null); + Assert.That(msg.UpdateSubscriberUrl, Is.Not.Null); + Assert.That(msg.HeartbeatUrl, Is.Not.Null); + Assert.That(msg.HeartbeatIntervalMs, Is.GreaterThan(0)); + Assert.That(msg.IdleTimeoutMs, Is.GreaterThan(0)); + AssertMessage(msg); + } + else if (i == 1) + { + Assert.That(msg.Selector, Is.EqualTo("cmd.onJoin")); + AssertMessage(msg); + } + + $"\n\n{i}".Print(); + msg.PrintDump(); + + if (++i == 2) + break; + } + Assert.That(i, Is.EqualTo(2)); + } + + [Test] + public async Task Does_receive_all_messages() + { + var client1 = GetClient(); + var client2 = GetClient(); + + Task.Factory.StartNew(async () => { + await Task.Delay(500); + await client2.PostAsync(new PostChatToChannel { + Channel = "send", + From = nameof(client2), + Message = "Hello from client2", + Selector = "cmd.chat", + }); + }); + + var responses = new List(); + await foreach (var msg in client1.StreamAsync(new StreamServerEvents { Channels = new[] { "send" } })) + { + responses.Add(msg); + + if (msg.Selector == "cmd.chat") + break; + } + + Assert.That(responses[0].Selector, Is.EqualTo("cmd.onConnect")); + Assert.That(responses[1].Selector, Is.EqualTo("cmd.onJoin")); + Assert.That(responses[2].Selector, Is.EqualTo("cmd.chat")); + var obj = (Dictionary) JSON.parse(responses[2].Json); + Assert.That(obj["message"], Is.EqualTo("Hello from client2")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/GrpcTests.cs b/tests/ServiceStack.Extensions.Tests/GrpcTests.cs new file mode 100644 index 00000000000..328e95a9f29 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/GrpcTests.cs @@ -0,0 +1,934 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; +using System.ServiceModel; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using Grpc.Core; +using Grpc.Net.Client; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf; +using ProtoBuf.Grpc.Client; +using ProtoBuf.Grpc.Configuration; +using ProtoBuf.Grpc.Server; +using ServiceStack.Auth; +using ServiceStack.FluentValidation; +using ServiceStack.FluentValidation.Validators; +using ServiceStack.Model; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.Extensions.Tests +{ + [ServiceContract(Name = "Hyper.Calculator")] + public interface ICalculator + { + ValueTask MultiplyAsync(MultiplyRequest request); + } + + [DataContract] + public class MultiplyRequest + { + [DataMember(Order = 1)] + public int X { get; set; } + + [DataMember(Order = 2)] + public int Y { get; set; } + } + + [DataContract] + public class MultiplyResult + { + [DataMember(Order = 1)] + public int Result { get; set; } + } + +// [ServiceContract] +// public interface ITimeService +// { +// IAsyncEnumerable SubscribeAsync(CallContext context = default); +// } + +// [ProtoContract] +// public class TimeResult +// { +// [ProtoMember(1, DataFormat = DataFormat.WellKnown)] +// public DateTime Time { get; set; } +// } + + public class MyCalculator : ICalculator + { + ValueTask ICalculator.MultiplyAsync(MultiplyRequest request) + { + var result = new MultiplyResult { Result = request.X * request.Y }; + return new ValueTask(result); + } + } + +// public class MyTimeService : ITimeService +// { +// public IAsyncEnumerable SubscribeAsync(CallContext context = default) +// => SubscribeAsyncImpl(default); // context.CancellationToken); +// +// private async IAsyncEnumerable SubscribeAsyncImpl([EnumeratorCancellation] CancellationToken cancel) +// { +// while (!cancel.IsCancellationRequested) +// { +// await Task.Delay(TimeSpan.FromSeconds(10)); +// yield return new TimeResult { Time = DateTime.UtcNow }; +// } +// } +// } + + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddCodeFirstGrpc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); +// endpoints.MapGrpcService(); + }); + } + } + + [DataContract] + public class Multiply : IReturn + { + [DataMember(Order = 1)] + public int X { get; set; } + + [DataMember(Order = 2)] + public int Y { get; set; } + } + + [DataContract] + public class MultiplyResponse + { + [DataMember(Order = 1)] + public int Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class Incr : IReturnVoid + { + internal static int Counter = 0; + + [DataMember(Order = 1)] + public int Amount { get; set; } + } + + [DataContract] + public class GetHello : IReturn, IGet + { + [DataMember(Order = 1)] + public string Name { get; set; } + } + + [DataContract] + public class AnyHello : IReturn + { + [DataMember(Order = 1)] + public string Name { get; set; } + } + + [DataContract] + public class HelloResponse + { + [DataMember(Order = 1)] + public string Result { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class Throw : IReturn + { + [DataMember(Order = 1)] + public string Message { get; set; } + } + + [DataContract] + public class ThrowVoid : IReturnVoid + { + [DataMember(Order = 1)] + public string Message { get; set; } + } + + [DataContract] + public class AddHeader : IReturnVoid + { + [DataMember(Order = 1)] + public string Name { get; set; } + [DataMember(Order = 2)] + public string Value { get; set; } + } + + [DataContract] + public class TriggerValidators : IReturn + { + [DataMember(Order = 1)] + public string CreditCard { get; set; } + [DataMember(Order = 2)] + public string Email { get; set; } + [DataMember(Order = 3)] + public string Empty { get; set; } + [DataMember(Order = 4)] + public string Equal { get; set; } + [DataMember(Order = 5)] + public int ExclusiveBetween { get; set; } + [DataMember(Order = 6)] + public int GreaterThanOrEqual { get; set; } + [DataMember(Order = 7)] + public int GreaterThan { get; set; } + [DataMember(Order = 8)] + public int InclusiveBetween { get; set; } + [DataMember(Order = 9)] + public string Length { get; set; } + [DataMember(Order = 10)] + public int LessThanOrEqual { get; set; } + [DataMember(Order = 11)] + public int LessThan { get; set; } + [DataMember(Order = 12)] + public string NotEmpty { get; set; } + [DataMember(Order = 13)] + public string NotEqual { get; set; } + [DataMember(Order = 14)] + public string Null { get; set; } + [DataMember(Order = 15)] + public string RegularExpression { get; set; } + [DataMember(Order = 16)] + public decimal ScalePrecision { get; set; } + } + + public class TriggerValidatorsValidator : AbstractValidator + { + public TriggerValidatorsValidator() + { + RuleFor(x => x.CreditCard).CreditCard(); + RuleFor(x => x.Email).EmailAddress(); + RuleFor(x => x.Empty).Empty(); + RuleFor(x => x.Equal).Equal("Equal"); + RuleFor(x => x.ExclusiveBetween).ExclusiveBetween(10, 20); + RuleFor(x => x.GreaterThanOrEqual).GreaterThanOrEqualTo(10); + RuleFor(x => x.GreaterThan).GreaterThan(10); + RuleFor(x => x.InclusiveBetween).InclusiveBetween(10, 20); + RuleFor(x => x.Length).Length(10); + RuleFor(x => x.LessThanOrEqual).LessThanOrEqualTo(10); + RuleFor(x => x.LessThan).LessThan(10); + RuleFor(x => x.NotEmpty).NotEmpty(); + RuleFor(x => x.NotEqual).NotEqual("NotEqual"); + RuleFor(x => x.Null).Null(); + RuleFor(x => x.RegularExpression).Matches(@"^[a-z]*$"); + RuleFor(x => x.ScalePrecision).SetValidator(new ScalePrecisionValidator(1, 1)); + } + } + + [Route("/channels/{Channel}/chat")] + [DataContract] + public class PostChatToChannel : IReturn, IPost + { + [DataMember(Order = 1)] + public string From { get; set; } + [DataMember(Order = 2)] + public string ToUserId { get; set; } + [DataMember(Order = 3)] + public string Channel { get; set; } + [DataMember(Order = 4)] + public string Message { get; set; } + [DataMember(Order = 5)] + public string Selector { get; set; } + } + + [DataContract] + public class ChatMessage + { + [DataMember(Order = 1)] + public long Id { get; set; } + [DataMember(Order = 2)] + public string Channel { get; set; } + [DataMember(Order = 3)] + public string FromUserId { get; set; } + [DataMember(Order = 4)] + public string FromName { get; set; } + [DataMember(Order = 5)] + public string DisplayName { get; set; } + [DataMember(Order = 6)] + public string Message { get; set; } + [DataMember(Order = 7)] + public string UserAuthId { get; set; } + [DataMember(Order = 8)] + public bool Private { get; set; } + } + + public class CustomException : Exception, IResponseStatusConvertible, IHasStatusCode + { + public ResponseStatus ToResponseStatus() => new ResponseStatus + { + ErrorCode = "CustomErrorCode", + Message = "Custom Error Message", + }; + + public int StatusCode { get; } = 401; + } + + [DataContract] + public class ThrowCustom : IReturn {} + + [DataContract] + public class ThrowCustomResponse + { + [DataMember(Order = 1)] + public ResponseStatus ResponseStatus { get; set; } + } + + + public class MyServices : Service + { + public Task Post(Multiply request) + { + var result = new MultiplyResponse { Result = request.X * request.Y }; + return Task.FromResult(result); + } + + public void Any(Incr request) + { + request.Amount.Times(x => Interlocked.Increment(ref Incr.Counter)); + } + + public object Get(GetHello request) => new HelloResponse { Result = $"Hello, {request.Name}!" }; + + public object Any(AnyHello request) => new HelloResponse { Result = $"Hello, {request.Name}!" }; + + public object Get(Throw request) => throw new Exception(request.Message ?? "Error in Throw"); + + public void Get(ThrowVoid request) => throw new Exception(request.Message ?? "Error in ThrowVoid"); + + public object Get(ThrowCustom request) => request; //thrown in Global Request Filters + + public object Post(TriggerValidators request) => new EmptyResponse(); + + public void Get(AddHeader request) + { + Response.AddHeader(request.Name, request.Value); + } + + public IServerEvents ServerEvents { get; set; } + public int Id = 0; + + public async Task Any(PostChatToChannel request) + { + var msg = new ChatMessage + { + Id = Id++, + Channel = request.Channel, + FromUserId = request.From, + FromName = request.From, + Message = request.Message.HtmlEncode(), + }; + + await ServerEvents.NotifyChannelAsync(request.Channel, request.Selector, msg); + + return msg; + } + } + + /// + /// TODO: + /// - Exceptions + /// - Validation + /// - Auth + /// - JWT + /// - Basic Auth + /// - AutoQuery + /// - Multitenancy? + /// + + public class GrpcTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(GrpcTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + RegisterService(); + + Plugins.Add(new ValidationFeature()); + Plugins.Add(new GrpcFeature(App)); + + GlobalRequestFilters.Add((req, res, dto) => { + if (dto is ThrowCustom) + throw new CustomException(); + }); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + }); + } + } + + private readonly ServiceStackHost appHost; + public GrpcTests() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + appHost = new AppHost() + .Init() + .Start(TestsConfig.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private static GrpcServiceClient GetClient() => new GrpcServiceClient(TestsConfig.BaseUri); + + [Test] + public async Task Can_call_MultiplyRequest_Grpc_Service_ICalculator() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + using var http = GrpcChannel.ForAddress(TestsConfig.BaseUri); + var calculator = http.CreateGrpcService(); + var result = await calculator.MultiplyAsync(new MultiplyRequest { X = 12, Y = 4 }); + Assert.That(result.Result, Is.EqualTo(48)); + } + + [Test] + public async Task Can_call_Multiply_Grpc_Service_GrpcChannel() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + using var http = GrpcChannel.ForAddress(TestsConfig.BaseUri); + + var response = await http.CreateCallInvoker().Execute(new Multiply { X = 12, Y = 4 }, "GrpcServices", + GrpcConfig.GetServiceName(HttpMethods.Post, nameof(Multiply))); + + Assert.That(response.Result, Is.EqualTo(48)); + } + + [Test] + public async Task Can_call_Multiply_Grpc_Service_GrpcServiceClient() + { + using var client = GetClient(); + + var response = await client.PostAsync(new Multiply { X = 12, Y = 4 }); + Assert.That(response.Result, Is.EqualTo(48)); + } + + [Test] + public void Can_call_Multiply_Grpc_Service_GrpcServiceClient_sync() + { + using var client = GetClient(); + + var response = client.Post(new Multiply { X = 12, Y = 4 }); + Assert.That(response.Result, Is.EqualTo(48)); + } + + [Test] + public async Task Can_call_Incr_ReturnVoid_GrpcServiceClient() + { + using var client = GetClient(); + + Incr.Counter = 0; + + await client.PublishAsync(new Incr { Amount = 1 }); + Assert.That(Incr.Counter, Is.EqualTo(1)); + + await client.PublishAsync(new Incr { Amount = 2 }); + Assert.That(Incr.Counter, Is.EqualTo(3)); + } + + [Test] + public async Task Can_call_GetHello_with_Get_or_Send() + { + using var client = GetClient(); + + var response = await client.GetAsync(new GetHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + + response = await client.SendAsync(new GetHello { Name = "SEND" }); + Assert.That(response.Result, Is.EqualTo($"Hello, SEND!")); + } + + [Test] + public void Can_call_GetHello_with_Get_or_Send_sync() + { + using var client = GetClient(); + + var response = client.Get(new GetHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + + response = client.Send(new GetHello { Name = "SEND" }); + Assert.That(response.Result, Is.EqualTo($"Hello, SEND!")); + } + + [Test] + public async Task Can_call_AnyHello_with_Get_Post_or_Send() + { + using var client = GetClient(); + + var response = await client.GetAsync(new AnyHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + + response = await client.PostAsync(new AnyHello { Name = "POST" }); + Assert.That(response.Result, Is.EqualTo($"Hello, POST!")); + + response = await client.SendAsync(new GetHello { Name = "SEND" }); + Assert.That(response.Result, Is.EqualTo($"Hello, SEND!")); + } + + [Test] + public void Can_call_AnyHello_with_Get_Post_or_Send_sync() + { + using var client = GetClient(); + + var response = client.Get(new AnyHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + + response = client.Post(new AnyHello { Name = "POST" }); + Assert.That(response.Result, Is.EqualTo($"Hello, POST!")); + + response = client.Send(new GetHello { Name = "SEND" }); + Assert.That(response.Result, Is.EqualTo($"Hello, SEND!")); + } + + [Test] + public async Task Can_call_AnyHello_Batch() + { + using var client = GetClient(); + + var requests = new[] { + new AnyHello {Name = "A"}, + new AnyHello {Name = "B"}, + new AnyHello {Name = "C"}, + }; + var responses = await client.SendAllAsync(requests); + Assert.That( responses.Map(x => x.Result), Is.EqualTo(new[] { + $"Hello, A!", + $"Hello, B!", + $"Hello, C!", + })); + } + + [Test] + public void Can_call_AnyHello_Batch_sync() + { + using var client = GetClient(); + + var requests = new[] { + new AnyHello {Name = "A"}, + new AnyHello {Name = "B"}, + new AnyHello {Name = "C"}, + }; + var responses = client.SendAll(requests); + Assert.That( responses.Map(x => x.Result), Is.EqualTo(new[] { + $"Hello, A!", + $"Hello, B!", + $"Hello, C!", + })); + } + + [Test] + public async Task Can_call_Incr_Batch_ReturnVoid() + { + using var client = GetClient(); + + Incr.Counter = 0; + + var requests = new[] { + new Incr {Amount = 1}, + new Incr {Amount = 2}, + new Incr {Amount = 3}, + }; + await client.PublishAllAsync(requests); + + Assert.That(Incr.Counter, Is.EqualTo(1 + 2 + 3)); + } + + [Test] + public void Can_call_Incr_Batch_ReturnVoid_sync() + { + using var client = GetClient(); + + Incr.Counter = 0; + + var requests = new[] { + new Incr {Amount = 1}, + new Incr {Amount = 2}, + new Incr {Amount = 3}, + }; + client.PublishAll(requests); + + Assert.That(Incr.Counter, Is.EqualTo(1 + 2 + 3)); + } + + [Test] + public async Task Does_throw_WebServiceException() + { + using var client = GetClient(); + + try + { + await client.GetAsync(new Throw { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public void Does_throw_WebServiceException_sync() + { + using var client = GetClient(); + + try + { + client.Get(new Throw { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public async Task Does_throw_WebServiceException_ReturnVoid() + { + using var client = GetClient(); + + try + { + await client.GetAsync(new ThrowVoid { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public void Does_throw_WebServiceException_ReturnVoid_sync() + { + using var client = GetClient(); + + try + { + client.Get(new ThrowVoid { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public async Task Triggering_all_validators_returns_right_ErrorCode() + { + var client = GetClient(); + var request = new TriggerValidators + { + CreditCard = "NotCreditCard", + Email = "NotEmail", + Empty = "NotEmpty", + Equal = "NotEqual", + ExclusiveBetween = 1, + GreaterThan = 1, + GreaterThanOrEqual = 1, + InclusiveBetween = 1, + Length = "Length", + LessThan = 20, + LessThanOrEqual = 20, + NotEmpty = "", + NotEqual = "NotEqual", + Null = "NotNull", + RegularExpression = "FOO", + ScalePrecision = 123.456m + }; + + try + { + var response = await client.PostAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + //ex.ResponseStatus.PrintDump(); + Assert.That(ex.StatusCode, Is.EqualTo(400)); + var errors = ex.ResponseStatus.Errors; + Assert.That(errors.First(x => x.FieldName == "CreditCard").ErrorCode, Is.EqualTo("CreditCard")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Empty").ErrorCode, Is.EqualTo("Empty")); + Assert.That(errors.First(x => x.FieldName == "Equal").ErrorCode, Is.EqualTo("Equal")); + Assert.That(errors.First(x => x.FieldName == "ExclusiveBetween").ErrorCode, Is.EqualTo("ExclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "GreaterThan").ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(errors.First(x => x.FieldName == "GreaterThanOrEqual").ErrorCode, Is.EqualTo("GreaterThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "InclusiveBetween").ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "Length").ErrorCode, Is.EqualTo("Length")); + Assert.That(errors.First(x => x.FieldName == "LessThan").ErrorCode, Is.EqualTo("LessThan")); + Assert.That(errors.First(x => x.FieldName == "LessThanOrEqual").ErrorCode, Is.EqualTo("LessThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "NotEmpty").ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors.First(x => x.FieldName == "NotEqual").ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errors.First(x => x.FieldName == "Null").ErrorCode, Is.EqualTo("Null")); + Assert.That(errors.First(x => x.FieldName == "RegularExpression").ErrorCode, Is.EqualTo("RegularExpression")); + Assert.That(errors.First(x => x.FieldName == "ScalePrecision").ErrorCode, Is.EqualTo("ScalePrecision")); + } + } + + [Test] + public async Task Does_throw_WebServiceException_on_CustomException() + { + using var client = GetClient(); + + try + { + await client.GetAsync(new ThrowCustom()); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(401)); + Assert.That(e.Message, Is.EqualTo("Custom Error Message")); + } + } + + [Test] + public async Task Does_return_Custom_Headers() + { + var client = GetClient(); + string customHeader = null; + client.ResponseFilter = ctx => customHeader = ctx.GetHeader("X-Custom"); + + await client.GetAsync(new AddHeader { Name = "X-Custom", Value = "A" }); + Assert.That(customHeader, Is.EqualTo("A")); + } + + [Test] + public async Task Can_download_file() + { + var client = GetClient(); + var response = await client.GetAsync(new GetFile { Path = "/js/ss-utils.js" }); + AssertSSUtils(response); + } + + private static void AssertSSUtils(FileContent response) + { + Assert.That(response.Name, Is.EqualTo("ss-utils.js")); + Assert.That(response.Length, Is.GreaterThan(0)); + Assert.That(response.Length, Is.EqualTo(response.Body.Length)); + var str = response.Body.FromUtf8Bytes(); + Assert.That(str, Does.Contain("if (!$.ss) $.ss = {};")); + } + + private static void AssertFiles(List responses) + { + Assert.That(responses.Count, Is.EqualTo(3)); + AssertSSUtils(responses[0]); + Assert.That(responses[1].Name, Is.EqualTo("hot-loader.js")); + Assert.That(responses[2].Name, Is.EqualTo("hot-fileloader.js")); + } + + [Test] + public async Task Can_download_multiple_files() + { + var client = GetClient(); + + var files = new[] { + new GetFile { Path = "/js/ss-utils.js" }, + new GetFile { Path = "/js/hot-loader.js" }, + new GetFile { Path = "/js/not-exists.js" }, + new GetFile { Path = "/js/hot-fileloader.js" }, + }; + + var responses = await client.SendAllAsync(files); + + Assert.That(responses.Count, Is.EqualTo(files.Length)); + Assert.That(responses[2].ResponseStatus.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.NotFound))); + responses = responses.Where(x => x.ResponseStatus == null).ToList(); + AssertFiles(responses); + } + + [Test] + public async Task Can_stream_multiple_files() + { + var client = GetClient(); + + var request = new StreamFiles { + Paths = new List { + "/js/ss-utils.js", + "/js/hot-loader.js", + "/js/not-exists.js", + "/js/hot-fileloader.js", + } + }; + + var files = new List(); + await foreach (var file in client.StreamAsync(request)) + { + files.Add(file); + } + Assert.That(files.Count, Is.EqualTo(request.Paths.Count)); + Assert.That(files[2].ResponseStatus.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.NotFound))); + files = files.Where(x => x.ResponseStatus == null).ToList(); + AssertFiles(files); + } + + static string GetServiceProto() + => GrpcConfig.TypeModel.GetSchema(MetaTypeConfig.GetMetaType().Type, ProtoBuf.Meta.ProtoSyntax.Proto3); + + [Test] + public void CheckServiceProto_BaseType() + { + var schema = GetServiceProto(); + Assert.AreEqual(@"syntax = ""proto3""; +package ServiceStack.Extensions.Tests; + +message Bar { + string Y = 2; +} +message Foo { + string X = 1; + oneof subtype { + Bar Bar = 210304982; + } +} +", schema); + } + + [Test] + public void CheckServiceProto_DerivedType() + { + var schema = GetServiceProto(); + Assert.AreEqual(@"syntax = ""proto3""; +package ServiceStack.Extensions.Tests; + +message Bar { + string Y = 2; +} +message Foo { + string X = 1; + oneof subtype { + Bar Bar = 210304982; + } +} +", schema); + } + + [Test] + public void CheckServiceProto_QueryDb_ShouldBeOffset() + { + var schema = GetServiceProto(); + Assert.AreEqual(@"syntax = ""proto3""; +package ServiceStack.Extensions.Tests; + +message QueryFoos { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string X = 201; +} +", schema); + } + + [Test] + public void CheckServiceProto_CustomRequestDto_ShouldBeOffset() + { + var schema = GetServiceProto(); + Assert.AreEqual(@"syntax = ""proto3""; +package ServiceStack.Extensions.Tests; + +message CustomRequestDto { + int32 PageName = 42; + string Name = 105; +} +", schema); + } + + [DataContract] + public class Foo + { + [DataMember(Order = 1)] + public string X { get; set; } + } + + [DataContract] + public class Bar : Foo + { + [DataMember(Order = 2)] + public string Y { get; set; } + } + + [Route("/query/foos")] + [DataContract] + public class QueryFoos : QueryDb + { + [DataMember(Order = 1)] + public string X { get; set; } + } + + [DataContract] + public abstract class CustomRequestDtoBase : IReturnVoid + { + [DataMember(Order = 42, Name = "PageName")] + public int Page { get; set; } + } + + [DataContract] + public class CustomRequestDto : CustomRequestDtoBase + { + [DataMember(Order = 5)] + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/GrpcTodoTests.cs b/tests/ServiceStack.Extensions.Tests/GrpcTodoTests.cs new file mode 100644 index 00000000000..cc47d58031e --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/GrpcTodoTests.cs @@ -0,0 +1,273 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; + +namespace ServiceStack.Extensions.Tests +{ + [DataContract] + public class Todo + { + [DataMember(Order = 1)] + public long Id { get; set; } + + [DataMember(Order = 2)] + public string Title { get; set; } + + [DataMember(Order = 3)] + public int Order { get; set; } + + [DataMember(Order = 4)] + public bool Completed { get; set; } + } + + [Route("/todos", "GET")] + [DataContract] + public class GetTodos : IReturn {} + [DataContract] + public class GetTodosResponse + { + [DataMember(Order = 1)] + public List Results { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/todos/{Id}", "GET")] + [DataContract] + public class GetTodo : IReturn + { + [DataMember(Order = 1)] + public long Id { get; set; } + } + [DataContract] + public class GetTodoResponse + { + [DataMember(Order = 1)] + public Todo Result { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/todos", "POST")] + [DataContract] + public class CreateTodo : IReturn + { + [DataMember(Order = 1)] + public string Title { get; set; } + + [DataMember(Order = 2)] + public int Order { get; set; } + } + [DataContract] + public class CreateTodoResponse + { + [DataMember(Order = 1)] + public Todo Result { get; set; } + [DataMember(Order = 2)] + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/todos/{Id}", "PUT")] + [DataContract] + public class UpdateTodo : IReturnVoid + { + [DataMember(Order = 1)] + public long Id { get; set; } + + [DataMember(Order = 2)] + public string Title { get; set; } + + [DataMember(Order = 3)] + public int Order { get; set; } + + [DataMember(Order = 4)] + public bool Completed { get; set; } + } + + [Route("/todos/{Id}", "DELETE")] + [DataContract] + public class DeleteTodo : IReturnVoid + { + [DataMember(Order = 1)] + public long Id { get; set; } + } + + [Route("/todos", "DELETE")] + [DataContract] + public class DeleteTodos : IReturnVoid + { + [DataMember(Order = 1)] + public List Ids { get; set; } + } + + [Route("/todos/reset", "POST")] + [DataContract] + public class ResetTodos : IReturnVoid {} + + public class TodoServices : Service + { + private static long Counter = 0; + public static List Todos { get; } = new List(); + + public IServerEvents ServerEvents { get; set; } + + public object Get(GetTodo request) => new GetTodoResponse { Result = Todos.FirstOrDefault(x => x.Id == request.Id) }; + + public object Get(GetTodos request) => new GetTodosResponse { Results = Todos }; + + public async Task Post(CreateTodo request) + { + var todo = request.ConvertTo(); + todo.Id = Interlocked.Increment(ref Counter); + Todos.Add(todo); + await ServerEvents.NotifyChannelAsync("todos", "todos.create", todo); + return new CreateTodoResponse { Result = todo }; + } + + public Task Put(UpdateTodo request) + { + var todo = Todos.FirstOrDefault(x => x.Id == request.Id) + ?? throw HttpError.NotFound($"Todo with Id '{request.Id}' does not exit"); + todo.PopulateWith(request); + return ServerEvents.NotifyChannelAsync("todos", "todos.update", todo); + } + + public Task Delete(DeleteTodo request) + { + Todos.RemoveAll(x => x.Id == request.Id); + return ServerEvents.NotifyChannelAsync("todos", "todos.delete", request.Id); + } + + public Task Delete(DeleteTodos request) + { + if (request.Ids.IsEmpty()) + return Task.CompletedTask; + + Todos.RemoveAll(x => request.Ids.Contains(x.Id)); + var tasks = request.Ids.Map(x => ServerEvents.NotifyChannelAsync("todos", "todos.delete", x)); + return Task.WhenAll(tasks); + } + + public void Post(ResetTodos request) + { + Counter = 0; + Todos.Clear(); + } + } + + public class GrpcTodoTests + { + private readonly ServiceStackHost appHost; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(GrpcTests), typeof(TodoServices).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new GrpcFeature(App)); + Plugins.Add(new ServerEventsFeature()); + + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + } + } + + public GrpcTodoTests() + { + appHost = new AppHost() + .Init() + .Start(TestsConfig.BaseUri); + + GrpcClientFactory.AllowUnencryptedHttp2 = true; + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + public IServiceClientAsync CreateClient() => new GrpcServiceClient(TestsConfig.BaseUri); + + [Test] + public async Task Can_CreateTodo() + { + var client = CreateClient(); + await client.PostAsync(new ResetTodos()); + + var response = await client.PostAsync(new CreateTodo { + Title = "A", + Order = 1, + }); + + Assert.That(response.Result.Id, Is.GreaterThan(0)); + Assert.That(response.Result.Title, Is.EqualTo("A")); + Assert.That(response.Result.Order, Is.EqualTo(1)); + Assert.That(response.Result.Completed, Is.False); + + await client.SendAllAsync(new [] { + new CreateTodo { Title = "B", Order = 2 }, + new CreateTodo { Title = "C", Order = 3 }, + }); + + var allTodos = await client.GetAsync(new GetTodos()); + Assert.That(allTodos.Results.Map(x => x.Title), Is.EqualTo(new[]{"A","B","C"})); + } + + [Test] + public async Task Does_CRUD_Example() + { + var client = CreateClient(); + await client.PostAsync(new ResetTodos()); + + //GET /todos + var all = await client.GetAsync(new GetTodos()); + Assert.That(all.Results?.Count ?? 0, Is.EqualTo(0)); + + //POST /todos + var todo = (await client.PostAsync(new CreateTodo { Title = "ServiceStack" })).Result; + Assert.That(todo.Id, Is.EqualTo(1)); + //GET /todos/1 + todo = (await client.GetAsync(new GetTodo { Id = todo.Id })).Result; + Assert.That(todo.Title, Is.EqualTo("ServiceStack")); + + //GET /todos + all = await client.GetAsync(new GetTodos()); + Assert.That(all.Results.Count, Is.EqualTo(1)); + + //PUT /todos/1 + await client.PutAsync(new UpdateTodo { Id = todo.Id, Title = "gRPC" }); + todo = (await client.GetAsync(new GetTodo { Id = todo.Id })).Result; + Assert.That(todo.Title, Is.EqualTo("gRPC")); + + //DELETE /todos/1 + await client.DeleteAsync(new DeleteTodo { Id = todo.Id }); + //GET /todos + all = await client.GetAsync(new GetTodos()); + Assert.That(all.Results?.Count ?? 0, Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Issues/GrpcServiceIssues.cs b/tests/ServiceStack.Extensions.Tests/Issues/GrpcServiceIssues.cs new file mode 100644 index 00000000000..32ed2e23eda --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Issues/GrpcServiceIssues.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Auth; +using ServiceStack.Validation; + +namespace ServiceStack.Extensions.Tests.Issues +{ + [Route("/endswith/{Suffix}", Summary = "suffix")] + [DataContract] + public class EndsWithSuffixRequest : IReturn + { + [DataMember(Order = 1), ApiMember(Name = "Suffix", Description = "Suffix", DataType = "string", IsRequired = true)] + public string Suffix { get; set; } + } + + [DataContract] + public class EndsWithSuffixResponse + { + [DataMember(Order = 1)] + public SearchResult Result { get; set; } + + [DataMember(Order = 2)] + public int Count { get; set; } + + [DataMember(Order = 3)] + public List Words { get; set; } + } + + [DataContract] + public class SearchResult + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public string Suffix { get; set; } + } + + public class GrpcIssueServices : Service + { + public object Any(EndsWithSuffixRequest request) => new EndsWithSuffixResponse { + Result = new SearchResult { Suffix = request.Suffix } + }; + } + + public partial class GrpcServiceIssues + { + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(GrpcServiceIssues), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + Plugins.Add(new GrpcFeature(App)); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + } + } + + public static readonly int Port = 20000; + public static readonly string BaseUri = $"http://localhost:{Port}"; + public static readonly string ListeningOn = BaseUri + "/"; + + private readonly ServiceStackHost appHost; + public GrpcServiceIssues() + { + appHost = new AppHost() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + public static GrpcServiceClient CreateClient() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + var client = new GrpcServiceClient(BaseUri); + return client; + } + + [Test] + public async Task Can_call_EndsWithSuffixRequest() + { + var client = CreateClient(); + var request = new EndsWithSuffixRequest { Suffix = "TheSuffix" }; + var response = await client.GetAsync(request); + Assert.That(response.Result.Suffix, Is.EqualTo(request.Suffix)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/ProtobufTests.cs b/tests/ServiceStack.Extensions.Tests/ProtobufTests.cs new file mode 100644 index 00000000000..dd1a204a533 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/ProtobufTests.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using NUnit.Framework; +using ProtoBuf.Meta; +using ServiceStack.Text; + +namespace ServiceStack.Extensions.Tests +{ + [DataContract] + public class Query + { + [DataMember(Order = 1)] + public virtual string Include { get; set; } + } + + [DataContract] + public class NonGenericQueryBase : QueryBase {} + + [DataContract] + public class NonGenericMyQueryBase : MyQueryBase {} + + [DataContract] + public abstract class MyQueryBase + { + [DataMember(Order = 1)] + public virtual string Include { get; set; } + } + + [DataContract] + public abstract class HiddenBase + { + [DataMember(Order = 1)] + public string FirstName { get; set; } + [DataMember(Order = 2)] + public LivingStatus LivingStatus { get; set; } + } + + [DataContract] + public class Shadowed : HiddenBase + { + [DataMember(Order = 1)] + public int Id { get; set; } + [DataMember(Order = 2)] + public new string FirstName { get; set; } + [DataMember(Order = 3)] + public new LivingStatus? LivingStatus { get; set; } //overridden property + } + + public class ProtobufTests + { + public T Serialize(T dto, TypeModel model = null) + { + if (model != null) + { + byte[] bytes = null; + using (var ms = new MemoryStream()) + { + model.Serialize(ms, dto); + bytes = ms.ToArray(); + } + using (var ms = new MemoryStream(bytes)) + { + var to = (T) model.Deserialize(ms, (object)null, typeof(T)); + return to; + } + } + else + { + var bytes = GrpcMarshaller.Instance.Serializer(dto); + var to = GrpcMarshaller.Instance.Deserializer(bytes); + return to; + } + } + + public T SerializeGrpc(T dto) + { + var bytes = GrpcMarshaller.Instance.Serializer(dto); + var to = GrpcMarshaller.Instance.Deserializer(bytes); + return to; + } + + [Test] + public void Can_Serialize_Query() + { + var dto = new Query { Include = "Total" }; + var to = Serialize(dto); + Assert.That(to.Include, Is.EqualTo(dto.Include)); + } + + [Test] + public void Can_Serialize_QueryRockstars_TypeModel() + { + var model = RuntimeTypeModel.Create(); + + //var metaType = model.Add(typeof(QueryBase), true); + model[typeof(QueryBase)].AddSubType(101, typeof(QueryDb)); + model[typeof(QueryDb)].AddSubType(101, typeof(QueryRockstars)); + + var dto = new QueryRockstars { Include = "Total" }; + var to = Serialize(dto, model); + Assert.That(to.Include, Is.EqualTo(dto.Include)); + } + + [Test] + public void Can_Serialize_QueryRockstars() + { + var dto = new QueryRockstars { Include = "Total" }; + var to = SerializeGrpc(dto); + Assert.That(to.Include, Is.EqualTo(dto.Include)); + } + + [Test] + public void Can_Serialize_QueryResponse_NamedRockstar() + { +// GrpcUtils.Register(); + var dto = new QueryResponse { + Total = 1, + Results = new List { + new NamedRockstar { + Id = 1, + FirstName = "Microsoft", + LastName = "SQL Server", + Age = 27, + DateOfBirth = new DateTime(1989,1,1), + LivingStatus = LivingStatus.Alive, + } + } + }; + var to = SerializeGrpc(dto); + to.PrintDump(); + Assert.That(to.Results[0].LastName, Is.EqualTo("SQL Server")); + } + + [Test] + public void Can_serialize_bytes() + { + var dto = new FileContent { + Body = "abc".ToUtf8Bytes(), + }; + var toDto = SerializeGrpc(dto); + Assert.That(toDto.Body, Is.EqualTo(dto.Body)); + } + + [Test] + public void Can_serialize_hidden_property() + { + var dto = new Shadowed { + Id = 1, + FirstName = "Updated", + LivingStatus = LivingStatus.Dead, + }; + var toDto = SerializeGrpc(dto); + Assert.That(toDto.Id, Is.EqualTo(dto.Id)); + Assert.That(toDto.FirstName, Is.EqualTo(dto.FirstName)); + Assert.That(toDto.LivingStatus, Is.EqualTo(dto.LivingStatus)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/Bcl.cs b/tests/ServiceStack.Extensions.Tests/Protoc/Bcl.cs new file mode 100644 index 00000000000..c9e68e8ed80 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/Bcl.cs @@ -0,0 +1,1118 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: bcl.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace ProtoBuf.Bcl { + + /// Holder for reflection information generated from bcl.proto + public static partial class BclReflection { + + #region Descriptor + /// File descriptor for bcl.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static BclReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CgliY2wucHJvdG8SA2JjbCKuAQoIVGltZVNwYW4SDQoFdmFsdWUYASABKBIS", + "KgoFc2NhbGUYAiABKA4yGy5iY2wuVGltZVNwYW4uVGltZVNwYW5TY2FsZSJn", + "Cg1UaW1lU3BhblNjYWxlEggKBERBWVMQABIJCgVIT1VSUxABEgsKB01JTlVU", + "RVMQAhILCgdTRUNPTkRTEAMSEAoMTUlMTElTRUNPTkRTEAQSCQoFVElDS1MQ", + "BRIKCgZNSU5NQVgQDyKNAgoIRGF0ZVRpbWUSDQoFdmFsdWUYASABKBISKgoF", + "c2NhbGUYAiABKA4yGy5iY2wuRGF0ZVRpbWUuVGltZVNwYW5TY2FsZRIoCgRr", + "aW5kGAMgASgOMhouYmNsLkRhdGVUaW1lLkRhdGVUaW1lS2luZCJnCg1UaW1l", + "U3BhblNjYWxlEggKBERBWVMQABIJCgVIT1VSUxABEgsKB01JTlVURVMQAhIL", + "CgdTRUNPTkRTEAMSEAoMTUlMTElTRUNPTkRTEAQSCQoFVElDS1MQBRIKCgZN", + "SU5NQVgQDyIzCgxEYXRlVGltZUtpbmQSDwoLVU5TUEVDSUZJRUQQABIHCgNV", + "VEMQARIJCgVMT0NBTBACIpEBCg5OZXRPYmplY3RQcm94eRIZChFleGlzdGlu", + "Z09iamVjdEtleRgBIAEoBRIUCgxuZXdPYmplY3RLZXkYAiABKAUSFwoPZXhp", + "c3RpbmdUeXBlS2V5GAMgASgFEhIKCm5ld1R5cGVLZXkYBCABKAUSEAoIdHlw", + "ZU5hbWUYCCABKAkSDwoHcGF5bG9hZBgKIAEoDCIeCgRHdWlkEgoKAmxvGAEg", + "ASgGEgoKAmhpGAIgASgGIjQKB0RlY2ltYWwSCgoCbG8YASABKAQSCgoCaGkY", + "AiABKA0SEQoJc2lnblNjYWxlGAMgASgNQg+qAgxQcm90b0J1Zi5CY2xiBnBy", + "b3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::ProtoBuf.Bcl.TimeSpan), global::ProtoBuf.Bcl.TimeSpan.Parser, new[]{ "Value", "Scale" }, null, new[]{ typeof(global::ProtoBuf.Bcl.TimeSpan.Types.TimeSpanScale) }, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ProtoBuf.Bcl.DateTime), global::ProtoBuf.Bcl.DateTime.Parser, new[]{ "Value", "Scale", "Kind" }, null, new[]{ typeof(global::ProtoBuf.Bcl.DateTime.Types.TimeSpanScale), typeof(global::ProtoBuf.Bcl.DateTime.Types.DateTimeKind) }, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ProtoBuf.Bcl.NetObjectProxy), global::ProtoBuf.Bcl.NetObjectProxy.Parser, new[]{ "ExistingObjectKey", "NewObjectKey", "ExistingTypeKey", "NewTypeKey", "TypeName", "Payload" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ProtoBuf.Bcl.Guid), global::ProtoBuf.Bcl.Guid.Parser, new[]{ "Lo", "Hi" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ProtoBuf.Bcl.Decimal), global::ProtoBuf.Bcl.Decimal.Parser, new[]{ "Lo", "Hi", "SignScale" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class TimeSpan : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TimeSpan()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ProtoBuf.Bcl.BclReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TimeSpan() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TimeSpan(TimeSpan other) : this() { + value_ = other.value_; + scale_ = other.scale_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TimeSpan Clone() { + return new TimeSpan(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private long value_; + /// + /// the size of the timespan (in units of the selected scale) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Value { + get { return value_; } + set { + value_ = value; + } + } + + /// Field number for the "scale" field. + public const int ScaleFieldNumber = 2; + private global::ProtoBuf.Bcl.TimeSpan.Types.TimeSpanScale scale_ = 0; + /// + /// the scale of the timespan [default = DAYS] + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ProtoBuf.Bcl.TimeSpan.Types.TimeSpanScale Scale { + get { return scale_; } + set { + scale_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TimeSpan); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TimeSpan other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + if (Scale != other.Scale) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Value != 0L) hash ^= Value.GetHashCode(); + if (Scale != 0) hash ^= Scale.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Value != 0L) { + output.WriteRawTag(8); + output.WriteSInt64(Value); + } + if (Scale != 0) { + output.WriteRawTag(16); + output.WriteEnum((int) Scale); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Value != 0L) { + size += 1 + pb::CodedOutputStream.ComputeSInt64Size(Value); + } + if (Scale != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Scale); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TimeSpan other) { + if (other == null) { + return; + } + if (other.Value != 0L) { + Value = other.Value; + } + if (other.Scale != 0) { + Scale = other.Scale; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadSInt64(); + break; + } + case 16: { + Scale = (global::ProtoBuf.Bcl.TimeSpan.Types.TimeSpanScale) input.ReadEnum(); + break; + } + } + } + } + + #region Nested types + /// Container for nested types declared in the TimeSpan message type. + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static partial class Types { + public enum TimeSpanScale { + [pbr::OriginalName("DAYS")] Days = 0, + [pbr::OriginalName("HOURS")] Hours = 1, + [pbr::OriginalName("MINUTES")] Minutes = 2, + [pbr::OriginalName("SECONDS")] Seconds = 3, + [pbr::OriginalName("MILLISECONDS")] Milliseconds = 4, + [pbr::OriginalName("TICKS")] Ticks = 5, + /// + /// dubious + /// + [pbr::OriginalName("MINMAX")] Minmax = 15, + } + + } + #endregion + + } + + public sealed partial class DateTime : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DateTime()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ProtoBuf.Bcl.BclReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DateTime() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DateTime(DateTime other) : this() { + value_ = other.value_; + scale_ = other.scale_; + kind_ = other.kind_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DateTime Clone() { + return new DateTime(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private long value_; + /// + /// the offset (in units of the selected scale) from 1970/01/01 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Value { + get { return value_; } + set { + value_ = value; + } + } + + /// Field number for the "scale" field. + public const int ScaleFieldNumber = 2; + private global::ProtoBuf.Bcl.DateTime.Types.TimeSpanScale scale_ = 0; + /// + /// the scale of the timespan [default = DAYS] + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ProtoBuf.Bcl.DateTime.Types.TimeSpanScale Scale { + get { return scale_; } + set { + scale_ = value; + } + } + + /// Field number for the "kind" field. + public const int KindFieldNumber = 3; + private global::ProtoBuf.Bcl.DateTime.Types.DateTimeKind kind_ = 0; + /// + /// the kind of date/time being represented [default = UNSPECIFIED] + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ProtoBuf.Bcl.DateTime.Types.DateTimeKind Kind { + get { return kind_; } + set { + kind_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DateTime); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DateTime other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + if (Scale != other.Scale) return false; + if (Kind != other.Kind) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Value != 0L) hash ^= Value.GetHashCode(); + if (Scale != 0) hash ^= Scale.GetHashCode(); + if (Kind != 0) hash ^= Kind.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Value != 0L) { + output.WriteRawTag(8); + output.WriteSInt64(Value); + } + if (Scale != 0) { + output.WriteRawTag(16); + output.WriteEnum((int) Scale); + } + if (Kind != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) Kind); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Value != 0L) { + size += 1 + pb::CodedOutputStream.ComputeSInt64Size(Value); + } + if (Scale != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Scale); + } + if (Kind != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Kind); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DateTime other) { + if (other == null) { + return; + } + if (other.Value != 0L) { + Value = other.Value; + } + if (other.Scale != 0) { + Scale = other.Scale; + } + if (other.Kind != 0) { + Kind = other.Kind; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Value = input.ReadSInt64(); + break; + } + case 16: { + Scale = (global::ProtoBuf.Bcl.DateTime.Types.TimeSpanScale) input.ReadEnum(); + break; + } + case 24: { + Kind = (global::ProtoBuf.Bcl.DateTime.Types.DateTimeKind) input.ReadEnum(); + break; + } + } + } + } + + #region Nested types + /// Container for nested types declared in the DateTime message type. + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static partial class Types { + public enum TimeSpanScale { + [pbr::OriginalName("DAYS")] Days = 0, + [pbr::OriginalName("HOURS")] Hours = 1, + [pbr::OriginalName("MINUTES")] Minutes = 2, + [pbr::OriginalName("SECONDS")] Seconds = 3, + [pbr::OriginalName("MILLISECONDS")] Milliseconds = 4, + [pbr::OriginalName("TICKS")] Ticks = 5, + /// + /// dubious + /// + [pbr::OriginalName("MINMAX")] Minmax = 15, + } + + public enum DateTimeKind { + /// + /// The time represented is not specified as either local time or Coordinated Universal Time (UTC). + /// + [pbr::OriginalName("UNSPECIFIED")] Unspecified = 0, + /// + /// The time represented is UTC. + /// + [pbr::OriginalName("UTC")] Utc = 1, + /// + /// The time represented is local time. + /// + [pbr::OriginalName("LOCAL")] Local = 2, + } + + } + #endregion + + } + + public sealed partial class NetObjectProxy : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NetObjectProxy()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ProtoBuf.Bcl.BclReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetObjectProxy() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetObjectProxy(NetObjectProxy other) : this() { + existingObjectKey_ = other.existingObjectKey_; + newObjectKey_ = other.newObjectKey_; + existingTypeKey_ = other.existingTypeKey_; + newTypeKey_ = other.newTypeKey_; + typeName_ = other.typeName_; + payload_ = other.payload_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetObjectProxy Clone() { + return new NetObjectProxy(this); + } + + /// Field number for the "existingObjectKey" field. + public const int ExistingObjectKeyFieldNumber = 1; + private int existingObjectKey_; + /// + /// for a tracked object, the key of the **first** time this object was seen + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ExistingObjectKey { + get { return existingObjectKey_; } + set { + existingObjectKey_ = value; + } + } + + /// Field number for the "newObjectKey" field. + public const int NewObjectKeyFieldNumber = 2; + private int newObjectKey_; + /// + /// for a tracked object, a **new** key, the first time this object is seen + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NewObjectKey { + get { return newObjectKey_; } + set { + newObjectKey_ = value; + } + } + + /// Field number for the "existingTypeKey" field. + public const int ExistingTypeKeyFieldNumber = 3; + private int existingTypeKey_; + /// + /// for dynamic typing, the key of the **first** time this type was seen + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ExistingTypeKey { + get { return existingTypeKey_; } + set { + existingTypeKey_ = value; + } + } + + /// Field number for the "newTypeKey" field. + public const int NewTypeKeyFieldNumber = 4; + private int newTypeKey_; + /// + /// for dynamic typing, a **new** key, the first time this type is seen + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NewTypeKey { + get { return newTypeKey_; } + set { + newTypeKey_ = value; + } + } + + /// Field number for the "typeName" field. + public const int TypeNameFieldNumber = 8; + private string typeName_ = ""; + /// + /// for dynamic typing, the name of the type (only present along with newTypeKey) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TypeName { + get { return typeName_; } + set { + typeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "payload" field. + public const int PayloadFieldNumber = 10; + private pb::ByteString payload_ = pb::ByteString.Empty; + /// + /// the new string/value (only present along with newObjectKey) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Payload { + get { return payload_; } + set { + payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NetObjectProxy); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NetObjectProxy other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ExistingObjectKey != other.ExistingObjectKey) return false; + if (NewObjectKey != other.NewObjectKey) return false; + if (ExistingTypeKey != other.ExistingTypeKey) return false; + if (NewTypeKey != other.NewTypeKey) return false; + if (TypeName != other.TypeName) return false; + if (Payload != other.Payload) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ExistingObjectKey != 0) hash ^= ExistingObjectKey.GetHashCode(); + if (NewObjectKey != 0) hash ^= NewObjectKey.GetHashCode(); + if (ExistingTypeKey != 0) hash ^= ExistingTypeKey.GetHashCode(); + if (NewTypeKey != 0) hash ^= NewTypeKey.GetHashCode(); + if (TypeName.Length != 0) hash ^= TypeName.GetHashCode(); + if (Payload.Length != 0) hash ^= Payload.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ExistingObjectKey != 0) { + output.WriteRawTag(8); + output.WriteInt32(ExistingObjectKey); + } + if (NewObjectKey != 0) { + output.WriteRawTag(16); + output.WriteInt32(NewObjectKey); + } + if (ExistingTypeKey != 0) { + output.WriteRawTag(24); + output.WriteInt32(ExistingTypeKey); + } + if (NewTypeKey != 0) { + output.WriteRawTag(32); + output.WriteInt32(NewTypeKey); + } + if (TypeName.Length != 0) { + output.WriteRawTag(66); + output.WriteString(TypeName); + } + if (Payload.Length != 0) { + output.WriteRawTag(82); + output.WriteBytes(Payload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ExistingObjectKey != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ExistingObjectKey); + } + if (NewObjectKey != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NewObjectKey); + } + if (ExistingTypeKey != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ExistingTypeKey); + } + if (NewTypeKey != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NewTypeKey); + } + if (TypeName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeName); + } + if (Payload.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Payload); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NetObjectProxy other) { + if (other == null) { + return; + } + if (other.ExistingObjectKey != 0) { + ExistingObjectKey = other.ExistingObjectKey; + } + if (other.NewObjectKey != 0) { + NewObjectKey = other.NewObjectKey; + } + if (other.ExistingTypeKey != 0) { + ExistingTypeKey = other.ExistingTypeKey; + } + if (other.NewTypeKey != 0) { + NewTypeKey = other.NewTypeKey; + } + if (other.TypeName.Length != 0) { + TypeName = other.TypeName; + } + if (other.Payload.Length != 0) { + Payload = other.Payload; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ExistingObjectKey = input.ReadInt32(); + break; + } + case 16: { + NewObjectKey = input.ReadInt32(); + break; + } + case 24: { + ExistingTypeKey = input.ReadInt32(); + break; + } + case 32: { + NewTypeKey = input.ReadInt32(); + break; + } + case 66: { + TypeName = input.ReadString(); + break; + } + case 82: { + Payload = input.ReadBytes(); + break; + } + } + } + } + + } + + public sealed partial class Guid : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Guid()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ProtoBuf.Bcl.BclReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Guid() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Guid(Guid other) : this() { + lo_ = other.lo_; + hi_ = other.hi_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Guid Clone() { + return new Guid(this); + } + + /// Field number for the "lo" field. + public const int LoFieldNumber = 1; + private ulong lo_; + /// + /// the first 8 bytes of the guid (note:crazy-endian) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Lo { + get { return lo_; } + set { + lo_ = value; + } + } + + /// Field number for the "hi" field. + public const int HiFieldNumber = 2; + private ulong hi_; + /// + /// the second 8 bytes of the guid (note:crazy-endian) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Hi { + get { return hi_; } + set { + hi_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Guid); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Guid other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Lo != other.Lo) return false; + if (Hi != other.Hi) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Lo != 0UL) hash ^= Lo.GetHashCode(); + if (Hi != 0UL) hash ^= Hi.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Lo != 0UL) { + output.WriteRawTag(9); + output.WriteFixed64(Lo); + } + if (Hi != 0UL) { + output.WriteRawTag(17); + output.WriteFixed64(Hi); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Lo != 0UL) { + size += 1 + 8; + } + if (Hi != 0UL) { + size += 1 + 8; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Guid other) { + if (other == null) { + return; + } + if (other.Lo != 0UL) { + Lo = other.Lo; + } + if (other.Hi != 0UL) { + Hi = other.Hi; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 9: { + Lo = input.ReadFixed64(); + break; + } + case 17: { + Hi = input.ReadFixed64(); + break; + } + } + } + } + + } + + public sealed partial class Decimal : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Decimal()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ProtoBuf.Bcl.BclReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Decimal() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Decimal(Decimal other) : this() { + lo_ = other.lo_; + hi_ = other.hi_; + signScale_ = other.signScale_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Decimal Clone() { + return new Decimal(this); + } + + /// Field number for the "lo" field. + public const int LoFieldNumber = 1; + private ulong lo_; + /// + /// the first 64 bits of the underlying value + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Lo { + get { return lo_; } + set { + lo_ = value; + } + } + + /// Field number for the "hi" field. + public const int HiFieldNumber = 2; + private uint hi_; + /// + /// the last 32 bis of the underlying value + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Hi { + get { return hi_; } + set { + hi_ = value; + } + } + + /// Field number for the "signScale" field. + public const int SignScaleFieldNumber = 3; + private uint signScale_; + /// + /// the number of decimal digits (bits 1-16), and the sign (bit 0) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint SignScale { + get { return signScale_; } + set { + signScale_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Decimal); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Decimal other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Lo != other.Lo) return false; + if (Hi != other.Hi) return false; + if (SignScale != other.SignScale) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Lo != 0UL) hash ^= Lo.GetHashCode(); + if (Hi != 0) hash ^= Hi.GetHashCode(); + if (SignScale != 0) hash ^= SignScale.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Lo != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Lo); + } + if (Hi != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Hi); + } + if (SignScale != 0) { + output.WriteRawTag(24); + output.WriteUInt32(SignScale); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Lo != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Lo); + } + if (Hi != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Hi); + } + if (SignScale != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(SignScale); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Decimal other) { + if (other == null) { + return; + } + if (other.Lo != 0UL) { + Lo = other.Lo; + } + if (other.Hi != 0) { + Hi = other.Hi; + } + if (other.SignScale != 0) { + SignScale = other.SignScale; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Lo = input.ReadUInt64(); + break; + } + case 16: { + Hi = input.ReadUInt32(); + break; + } + case 24: { + SignScale = input.ReadUInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/ProtocAuthTests.cs b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocAuthTests.cs new file mode 100644 index 00000000000..4c4a8f53f20 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocAuthTests.cs @@ -0,0 +1,378 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using Grpc.Core; +using Grpc.Core.Interceptors; +using Grpc.Net.Client; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Auth; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.Extensions.Tests.Protoc +{ + public class ProtocAuthTests + { + public static readonly byte[] AuthKey = AesUtils.CreateKey(); + public const string Username = "mythz"; + public const string Password = "p@55word"; + + private static IManageApiKeys apiRepo; + private const string userId = "1"; + private static ApiKey liveKey; + private static ApiKey testKey; + + public class AppHost : AppSelfHostBase + { + public static ApiKey LastApiKey; + public AppHost() + : base(nameof(ProtocTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + RegisterService(); + Plugins.Add(new GrpcFeature(App) { + CreateDynamicService = GrpcConfig.AutoQueryOrDynamicAttribute // required by protoc AutoQuery Tests + }); + + Plugins.Add(new ValidationFeature()); + Plugins.Add(new AutoQueryFeature()); + + container.Register(new InMemoryAuthRepository()); + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + new JwtAuthProvider + { + AuthKey = AuthKey, + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + IncludeJwtInConvertSessionToTokenResponse = true, + }, + new ApiKeyAuthProvider(AppSettings) { RequireSecureConnection = false }, + })); + + Plugins.Add(new RegistrationFeature()); + + GlobalRequestFilters.Add((req, res, dto) => + { + LastApiKey = req.GetApiKey(); + }); + + AfterInitCallbacks.Add(host => { + + var authRepo = GetAuthRepository(); + (authRepo as InMemoryAuthRepository)?.Clear(); + + authRepo.CreateUserAuth(new UserAuth + { + Id = userId.ToInt(), + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + + apiRepo = (IManageApiKeys)container.Resolve(); + var apiKeyProvider = (ApiKeyAuthProvider)AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name); + var apiKeys = apiKeyProvider.GenerateNewApiKeys(userId); + using (authRepo as IDisposable) + { + apiRepo.StoreAll(apiKeys); + } + liveKey = apiKeys.First(x => x.Environment == "live"); + testKey = apiKeys.First(x => x.Environment == "test"); + }); + + ScriptContext.AddRequiredConfig(); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; // use for tests + // listenOptions.Protocols = HttpProtocols.Http1AndHttp2; // use for UpdateProto + }); + } + } + + // [Test] public void TestProtoTypes() => TestsConfig.BaseUri.CombineWith("/types/proto").GetStringFromUrl().Print(); + // [Test] // needs: listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + public void UpdateProto() + { + Directory.GetCurrentDirectory().Print(); + var protoc = TestsConfig.BaseUri.CombineWith("/types/proto").GetStringFromUrl(); + protoc = protoc.Replace("ServiceStack.Extensions.Tests","ServiceStack.Extensions.Tests.Protoc"); + + Directory.SetCurrentDirectory("../../../Protoc"); + File.WriteAllText("services.proto", protoc); + ExecUtils.ShellExec("x proto-csharp services.proto"); + } + + private readonly ServiceStackHost appHost; + public ProtocAuthTests() + { + appHost = new AppHost() + .Init() + .Start(TestsConfig.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private static string CreateExpiredToken() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name); + jwtProvider.CreatePayloadFilter = (jwtPayload, session) => + jwtPayload["exp"] = DateTime.UtcNow.AddSeconds(-1).ToUnixTime().ToString(); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + jwtProvider.CreatePayloadFilter = null; + return token; + } + + private static GrpcServices.GrpcServicesClient GetClient(Action init = null) => + ProtocTests.GetClient(init); + + private async Task GetRefreshToken() + { + var authClient = GetClient(); + var response = await authClient.PostAuthenticateAsync(new Authenticate + { + Provider = "credentials", + UserName = Username, + Password = Password, + }); + return response.RefreshToken; + } + + protected virtual async Task GetClientWithRefreshToken(string refreshToken = null, string accessToken = null) + { + if (refreshToken == null) + { + refreshToken = await GetRefreshToken(); + } + + var client = GetClient(c => { + c.RefreshToken = refreshToken; + c.BearerToken = accessToken; + }); + return client; + } + + protected virtual GrpcServices.GrpcServicesClient GetClientWithBasicAuthCredentials() + { + var client = GetClient(c => { + c.UserName = Username; + c.Password = Password; + }); + return client; + } + + [Test] + public async Task Can_not_access_Secured_without_Auth() + { + var client = GetClient(); + + try + { + var request = new Secured { Name = "test" }; + var response = await client.PostSecuredAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.Message.Print(); + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + } + + [Test] + public async Task Can_access_Secured_using_BasicAuth() + { + var client = GetClientWithBasicAuthCredentials(); + + var request = new Secured { Name = "test" }; + + var response = await client.PostSecuredAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = await client.PostSecuredAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public async Task Can_ConvertSessionToToken() + { + var authClient = GetClient(); + var authResponse = await authClient.PostAuthenticateAsync(new Authenticate + { + Provider = "credentials", + UserName = Username, + Password = Password, + }); + Assert.That(authResponse.SessionId, Is.Not.Null); + Assert.That(authResponse.UserName, Is.EqualTo(Username)); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + authClient = GetClient(c => c.SessionId = authResponse.SessionId); + + var response = await authClient.PostHelloJwtAsync(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + + GrpcClientConfig config = null; + string bearerToken = null; + authClient = GetClient(c => { + bearerToken = authClient.PostConvertSessionToToken(new ConvertSessionToToken()).AccessToken; + (config = c).BearerToken = bearerToken; + }); + + Assert.That(bearerToken, Is.Not.Null); + + config.SessionId = null; + + response = await authClient.PostHelloJwtAsync(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + } + + [Test] + public async Task Invalid_RefreshToken_throws_RefreshTokenException() + { + var client = await GetClientWithRefreshToken("Invalid.Refresh.Token"); + try + { + var request = new Secured { Name = "test" }; + var response = await client.PostSecuredAsync(request); + Assert.Fail("Should throw"); + } + catch (RefreshTokenException ex) + { + ex.Message.Print(); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + } + } + + [Test] + public async Task Can_Auto_reconnect_with_just_RefreshToken() + { + var client = await GetClientWithRefreshToken(); + + var request = new Secured { Name = "test" }; + var response = await client.PostSecuredAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = await client.PostSecuredAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public async Task Can_Auto_reconnect_with_RefreshToken_after_expired_token() + { + var client = await GetClientWithRefreshToken(await GetRefreshToken(), CreateExpiredToken()); + + var request = new Secured { Name = "test" }; + var response = await client.PostSecuredAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = await client.PostSecuredAsync(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public void Can_Auto_reconnect_with_RefreshToken_after_expired_token_Sync() + { + var client = GetClientWithRefreshToken(GetRefreshToken().Result, CreateExpiredToken()).Result; + + var request = new Secured { Name = "test" }; + var response = client.PostSecured(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + + response = client.PostSecured(request); + Assert.That(response.Result, Is.EqualTo("Hello, test")); + } + + [Test] + public async Task Does_return_token_on_subsequent_BasicAuth_Authentication_requests() + { + var client = GetClientWithBasicAuthCredentials(); + + var response = await client.PostAuthenticateAsync(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + + response = await client.PostAuthenticateAsync(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + } + + [Test] + public async Task Can_Authenticate_with_ApiKey() + { + AppHost.LastApiKey = null; + RequiresAuthService.LastApiKey = null; + + var client = GetClient(c => c.BearerToken = liveKey.Id); + + var request = new RequiresAuth { Name = "foo" }; + var response = await client.PostRequiresAuthAsync(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + Assert.That(RequiresAuthService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + + client = GetClient(c => c.BearerToken = testKey.Id); + var testResponse = await client.PostSecuredAsync(new Secured { Name = "test" }); + Assert.That(testResponse.Result, Is.EqualTo("Hello, test")); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(testKey.Id)); + } + + [Test] + public async Task Does_allow_ApiKey_in_IHasBearerToken_RequestDto() + { + AppHost.LastApiKey = null; + RequiresAuthService.LastApiKey = null; + + var client = GetClient(); + + var request = new RequiresAuth { BearerToken = liveKey.Id, Name = "foo" }; + var response = await client.PostRequiresAuthAsync(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + Assert.That(RequiresAuthService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/ProtocDynamicAutoQueryTests.cs b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocDynamicAutoQueryTests.cs new file mode 100644 index 00000000000..b38a6a36061 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocDynamicAutoQueryTests.cs @@ -0,0 +1,1231 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Text; + +namespace ServiceStack.Extensions.Tests.Protoc +{ + public class ProtocDynamicAutoQueryTests + { + private readonly ServiceStackHost appHost; + public GrpcServices.GrpcServicesClient client; + + private static readonly int TotalRockstars = AutoQueryAppHost.SeedRockstars.Length; + private static readonly int TotalAlbums = AutoQueryAppHost.SeedAlbums.Length; + + public ProtocDynamicAutoQueryTests() + { + ConsoleLogFactory.Configure(); + appHost = new AutoQueryAppHost { + ConfigureGrpc = feature => feature.CreateDynamicService = GrpcConfig.AutoQueryOrDynamicAttribute + } + .Init() + .Start(TestsConfig.ListeningOn); + + client = ProtocTests.GetClient(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public List Rockstars => AutoQueryAppHost.SeedRockstars.Map(x => x.ConvertTo()); + + public List PagingTests => AutoQueryAppHost.SeedPagingTest.Map(x => x.ConvertTo()); + + [Test] + public async Task Can_execute_basic_query_dynamic() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + {"Include", "Total"}, + } + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public async Task Can_execute_basic_query_NamedRockstar() + { + var response = await client.GetDynamicQueryNamedRockstarsAsync(new DynamicRequest { + Params = { + {"Include", "Total"}, + } + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("SQL Server")); + } + + [Test] + public async Task Can_execute_overridden_basic_query() + { + var response = await client.GetDynamicQueryOverridedRockstarsAsync(new DynamicRequest { + Params = { + {"Include", "Total"}, + } + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Can_execute_overridden_basic_query_with_case_insensitive_orderBy() + { + var response = await client.GetDynamicQueryCaseInsensitiveOrderByAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "OrderBy", "FirstName" }, + } + }); + + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_AdhocRockstars_query() + { + var response = await client.GetDynamicQueryAdhocRockstarsAsync(new DynamicRequest { + Params = { + { "FirstName", "Jimi" }, + { "Include", "Total" }, + } + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Jimi")); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_on_overridden_CustomRockstar() + { + var response = await client.GetDynamicQueryOverridedCustomRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Total" }, + } + }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Can_execute_basic_query_with_limits() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Skip", "2" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 2)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Take", "2" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Skip", "2" }, + { "Take", "2" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Total" }, + } + }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_implicitly() + { + var response = await client.GetDynamicQueryRockstarsImplicitAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Total" }, + } + }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_on_CustomRockstar() + { + var response = await client.GetDynamicQueryCustomRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Total" }, + } + }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_explicit_equality_condition_on_CustomRockstarSchema() + { + var response = await client.GetDynamicQueryCustomRockstarsSchemaAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Total" }, + } + }); + + response.PrintDump(); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results[0].FirstName, Is.Not.Null); + Assert.That(response.Results[0].LastName, Is.Not.Null); + Assert.That(response.Results[0].Age, Is.EqualTo(27)); + } + + [Test] + public async Task Can_execute_query_with_JOIN_on_RockstarAlbums() + { + var response = await client.GetDynamicQueryJoinedRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", "Foo Fighters", "Into the Wild", + })); + + response = await client.GetDynamicQueryJoinedRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(6)); + Assert.That(response.Results.Count, Is.EqualTo(6)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", + })); + + response = await client.GetDynamicQueryJoinedRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "RockstarAlbumName", "Nevermind" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + } + + [Test] + public async Task Can_execute_query_with_JOIN_on_RockstarAlbums_and_CustomSelectRockstar() + { + var response = await client.GetDynamicQueryJoinedRockstarAlbumsCustomSelectAsync(new DynamicRequest { + Params = { + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var ages = response.Results.Select(x => x.Age); + Assert.That(ages.Contains(27 * 2)); + + var customRes = await client.GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponseAsync(new DynamicRequest { + Params = { + { "Include", "Total" }, + } + }); + Assert.That(customRes.Total, Is.EqualTo(TotalAlbums)); + Assert.That(customRes.Results.Count, Is.EqualTo(TotalAlbums)); + ages = customRes.Results.Select(x => x.Age); + Assert.That(ages.Contains(27 * 2)); + } + + [Test] + public async Task Can_execute_query_with_multiple_JOINs_on_Rockstar_Albums_and_Genres() + { + var response = await client.GetDynamicQueryMultiJoinRockstarAsync(new DynamicRequest { + Params = { + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", "Foo Fighters", "Into the Wild", + })); + + var genreNames = response.Results.Select(x => x.RockstarGenreName).Distinct(); + Assert.That(genreNames, Is.EquivalentTo(new[] { + "Rock", "Grunge", "Alternative Rock", "Folk Rock" + })); + + response = await client.GetDynamicQueryMultiJoinRockstarAsync(new DynamicRequest { + Params = { + { "RockstarAlbumName", "Nevermind" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + + response = await client.GetDynamicQueryMultiJoinRockstarAsync(new DynamicRequest { + Params = { + { "RockstarGenreName", "Folk Rock" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarGenreName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Folk Rock" })); + } + + [Test] + public async Task Can_execute_query_with_LEFTJOIN_on_RockstarAlbums() + { + var response = await client.GetDynamicQueryRockstarAlbumsLeftJoinAsync(new DynamicRequest { + Params = { + { "IdNotEqualTo", "3" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(TotalRockstars - 1)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 1)); + var albumNames = response.Results.Where(x => !x.RockstarAlbumName.IsEmpty()).Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Foo Fighters", "Into the Wild" + })); + } + + [Test] + public async Task Can_execute_query_with_custom_LEFTJOIN_on_RockstarAlbums() + { + var response = await client.GetDynamicQueryRockstarAlbumsCustomLeftJoinAsync(new DynamicRequest { + Params = { + { "IdNotEqualTo", "3" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(TotalRockstars - 1)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 1)); + var albumNames = response.Results.Where(x => !x.RockstarAlbumName.IsEmpty()).Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Foo Fighters", "Into the Wild" + })); + } + + [Test] + public async Task Can_execute_custom_QueryFields() + { + var response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstName", "Jim" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNames", "Jim,Kurt" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameCaseInsensitive", "Jim" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameStartsWith", "Jim" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "LastNameEndsWith", "son" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameBetween", "A,F" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "LastNameEndsWith", "son" }, + { "OrLastName", "Hendrix" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameStartsWith", "Jim" }, + { "OrLastName", "Presley" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "42" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public async Task Can_execute_combination_of_QueryFields() + { + var response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameStartsWith", "Jim" }, + { "LastNameEndsWith", "son" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameStartsWith", "Jim" }, + { "OrLastName", "Cobain" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Does_escape_values() + { + var response = await client.GetDynamicQueryFieldRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNameStartsWith", "Jim'\"" }, + } + }); + Assert.That(response.Results?.Count ?? 0, Is.EqualTo(0)); + } + + [Test] + public async Task Does_use_custom_model_to_select_columns() + { + var response = await client.GetDynamicQueryRockstarAliasAsync(new DynamicRequest { + Params = { + { "RockstarAlbumName", "Nevermind" }, + { "OrLastName", "Cobain" }, + } + }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].RockstarId, Is.EqualTo(3)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Kurt")); + Assert.That(response.Results[0].Album, Is.EqualTo("Nevermind")); + } + + // [Test] + // public async Task Does_allow_adding_attributes_dynamically() + // { + // typeof(QueryFieldRockstarsDynamic) + // .GetProperty("Age") + // .AddAttributes(new QueryDbFieldAttribute { Operand = ">=" }); + // + // var response = await client.GetDynamicQueryFieldRockstarsDynamicAsync(new DynamicRequest { + // Params = { + // { "Age", "42" }, + // } + // }); + // Assert.That(response.Results.Count, Is.EqualTo(4)); + // } + + [Test] + public async Task Does_execute_typed_QueryFilters() + { + // QueryFilter appends additional: x => x.LastName.EndsWith("son") + var response = await client.GetDynamicQueryRockstarsFilterAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + var custom = await client.GetDynamicQueryCustomRockstarsFilterAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + } + }); + Assert.That(custom.Results.Count, Is.EqualTo(1)); + + response = await client.GetDynamicQueryRockstarsIFilterAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public async Task Can_execute_OR_QueryFilters() + { + var response = await client.GetDynamicQueryOrRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "42" }, + { "FirstName", "Jim" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Does_retain_implicit_convention_when_not_overriding_template_or_ValueFormat() + { + var response = await client.GetDynamicQueryFieldsImplicitConventionsAsync(new DynamicRequest { + Params = { + { "FirstNameContains", "im" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryFieldsImplicitConventionsAsync(new DynamicRequest { + Params = { + { "LastNameEndsWith", "son" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Can_execute_OR_QueryFilters_Fields() + { + var response = await client.GetDynamicQueryOrRockstarsFieldsAsync(new DynamicRequest { + Params = { + { "FirstName", "Jim" }, + { "LastName", "Vedder" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public async Task Can_execute_Explicit_conventions() + { + var response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "Ids", "1,2,3" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "AgeOlderThan", "42" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "AgeGreaterThanOrEqualTo", "42" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "AgeGreaterThan", "42" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "GreaterThanAge", "42" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "FirstNameStartsWith", "Jim" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "LastNameEndsWith", "son" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "LastNameContains", "e" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "DateOfBirthGreaterThan", "1960-01-01" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = await client.GetDynamicQueryRockstarsConventionsAsync(new DynamicRequest { + Params = { + { "DateDiedLessThan", "1980-01-01" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Can_execute_In_OR_Queries() + { + var response = await client.GetDynamicQueryGetRockstarsAsync(new DynamicRequest()); + Assert.That(response.Results?.Count ?? 0, Is.EqualTo(0)); + + response = await client.GetDynamicQueryGetRockstarsAsync(new DynamicRequest { + Params = { + { "Ids", "1,2,3" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = await client.GetDynamicQueryGetRockstarsAsync(new DynamicRequest { + Params = { + { "Ages", "42,44" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryGetRockstarsAsync(new DynamicRequest { + Params = { + { "FirstNames", "Jim,Kurt" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = await client.GetDynamicQueryGetRockstarsAsync(new DynamicRequest { + Params = { + { "IdsBetween", "1,3" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public async Task Does_ignore_empty_collection_filters_by_default() + { + var response = await client.GetDynamicQueryRockstarFiltersAsync(new DynamicRequest()); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryAppHost.SeedRockstars.Length)); + + response = await client.GetDynamicQueryRockstarFiltersAsync(new DynamicRequest + { + Params = { + { "Ids", "[]" }, + { "Ages", "[]" }, + { "FirstNames", "[]" }, + { "IdsBetween", "[]" }, + }, + }); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryAppHost.SeedRockstars.Length)); + } + + [Test] + public async Task Can_query_Movie_Ratings() + { + var response = await client.GetDynamicQueryMoviesAsync(new DynamicRequest { + Params = { + { "Ratings", "G,PG-13" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + response = await client.GetDynamicQueryMoviesAsync(new DynamicRequest { + Params = { + { "Ids", "1,2" }, + { "ImdbIds", "tt0071562,tt0060196" }, + { "Ratings", "G,PG-13" }, + }, + }); + Assert.That(response.Results.Count, Is.EqualTo(9)); + } + + [Test] + public async Task Does_implicitly_OrderBy_PrimaryKey_when_limits_is_specified() + { + var movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + } + }); + var ids = movies.Results.Map(x => x.Id); + var orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var rockstars = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + } + }); + ids = rockstars.Results.Map(x => x.Id); + orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public async Task Can_OrderBy_queries() + { + var movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + { "OrderBy", "ImdbId" }, + } + }); + var ids = movies.Results.Map(x => x.ImdbId); + var orderedIds = ids.OrderBy(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + { "OrderBy", "Rating,ImdbId" }, + } + }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + { "OrderByDesc", "ImdbId" }, + } + }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = ids.OrderByDescending(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + { "OrderByDesc", "Rating,ImdbId" }, + } + }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + { "OrderBy", "Rating,-ImdbId" }, + } + }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = await client.GetDynamicSearchMoviesAsync(new DynamicRequest { + Params = { + { "Take", "100" }, + { "OrderByDesc", "Rating,-ImdbId" }, + } + }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public async Task Does_not_query_Ignored_properties() + { + var response = await client.GetDynamicQueryUnknownRockstarsAsync(new DynamicRequest { + Params = { + { "UnknownProperty", "Foo" }, + { "UnknownInt", "1" }, + { "Include", "Total" }, + } + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public async Task Can_Query_Rockstars_with_References() + { + var response = await client.GetDynamicQueryRockstarsWithReferencesAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + } + }); + + Assert.That(response.Results.Count, Is.EqualTo(3)); + + var jimi = response.Results.First(x => x.FirstName == "Jimi"); + Assert.That(jimi.Albums.Count, Is.EqualTo(1)); + Assert.That(jimi.Albums[0].Name, Is.EqualTo("Electric Ladyland")); + + var jim = response.Results.First(x => x.FirstName == "Jim"); + Assert.That(jim.Albums.Count, Is.EqualTo(0)); + + var kurt = response.Results.First(x => x.FirstName == "Kurt"); + Assert.That(kurt.Albums.Count, Is.EqualTo(5)); + + response = await client.GetDynamicQueryRockstarsWithReferencesAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Fields", "Id,FirstName,Age" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.LastName.IsEmpty())); + Assert.That(response.Results.All(x => x.Albums.Count == 0)); + + response = await client.GetDynamicQueryRockstarsWithReferencesAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Fields", "Id,FirstName,Age,Albums" }, + } + }); + Assert.That(response.Results.Where(x => x.FirstName != "Jim").All(x => x.Albums.Count > 0)); + } + + [Test] + public async Task Can_Query_RockstarReference_without_References() + { + var response = await client.GetDynamicQueryCustomRockstarsReferencesAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results.All(x => x.Albums.Count == 0)); + } + + [Test] + public async Task Can_Query_AllFields_Guid() + { + var guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"); + var response = await client.GetDynamicQueryAllFieldsAsync(new DynamicRequest { + Params = { + { "Guid", "3EE6865A-4149-4940-B7A2-F952E0FEFC5E" }, + } + }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + + // Assert.That(ProtocTests.ToGuid(response.Results[0].Guid), Is.EqualTo(guid)); + Assert.That(response.Results[0].Guid, Is.EqualTo(guid.ToString())); + } + + [Test] + public async Task Does_populate_Total() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta.Count, Is.EqualTo(0)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT(*)" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT(DISTINCT LivingStatus), Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "Count(*), Min(Age), Max(Age), Sum(Id)" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Count(*), Min(Age), Max(Age), Sum(Id)" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public async Task Can_Include_Aggregates_in_AutoQuery() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT" }, + } + }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT(*)" }, + } + }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT(DISTINCT LivingStatus)" }, + } + }); + Assert.That(response.Meta["COUNT(DISTINCT LivingStatus)"], Is.EqualTo("2")); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "MIN(Age)" }, + } + }); + Assert.That(response.Meta["MIN(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age)" }, + { "OrderBy", "Id" }, + } + }); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + Assert.That(double.Parse(response.Meta["Avg(Age)"]), Is.EqualTo(Rockstars.Average(x => x.Age)).Within(1d)); + //Not supported by Sqlite + //Assert.That(response.Meta["First(Id)"], Is.EqualTo(Rockstars.First().Id.ToString())); + //Assert.That(response.Meta["Last(Id)"], Is.EqualTo(Rockstars.Last().Id.ToString())); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Age", "27" }, + { "Include", "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age)" }, + { "OrderBy", "Id" }, + } + }); + var rockstars27 = Rockstars.Where(x => x.Age == 27).ToList(); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(rockstars27.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(rockstars27.Map(x => x.Id).Sum().ToString())); + Assert.That(double.Parse(response.Meta["Avg(Age)"]), Is.EqualTo(rockstars27.Average(x => x.Age)).Within(1d)); + //Not supported by Sqlite + //Assert.That(response.Meta["First(Id)"], Is.EqualTo(rockstars27.First().Id.ToString())); + //Assert.That(response.Meta["Last(Id)"], Is.EqualTo(rockstars27.Last().Id.ToString())); + } + + [Test] + public async Task Does_ignore_unknown_aggregate_commands() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "FOO(1), Total" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta.Count, Is.EqualTo(0)); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "FOO(1), Min(Age), Bar('a') alias, Count(*), Baz(1,'foo')" }, + } + }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + } + + [Test] + public async Task Can_Include_Aggregates_in_AutoQuery_with_Aliases() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT(*) count" }, + } + }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "COUNT(DISTINCT LivingStatus) as uniquestatus" }, + } + }); + Assert.That(response.Meta["uniquestatus"], Is.EqualTo("2")); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "MIN(Age) minage" }, + } + }); + Assert.That(response.Meta["minage"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "Count(*) count, Min(Age) min, Max(Age) max, Sum(Id) sum" }, + } + }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["min"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["max"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["sum"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + } + + [Test] + public async Task Can_execute_custom_aggregate_functions() + { + var response = await client.GetDynamicQueryRockstarsAsync(new DynamicRequest { + Params = { + { "Include", "ADD(6,2), Multiply(6,2) SixTimesTwo, Subtract(6,2), divide(6,2) TheDivide" }, + } + }); + Assert.That(response.Meta["ADD(6,2)"], Is.EqualTo("8")); + Assert.That(response.Meta["SixTimesTwo"], Is.EqualTo("12")); + Assert.That(response.Meta["Subtract(6,2)"], Is.EqualTo("4")); + Assert.That(response.Meta["TheDivide"], Is.EqualTo("3")); + } + + [Test] + public async Task Sending_empty_ChangeDb_returns_default_info() + { + var response = await client.GetChangeDbAsync(new ChangeDb()); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + + var aqResponse = await client.GetDynamicQueryChangeDbAsync(new DynamicRequest()); + Assert.That(aqResponse.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public async Task Can_ChangeDb_with_Named_Connection() + { + var response = await client.GetChangeDbAsync(new ChangeDb { NamedConnection = AutoQueryAppHost.SqlServerNamedConnection }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = await client.GetDynamicQueryChangeDbAsync(new DynamicRequest { + Params = { + { "NamedConnection", AutoQueryAppHost.SqlServerNamedConnection }, + } + }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public async Task Can_ChangeDb_with_ConnectionString() + { + var response = await client.GetChangeDbAsync(new ChangeDb { ConnectionString = AutoQueryAppHost.SqliteFileConnString }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Sqlite")); + + var aqResponse = await client.GetDynamicQueryChangeDbAsync(new DynamicRequest { + Params = { + { "ConnectionString", AutoQueryAppHost.SqliteFileConnString }, + } + }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Sqlite")); + } + + [Test] + public async Task Can_ChangeDb_with_ConnectionString_and_Provider() + { + var response = await client.GetChangeDbAsync(new ChangeDb + { + ConnectionString = AutoQueryAppHost.SqlServerConnString, + ProviderName = AutoQueryAppHost.SqlServerProvider, + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = await client.GetDynamicQueryChangeDbAsync(new DynamicRequest { + Params = { + { "ConnectionString", AutoQueryAppHost.SqlServerConnString }, + { "ProviderName", AutoQueryAppHost.SqlServerProvider }, + } + }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public async Task Can_Change_Named_Connection_with_ConnectionInfoAttribute() + { + var response = await client.GetChangeConnectionInfoAsync(new ChangeConnectionInfo()); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = await client.GetDynamicQueryChangeConnectionInfoAsync(new DynamicRequest()); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public async Task Does_return_MaxLimit_results() + { + var response = await client.GetDynamicQueryPagingTestAsync(new DynamicRequest { + Params = { + { "Include", "Total" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = await client.GetDynamicQueryPagingTestAsync(new DynamicRequest { + Params = { + { "Skip", "200" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(PagingTests.Skip(200).Count())); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = await client.GetDynamicQueryPagingTestAsync(new DynamicRequest { + Params = { + { "Value", "1" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count(x => x.Value == 1))); + } + + [Test] + public async Task Can_query_on_ForeignKey_and_Index() + { + var response = await client.GetDynamicQueryRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "RockstarId", "3" }, + { "Include", "Total" }, + } + }); //Hash + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Total, Is.EqualTo(5)); + + response = await client.GetDynamicQueryRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "RockstarId", "3" }, + { "Id", "3" }, + { "Include", "Total" }, + } + }); //Hash + Range + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Name, Is.EqualTo("Nevermind")); + + //Hash + Range BETWEEN + response = await client.GetDynamicQueryRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "RockstarId", "3" }, + { "IdBetween", "2,3" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(2)); + + //Hash + Range BETWEEN + Filter + response = await client.GetDynamicQueryRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "RockstarId", "3" }, + { "IdBetween", "2,3" }, + { "Name", "Nevermind" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Id, Is.EqualTo(3)); + + //Hash + LocalSecondaryIndex + response = await client.GetDynamicQueryRockstarAlbumsAsync(new DynamicRequest { + Params = { + { "RockstarId", "3" }, + { "Genre", "Grunge" }, + { "Include", "Total" }, + } + }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + Assert.That(response.Total, Is.EqualTo(4)); + + response.PrintDump(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/ProtocServerEventsTests.cs b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocServerEventsTests.cs new file mode 100644 index 00000000000..cc992717f35 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocServerEventsTests.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Text; + +namespace ServiceStack.Extensions.Tests.Protoc +{ + public class ProtocServerEventsTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(GrpcServerEventsTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new GrpcFeature(App)); + Plugins.Add(new ServerEventsFeature()); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) => services.AddServiceStackGrpc(); + + public override void Configure(IApplicationBuilder app) => app.UseRouting(); + } + + private readonly ServiceStackHost appHost; + public ProtocServerEventsTests() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + appHost = new AppHost() + .Init() + .Start(TestsConfig.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private static GrpcServices.GrpcServicesClient GetClient(Action init = null) => + ProtocTests.GetClient(init); + + [Test] + public async Task Can_subscribe_to_ServerEvents() + { + var client = GetClient(); + + void AssertMessage(StreamServerEventsResponse msg) + { + Assert.That(msg.EventId, Is.GreaterThan(0)); + Assert.That(msg.Channels, Is.EqualTo(new[] { "home" })); + Assert.That(msg.Json, Is.Not.Null); + Assert.That(msg.Op, Is.EqualTo("cmd")); + Assert.That(msg.UserId, Is.EqualTo("-1")); + Assert.That(msg.DisplayName, Is.Not.Null); + Assert.That(msg.ProfileUrl, Is.Not.Null); + Assert.That(msg.IsAuthenticated, Is.False); + } + + var i = 0; + var stream = client.ServerStreamServerEvents(new StreamServerEvents { Channels = {"home"} }).ResponseStream; + while (await stream.MoveNext(default)) + { + var msg = stream.Current; + if (i == 0) + { + Assert.That(msg.Selector, Is.EqualTo("cmd.onConnect")); + Assert.That(msg.Id, Is.Not.Null); + Assert.That(msg.UnRegisterUrl, Is.Not.Null); + Assert.That(msg.UpdateSubscriberUrl, Is.Not.Null); + Assert.That(msg.HeartbeatUrl, Is.Not.Null); + Assert.That(msg.HeartbeatIntervalMs, Is.GreaterThan(0)); + Assert.That(msg.IdleTimeoutMs, Is.GreaterThan(0)); + AssertMessage(msg); + } + else if (i == 1) + { + Assert.That(msg.Selector, Is.EqualTo("cmd.onJoin")); + AssertMessage(msg); + } + + $"\n\n{i}".Print(); + msg.PrintDump(); + + if (++i == 2) + break; + } + Assert.That(i, Is.EqualTo(2)); + } + + [Test] + public async Task Does_receive_all_messages() + { + var client1 = GetClient(); + var client2 = GetClient(); + + Task.Factory.StartNew(async () => { + await Task.Delay(500); + await client2.CallPostChatToChannelAsync(new PostChatToChannel { + Channel = "send", + From = nameof(client2), + Message = "Hello from client2", + Selector = "cmd.chat", + }); + }); + + var responses = new List(); + var stream = client1.ServerStreamServerEvents(new StreamServerEvents { Channels = {"send"} }).ResponseStream; + while (await stream.MoveNext(default)) + { + var msg = stream.Current; + responses.Add(msg); + + if (msg.Selector == "cmd.chat") + break; + } + + Assert.That(responses[0].Selector, Is.EqualTo("cmd.onConnect")); + Assert.That(responses[1].Selector, Is.EqualTo("cmd.onJoin")); + Assert.That(responses[2].Selector, Is.EqualTo("cmd.chat")); + var obj = (Dictionary) JSON.parse(responses[2].Json); + Assert.That(obj["message"], Is.EqualTo("Hello from client2")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/ProtocTests.cs b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocTests.cs new file mode 100644 index 00000000000..1683c167f4d --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocTests.cs @@ -0,0 +1,429 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.Extensions.Tests.Protoc +{ + public class ProtocTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ProtocTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + RegisterService(); + + Plugins.Add(new ValidationFeature()); + Plugins.Add(new GrpcFeature(App)); + + GlobalRequestFilters.Add((req, res, dto) => { + if (dto is ServiceStack.Extensions.Tests.ThrowCustom) + throw new CustomException(); + }); + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + }); + } + } + + private readonly ServiceStackHost appHost; + public ProtocTests() + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + appHost = new AppHost() + .Init() + .Start(TestsConfig.BaseUri); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + + public static GrpcServices.GrpcServicesClient GetClient(Action init=null) + { + GrpcClientFactory.AllowUnencryptedHttp2 = true; + GrpcServiceStack.ParseResponseStatus = bytes => ResponseStatus.Parser.ParseFrom(bytes); + + var config = new GrpcClientConfig(); + init?.Invoke(config); + var client = new GrpcServices.GrpcServicesClient( + GrpcServiceStack.Client(TestsConfig.BaseUri, config)); + return client; + } + + [Test] + public async Task Can_call_Multiply_Grpc_Service_GrpcServiceClient() + { + var client = GetClient(); + + var response = await client.PostMultiplyAsync(new Multiply { X = 12, Y = 4 }); + Assert.That(response.Result, Is.EqualTo(48)); + } + + [Test] + public void Can_call_Multiply_Grpc_Service_GrpcServiceClient_sync() + { + var client = GetClient(); + + var response = client.PostMultiply(new Multiply { X = 12, Y = 4 }); + Assert.That(response.Result, Is.EqualTo(48)); + } + + [Test] + public async Task Can_call_Incr_ReturnVoid_GrpcServiceClient() + { + var client = GetClient(); + + ServiceStack.Extensions.Tests.Incr.Counter = 0; + + await client.PostIncrAsync(new Incr { Amount = 1 }); + Assert.That(ServiceStack.Extensions.Tests.Incr.Counter, Is.EqualTo(1)); + + await client.PostIncrAsync(new Incr { Amount = 2 }); + Assert.That(ServiceStack.Extensions.Tests.Incr.Counter, Is.EqualTo(3)); + } + + [Test] + public async Task Can_call_GetHello_with_Get() + { + var client = GetClient(); + + var response = await client.CallGetHelloAsync(new GetHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + } + + [Test] + public void Can_call_GetHello_with_Get_sync() + { + var client = GetClient(); + + var response = client.CallGetHello(new GetHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + } + + [Test] + public async Task Can_call_AnyHello_with_Get_Post_or_Send() + { + var client = GetClient(); + + var response = await client.GetAnyHelloAsync(new AnyHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + + response = await client.PostAnyHelloAsync(new AnyHello { Name = "POST" }); + Assert.That(response.Result, Is.EqualTo($"Hello, POST!")); + } + + [Test] + public void Can_call_AnyHello_with_Get_Post_or_Send_sync() + { + var client = GetClient(); + + var response = client.GetAnyHello(new AnyHello { Name = "GET" }); + Assert.That(response.Result, Is.EqualTo($"Hello, GET!")); + + response = client.PostAnyHello(new AnyHello { Name = "POST" }); + Assert.That(response.Result, Is.EqualTo($"Hello, POST!")); + } + + [Test] + public async Task Does_throw_WebServiceException() + { + var client = GetClient(); + + try + { + await client.GetThrowAsync(new Throw { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public void Does_throw_WebServiceException_sync() + { + var client = GetClient(); + + try + { + client.GetThrow(new Throw { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public async Task Does_throw_WebServiceException_ReturnVoid() + { + var client = GetClient(); + + try + { + await client.GetThrowVoidAsync(new ThrowVoid { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + [Test] + public void Does_throw_WebServiceException_ReturnVoid_sync() + { + var client = GetClient(); + + try + { + client.GetThrowVoid(new ThrowVoid { Message = "throw test" }); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(500)); + Assert.That(e.Message, Is.EqualTo("throw test")); + } + } + + public static ProtoBuf.Bcl.Decimal ToProtoBufDecimal(decimal value) + { + // https://github.com/protobuf-net/protobuf-net/blob/master/src/protobuf-net.Core/Internal/PrimaryTypeProvider.Decimal.cs + var to = new ProtoBuf.Bcl.Decimal(); + int[] bits = decimal.GetBits(value); + ulong a = ((ulong) bits[1]) << 32, b = ((ulong) bits[0]) & 0xFFFFFFFFL; + to.Lo = a | b; + to.Hi = (uint) bits[2]; + to.SignScale = (uint) (((bits[3] >> 15) & 0x01FE) | ((bits[3] >> 31) & 0x0001)); + return to; + } + + public static Guid ToGuid(ProtoBuf.Bcl.Guid value) + { + // https://github.com/protobuf-net/protobuf-net/blob/master/src/protobuf-net.Core/Internal/PrimaryTypeProvider.Guid.cs + var low = value.Lo; + var high = value.Hi; + uint a = (uint)(low >> 32), b = (uint)low, c = (uint)(high >> 32), d = (uint)high; + return new Guid((int)b, (short)a, (short)(a >> 16), + (byte)d, (byte)(d >> 8), (byte)(d >> 16), (byte)(d >> 24), + (byte)c, (byte)(c >> 8), (byte)(c >> 16), (byte)(c >> 24)); + } + + [Test] + public async Task Triggering_all_validators_returns_right_ErrorCode() + { + var client = GetClient(); + + var request = new TriggerValidators + { + CreditCard = "NotCreditCard", + Email = "NotEmail", + Empty = "NotEmpty", + Equal = "NotEqual", + ExclusiveBetween = 1, + GreaterThan = 1, + GreaterThanOrEqual = 1, + InclusiveBetween = 1, + Length = "Length", + LessThan = 20, + LessThanOrEqual = 20, + NotEmpty = "", + NotEqual = "NotEqual", + Null = "NotNull", + RegularExpression = "FOO", + ScalePrecision = 123.456m.ToString(CultureInfo.InvariantCulture) + }; + + try + { + var response = await client.PostTriggerValidatorsAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + //ex.ResponseStatus.PrintDump(); + AssertTriggerValidatorsResponse(ex); + } + } + + [Test] + public async Task Triggering_all_validators_returns_right_ErrorCode_from_Headers() + { + var client = GetClient(); + + try + { + var response = await client.PostTriggerValidatorsAsync(new TriggerValidators(), + GrpcUtils.ToHeaders(new { + CreditCard = "NotCreditCard", + Email = "NotEmail", + Empty = "NotEmpty", + Equal = "NotEqual", + ExclusiveBetween = 1, + GreaterThan = 1, + GreaterThanOrEqual = 1, + InclusiveBetween = 1, + Length = "Length", + LessThan = 20, + LessThanOrEqual = 20, + NotEmpty = "", + NotEqual = "NotEqual", + Null = "NotNull", + RegularExpression = "FOO", + ScalePrecision = 123.456m + })); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + //ex.ResponseStatus.PrintDump(); + AssertTriggerValidatorsResponse(ex); + } + } + + private static void AssertTriggerValidatorsResponse(WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + var errors = ex.ResponseStatus.Errors; + Assert.That(errors.First(x => x.FieldName == "CreditCard").ErrorCode, Is.EqualTo("CreditCard")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Empty").ErrorCode, Is.EqualTo("Empty")); + Assert.That(errors.First(x => x.FieldName == "Equal").ErrorCode, Is.EqualTo("Equal")); + Assert.That(errors.First(x => x.FieldName == "ExclusiveBetween").ErrorCode, Is.EqualTo("ExclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "GreaterThan").ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(errors.First(x => x.FieldName == "GreaterThanOrEqual").ErrorCode, Is.EqualTo("GreaterThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "InclusiveBetween").ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "Length").ErrorCode, Is.EqualTo("Length")); + Assert.That(errors.First(x => x.FieldName == "LessThan").ErrorCode, Is.EqualTo("LessThan")); + Assert.That(errors.First(x => x.FieldName == "LessThanOrEqual").ErrorCode, Is.EqualTo("LessThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "NotEmpty").ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors.First(x => x.FieldName == "NotEqual").ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errors.First(x => x.FieldName == "Null").ErrorCode, Is.EqualTo("Null")); + Assert.That(errors.First(x => x.FieldName == "RegularExpression").ErrorCode, Is.EqualTo("RegularExpression")); + Assert.That(errors.First(x => x.FieldName == "ScalePrecision").ErrorCode, Is.EqualTo("ScalePrecision")); + } + + [Test] + public async Task Does_throw_WebServiceException_on_CustomException() + { + var client = GetClient(); + + try + { + await client.GetThrowCustomAsync(new ThrowCustom()); + Assert.Fail("should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(401)); + Assert.That(e.Message, Is.EqualTo("Custom Error Message")); + } + } + + [Test] + public async Task Does_return_Custom_Headers() + { + string customHeader = null; + var client = GetClient(c => { + c.ResponseFilter = ctx => customHeader = ctx.GetHeader("X-Custom"); + }); + + await client.GetAddHeaderAsync(new AddHeader { Name = "X-Custom", Value = "A" }); + Assert.That(customHeader, Is.EqualTo("A")); + } + + [Test] + public async Task Can_download_file() + { + var client = GetClient(); + var response = await client.CallGetFileAsync(new GetFile { Path = "/js/ss-utils.js" }); + AssertSSUtils(response); + } + + private static void AssertSSUtils(FileContent response) + { + Assert.That(response.Name, Is.EqualTo("ss-utils.js")); + Assert.That(response.Length, Is.GreaterThan(0)); + Assert.That(response.Length, Is.EqualTo(response.Body.Length)); + var str = response.Body.Span.FromUtf8Bytes(); + Assert.That(str, Does.Contain("if (!$.ss) $.ss = {};")); + } + + private static void AssertFiles(List responses) + { + Assert.That(responses.Count, Is.EqualTo(3)); + AssertSSUtils(responses[0]); + Assert.That(responses[1].Name, Is.EqualTo("hot-loader.js")); + Assert.That(responses[2].Name, Is.EqualTo("hot-fileloader.js")); + } + + [Test] + public async Task Can_stream_multiple_files() + { + var client = GetClient(); + + var request = new StreamFiles { + Paths = { + "/js/ss-utils.js", + "/js/hot-loader.js", + "/js/not-exists.js", + "/js/hot-fileloader.js", + } + }; + + var files = new List(); + var stream = client.ServerStreamFiles(request).ResponseStream; + while (await stream.MoveNext(default)) + { + var file = stream.Current; + files.Add(file); + } + + Assert.That(files.Count, Is.EqualTo(request.Paths.Count)); + Assert.That(files[2].ResponseStatus.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.NotFound))); + files = files.Where(x => x.ResponseStatus == null).ToList(); + AssertFiles(files); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/ProtocTodoTests.cs b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocTodoTests.cs new file mode 100644 index 00000000000..f058e37dabe --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/ProtocTodoTests.cs @@ -0,0 +1,109 @@ +using System; +using System.Threading.Tasks; +using Funq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; +using ProtoBuf.Grpc.Client; + +namespace ServiceStack.Extensions.Tests.Protoc +{ + public class ProtocTodoTests + { + private readonly ServiceStackHost appHost; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(GrpcTests), typeof(TodoServices).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new GrpcFeature(App)); + Plugins.Add(new ServerEventsFeature()); + + } + + public override void ConfigureKestrel(KestrelServerOptions options) + { + options.ListenLocalhost(TestsConfig.Port, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + } + + public override void Configure(IServiceCollection services) + { + services.AddServiceStackGrpc(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseRouting(); + } + } + + public ProtocTodoTests() + { + appHost = new AppHost() + .Init() + .Start(TestsConfig.BaseUri); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private static GrpcServices.GrpcServicesClient GetClient(Action init = null) => + ProtocTests.GetClient(init); + + [Test] + public async Task Can_CreateTodo() + { + var client = GetClient(); + await client.PostResetTodosAsync(new ResetTodos()); + + var response = await client.PostCreateTodoAsync(new CreateTodo { + Title = "A", + Order = 1, + }); + + Assert.That(response.Result.Id, Is.GreaterThan(0)); + Assert.That(response.Result.Title, Is.EqualTo("A")); + Assert.That(response.Result.Order, Is.EqualTo(1)); + Assert.That(response.Result.Completed, Is.False); + } + + [Test] + public async Task Does_CRUD_Example() + { + var client = GetClient(); + await client.PostResetTodosAsync(new ResetTodos()); + + //GET /todos + var all = await client.CallGetTodosAsync(new GetTodos()); + Assert.That(all.Results?.Count ?? 0, Is.EqualTo(0)); + + //POST /todos + var todo = (await client.PostCreateTodoAsync(new CreateTodo { Title = "ServiceStack" })).Result; + Assert.That(todo.Id, Is.EqualTo(1)); + //GET /todos/1 + todo = (await client.CallGetTodoAsync(new GetTodo { Id = todo.Id })).Result; + Assert.That(todo.Title, Is.EqualTo("ServiceStack")); + + //GET /todos + all = await client.CallGetTodosAsync(new GetTodos()); + Assert.That(all.Results.Count, Is.EqualTo(1)); + + //PUT /todos/1 + await client.PutUpdateTodoAsync(new UpdateTodo { Id = todo.Id, Title = "gRPC" }); + todo = (await client.CallGetTodoAsync(new GetTodo { Id = todo.Id })).Result; + Assert.That(todo.Title, Is.EqualTo("gRPC")); + + //DELETE /todos/1 + await client.CallDeleteTodoAsync(new DeleteTodo { Id = todo.Id }); + //GET /todos + all = await client.CallGetTodosAsync(new GetTodos()); + Assert.That(all.Results?.Count ?? 0, Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/Services.cs b/tests/ServiceStack.Extensions.Tests/Protoc/Services.cs new file mode 100644 index 00000000000..189c1677821 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/Services.cs @@ -0,0 +1,53600 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: services.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace ServiceStack.Extensions.Tests.Protoc { + + /// Holder for reflection information generated from services.proto + public static partial class ServicesReflection { + + #region Descriptor + /// File descriptor for services.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static ServicesReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Cg5zZXJ2aWNlcy5wcm90bxofZ29vZ2xlL3Byb3RvYnVmL3RpbWVzdGFtcC5w", + "cm90bxoeZ29vZ2xlL3Byb3RvYnVmL2R1cmF0aW9uLnByb3RvIigKCUFkZEhl", + "YWRlchIMCgROYW1lGAEgASgJEg0KBVZhbHVlGAIgASgJIjkKBUFkaG9jEgoK", + "AklkGAEgASgFEhIKCmZpcnN0X25hbWUYAiABKAkSEAoITGFzdE5hbWUYAyAB", + "KAkigAQKCUFsbEZpZWxkcxIKCgJJZBgBIAEoBRISCgpOdWxsYWJsZUlkGAIg", + "ASgFEgwKBEJ5dGUYAyABKA0SDQoFU2hvcnQYBCABKAUSCwoDSW50GAUgASgF", + "EgwKBExvbmcYBiABKAMSDgoGVVNob3J0GAcgASgNEgwKBFVJbnQYCCABKA0S", + "DQoFVUxvbmcYCSABKAQSDQoFRmxvYXQYCiABKAISDgoGRG91YmxlGAsgASgB", + "Eg8KB0RlY2ltYWwYDCABKAkSDgoGU3RyaW5nGA0gASgJEiwKCERhdGVUaW1l", + "GA4gASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIrCghUaW1lU3Bh", + "bhgPIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbhIMCgRHdWlkGBAg", + "ASgJEjQKEE51bGxhYmxlRGF0ZVRpbWUYESABKAsyGi5nb29nbGUucHJvdG9i", + "dWYuVGltZXN0YW1wEjMKEE51bGxhYmxlVGltZVNwYW4YEiABKAsyGS5nb29n", + "bGUucHJvdG9idWYuRHVyYXRpb24SFAoMTnVsbGFibGVHdWlkGBMgASgJEh0K", + "BEVudW0YFCABKA4yDy5IdHRwU3RhdHVzQ29kZRIlCgxOdWxsYWJsZUVudW0Y", + "FSABKA4yDy5IdHRwU3RhdHVzQ29kZSIYCghBbnlIZWxsbxIMCgROYW1lGAEg", + "ASgJIpYBCgtBc3NpZ25Sb2xlcxIQCghVc2VyTmFtZRgBIAEoCRITCgtQZXJt", + "aXNzaW9ucxgCIAMoCRINCgVSb2xlcxgDIAMoCRIkCgRNZXRhGAQgAygLMhYu", + "QXNzaWduUm9sZXMuTWV0YUVudHJ5GisKCU1ldGFFbnRyeRILCgNrZXkYASAB", + "KAkSDQoFdmFsdWUYAiABKAk6AjgBIsMBChNBc3NpZ25Sb2xlc1Jlc3BvbnNl", + "EhAKCEFsbFJvbGVzGAEgAygJEhYKDkFsbFBlcm1pc3Npb25zGAIgAygJEiwK", + "BE1ldGEYAyADKAsyHi5Bc3NpZ25Sb2xlc1Jlc3BvbnNlLk1ldGFFbnRyeRIn", + "Cg5SZXNwb25zZVN0YXR1cxgEIAEoCzIPLlJlc3BvbnNlU3RhdHVzGisKCU1l", + "dGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIugCCglB", + "dWRpdEJhc2USLwoLQ3JlYXRlZERhdGUYASABKAsyGi5nb29nbGUucHJvdG9i", + "dWYuVGltZXN0YW1wEhEKCUNyZWF0ZWRCeRgCIAEoCRITCgtDcmVhdGVkSW5m", + "bxgDIAEoCRIwCgxNb2RpZmllZERhdGUYBCABKAsyGi5nb29nbGUucHJvdG9i", + "dWYuVGltZXN0YW1wEhIKCk1vZGlmaWVkQnkYBSABKAkSFAoMTW9kaWZpZWRJ", + "bmZvGAYgASgJEjMKD1NvZnREZWxldGVkRGF0ZRgHIAEoCzIaLmdvb2dsZS5w", + "cm90b2J1Zi5UaW1lc3RhbXASFQoNU29mdERlbGV0ZWRCeRgIIAEoCRIXCg9T", + "b2Z0RGVsZXRlZEluZm8YCSABKAkSNgoTUm9ja3N0YXJBdWRpdFRlbmFudBiC", + "haR4IAEoCzIULlJvY2tzdGFyQXVkaXRUZW5hbnRIAEIJCgdzdWJ0eXBlIqkD", + "CgxBdXRoZW50aWNhdGUSEAoIcHJvdmlkZXIYASABKAkSDQoFU3RhdGUYAiAB", + "KAkSEwoLb2F1dGhfdG9rZW4YAyABKAkSFgoOb2F1dGhfdmVyaWZpZXIYBCAB", + "KAkSEAoIVXNlck5hbWUYBSABKAkSEAoIUGFzc3dvcmQYBiABKAkSEgoKUmVt", + "ZW1iZXJNZRgHIAEoCBIRCglFcnJvclZpZXcYCSABKAkSDQoFbm9uY2UYCiAB", + "KAkSCwoDdXJpGAsgASgJEhAKCHJlc3BvbnNlGAwgASgJEgsKA3FvcBgNIAEo", + "CRIKCgJuYxgOIAEoCRIOCgZjbm9uY2UYDyABKAkSFgoOVXNlVG9rZW5Db29r", + "aWUYECABKAgSEwoLQWNjZXNzVG9rZW4YESABKAkSGQoRQWNjZXNzVG9rZW5T", + "ZWNyZXQYEiABKAkSDQoFc2NvcGUYEyABKAkSJQoETWV0YRgUIAMoCzIXLkF1", + "dGhlbnRpY2F0ZS5NZXRhRW50cnkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEo", + "CRINCgV2YWx1ZRgCIAEoCToCOAEi3QIKFEF1dGhlbnRpY2F0ZVJlc3BvbnNl", + "Eg4KBlVzZXJJZBgBIAEoCRIRCglTZXNzaW9uSWQYAiABKAkSEAoIVXNlck5h", + "bWUYAyABKAkSEwoLRGlzcGxheU5hbWUYBCABKAkSEwoLUmVmZXJyZXJVcmwY", + "BSABKAkSEwoLQmVhcmVyVG9rZW4YBiABKAkSFAoMUmVmcmVzaFRva2VuGAcg", + "ASgJEhIKClByb2ZpbGVVcmwYCCABKAkSDQoFUm9sZXMYCSADKAkSEwoLUGVy", + "bWlzc2lvbnMYCiADKAkSJwoOUmVzcG9uc2VTdGF0dXMYCyABKAsyDy5SZXNw", + "b25zZVN0YXR1cxItCgRNZXRhGAwgAygLMh8uQXV0aGVudGljYXRlUmVzcG9u", + "c2UuTWV0YUVudHJ5GisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFs", + "dWUYAiABKAk6AjgBIhAKA0JhchIJCgFZGAIgASgJIkkKCEJvb2ttYXJrEgwK", + "BFNsdWcYASABKAkSDQoFVGl0bGUYAiABKAkSEwoLRGVzY3JpcHRpb24YAyAB", + "KAkSCwoDVXJsGAQgASgJIhYKFENoYW5nZUNvbm5lY3Rpb25JbmZvIlMKCENo", + "YW5nZURiEhcKD05hbWVkQ29ubmVjdGlvbhgBIAEoCRIYChBDb25uZWN0aW9u", + "U3RyaW5nGAIgASgJEhQKDFByb3ZpZGVyTmFtZRgDIAEoCSIuChBDaGFuZ2VE", + "YlJlc3BvbnNlEhoKB1Jlc3VsdHMYASADKAsyCS5Sb2Nrc3RhciKbAQoLQ2hh", + "dE1lc3NhZ2USCgoCSWQYASABKAMSDwoHQ2hhbm5lbBgCIAEoCRISCgpGcm9t", + "VXNlcklkGAMgASgJEhAKCEZyb21OYW1lGAQgASgJEhMKC0Rpc3BsYXlOYW1l", + "GAUgASgJEg8KB01lc3NhZ2UYBiABKAkSEgoKVXNlckF1dGhJZBgHIAEoCRIP", + "CgdQcml2YXRlGAggASgIIo0BChVDb252ZXJ0U2Vzc2lvblRvVG9rZW4SFwoP", + "UHJlc2VydmVTZXNzaW9uGAEgASgIEi4KBE1ldGEYAiADKAsyIC5Db252ZXJ0", + "U2Vzc2lvblRvVG9rZW4uTWV0YUVudHJ5GisKCU1ldGFFbnRyeRILCgNrZXkY", + "ASABKAkSDQoFdmFsdWUYAiABKAk6AjgBItgBCh1Db252ZXJ0U2Vzc2lvblRv", + "VG9rZW5SZXNwb25zZRI2CgRNZXRhGAEgAygLMiguQ29udmVydFNlc3Npb25U", + "b1Rva2VuUmVzcG9uc2UuTWV0YUVudHJ5EhMKC0FjY2Vzc1Rva2VuGAIgASgJ", + "EhQKDFJlZnJlc2hUb2tlbhgDIAEoCRInCg5SZXNwb25zZVN0YXR1cxgEIAEo", + "CzIPLlJlc3BvbnNlU3RhdHVzGisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkS", + "DQoFdmFsdWUYAiABKAk6AjgBIkUKQ0NyZWF0ZUF1ZGl0QmFzZV9Sb2Nrc3Rh", + "ckF1ZGl0VGVuYW50X1JvY2tzdGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2Ui", + "SwpJQ3JlYXRlQXVkaXRUZW5hbnRCYXNlX1JvY2tzdGFyQXVkaXRUZW5hbnRf", + "Um9ja3N0YXJXaXRoSWRBbmRSZXN1bHRSZXNwb25zZSJPCg5DcmVhdGVCb29r", + "bWFyaxIMCgRTbHVnGAEgASgJEg0KBVRpdGxlGAIgASgJEhMKC0Rlc2NyaXB0", + "aW9uGAMgASgJEgsKA1VybBgEIAEoCSJnChZDcmVhdGVCb29rbWFya1Jlc3Bv", + "bnNlEgoKAklkGAEgASgJEhgKBlJlc3VsdBgCIAEoCzIILkRhb0Jhc2USJwoO", + "UmVzcG9uc2VTdGF0dXMYAyABKAsyDy5SZXNwb25zZVN0YXR1cyLgAQocQ3Jl", + "YXRlQ29ubmVjdGlvbkluZm9Sb2Nrc3RhchIRCglGaXJzdE5hbWUYASABKAkS", + "EAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMgASgFEi8KC0RhdGVPZkJpcnRo", + "GAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghEYXRlRGll", + "ZBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5n", + "U3RhdHVzGAYgASgOMg0uTGl2aW5nU3RhdHVzEgoKAklkGGUgASgFItcBChND", + "cmVhdGVOYW1lZFJvY2tzdGFyEhEKCUZpcnN0TmFtZRgBIAEoCRIQCghMYXN0", + "TmFtZRgCIAEoCRILCgNBZ2UYAyABKAUSLwoLRGF0ZU9mQmlydGgYBCABKAsy", + "Gi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiwKCERhdGVEaWVkGAUgASgL", + "MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIjCgxMaXZpbmdTdGF0dXMY", + "BiABKA4yDS5MaXZpbmdTdGF0dXMSCgoCSWQYZSABKAUixgEKDkNyZWF0ZVJv", + "Y2tzdGFyEhEKCUZpcnN0TmFtZRgBIAEoCRIQCghMYXN0TmFtZRgCIAEoCRIL", + "CgNBZ2UYAyABKAUSLwoLRGF0ZU9mQmlydGgYBCABKAsyGi5nb29nbGUucHJv", + "dG9idWYuVGltZXN0YW1wEiwKCERhdGVEaWVkGAUgASgLMhouZ29vZ2xlLnBy", + "b3RvYnVmLlRpbWVzdGFtcBIjCgxMaXZpbmdTdGF0dXMYBiABKA4yDS5MaXZp", + "bmdTdGF0dXMi1gEKHkNyZWF0ZVJvY2tzdGFyQWRob2NOb25EZWZhdWx0cxIR", + "CglGaXJzdE5hbWUYASABKAkSEAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMg", + "ASgFEi8KC0RhdGVPZkJpcnRoGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRp", + "bWVzdGFtcBIsCghEYXRlRGllZBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5U", + "aW1lc3RhbXASIwoMTGl2aW5nU3RhdHVzGAYgASgOMg0uTGl2aW5nU3RhdHVz", + "IssBChNDcmVhdGVSb2Nrc3RhckF1ZGl0EhEKCUZpcnN0TmFtZRgBIAEoCRIQ", + "CghMYXN0TmFtZRgCIAEoCRILCgNBZ2UYAyABKAUSLwoLRGF0ZU9mQmlydGgY", + "BCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiwKCERhdGVEaWVk", + "GAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIjCgxMaXZpbmdT", + "dGF0dXMYBiABKA4yDS5MaXZpbmdTdGF0dXMi5wEKGkNyZWF0ZVJvY2tzdGFy", + "QXVkaXRNcVRva2VuEhEKCUZpcnN0TmFtZRgBIAEoCRIQCghMYXN0TmFtZRgC", + "IAEoCRILCgNBZ2UYAyABKAUSLwoLRGF0ZU9mQmlydGgYBCABKAsyGi5nb29n", + "bGUucHJvdG9idWYuVGltZXN0YW1wEiwKCERhdGVEaWVkGAUgASgLMhouZ29v", + "Z2xlLnByb3RvYnVmLlRpbWVzdGFtcBIjCgxMaXZpbmdTdGF0dXMYBiABKA4y", + "DS5MaXZpbmdTdGF0dXMSEwoLQmVhcmVyVG9rZW4YZSABKAki7QEKGUNyZWF0", + "ZVJvY2tzdGFyQXVkaXRUZW5hbnQSFAoLQmVhcmVyVG9rZW4YyQEgASgJEhIK", + "CUZpcnN0TmFtZRjKASABKAkSEQoITGFzdE5hbWUYywEgASgJEgwKA0FnZRjM", + "ASABKAUSMAoLRGF0ZU9mQmlydGgYzQEgASgLMhouZ29vZ2xlLnByb3RvYnVm", + "LlRpbWVzdGFtcBItCghEYXRlRGllZBjOASABKAsyGi5nb29nbGUucHJvdG9i", + "dWYuVGltZXN0YW1wEiQKDExpdmluZ1N0YXR1cxjPASABKA4yDS5MaXZpbmdT", + "dGF0dXMi2AEKIENyZWF0ZVJvY2tzdGFyQXVkaXRUZW5hbnRHYXRld2F5EhEK", + "CUZpcnN0TmFtZRgBIAEoCRIQCghMYXN0TmFtZRgCIAEoCRILCgNBZ2UYAyAB", + "KAUSLwoLRGF0ZU9mQmlydGgYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGlt", + "ZXN0YW1wEiwKCERhdGVEaWVkGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRp", + "bWVzdGFtcBIjCgxMaXZpbmdTdGF0dXMYBiABKA4yDS5MaXZpbmdTdGF0dXMi", + "0wEKG0NyZWF0ZVJvY2tzdGFyQXVkaXRUZW5hbnRNcRIRCglGaXJzdE5hbWUY", + "ASABKAkSEAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMgASgFEi8KC0RhdGVP", + "ZkJpcnRoGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghE", + "YXRlRGllZBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoM", + "TGl2aW5nU3RhdHVzGAYgASgOMg0uTGl2aW5nU3RhdHVzIt8BChVDcmVhdGVS", + "b2Nrc3RhckF1dG9NYXASFAoMTWFwRmlyc3ROYW1lGAEgASgJEhMKC01hcExh", + "c3ROYW1lGAIgASgJEg4KBk1hcEFnZRgDIAEoBRIyCg5NYXBEYXRlT2ZCaXJ0", + "aBgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASLwoLTWFwRGF0", + "ZURpZWQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiYKD01h", + "cExpdmluZ1N0YXR1cxgGIAEoDjINLkxpdmluZ1N0YXR1cyJBChZDcmVhdGVS", + "b2Nrc3RhclJlc3BvbnNlEicKDlJlc3BvbnNlU3RhdHVzGAEgASgLMg8uUmVz", + "cG9uc2VTdGF0dXMizQEKFUNyZWF0ZVJvY2tzdGFyVmVyc2lvbhIRCglGaXJz", + "dE5hbWUYASABKAkSEAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMgASgFEi8K", + "C0RhdGVPZkJpcnRoGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFt", + "cBIsCghEYXRlRGllZBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3Rh", + "bXASIwoMTGl2aW5nU3RhdHVzGAYgASgOMg0uTGl2aW5nU3RhdHVzItIBChpD", + "cmVhdGVSb2Nrc3RhcldpdGhBdXRvR3VpZBIRCglGaXJzdE5hbWUYASABKAkS", + "EAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMgASgFEi8KC0RhdGVPZkJpcnRo", + "GAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghEYXRlRGll", + "ZBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5n", + "U3RhdHVzGAYgASgOMg0uTGl2aW5nU3RhdHVzItABChhDcmVhdGVSb2Nrc3Rh", + "cldpdGhSZXR1cm4SEQoJRmlyc3ROYW1lGAEgASgJEhAKCExhc3ROYW1lGAIg", + "ASgJEgsKA0FnZRgDIAEoBRIvCgtEYXRlT2ZCaXJ0aBgEIAEoCzIaLmdvb2ds", + "ZS5wcm90b2J1Zi5UaW1lc3RhbXASLAoIRGF0ZURpZWQYBSABKAsyGi5nb29n", + "bGUucHJvdG9idWYuVGltZXN0YW1wEiMKDExpdmluZ1N0YXR1cxgGIAEoDjIN", + "LkxpdmluZ1N0YXR1cyJ6CiRDcmVhdGVSb2Nrc3RhcldpdGhSZXR1cm5HdWlk", + "UmVzcG9uc2USCgoCSWQYASABKAkSHQoGUmVzdWx0GAIgASgLMg0uUm9ja3N0", + "YXJCYXNlEicKDlJlc3BvbnNlU3RhdHVzGAMgASgLMg8uUmVzcG9uc2VTdGF0", + "dXMi1AEKHENyZWF0ZVJvY2tzdGFyV2l0aFZvaWRSZXR1cm4SEQoJRmlyc3RO", + "YW1lGAEgASgJEhAKCExhc3ROYW1lGAIgASgJEgsKA0FnZRgDIAEoBRIvCgtE", + "YXRlT2ZCaXJ0aBgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAS", + "LAoIRGF0ZURpZWQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w", + "EiMKDExpdmluZ1N0YXR1cxgGIAEoDjINLkxpdmluZ1N0YXR1cyIqCgpDcmVh", + "dGVUb2RvEg0KBVRpdGxlGAEgASgJEg0KBU9yZGVyGAIgASgFIlQKEkNyZWF0", + "ZVRvZG9SZXNwb25zZRIVCgZSZXN1bHQYASABKAsyBS5Ub2RvEicKDlJlc3Bv", + "bnNlU3RhdHVzGAIgASgLMg8uUmVzcG9uc2VTdGF0dXMieAoOQ3VzdG9tUm9j", + "a3N0YXISEQoJRmlyc3ROYW1lGAEgASgJEhAKCExhc3ROYW1lGAIgASgJEgsK", + "A0FnZRgDIAEoBRIZChFSb2Nrc3RhckFsYnVtTmFtZRgEIAEoCRIZChFSb2Nr", + "c3RhckdlbnJlTmFtZRgFIAEoCSJ+ChRDdXN0b21Sb2Nrc3RhclNjaGVtYRIR", + "CglGaXJzdE5hbWUYASABKAkSEAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMg", + "ASgFEhkKEVJvY2tzdGFyQWxidW1OYW1lGAQgASgJEhkKEVJvY2tzdGFyR2Vu", + "cmVOYW1lGAUgASgJIlQKFEN1c3RvbVNlbGVjdFJvY2tzdGFyEgoKAklkGAEg", + "ASgFEhEKCUZpcnN0TmFtZRgCIAEoCRIQCghMYXN0TmFtZRgDIAEoCRILCgNB", + "Z2UYBCABKAUiSgocQ3VzdG9tU2VsZWN0Um9ja3N0YXJSZXNwb25zZRIKCgJJ", + "ZBgBIAEoBRIRCglGaXJzdE5hbWUYAiABKAkSCwoDQWdlGAMgASgFItIBChZD", + "dXN0b21WYWxpZGF0aW9uRXJyb3JzEhcKD0N1c3RvbUVycm9yQ29kZRgBIAEo", + "CRIhChlDdXN0b21FcnJvckNvZGVBbmRNZXNzYWdlGAIgASgFEhUKDUVycm9y", + "Q29kZVJ1bGUYAyABKAkSFgoOSXNPZGRDb25kaXRpb24YBCABKAUSJgoeSXNP", + "ZGRBbmRPdmVyVHdvRGlnaXRzQ29uZGl0aW9uGAUgASgFEiUKHUlzT2RkT3JP", + "dmVyVHdvRGlnaXRzQ29uZGl0aW9uGAYgASgFIswBCgdEYW9CYXNlEgoKAklk", + "GAEgASgJEi4KCkNyZWF0ZURhdGUYAiABKAsyGi5nb29nbGUucHJvdG9idWYu", + "VGltZXN0YW1wEhEKCUNyZWF0ZWRCeRgDIAEoCRIwCgxNb2RpZmllZERhdGUY", + "BCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEhIKCk1vZGlmaWVk", + "QnkYBSABKAkSIQoIQm9va21hcmsY4/XF0QEgASgLMgkuQm9va21hcmtIAEIJ", + "CgdzdWJ0eXBlIhwKDkRlbGV0ZVJvY2tzdGFyEgoKAklkGAEgASgFIiEKE0Rl", + "bGV0ZVJvY2tzdGFyQXVkaXQSCgoCSWQYASABKAUiVQobRGVsZXRlUm9ja3N0", + "YXJDb3VudFJlc3BvbnNlEg0KBUNvdW50GAEgASgFEicKDlJlc3BvbnNlU3Rh", + "dHVzGAIgASgLMg8uUmVzcG9uc2VTdGF0dXMiSQoVRGVsZXRlUm9ja3N0YXJG", + "aWx0ZXJzEhEKCUZpcnN0TmFtZRgBIAEoCRIQCghMYXN0TmFtZRgCIAEoCRIL", + "CgNBZ2UYAyABKAUiGAoKRGVsZXRlVG9kbxIKCgJJZBgBIAEoAyIeCgtEZWxl", + "dGVUb2RvcxIPCgNJZHMYASADKANCAhAAImwKDkR5bmFtaWNSZXF1ZXN0EisK", + "BlBhcmFtcxgBIAMoCzIbLkR5bmFtaWNSZXF1ZXN0LlBhcmFtc0VudHJ5Gi0K", + "C1BhcmFtc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi", + "oAEKFkR5bmFtaWNWYWxpZGF0aW9uUnVsZXMSEQoJRmlyc3ROYW1lGAEgASgJ", + "EhAKCExhc3ROYW1lGAIgASgJEgsKA0FnZRgDIAEoBRIvCgtEYXRlT2ZCaXJ0", + "aBgEIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5n", + "U3RhdHVzGAUgASgOMg0uTGl2aW5nU3RhdHVzIjgKDUVtcHR5UmVzcG9uc2US", + "JwoOUmVzcG9uc2VTdGF0dXMYASABKAsyDy5SZXNwb25zZVN0YXR1cyLBAQoP", + "RW1wdHlWYWxpZGF0b3JzEgsKA0ludBgBIAEoBRIMCgROSW50GAIgASgFEisK", + "CFRpbWVTcGFuGAMgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uEiwK", + "CU5UaW1lU3BhbhgEIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbhIO", + "CgZTdHJpbmcYBSABKAkSFAoISW50QXJyYXkYBiADKAVCAhAAEhIKClN0cmlu", + "Z0xpc3QYByADKAkiJwoVRW5kc1dpdGhTdWZmaXhSZXF1ZXN0Eg4KBlN1ZmZp", + "eBgBIAEoCSJVChZFbmRzV2l0aFN1ZmZpeFJlc3BvbnNlEh0KBlJlc3VsdBgB", + "IAEoCzINLlNlYXJjaFJlc3VsdBINCgVDb3VudBgCIAEoBRINCgVXb3JkcxgD", + "IAMoCSIHCgVFbnRyeSJwCgtGaWxlQ29udGVudBIMCgROYW1lGAEgASgJEgwK", + "BFR5cGUYAiABKAkSDgoGTGVuZ3RoGAMgASgFEgwKBEJvZHkYBCABKAwSJwoO", + "UmVzcG9uc2VTdGF0dXMYBSABKAsyDy5SZXNwb25zZVN0YXR1cyIzCgNGb28S", + "CQoBWBgBIAEoCRIWCgNCYXIY1v+jZCABKAsyBC5CYXJIAEIJCgdzdWJ0eXBl", + "IpQBCg5HZXRBY2Nlc3NUb2tlbhIUCgxSZWZyZXNoVG9rZW4YASABKAkSFgoO", + "VXNlVG9rZW5Db29raWUYAiABKAgSJwoETWV0YRgDIAMoCzIZLkdldEFjY2Vz", + "c1Rva2VuLk1ldGFFbnRyeRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0K", + "BXZhbHVlGAIgASgJOgI4ASK0AQoWR2V0QWNjZXNzVG9rZW5SZXNwb25zZRIT", + "CgtBY2Nlc3NUb2tlbhgBIAEoCRIvCgRNZXRhGAIgAygLMiEuR2V0QWNjZXNz", + "VG9rZW5SZXNwb25zZS5NZXRhRW50cnkSJwoOUmVzcG9uc2VTdGF0dXMYAyAB", + "KAsyDy5SZXNwb25zZVN0YXR1cxorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJ", + "Eg0KBXZhbHVlGAIgASgJOgI4ASJzCgpHZXRBcGlLZXlzEhMKC0Vudmlyb25t", + "ZW50GAEgASgJEiMKBE1ldGEYAiADKAsyFS5HZXRBcGlLZXlzLk1ldGFFbnRy", + "eRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4", + "ASK1AQoSR2V0QXBpS2V5c1Jlc3BvbnNlEhwKB1Jlc3VsdHMYASADKAsyCy5V", + "c2VyQXBpS2V5EisKBE1ldGEYAiADKAsyHS5HZXRBcGlLZXlzUmVzcG9uc2Uu", + "TWV0YUVudHJ5EicKDlJlc3BvbnNlU3RhdHVzGAMgASgLMg8uUmVzcG9uc2VT", + "dGF0dXMaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEo", + "CToCOAEiFwoHR2V0RmlsZRIMCgRQYXRoGAEgASgJIhgKCEdldEhlbGxvEgwK", + "BE5hbWUYASABKAkiFQoHR2V0VG9kbxIKCgJJZBgBIAEoAyJRCg9HZXRUb2Rv", + "UmVzcG9uc2USFQoGUmVzdWx0GAEgASgLMgUuVG9kbxInCg5SZXNwb25zZVN0", + "YXR1cxgCIAEoCzIPLlJlc3BvbnNlU3RhdHVzIgoKCEdldFRvZG9zIlMKEEdl", + "dFRvZG9zUmVzcG9uc2USFgoHUmVzdWx0cxgBIAMoCzIFLlRvZG8SJwoOUmVz", + "cG9uc2VTdGF0dXMYAiABKAsyDy5SZXNwb25zZVN0YXR1cyItCghIZWxsb0p3", + "dBIMCgROYW1lGAEgASgJEhMKC0JlYXJlclRva2VuGAIgASgJIksKEEhlbGxv", + "Snd0UmVzcG9uc2USDgoGUmVzdWx0GAEgASgJEicKDlJlc3BvbnNlU3RhdHVz", + "GAIgASgLMg8uUmVzcG9uc2VTdGF0dXMiSAoNSGVsbG9SZXNwb25zZRIOCgZS", + "ZXN1bHQYASABKAkSJwoOUmVzcG9uc2VTdGF0dXMYAiABKAsyDy5SZXNwb25z", + "ZVN0YXR1cyIWCgRJbmNyEg4KBkFtb3VudBgBIAEoBSK1AQoFTW92aWUSCgoC", + "SWQYASABKAUSDgoGSW1kYklkGAIgASgJEg0KBVRpdGxlGAMgASgJEg4KBlJh", + "dGluZxgEIAEoCRINCgVTY29yZRgFIAEoCRIQCghEaXJlY3RvchgGIAEoCRIv", + "CgtSZWxlYXNlRGF0ZRgHIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3Rh", + "bXASDwoHVGFnTGluZRgIIAEoCRIOCgZHZW5yZXMYCSADKAkiIAoITXVsdGlw", + "bHkSCQoBWBgBIAEoBRIJCgFZGAIgASgFIiIKEE11bHRpcGx5UmVzcG9uc2US", + "DgoGUmVzdWx0GAEgASgFIg8KDU5hbWVkUm9ja3N0YXIinQEKE05vQWJzdHJh", + "Y3RWYWxpZGF0b3ISEQoJRmlyc3ROYW1lGAEgASgJEhAKCExhc3ROYW1lGAIg", + "ASgJEgsKA0FnZRgDIAEoBRIvCgtEYXRlT2ZCaXJ0aBgEIAEoCzIaLmdvb2ds", + "ZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5nU3RhdHVzGAUgASgOMg0u", + "TGl2aW5nU3RhdHVzIjUKFE9ubHlWYWxpZGF0ZXNSZXF1ZXN0EgwKBFRlc3QY", + "ASABKAUSDwoHTm90TnVsbBgCIAEoCSI1CgpQYWdpbmdUZXN0EgoKAklkGAEg", + "ASgFEgwKBE5hbWUYAiABKAkSDQoFVmFsdWUYAyABKAUiRApCUGF0Y2hBdWRp", + "dEJhc2VfUm9ja3N0YXJBdWRpdFRlbmFudF9Sb2Nrc3RhcldpdGhJZEFuZFJl", + "c3VsdFJlc3BvbnNlIkoKSFBhdGNoQXVkaXRUZW5hbnRCYXNlX1JvY2tzdGFy", + "QXVkaXRUZW5hbnRfUm9ja3N0YXJXaXRoSWRBbmRSZXN1bHRSZXNwb25zZSLR", + "AQoNUGF0Y2hSb2Nrc3RhchIRCglGaXJzdE5hbWUYASABKAkSEAoITGFzdE5h", + "bWUYAiABKAkSCwoDQWdlGAMgASgFEi8KC0RhdGVPZkJpcnRoGAQgASgLMhou", + "Z29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghEYXRlRGllZBgFIAEoCzIa", + "Lmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5nU3RhdHVzGAYg", + "ASgOMg0uTGl2aW5nU3RhdHVzEgoKAklkGGUgASgFIncKGFBhdGNoUm9ja3N0", + "YXJBdWRpdFRlbmFudBIUCgtCZWFyZXJUb2tlbhjJASABKAkSCwoCSWQYygEg", + "ASgFEhIKCUZpcnN0TmFtZRjLASABKAkSJAoMTGl2aW5nU3RhdHVzGMwBIAEo", + "DjINLkxpdmluZ1N0YXR1cyJlCh9QYXRjaFJvY2tzdGFyQXVkaXRUZW5hbnRH", + "YXRld2F5EgoKAklkGAEgASgFEhEKCUZpcnN0TmFtZRgCIAEoCRIjCgxMaXZp", + "bmdTdGF0dXMYAyABKA4yDS5MaXZpbmdTdGF0dXMiYAoaUGF0Y2hSb2Nrc3Rh", + "ckF1ZGl0VGVuYW50TXESCgoCSWQYASABKAUSEQoJRmlyc3ROYW1lGAIgASgJ", + "EiMKDExpdmluZ1N0YXR1cxgDIAEoDjINLkxpdmluZ1N0YXR1cyJnChFQb3N0", + "Q2hhdFRvQ2hhbm5lbBIMCgRGcm9tGAEgASgJEhAKCFRvVXNlcklkGAIgASgJ", + "Eg8KB0NoYW5uZWwYAyABKAkSDwoHTWVzc2FnZRgEIAEoCRIQCghTZWxlY3Rv", + "chgFIAEoCSLBAQoKUXVlcnlBZGhvYxIMCgRTa2lwGAEgASgFEgwKBFRha2UY", + "AiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIP", + "CgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEoCRIjCgRNZXRhGAcgAygL", + "MhUuUXVlcnlBZGhvYy5NZXRhRW50cnkaKwoJTWV0YUVudHJ5EgsKA2tleRgB", + "IAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi6AEKE1F1ZXJ5QWRob2NSb2Nrc3Rh", + "cnMSDAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyAB", + "KAkSEwoLT3JkZXJCeURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZG", + "aWVsZHMYBiABKAkSLAoETWV0YRgHIAMoCzIeLlF1ZXJ5QWRob2NSb2Nrc3Rh", + "cnMuTWV0YUVudHJ5EhMKCmZpcnN0X25hbWUYyQEgASgJGisKCU1ldGFFbnRy", + "eRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBItgBCg5RdWVyeUFs", + "bEZpZWxkcxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJC", + "eRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJ", + "Eg4KBkZpZWxkcxgGIAEoCRInCgRNZXRhGAcgAygLMhkuUXVlcnlBbGxGaWVs", + "ZHMuTWV0YUVudHJ5Eg0KBEd1aWQYyQEgASgJGisKCU1ldGFFbnRyeRILCgNr", + "ZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIskBCg5RdWVyeUJvb2ttYXJr", + "cxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEo", + "CRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZp", + "ZWxkcxgGIAEoCRInCgRNZXRhGAcgAygLMhkuUXVlcnlCb29rbWFya3MuTWV0", + "YUVudHJ5GisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiAB", + "KAk6AjgBIvEBChtRdWVyeUNhc2VJbnNlbnNpdGl2ZU9yZGVyQnkSDAoEU2tp", + "cBgBIAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3Jk", + "ZXJCeURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiAB", + "KAkSNAoETWV0YRgHIAMoCzImLlF1ZXJ5Q2FzZUluc2Vuc2l0aXZlT3JkZXJC", + "eS5NZXRhRW50cnkSDAoDQWdlGMkBIAEoBRorCglNZXRhRW50cnkSCwoDa2V5", + "GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLfAQoZUXVlcnlDaGFuZ2VDb25u", + "ZWN0aW9uSW5mbxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3Jk", + "ZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUg", + "ASgJEg4KBkZpZWxkcxgGIAEoCRIyCgRNZXRhGAcgAygLMiQuUXVlcnlDaGFu", + "Z2VDb25uZWN0aW9uSW5mby5NZXRhRW50cnkaKwoJTWV0YUVudHJ5EgsKA2tl", + "eRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEikwIKDVF1ZXJ5Q2hhbmdlRGIS", + "DAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkS", + "EwoLT3JkZXJCeURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVs", + "ZHMYBiABKAkSJgoETWV0YRgHIAMoCzIYLlF1ZXJ5Q2hhbmdlRGIuTWV0YUVu", + "dHJ5EhgKD05hbWVkQ29ubmVjdGlvbhjJASABKAkSGQoQQ29ubmVjdGlvblN0", + "cmluZxjKASABKAkSFQoMUHJvdmlkZXJOYW1lGMsBIAEoCRorCglNZXRhRW50", + "cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLjAQoUUXVlcnlD", + "dXN0b21Sb2Nrc3RhcnMSDAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIgASgFEg8K", + "B09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkSDwoHSW5jbHVk", + "ZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSLQoETWV0YRgHIAMoCzIfLlF1ZXJ5", + "Q3VzdG9tUm9ja3N0YXJzLk1ldGFFbnRyeRIMCgNBZ2UYyQEgASgFGisKCU1l", + "dGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIu8BChpR", + "dWVyeUN1c3RvbVJvY2tzdGFyc0ZpbHRlchIMCgRTa2lwGAEgASgFEgwKBFRh", + "a2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEo", + "CRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEoCRIzCgRNZXRhGAcg", + "AygLMiUuUXVlcnlDdXN0b21Sb2Nrc3RhcnNGaWx0ZXIuTWV0YUVudHJ5EgwK", + "A0FnZRjJASABKAUaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1", + "ZRgCIAEoCToCOAEi9wEKHlF1ZXJ5Q3VzdG9tUm9ja3N0YXJzUmVmZXJlbmNl", + "cxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEo", + "CRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZp", + "ZWxkcxgGIAEoCRI3CgRNZXRhGAcgAygLMikuUXVlcnlDdXN0b21Sb2Nrc3Rh", + "cnNSZWZlcmVuY2VzLk1ldGFFbnRyeRIMCgNBZ2UYyQEgASgFGisKCU1ldGFF", + "bnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIu8BChpRdWVy", + "eUN1c3RvbVJvY2tzdGFyc1NjaGVtYRIMCgRTa2lwGAEgASgFEgwKBFRha2UY", + "AiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIP", + "CgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEoCRIzCgRNZXRhGAcgAygL", + "MiUuUXVlcnlDdXN0b21Sb2Nrc3RhcnNTY2hlbWEuTWV0YUVudHJ5EgwKA0Fn", + "ZRjJASABKAUaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgC", + "IAEoCToCOAEiMAouUXVlcnlEYlRlbmFudF9Sb2Nrc3RhckF1ZGl0VGVuYW50", + "X1JvY2tzdGFyQXV0byKWAwoTUXVlcnlGaWVsZFJvY2tzdGFycxIMCgRTa2lw", + "GAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRl", + "ckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEo", + "CRIsCgRNZXRhGAcgAygLMh4uUXVlcnlGaWVsZFJvY2tzdGFycy5NZXRhRW50", + "cnkSEgoJRmlyc3ROYW1lGMkBIAEoCRITCgpGaXJzdE5hbWVzGMoBIAMoCRIM", + "CgNBZ2UYywEgASgFEiEKGEZpcnN0TmFtZUNhc2VJbnNlbnNpdGl2ZRjMASAB", + "KAkSHAoTRmlyc3ROYW1lU3RhcnRzV2l0aBjNASABKAkSGQoQTGFzdE5hbWVF", + "bmRzV2l0aBjOASABKAkSGQoQRmlyc3ROYW1lQmV0d2VlbhjPASADKAkSEwoK", + "T3JMYXN0TmFtZRjQASABKAkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRIN", + "CgV2YWx1ZRgCIAEoCToCOAEi7wEKGlF1ZXJ5RmllbGRSb2Nrc3RhcnNEeW5h", + "bWljEgwKBFNraXAYASABKAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMg", + "ASgJEhMKC09yZGVyQnlEZXNjGAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoG", + "RmllbGRzGAYgASgJEjMKBE1ldGEYByADKAsyJS5RdWVyeUZpZWxkUm9ja3N0", + "YXJzRHluYW1pYy5NZXRhRW50cnkSDAoDQWdlGMkBIAEoBRorCglNZXRhRW50", + "cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASKgAgoeUXVlcnlG", + "aWVsZHNJbXBsaWNpdENvbnZlbnRpb25zEgwKBFNraXAYASABKAUSDAoEVGFr", + "ZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMKC09yZGVyQnlEZXNjGAQgASgJ", + "Eg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRzGAYgASgJEjcKBE1ldGEYByAD", + "KAsyKS5RdWVyeUZpZWxkc0ltcGxpY2l0Q29udmVudGlvbnMuTWV0YUVudHJ5", + "EhoKEUZpcnN0TmFtZUNvbnRhaW5zGMkBIAEoCRIZChBMYXN0TmFtZUVuZHNX", + "aXRoGMoBIAEoCRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVl", + "GAIgASgJOgI4ASLLAQoJUXVlcnlGb29zEgwKBFNraXAYASABKAUSDAoEVGFr", + "ZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMKC09yZGVyQnlEZXNjGAQgASgJ", + "Eg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRzGAYgASgJEiIKBE1ldGEYByAD", + "KAsyFC5RdWVyeUZvb3MuTWV0YUVudHJ5EgoKAVgYyQEgASgJGisKCU1ldGFF", + "bnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIqICChFRdWVy", + "eUdldFJvY2tzdGFycxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoH", + "T3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRl", + "GAUgASgJEg4KBkZpZWxkcxgGIAEoCRIqCgRNZXRhGAcgAygLMhwuUXVlcnlH", + "ZXRSb2Nrc3RhcnMuTWV0YUVudHJ5EhAKA0lkcxjJASADKAVCAhAAEhEKBEFn", + "ZXMYygEgAygFQgIQABITCgpGaXJzdE5hbWVzGMsBIAMoCRIXCgpJZHNCZXR3", + "ZWVuGMwBIAMoBUICEAAaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2", + "YWx1ZRgCIAEoCToCOAEi3QEKGFF1ZXJ5R2V0Um9ja3N0YXJzRHluYW1pYxIM", + "CgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRIT", + "CgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxk", + "cxgGIAEoCRIxCgRNZXRhGAcgAygLMiMuUXVlcnlHZXRSb2Nrc3RhcnNEeW5h", + "bWljLk1ldGFFbnRyeRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZh", + "bHVlGAIgASgJOgI4ASKJAgoZUXVlcnlKb2luZWRSb2Nrc3RhckFsYnVtcxIM", + "CgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRIT", + "CgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxk", + "cxgGIAEoCRIyCgRNZXRhGAcgAygLMiQuUXVlcnlKb2luZWRSb2Nrc3RhckFs", + "YnVtcy5NZXRhRW50cnkSDAoDQWdlGMkBIAEoBRIaChFSb2Nrc3RhckFsYnVt", + "TmFtZRjKASABKAkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1", + "ZRgCIAEoCToCOAEioQIKJVF1ZXJ5Sm9pbmVkUm9ja3N0YXJBbGJ1bXNDdXN0", + "b21TZWxlY3QSDAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVy", + "QnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEo", + "CRIOCgZGaWVsZHMYBiABKAkSPgoETWV0YRgHIAMoCzIwLlF1ZXJ5Sm9pbmVk", + "Um9ja3N0YXJBbGJ1bXNDdXN0b21TZWxlY3QuTWV0YUVudHJ5EgwKA0FnZRjJ", + "ASABKAUSGgoRUm9ja3N0YXJBbGJ1bU5hbWUYygEgASgJGisKCU1ldGFFbnRy", + "eRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIrECCi1RdWVyeUpv", + "aW5lZFJvY2tzdGFyQWxidW1zQ3VzdG9tU2VsZWN0UmVzcG9uc2USDAoEU2tp", + "cBgBIAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3Jk", + "ZXJCeURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiAB", + "KAkSRgoETWV0YRgHIAMoCzI4LlF1ZXJ5Sm9pbmVkUm9ja3N0YXJBbGJ1bXND", + "dXN0b21TZWxlY3RSZXNwb25zZS5NZXRhRW50cnkSDAoDQWdlGMkBIAEoBRIa", + "ChFSb2Nrc3RhckFsYnVtTmFtZRjKASABKAkaKwoJTWV0YUVudHJ5EgsKA2tl", + "eRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi+QEKC1F1ZXJ5TW92aWVzEgwK", + "BFNraXAYASABKAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMK", + "C09yZGVyQnlEZXNjGAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRz", + "GAYgASgJEiQKBE1ldGEYByADKAsyFi5RdWVyeU1vdmllcy5NZXRhRW50cnkS", + "EAoDSWRzGMkBIAMoBUICEAASEAoHSW1kYklkcxjKASADKAkSEAoHUmF0aW5n", + "cxjLASADKAkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgC", + "IAEoCToCOAEinwIKFlF1ZXJ5TXVsdGlKb2luUm9ja3N0YXISDAoEU2tpcBgB", + "IAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJC", + "eURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkS", + "LwoETWV0YRgHIAMoCzIhLlF1ZXJ5TXVsdGlKb2luUm9ja3N0YXIuTWV0YUVu", + "dHJ5EgwKA0FnZRjJASABKAUSGgoRUm9ja3N0YXJBbGJ1bU5hbWUYygEgASgJ", + "EhoKEVJvY2tzdGFyR2VucmVOYW1lGMsBIAEoCRorCglNZXRhRW50cnkSCwoD", + "a2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLhAQoTUXVlcnlOYW1lZFJv", + "Y2tzdGFycxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJC", + "eRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJ", + "Eg4KBkZpZWxkcxgGIAEoCRIsCgRNZXRhGAcgAygLMh4uUXVlcnlOYW1lZFJv", + "Y2tzdGFycy5NZXRhRW50cnkSDAoDQWdlGMkBIAEoBRorCglNZXRhRW50cnkS", + "CwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLvAQoQUXVlcnlPclJv", + "Y2tzdGFycxIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJC", + "eRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJ", + "Eg4KBkZpZWxkcxgGIAEoCRIpCgRNZXRhGAcgAygLMhsuUXVlcnlPclJvY2tz", + "dGFycy5NZXRhRW50cnkSDAoDQWdlGMkBIAEoBRISCglGaXJzdE5hbWUYygEg", + "ASgJGisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6", + "AjgBIoACChZRdWVyeU9yUm9ja3N0YXJzRmllbGRzEgwKBFNraXAYASABKAUS", + "DAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMKC09yZGVyQnlEZXNj", + "GAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRzGAYgASgJEi8KBE1l", + "dGEYByADKAsyIS5RdWVyeU9yUm9ja3N0YXJzRmllbGRzLk1ldGFFbnRyeRIS", + "CglGaXJzdE5hbWUYyQEgASgJEhEKCExhc3ROYW1lGMoBIAEoCRorCglNZXRh", + "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASL1AQodUXVl", + "cnlPdmVycmlkZWRDdXN0b21Sb2Nrc3RhcnMSDAoEU2tpcBgBIAEoBRIMCgRU", + "YWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCAB", + "KAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSNgoETWV0YRgH", + "IAMoCzIoLlF1ZXJ5T3ZlcnJpZGVkQ3VzdG9tUm9ja3N0YXJzLk1ldGFFbnRy", + "eRIMCgNBZ2UYyQEgASgFGisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoF", + "dmFsdWUYAiABKAk6AjgBIukBChdRdWVyeU92ZXJyaWRlZFJvY2tzdGFycxIM", + "CgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRIT", + "CgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxk", + "cxgGIAEoCRIwCgRNZXRhGAcgAygLMiIuUXVlcnlPdmVycmlkZWRSb2Nrc3Rh", + "cnMuTWV0YUVudHJ5EgwKA0FnZRjJASABKAUaKwoJTWV0YUVudHJ5EgsKA2tl", + "eRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi9wEKD1F1ZXJ5UGFnaW5nVGVz", + "dBIMCgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEo", + "CRITCgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZp", + "ZWxkcxgGIAEoCRIoCgRNZXRhGAcgAygLMhouUXVlcnlQYWdpbmdUZXN0Lk1l", + "dGFFbnRyeRILCgJJZBjJASABKAUSDQoETmFtZRjKASABKAkSDgoFVmFsdWUY", + "ywEgASgFGisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiAB", + "KAk6AjgBItEBChNRdWVyeVJlc3BvbnNlX0FkaG9jEg4KBk9mZnNldBgBIAEo", + "BRINCgVUb3RhbBgCIAEoBRIXCgdSZXN1bHRzGAMgAygLMgYuQWRob2MSLAoE", + "TWV0YRgEIAMoCzIeLlF1ZXJ5UmVzcG9uc2VfQWRob2MuTWV0YUVudHJ5EicK", + "DlJlc3BvbnNlU3RhdHVzGAUgASgLMg8uUmVzcG9uc2VTdGF0dXMaKwoJTWV0", + "YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi3QEKF1F1", + "ZXJ5UmVzcG9uc2VfQWxsRmllbGRzEg4KBk9mZnNldBgBIAEoBRINCgVUb3Rh", + "bBgCIAEoBRIbCgdSZXN1bHRzGAMgAygLMgouQWxsRmllbGRzEjAKBE1ldGEY", + "BCADKAsyIi5RdWVyeVJlc3BvbnNlX0FsbEZpZWxkcy5NZXRhRW50cnkSJwoO", + "UmVzcG9uc2VTdGF0dXMYBSABKAsyDy5SZXNwb25zZVN0YXR1cxorCglNZXRh", + "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLZAQoWUXVl", + "cnlSZXNwb25zZV9Cb29rbWFyaxIOCgZPZmZzZXQYASABKAUSDQoFVG90YWwY", + "AiABKAUSGQoHUmVzdWx0cxgDIAMoCzIILkRhb0Jhc2USLwoETWV0YRgEIAMo", + "CzIhLlF1ZXJ5UmVzcG9uc2VfQm9va21hcmsuTWV0YUVudHJ5EicKDlJlc3Bv", + "bnNlU3RhdHVzGAUgASgLMg8uUmVzcG9uc2VTdGF0dXMaKwoJTWV0YUVudHJ5", + "EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi7AEKHFF1ZXJ5UmVz", + "cG9uc2VfQ3VzdG9tUm9ja3N0YXISDgoGT2Zmc2V0GAEgASgFEg0KBVRvdGFs", + "GAIgASgFEiAKB1Jlc3VsdHMYAyADKAsyDy5DdXN0b21Sb2Nrc3RhchI1CgRN", + "ZXRhGAQgAygLMicuUXVlcnlSZXNwb25zZV9DdXN0b21Sb2Nrc3Rhci5NZXRh", + "RW50cnkSJwoOUmVzcG9uc2VTdGF0dXMYBSABKAsyDy5SZXNwb25zZVN0YXR1", + "cxorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4", + "ASL+AQoiUXVlcnlSZXNwb25zZV9DdXN0b21Sb2Nrc3RhclNjaGVtYRIOCgZP", + "ZmZzZXQYASABKAUSDQoFVG90YWwYAiABKAUSJgoHUmVzdWx0cxgDIAMoCzIV", + "LkN1c3RvbVJvY2tzdGFyU2NoZW1hEjsKBE1ldGEYBCADKAsyLS5RdWVyeVJl", + "c3BvbnNlX0N1c3RvbVJvY2tzdGFyU2NoZW1hLk1ldGFFbnRyeRInCg5SZXNw", + "b25zZVN0YXR1cxgFIAEoCzIPLlJlc3BvbnNlU3RhdHVzGisKCU1ldGFFbnRy", + "eRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIv4BCiJRdWVyeVJl", + "c3BvbnNlX0N1c3RvbVNlbGVjdFJvY2tzdGFyEg4KBk9mZnNldBgBIAEoBRIN", + "CgVUb3RhbBgCIAEoBRImCgdSZXN1bHRzGAMgAygLMhUuQ3VzdG9tU2VsZWN0", + "Um9ja3N0YXISOwoETWV0YRgEIAMoCzItLlF1ZXJ5UmVzcG9uc2VfQ3VzdG9t", + "U2VsZWN0Um9ja3N0YXIuTWV0YUVudHJ5EicKDlJlc3BvbnNlU3RhdHVzGAUg", + "ASgLMg8uUmVzcG9uc2VTdGF0dXMaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEo", + "CRINCgV2YWx1ZRgCIAEoCToCOAEilgIKKlF1ZXJ5UmVzcG9uc2VfQ3VzdG9t", + "U2VsZWN0Um9ja3N0YXJSZXNwb25zZRIOCgZPZmZzZXQYASABKAUSDQoFVG90", + "YWwYAiABKAUSLgoHUmVzdWx0cxgDIAMoCzIdLkN1c3RvbVNlbGVjdFJvY2tz", + "dGFyUmVzcG9uc2USQwoETWV0YRgEIAMoCzI1LlF1ZXJ5UmVzcG9uc2VfQ3Vz", + "dG9tU2VsZWN0Um9ja3N0YXJSZXNwb25zZS5NZXRhRW50cnkSJwoOUmVzcG9u", + "c2VTdGF0dXMYBSABKAsyDy5SZXNwb25zZVN0YXR1cxorCglNZXRhRW50cnkS", + "CwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLLAQoRUXVlcnlSZXNw", + "b25zZV9Gb28SDgoGT2Zmc2V0GAEgASgFEg0KBVRvdGFsGAIgASgFEhUKB1Jl", + "c3VsdHMYAyADKAsyBC5Gb28SKgoETWV0YRgEIAMoCzIcLlF1ZXJ5UmVzcG9u", + "c2VfRm9vLk1ldGFFbnRyeRInCg5SZXNwb25zZVN0YXR1cxgFIAEoCzIPLlJl", + "c3BvbnNlU3RhdHVzGisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFs", + "dWUYAiABKAk6AjgBItEBChNRdWVyeVJlc3BvbnNlX01vdmllEg4KBk9mZnNl", + "dBgBIAEoBRINCgVUb3RhbBgCIAEoBRIXCgdSZXN1bHRzGAMgAygLMgYuTW92", + "aWUSLAoETWV0YRgEIAMoCzIeLlF1ZXJ5UmVzcG9uc2VfTW92aWUuTWV0YUVu", + "dHJ5EicKDlJlc3BvbnNlU3RhdHVzGAUgASgLMg8uUmVzcG9uc2VTdGF0dXMa", + "KwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi", + "5AEKG1F1ZXJ5UmVzcG9uc2VfTmFtZWRSb2Nrc3RhchIOCgZPZmZzZXQYASAB", + "KAUSDQoFVG90YWwYAiABKAUSGgoHUmVzdWx0cxgDIAMoCzIJLlJvY2tzdGFy", + "EjQKBE1ldGEYBCADKAsyJi5RdWVyeVJlc3BvbnNlX05hbWVkUm9ja3N0YXIu", + "TWV0YUVudHJ5EicKDlJlc3BvbnNlU3RhdHVzGAUgASgLMg8uUmVzcG9uc2VT", + "dGF0dXMaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEo", + "CToCOAEi4AEKGFF1ZXJ5UmVzcG9uc2VfUGFnaW5nVGVzdBIOCgZPZmZzZXQY", + "ASABKAUSDQoFVG90YWwYAiABKAUSHAoHUmVzdWx0cxgDIAMoCzILLlBhZ2lu", + "Z1Rlc3QSMQoETWV0YRgEIAMoCzIjLlF1ZXJ5UmVzcG9uc2VfUGFnaW5nVGVz", + "dC5NZXRhRW50cnkSJwoOUmVzcG9uc2VTdGF0dXMYBSABKAsyDy5SZXNwb25z", + "ZVN0YXR1cxorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIg", + "ASgJOgI4ASLaAQoWUXVlcnlSZXNwb25zZV9Sb2Nrc3RhchIOCgZPZmZzZXQY", + "ASABKAUSDQoFVG90YWwYAiABKAUSGgoHUmVzdWx0cxgDIAMoCzIJLlJvY2tz", + "dGFyEi8KBE1ldGEYBCADKAsyIS5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyLk1l", + "dGFFbnRyeRInCg5SZXNwb25zZVN0YXR1cxgFIAEoCzIPLlJlc3BvbnNlU3Rh", + "dHVzGisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6", + "AjgBIukBChtRdWVyeVJlc3BvbnNlX1JvY2tzdGFyQWxidW0SDgoGT2Zmc2V0", + "GAEgASgFEg0KBVRvdGFsGAIgASgFEh8KB1Jlc3VsdHMYAyADKAsyDi5Sb2Nr", + "c3RhckFsYnVtEjQKBE1ldGEYBCADKAsyJi5RdWVyeVJlc3BvbnNlX1JvY2tz", + "dGFyQWxidW0uTWV0YUVudHJ5EicKDlJlc3BvbnNlU3RhdHVzGAUgASgLMg8u", + "UmVzcG9uc2VTdGF0dXMaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2", + "YWx1ZRgCIAEoCToCOAEi6QEKG1F1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJBbGlh", + "cxIOCgZPZmZzZXQYASABKAUSDQoFVG90YWwYAiABKAUSHwoHUmVzdWx0cxgD", + "IAMoCzIOLlJvY2tzdGFyQWxpYXMSNAoETWV0YRgEIAMoCzImLlF1ZXJ5UmVz", + "cG9uc2VfUm9ja3N0YXJBbGlhcy5NZXRhRW50cnkSJwoOUmVzcG9uc2VTdGF0", + "dXMYBSABKAsyDy5SZXNwb25zZVN0YXR1cxorCglNZXRhRW50cnkSCwoDa2V5", + "GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLmAQoaUXVlcnlSZXNwb25zZV9S", + "b2Nrc3RhckF1dG8SDgoGT2Zmc2V0GAEgASgFEg0KBVRvdGFsGAIgASgFEh4K", + "B1Jlc3VsdHMYAyADKAsyDS5Sb2Nrc3RhckJhc2USMwoETWV0YRgEIAMoCzIl", + "LlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJBdXRvLk1ldGFFbnRyeRInCg5SZXNw", + "b25zZVN0YXR1cxgFIAEoCzIPLlJlc3BvbnNlU3RhdHVzGisKCU1ldGFFbnRy", + "eRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIvUBCh9RdWVyeVJl", + "c3BvbnNlX1JvY2tzdGFyUmVmZXJlbmNlEg4KBk9mZnNldBgBIAEoBRINCgVU", + "b3RhbBgCIAEoBRIjCgdSZXN1bHRzGAMgAygLMhIuUm9ja3N0YXJSZWZlcmVu", + "Y2USOAoETWV0YRgEIAMoCzIqLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJSZWZl", + "cmVuY2UuTWV0YUVudHJ5EicKDlJlc3BvbnNlU3RhdHVzGAUgASgLMg8uUmVz", + "cG9uc2VTdGF0dXMaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1", + "ZRgCIAEoCToCOAEi5gEKGlF1ZXJ5UmVzcG9uc2VfVHlwZVdpdGhFbnVtEg4K", + "Bk9mZnNldBgBIAEoBRINCgVUb3RhbBgCIAEoBRIeCgdSZXN1bHRzGAMgAygL", + "Mg0uVHlwZVdpdGhFbnVtEjMKBE1ldGEYBCADKAsyJS5RdWVyeVJlc3BvbnNl", + "X1R5cGVXaXRoRW51bS5NZXRhRW50cnkSJwoOUmVzcG9uc2VTdGF0dXMYBSAB", + "KAsyDy5SZXNwb25zZVN0YXR1cxorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJ", + "Eg0KBXZhbHVlGAIgASgJOgI4ASKsAgoTUXVlcnlSb2Nrc3RhckFsYnVtcxIM", + "CgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRIT", + "CgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxk", + "cxgGIAEoCRIsCgRNZXRhGAcgAygLMh4uUXVlcnlSb2Nrc3RhckFsYnVtcy5N", + "ZXRhRW50cnkSCwoCSWQYyQEgASgFEhMKClJvY2tzdGFySWQYygEgASgFEg0K", + "BE5hbWUYywEgASgJEg4KBUdlbnJlGMwBIAEoCRIWCglJZEJldHdlZW4YzQEg", + "AygFQgIQABorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIg", + "ASgJOgI4ASKoAgohUXVlcnlSb2Nrc3RhckFsYnVtc0N1c3RvbUxlZnRKb2lu", + "EgwKBFNraXAYASABKAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJ", + "EhMKC09yZGVyQnlEZXNjGAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoGRmll", + "bGRzGAYgASgJEjoKBE1ldGEYByADKAsyLC5RdWVyeVJvY2tzdGFyQWxidW1z", + "Q3VzdG9tTGVmdEpvaW4uTWV0YUVudHJ5EgwKA0FnZRjJASABKAUSEgoJQWxi", + "dW1OYW1lGMoBIAEoCRIVCgxJZE5vdEVxdWFsVG8YywEgASgFGisKCU1ldGFF", + "bnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIuMBChtRdWVy", + "eVJvY2tzdGFyQWxidW1zSW1wbGljaXQSDAoEU2tpcBgBIAEoBRIMCgRUYWtl", + "GAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkS", + "DwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSNAoETWV0YRgHIAMo", + "CzImLlF1ZXJ5Um9ja3N0YXJBbGJ1bXNJbXBsaWNpdC5NZXRhRW50cnkaKwoJ", + "TWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEinAIK", + "G1F1ZXJ5Um9ja3N0YXJBbGJ1bXNMZWZ0Sm9pbhIMCgRTa2lwGAEgASgFEgwK", + "BFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgE", + "IAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEoCRI0CgRNZXRh", + "GAcgAygLMiYuUXVlcnlSb2Nrc3RhckFsYnVtc0xlZnRKb2luLk1ldGFFbnRy", + "eRIMCgNBZ2UYyQEgASgFEhIKCUFsYnVtTmFtZRjKASABKAkSFQoMSWROb3RF", + "cXVhbFRvGMsBIAEoBRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZh", + "bHVlGAIgASgJOgI4ASL7AQoSUXVlcnlSb2Nrc3RhckFsaWFzEgwKBFNraXAY", + "ASABKAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMKC09yZGVy", + "QnlEZXNjGAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRzGAYgASgJ", + "EisKBE1ldGEYByADKAsyHS5RdWVyeVJvY2tzdGFyQWxpYXMuTWV0YUVudHJ5", + "EgwKA0FnZRjJASABKAUSGgoRUm9ja3N0YXJBbGJ1bU5hbWUYygEgASgJGisK", + "CU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIt4B", + "ChJRdWVyeVJvY2tzdGFyQXVkaXQSDAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIg", + "ASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkSDwoH", + "SW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSKwoETWV0YRgHIAMoCzId", + "LlF1ZXJ5Um9ja3N0YXJBdWRpdC5NZXRhRW50cnkSCwoCSWQYrQIgASgFGisK", + "CU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIpAC", + "ChdRdWVyeVJvY2tzdGFyQXVkaXRTdWJPchIMCgRTa2lwGAEgASgFEgwKBFRh", + "a2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVzYxgEIAEo", + "CRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEoCRIwCgRNZXRhGAcg", + "AygLMiIuUXVlcnlSb2Nrc3RhckF1ZGl0U3ViT3IuTWV0YUVudHJ5EhwKE0Zp", + "cnN0TmFtZVN0YXJ0c1dpdGgYyQEgASgJEhUKDEFnZU9sZGVyVGhhbhjKASAB", + "KAUaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToC", + "OAEiqAIKFFF1ZXJ5Um9ja3N0YXJGaWx0ZXJzEgwKBFNraXAYASABKAUSDAoE", + "VGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMKC09yZGVyQnlEZXNjGAQg", + "ASgJEg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRzGAYgASgJEi0KBE1ldGEY", + "ByADKAsyHy5RdWVyeVJvY2tzdGFyRmlsdGVycy5NZXRhRW50cnkSEAoDSWRz", + "GMkBIAMoBUICEAASEQoEQWdlcxjKASADKAVCAhAAEhMKCkZpcnN0TmFtZXMY", + "ywEgAygJEhcKCklkc0JldHdlZW4YzAEgAygFQgIQABorCglNZXRhRW50cnkS", + "CwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLXAQoOUXVlcnlSb2Nr", + "c3RhcnMSDAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkY", + "AyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIO", + "CgZGaWVsZHMYBiABKAkSJwoETWV0YRgHIAMoCzIZLlF1ZXJ5Um9ja3N0YXJz", + "Lk1ldGFFbnRyeRIMCgNBZ2UYyQEgASgFGisKCU1ldGFFbnRyeRILCgNrZXkY", + "ASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIoAFChlRdWVyeVJvY2tzdGFyc0Nv", + "bnZlbnRpb25zEgwKBFNraXAYASABKAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRl", + "ckJ5GAMgASgJEhMKC09yZGVyQnlEZXNjGAQgASgJEg8KB0luY2x1ZGUYBSAB", + "KAkSDgoGRmllbGRzGAYgASgJEjIKBE1ldGEYByADKAsyJC5RdWVyeVJvY2tz", + "dGFyc0NvbnZlbnRpb25zLk1ldGFFbnRyeRI7ChZEYXRlT2ZCaXJ0aEdyZWF0", + "ZXJUaGFuGMkBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASNQoQ", + "RGF0ZURpZWRMZXNzVGhhbhjKASABKAsyGi5nb29nbGUucHJvdG9idWYuVGlt", + "ZXN0YW1wEhAKA0lkcxjLASADKAVCAhAAEhUKDEFnZU9sZGVyVGhhbhjMASAB", + "KAUSIAoXQWdlR3JlYXRlclRoYW5PckVxdWFsVG8YzQEgASgFEhcKDkFnZUdy", + "ZWF0ZXJUaGFuGM4BIAEoBRIXCg5HcmVhdGVyVGhhbkFnZRjPASABKAUSHAoT", + "Rmlyc3ROYW1lU3RhcnRzV2l0aBjQASABKAkSGQoQTGFzdE5hbWVFbmRzV2l0", + "aBjRASABKAkSGQoQTGFzdE5hbWVDb250YWlucxjSASABKAkSIgoZUm9ja3N0", + "YXJBbGJ1bU5hbWVDb250YWlucxjTASABKAkSGAoPUm9ja3N0YXJJZEFmdGVy", + "GNQBIAEoBRIcChNSb2Nrc3RhcklkT25PckFmdGVyGNUBIAEoBRorCglNZXRh", + "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLjAQoUUXVl", + "cnlSb2Nrc3RhcnNGaWx0ZXISDAoEU2tpcBgBIAEoBRIMCgRUYWtlGAIgASgF", + "Eg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkSDwoHSW5j", + "bHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSLQoETWV0YRgHIAMoCzIfLlF1", + "ZXJ5Um9ja3N0YXJzRmlsdGVyLk1ldGFFbnRyeRIMCgNBZ2UYyQEgASgFGisK", + "CU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIuUB", + "ChVRdWVyeVJvY2tzdGFyc0lGaWx0ZXISDAoEU2tpcBgBIAEoBRIMCgRUYWtl", + "GAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURlc2MYBCABKAkS", + "DwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSLgoETWV0YRgHIAMo", + "CzIgLlF1ZXJ5Um9ja3N0YXJzSUZpbHRlci5NZXRhRW50cnkSDAoDQWdlGMkB", + "IAEoBRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJ", + "OgI4ASLZAQoWUXVlcnlSb2Nrc3RhcnNJbXBsaWNpdBIMCgRTa2lwGAEgASgF", + "EgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRITCgtPcmRlckJ5RGVz", + "YxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxkcxgGIAEoCRIvCgRN", + "ZXRhGAcgAygLMiEuUXVlcnlSb2Nrc3RhcnNJbXBsaWNpdC5NZXRhRW50cnka", + "KwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEi", + "8wEKHFF1ZXJ5Um9ja3N0YXJzV2l0aFJlZmVyZW5jZXMSDAoEU2tpcBgBIAEo", + "BRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURl", + "c2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSNQoE", + "TWV0YRgHIAMoCzInLlF1ZXJ5Um9ja3N0YXJzV2l0aFJlZmVyZW5jZXMuTWV0", + "YUVudHJ5EgwKA0FnZRjJASABKAUaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEo", + "CRINCgV2YWx1ZRgCIAEoCToCOAEi0QEKElF1ZXJ5VHlwZVdpdGhFbnVtcxIM", + "CgRTa2lwGAEgASgFEgwKBFRha2UYAiABKAUSDwoHT3JkZXJCeRgDIAEoCRIT", + "CgtPcmRlckJ5RGVzYxgEIAEoCRIPCgdJbmNsdWRlGAUgASgJEg4KBkZpZWxk", + "cxgGIAEoCRIrCgRNZXRhGAcgAygLMh0uUXVlcnlUeXBlV2l0aEVudW1zLk1l", + "dGFFbnRyeRorCglNZXRhRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIg", + "ASgJOgI4ASKGAgoVUXVlcnlVbmtub3duUm9ja3N0YXJzEgwKBFNraXAYASAB", + "KAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMgASgJEhMKC09yZGVyQnlE", + "ZXNjGAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoGRmllbGRzGAYgASgJEi4K", + "BE1ldGEYByADKAsyIC5RdWVyeVVua25vd25Sb2Nrc3RhcnMuTWV0YUVudHJ5", + "EhMKClVua25vd25JbnQYyQEgASgFEhgKD1Vua25vd25Qcm9wZXJ0eRjKASAB", + "KAkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToC", + "OAEiRQoVUmVhbERlbGV0ZUF1ZGl0VGVuYW50EhMKC0JlYXJlclRva2VuGAEg", + "ASgJEgoKAklkGAIgASgFEgsKA0FnZRgDIAEoBSIqChxSZWFsRGVsZXRlQXVk", + "aXRUZW5hbnRHYXRld2F5EgoKAklkGAEgASgFIiUKF1JlYWxEZWxldGVBdWRp", + "dFRlbmFudE1xEgoKAklkGAEgASgFIoEBChFSZWdlbmVyYXRlQXBpS2V5cxIT", + "CgtFbnZpcm9ubWVudBgBIAEoCRIqCgRNZXRhGAIgAygLMhwuUmVnZW5lcmF0", + "ZUFwaUtleXMuTWV0YUVudHJ5GisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkS", + "DQoFdmFsdWUYAiABKAk6AjgBIsMBChlSZWdlbmVyYXRlQXBpS2V5c1Jlc3Bv", + "bnNlEhwKB1Jlc3VsdHMYASADKAsyCy5Vc2VyQXBpS2V5EjIKBE1ldGEYAiAD", + "KAsyJC5SZWdlbmVyYXRlQXBpS2V5c1Jlc3BvbnNlLk1ldGFFbnRyeRInCg5S", + "ZXNwb25zZVN0YXR1cxgDIAEoCzIPLlJlc3BvbnNlU3RhdHVzGisKCU1ldGFF", + "bnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIoYCCghSZWdp", + "c3RlchIQCghVc2VyTmFtZRgBIAEoCRIRCglGaXJzdE5hbWUYAiABKAkSEAoI", + "TGFzdE5hbWUYAyABKAkSEwoLRGlzcGxheU5hbWUYBCABKAkSDQoFRW1haWwY", + "BSABKAkSEAoIUGFzc3dvcmQYBiABKAkSFwoPQ29uZmlybVBhc3N3b3JkGAcg", + "ASgJEhEKCUF1dG9Mb2dpbhgIIAEoCBIRCglFcnJvclZpZXcYCiABKAkSIQoE", + "TWV0YRgLIAMoCzITLlJlZ2lzdGVyLk1ldGFFbnRyeRorCglNZXRhRW50cnkS", + "CwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASKIAgoQUmVnaXN0ZXJS", + "ZXNwb25zZRIOCgZVc2VySWQYASABKAkSEQoJU2Vzc2lvbklkGAIgASgJEhAK", + "CFVzZXJOYW1lGAMgASgJEhMKC1JlZmVycmVyVXJsGAQgASgJEhMKC0JlYXJl", + "clRva2VuGAUgASgJEhQKDFJlZnJlc2hUb2tlbhgGIAEoCRInCg5SZXNwb25z", + "ZVN0YXR1cxgHIAEoCzIPLlJlc3BvbnNlU3RhdHVzEikKBE1ldGEYCCADKAsy", + "Gy5SZWdpc3RlclJlc3BvbnNlLk1ldGFFbnRyeRorCglNZXRhRW50cnkSCwoD", + "a2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASIxCgxSZXF1aXJlc0F1dGgS", + "DAoETmFtZRgBIAEoCRITCgtCZWFyZXJUb2tlbhgCIAEoCSIMCgpSZXNldFRv", + "ZG9zIpsBCg1SZXNwb25zZUVycm9yEhEKCUVycm9yQ29kZRgBIAEoCRIRCglG", + "aWVsZE5hbWUYAiABKAkSDwoHTWVzc2FnZRgDIAEoCRImCgRNZXRhGAQgAygL", + "MhguUmVzcG9uc2VFcnJvci5NZXRhRW50cnkaKwoJTWV0YUVudHJ5EgsKA2tl", + "eRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEivgEKDlJlc3BvbnNlU3RhdHVz", + "EhEKCUVycm9yQ29kZRgBIAEoCRIPCgdNZXNzYWdlGAIgASgJEhIKClN0YWNr", + "VHJhY2UYAyABKAkSHgoGRXJyb3JzGAQgAygLMg4uUmVzcG9uc2VFcnJvchIn", + "CgRNZXRhGAUgAygLMhkuUmVzcG9uc2VTdGF0dXMuTWV0YUVudHJ5GisKCU1l", + "dGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIoQCCghS", + "b2Nrc3RhchIKCgJJZBgBIAEoBRIRCglGaXJzdE5hbWUYAiABKAkSEAoITGFz", + "dE5hbWUYAyABKAkSCwoDQWdlGAQgASgFEi8KC0RhdGVPZkJpcnRoGAUgASgL", + "MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghEYXRlRGllZBgGIAEo", + "CzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5nU3RhdHVz", + "GAcgASgOMg0uTGl2aW5nU3RhdHVzEisKDU5hbWVkUm9ja3N0YXIYqNzGpAEg", + "ASgLMg4uTmFtZWRSb2Nrc3RhckgAQgkKB3N1YnR5cGUiTAoNUm9ja3N0YXJB", + "bGJ1bRIKCgJJZBgBIAEoBRISCgpSb2Nrc3RhcklkGAIgASgFEgwKBE5hbWUY", + "AyABKAkSDQoFR2VucmUYBCABKAkiVgoNUm9ja3N0YXJBbGlhcxISCgpSb2Nr", + "c3RhcklkGAEgASgFEhEKCUZpcnN0TmFtZRgCIAEoCRIPCgdTdXJuYW1lGAMg", + "ASgJEg0KBWFsYnVtGAQgASgJItABCg1Sb2Nrc3RhckF1ZGl0EgoKAklkGAEg", + "ASgFEi8KC0NyZWF0ZWREYXRlGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRp", + "bWVzdGFtcBIRCglDcmVhdGVkQnkYAyABKAkSEwoLQ3JlYXRlZEluZm8YBCAB", + "KAkSMAoMTW9kaWZpZWREYXRlGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRp", + "bWVzdGFtcBISCgpNb2RpZmllZEJ5GAYgASgJEhQKDE1vZGlmaWVkSW5mbxgH", + "IAEoCSLpAQoTUm9ja3N0YXJBdWRpdFRlbmFudBIQCghUZW5hbnRJZBgBIAEo", + "BRIKCgJJZBgCIAEoBRIRCglGaXJzdE5hbWUYAyABKAkSEAoITGFzdE5hbWUY", + "BCABKAkSCwoDQWdlGAUgASgFEi8KC0RhdGVPZkJpcnRoGAYgASgLMhouZ29v", + "Z2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghEYXRlRGllZBgHIAEoCzIaLmdv", + "b2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5nU3RhdHVzGAggASgO", + "Mg0uTGl2aW5nU3RhdHVzIhoKDFJvY2tzdGFyQXV0bxIKCgJJZBgBIAEoBSIe", + "ChBSb2Nrc3RhckF1dG9HdWlkEgoKAklkGAEgASgJIogDCgxSb2Nrc3RhckJh", + "c2USEQoJRmlyc3ROYW1lGAEgASgJEhAKCExhc3ROYW1lGAIgASgJEgsKA0Fn", + "ZRgDIAEoBRIvCgtEYXRlT2ZCaXJ0aBgEIAEoCzIaLmdvb2dsZS5wcm90b2J1", + "Zi5UaW1lc3RhbXASLAoIRGF0ZURpZWQYBSABKAsyGi5nb29nbGUucHJvdG9i", + "dWYuVGltZXN0YW1wEiMKDExpdmluZ1N0YXR1cxgGIAEoDjINLkxpdmluZ1N0", + "YXR1cxIwChBSb2Nrc3RhckF1dG9HdWlkGL2k7ysgASgLMhEuUm9ja3N0YXJB", + "dXRvR3VpZEgAEigKDFJvY2tzdGFyQXV0bxif+P4rIAEoCzINLlJvY2tzdGFy", + "QXV0b0gAEioKDVJvY2tzdGFyQXVkaXQY+MuUOSABKAsyDi5Sb2Nrc3RhckF1", + "ZGl0SAASLwoPUm9ja3N0YXJWZXJzaW9uGKOq85gBIAEoCzIQLlJvY2tzdGFy", + "VmVyc2lvbkgAQgkKB3N1YnR5cGUiPQoNUm9ja3N0YXJHZW5yZRIKCgJJZBgB", + "IAEoBRISCgpSb2Nrc3RhcklkGAIgASgFEgwKBE5hbWUYAyABKAkicQoRUm9j", + "a3N0YXJSZWZlcmVuY2USCgoCSWQYASABKAUSEQoJRmlyc3ROYW1lGAIgASgJ", + "EhAKCExhc3ROYW1lGAMgASgJEgsKA0FnZRgEIAEoBRIeCgZBbGJ1bXMYBSAD", + "KAsyDi5Sb2Nrc3RhckFsYnVtIjEKD1JvY2tzdGFyVmVyc2lvbhIKCgJJZBgB", + "IAEoBRISCgpSb3dWZXJzaW9uGAIgASgEImQKHlJvY2tzdGFyV2l0aElkQW5k", + "Q291bnRSZXNwb25zZRIKCgJJZBgBIAEoBRINCgVDb3VudBgCIAEoBRInCg5S", + "ZXNwb25zZVN0YXR1cxgDIAEoCzIPLlJlc3BvbnNlU3RhdHVzInUKH1JvY2tz", + "dGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2USCgoCSWQYASABKAUSHQoGUmVz", + "dWx0GAIgASgLMg0uUm9ja3N0YXJCYXNlEicKDlJlc3BvbnNlU3RhdHVzGAMg", + "ASgLMg8uUmVzcG9uc2VTdGF0dXMibgojUm9ja3N0YXJXaXRoSWRBbmRSb3dW", + "ZXJzaW9uUmVzcG9uc2USCgoCSWQYASABKAUSEgoKUm93VmVyc2lvbhgCIAEo", + "DRInCg5SZXNwb25zZVN0YXR1cxgDIAEoCzIPLlJlc3BvbnNlU3RhdHVzIk0K", + "FlJvY2tzdGFyV2l0aElkUmVzcG9uc2USCgoCSWQYASABKAUSJwoOUmVzcG9u", + "c2VTdGF0dXMYAiABKAsyDy5SZXNwb25zZVN0YXR1cyLFAQoMU2VhcmNoTW92", + "aWVzEgwKBFNraXAYASABKAUSDAoEVGFrZRgCIAEoBRIPCgdPcmRlckJ5GAMg", + "ASgJEhMKC09yZGVyQnlEZXNjGAQgASgJEg8KB0luY2x1ZGUYBSABKAkSDgoG", + "RmllbGRzGAYgASgJEiUKBE1ldGEYByADKAsyFy5TZWFyY2hNb3ZpZXMuTWV0", + "YUVudHJ5GisKCU1ldGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiAB", + "KAk6AjgBIioKDFNlYXJjaFJlc3VsdBIKCgJJZBgBIAEoBRIOCgZTdWZmaXgY", + "AiABKAkiFwoHU2VjdXJlZBIMCgROYW1lGAEgASgJIkoKD1NlY3VyZWRSZXNw", + "b25zZRIOCgZSZXN1bHQYASABKAkSJwoOUmVzcG9uc2VTdGF0dXMYAiABKAsy", + "Dy5SZXNwb25zZVN0YXR1cyJJCkdTb2Z0RGVsZXRlQXVkaXRCYXNlX1JvY2tz", + "dGFyQXVkaXRUZW5hbnRfUm9ja3N0YXJXaXRoSWRBbmRSZXN1bHRSZXNwb25z", + "ZSIkChVTb2Z0RGVsZXRlQXVkaXRUZW5hbnQSCwoCSWQYyQEgASgFIk8KTVNv", + "ZnREZWxldGVBdWRpdFRlbmFudEJhc2VfUm9ja3N0YXJBdWRpdFRlbmFudF9S", + "b2Nrc3RhcldpdGhJZEFuZFJlc3VsdFJlc3BvbnNlIhwKC1N0cmVhbUZpbGVz", + "Eg0KBVBhdGhzGAEgAygJItcBCgxTdHJlYW1Nb3ZpZXMSDAoEU2tpcBgBIAEo", + "BRIMCgRUYWtlGAIgASgFEg8KB09yZGVyQnkYAyABKAkSEwoLT3JkZXJCeURl", + "c2MYBCABKAkSDwoHSW5jbHVkZRgFIAEoCRIOCgZGaWVsZHMYBiABKAkSJQoE", + "TWV0YRgHIAMoCzIXLlN0cmVhbU1vdmllcy5NZXRhRW50cnkSEAoHUmF0aW5n", + "cxjJASADKAkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgC", + "IAEoCToCOAEiJgoSU3RyZWFtU2VydmVyRXZlbnRzEhAKCENoYW5uZWxzGAEg", + "AygJIpsEChpTdHJlYW1TZXJ2ZXJFdmVudHNSZXNwb25zZRIPCgdFdmVudElk", + "GAEgASgDEg8KB0NoYW5uZWwYAiABKAkSEAoIU2VsZWN0b3IYBCABKAkSDAoE", + "SnNvbhgFIAEoCRIKCgJPcBgGIAEoCRIOCgZUYXJnZXQYByABKAkSEwoLQ3Nz", + "U2VsZWN0b3IYCCABKAkSMwoETWV0YRgJIAMoCzIlLlN0cmVhbVNlcnZlckV2", + "ZW50c1Jlc3BvbnNlLk1ldGFFbnRyeRIOCgZVc2VySWQYCiABKAkSEwoLRGlz", + "cGxheU5hbWUYCyABKAkSEgoKUHJvZmlsZVVybBgMIAEoCRIXCg9Jc0F1dGhl", + "bnRpY2F0ZWQYDSABKAgSEAoIQ2hhbm5lbHMYDiADKAkSEQoJQ3JlYXRlZEF0", + "GA8gASgDEgoKAklkGBUgASgJEhUKDVVuUmVnaXN0ZXJVcmwYFiABKAkSGwoT", + "VXBkYXRlU3Vic2NyaWJlclVybBgXIAEoCRIUCgxIZWFydGJlYXRVcmwYGCAB", + "KAkSGwoTSGVhcnRiZWF0SW50ZXJ2YWxNcxgZIAEoAxIVCg1JZGxlVGltZW91", + "dE1zGBogASgDEicKDlJlc3BvbnNlU3RhdHVzGB4gASgLMg8uUmVzcG9uc2VT", + "dGF0dXMaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEo", + "CToCOAEiJQoSVGVzdEF1dGhWYWxpZGF0b3JzEg8KB05vdE51bGwYASABKAki", + "LgoPVGVzdERiQ29uZGl0aW9uEgoKAklkGAEgASgFEg8KB05vdE51bGwYAiAB", + "KAkiLgoPVGVzdERiVmFsaWRhdG9yEgoKAklkGAEgASgFEg8KB05vdE51bGwY", + "AiABKAkiHgoLVGVzdElzQWRtaW4SDwoHTm90TnVsbBgBIAEoCSIqChdUZXN0", + "TXVsdGlBdXRoVmFsaWRhdG9ycxIPCgdOb3ROdWxsGAEgASgJIhgKBVRocm93", + "Eg8KB01lc3NhZ2UYASABKAkiDQoLVGhyb3dDdXN0b20iPgoTVGhyb3dDdXN0", + "b21SZXNwb25zZRInCg5SZXNwb25zZVN0YXR1cxgBIAEoCzIPLlJlc3BvbnNl", + "U3RhdHVzIhwKCVRocm93Vm9pZBIPCgdNZXNzYWdlGAEgASgJIkMKBFRvZG8S", + "CgoCSWQYASABKAMSDQoFVGl0bGUYAiABKAkSDQoFT3JkZXIYAyABKAUSEQoJ", + "Q29tcGxldGVkGAQgASgIItwCChRUcmlnZ2VyQWxsVmFsaWRhdG9ycxISCgpD", + "cmVkaXRDYXJkGAEgASgJEg0KBUVtYWlsGAIgASgJEg0KBUVtcHR5GAMgASgJ", + "Eg0KBUVxdWFsGAQgASgJEhgKEEV4Y2x1c2l2ZUJldHdlZW4YBSABKAUSGgoS", + "R3JlYXRlclRoYW5PckVxdWFsGAYgASgFEhMKC0dyZWF0ZXJUaGFuGAcgASgF", + "EhgKEEluY2x1c2l2ZUJldHdlZW4YCCABKAUSDgoGTGVuZ3RoGAkgASgJEhcK", + "D0xlc3NUaGFuT3JFcXVhbBgKIAEoBRIQCghMZXNzVGhhbhgLIAEoBRIQCghO", + "b3RFbXB0eRgMIAEoCRIQCghOb3RFcXVhbBgNIAEoCRIMCgROdWxsGA4gASgJ", + "EhkKEVJlZ3VsYXJFeHByZXNzaW9uGA8gASgJEhYKDlNjYWxlUHJlY2lzaW9u", + "GBAgASgJItkCChFUcmlnZ2VyVmFsaWRhdG9ycxISCgpDcmVkaXRDYXJkGAEg", + "ASgJEg0KBUVtYWlsGAIgASgJEg0KBUVtcHR5GAMgASgJEg0KBUVxdWFsGAQg", + "ASgJEhgKEEV4Y2x1c2l2ZUJldHdlZW4YBSABKAUSGgoSR3JlYXRlclRoYW5P", + "ckVxdWFsGAYgASgFEhMKC0dyZWF0ZXJUaGFuGAcgASgFEhgKEEluY2x1c2l2", + "ZUJldHdlZW4YCCABKAUSDgoGTGVuZ3RoGAkgASgJEhcKD0xlc3NUaGFuT3JF", + "cXVhbBgKIAEoBRIQCghMZXNzVGhhbhgLIAEoBRIQCghOb3RFbXB0eRgMIAEo", + "CRIQCghOb3RFcXVhbBgNIAEoCRIMCgROdWxsGA4gASgJEhkKEVJlZ3VsYXJF", + "eHByZXNzaW9uGA8gASgJEhYKDlNjYWxlUHJlY2lzaW9uGBAgASgJIrIBCgxU", + "eXBlV2l0aEVudW0SCgoCSWQYASABKAUSDAoETmFtZRgCIAEoCRIbCghTb21l", + "RW51bRgDIAEoDjIJLlNvbWVFbnVtEiUKDVNvbWVFbnVtQXNJbnQYBCABKA4y", + "Di5Tb21lRW51bUFzSW50EhwKCU5Tb21lRW51bRgFIAEoDjIJLlNvbWVFbnVt", + "EiYKDk5Tb21lRW51bUFzSW50GAYgASgOMg4uU29tZUVudW1Bc0ludCKaAQoN", + "VW5Bc3NpZ25Sb2xlcxIQCghVc2VyTmFtZRgBIAEoCRITCgtQZXJtaXNzaW9u", + "cxgCIAMoCRINCgVSb2xlcxgDIAMoCRImCgRNZXRhGAQgAygLMhguVW5Bc3Np", + "Z25Sb2xlcy5NZXRhRW50cnkaKwoJTWV0YUVudHJ5EgsKA2tleRgBIAEoCRIN", + "CgV2YWx1ZRgCIAEoCToCOAEixwEKFVVuQXNzaWduUm9sZXNSZXNwb25zZRIQ", + "CghBbGxSb2xlcxgBIAMoCRIWCg5BbGxQZXJtaXNzaW9ucxgCIAMoCRIuCgRN", + "ZXRhGAMgAygLMiAuVW5Bc3NpZ25Sb2xlc1Jlc3BvbnNlLk1ldGFFbnRyeRIn", + "Cg5SZXNwb25zZVN0YXR1cxgEIAEoCzIPLlJlc3BvbnNlU3RhdHVzGisKCU1l", + "dGFFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIkUKQ1Vw", + "ZGF0ZUF1ZGl0QmFzZV9Sb2Nrc3RhckF1ZGl0VGVuYW50X1JvY2tzdGFyV2l0", + "aElkQW5kUmVzdWx0UmVzcG9uc2UiSwpJVXBkYXRlQXVkaXRUZW5hbnRCYXNl", + "X1JvY2tzdGFyQXVkaXRUZW5hbnRfUm9ja3N0YXJXaXRoSWRBbmRSZXN1bHRS", + "ZXNwb25zZSLgAQocVXBkYXRlQ29ubmVjdGlvbkluZm9Sb2Nrc3RhchIRCglG", + "aXJzdE5hbWUYASABKAkSEAoITGFzdE5hbWUYAiABKAkSCwoDQWdlGAMgASgF", + "Ei8KC0RhdGVPZkJpcnRoGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVz", + "dGFtcBIsCghEYXRlRGllZBgFIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1l", + "c3RhbXASIwoMTGl2aW5nU3RhdHVzGAYgASgOMg0uTGl2aW5nU3RhdHVzEgoK", + "AklkGGUgASgFItcBChNVcGRhdGVOYW1lZFJvY2tzdGFyEhEKCUZpcnN0TmFt", + "ZRgBIAEoCRIQCghMYXN0TmFtZRgCIAEoCRILCgNBZ2UYAyABKAUSLwoLRGF0", + "ZU9mQmlydGgYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiwK", + "CERhdGVEaWVkGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIj", + "CgxMaXZpbmdTdGF0dXMYBiABKA4yDS5MaXZpbmdTdGF0dXMSCgoCSWQYZSAB", + "KAUi0gEKDlVwZGF0ZVJvY2tzdGFyEhEKCUZpcnN0TmFtZRgBIAEoCRIQCghM", + "YXN0TmFtZRgCIAEoCRILCgNBZ2UYAyABKAUSLwoLRGF0ZU9mQmlydGgYBCAB", + "KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiwKCERhdGVEaWVkGAUg", + "ASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIjCgxMaXZpbmdTdGF0", + "dXMYBiABKA4yDS5MaXZpbmdTdGF0dXMSCgoCSWQYZSABKAUi4gEKHlVwZGF0", + "ZVJvY2tzdGFyQWRob2NOb25EZWZhdWx0cxIKCgJJZBgBIAEoBRIRCglGaXJz", + "dE5hbWUYAiABKAkSEAoITGFzdE5hbWUYAyABKAkSCwoDQWdlGAQgASgFEi8K", + "C0RhdGVPZkJpcnRoGAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFt", + "cBIsCghEYXRlRGllZBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3Rh", + "bXASIwoMTGl2aW5nU3RhdHVzGAcgASgOMg0uTGl2aW5nU3RhdHVzItcBChNV", + "cGRhdGVSb2Nrc3RhckF1ZGl0EhEKCUZpcnN0TmFtZRgBIAEoCRIQCghMYXN0", + "TmFtZRgCIAEoCRILCgNBZ2UYAyABKAUSLwoLRGF0ZU9mQmlydGgYBCABKAsy", + "Gi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiwKCERhdGVEaWVkGAUgASgL", + "MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIjCgxMaXZpbmdTdGF0dXMY", + "BiABKA4yDS5MaXZpbmdTdGF0dXMSCgoCSWQYZSABKAUieAoZVXBkYXRlUm9j", + "a3N0YXJBdWRpdFRlbmFudBIUCgtCZWFyZXJUb2tlbhjJASABKAkSCwoCSWQY", + "ygEgASgFEhIKCUZpcnN0TmFtZRjLASABKAkSJAoMTGl2aW5nU3RhdHVzGMwB", + "IAEoDjINLkxpdmluZ1N0YXR1cyJmCiBVcGRhdGVSb2Nrc3RhckF1ZGl0VGVu", + "YW50R2F0ZXdheRIKCgJJZBgBIAEoBRIRCglGaXJzdE5hbWUYAiABKAkSIwoM", + "TGl2aW5nU3RhdHVzGAMgASgOMg0uTGl2aW5nU3RhdHVzImEKG1VwZGF0ZVJv", + "Y2tzdGFyQXVkaXRUZW5hbnRNcRIKCgJJZBgBIAEoBRIRCglGaXJzdE5hbWUY", + "AiABKAkSIwoMTGl2aW5nU3RhdHVzGAMgASgOMg0uTGl2aW5nU3RhdHVzIu0B", + "ChVVcGRhdGVSb2Nrc3RhclZlcnNpb24SEQoJRmlyc3ROYW1lGAEgASgJEhAK", + "CExhc3ROYW1lGAIgASgJEgsKA0FnZRgDIAEoBRIvCgtEYXRlT2ZCaXJ0aBgE", + "IAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASLAoIRGF0ZURpZWQY", + "BSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiMKDExpdmluZ1N0", + "YXR1cxgGIAEoDjINLkxpdmluZ1N0YXR1cxIKCgJJZBhlIAEoBRISCgpSb3dW", + "ZXJzaW9uGGYgASgEIkkKClVwZGF0ZVRvZG8SCgoCSWQYASABKAMSDQoFVGl0", + "bGUYAiABKAkSDQoFT3JkZXIYAyABKAUSEQoJQ29tcGxldGVkGAQgASgIIqwB", + "CgpVc2VyQXBpS2V5EgsKA0tleRgBIAEoCRIPCgdLZXlUeXBlGAIgASgJEi4K", + "CkV4cGlyeURhdGUYAyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w", + "EiMKBE1ldGEYBCADKAsyFS5Vc2VyQXBpS2V5Lk1ldGFFbnRyeRorCglNZXRh", + "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASLOAQoWVmFs", + "aWRhdGVDcmVhdGVSb2Nrc3RhchIRCglGaXJzdE5hbWUYASABKAkSEAoITGFz", + "dE5hbWUYAiABKAkSCwoDQWdlGAMgASgFEi8KC0RhdGVPZkJpcnRoGAQgASgL", + "MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIsCghEYXRlRGllZBgFIAEo", + "CzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASIwoMTGl2aW5nU3RhdHVz", + "GAYgASgOMg0uTGl2aW5nU3RhdHVzKo8LCg5IdHRwU3RhdHVzQ29kZRIICgRa", + "RVJPEAASDAoIQ29udGludWUQZBIWChJTd2l0Y2hpbmdQcm90b2NvbHMQZRIO", + "CgpQcm9jZXNzaW5nEGYSDgoKRWFybHlIaW50cxBnEgcKAk9LEMgBEgwKB0Ny", + "ZWF0ZWQQyQESDQoIQWNjZXB0ZWQQygESIAobTm9uQXV0aG9yaXRhdGl2ZUlu", + "Zm9ybWF0aW9uEMsBEg4KCU5vQ29udGVudBDMARIRCgxSZXNldENvbnRlbnQQ", + "zQESEwoOUGFydGlhbENvbnRlbnQQzgESEAoLTXVsdGlTdGF0dXMQzwESFAoP", + "QWxyZWFkeVJlcG9ydGVkENABEgsKBklNVXNlZBDiARIUCg9NdWx0aXBsZUNo", + "b2ljZXMQrAISDgoJQW1iaWd1b3VzEKwCEhUKEE1vdmVkUGVybWFuZW50bHkQ", + "rQISCgoFTW92ZWQQrQISCgoFRm91bmQQrgISDQoIUmVkaXJlY3QQrgISDQoI", + "U2VlT3RoZXIQrwISEwoOUmVkaXJlY3RNZXRob2QQrwISEAoLTm90TW9kaWZp", + "ZWQQsAISDQoIVXNlUHJveHkQsQISCwoGVW51c2VkELICEhYKEVRlbXBvcmFy", + "eVJlZGlyZWN0ELMCEhUKEFJlZGlyZWN0S2VlcFZlcmIQswISFgoRUGVybWFu", + "ZW50UmVkaXJlY3QQtAISDwoKQmFkUmVxdWVzdBCQAxIRCgxVbmF1dGhvcml6", + "ZWQQkQMSFAoPUGF5bWVudFJlcXVpcmVkEJIDEg4KCUZvcmJpZGRlbhCTAxIN", + "CghOb3RGb3VuZBCUAxIVChBNZXRob2ROb3RBbGxvd2VkEJUDEhIKDU5vdEFj", + "Y2VwdGFibGUQlgMSIAobUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkEJcD", + "EhMKDlJlcXVlc3RUaW1lb3V0EJgDEg0KCENvbmZsaWN0EJkDEgkKBEdvbmUQ", + "mgMSEwoOTGVuZ3RoUmVxdWlyZWQQmwMSFwoSUHJlY29uZGl0aW9uRmFpbGVk", + "EJwDEhoKFVJlcXVlc3RFbnRpdHlUb29MYXJnZRCdAxIWChFSZXF1ZXN0VXJp", + "VG9vTG9uZxCeAxIZChRVbnN1cHBvcnRlZE1lZGlhVHlwZRCfAxIhChxSZXF1", + "ZXN0ZWRSYW5nZU5vdFNhdGlzZmlhYmxlEKADEhYKEUV4cGVjdGF0aW9uRmFp", + "bGVkEKEDEhcKEk1pc2RpcmVjdGVkUmVxdWVzdBClAxIYChNVbnByb2Nlc3Nh", + "YmxlRW50aXR5EKYDEgsKBkxvY2tlZBCnAxIVChBGYWlsZWREZXBlbmRlbmN5", + "EKgDEhQKD1VwZ3JhZGVSZXF1aXJlZBCqAxIZChRQcmVjb25kaXRpb25SZXF1", + "aXJlZBCsAxIUCg9Ub29NYW55UmVxdWVzdHMQrQMSIAobUmVxdWVzdEhlYWRl", + "ckZpZWxkc1Rvb0xhcmdlEK8DEh8KGlVuYXZhaWxhYmxlRm9yTGVnYWxSZWFz", + "b25zEMMDEhgKE0ludGVybmFsU2VydmVyRXJyb3IQ9AMSEwoOTm90SW1wbGVt", + "ZW50ZWQQ9QMSDwoKQmFkR2F0ZXdheRD2AxIXChJTZXJ2aWNlVW5hdmFpbGFi", + "bGUQ9wMSEwoOR2F0ZXdheVRpbWVvdXQQ+AMSHAoXSHR0cFZlcnNpb25Ob3RT", + "dXBwb3J0ZWQQ+QMSGgoVVmFyaWFudEFsc29OZWdvdGlhdGVzEPoDEhgKE0lu", + "c3VmZmljaWVudFN0b3JhZ2UQ+wMSEQoMTG9vcERldGVjdGVkEPwDEhAKC05v", + "dEV4dGVuZGVkEP4DEiIKHU5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVk", + "EP8DGgIQASojCgxMaXZpbmdTdGF0dXMSCQoFQWxpdmUQABIICgREZWFkEAEq", + "XgoIU29tZUVudW0SEwoPU29tZUVudW1fVmFsdWUwEAASEwoPU29tZUVudW1f", + "VmFsdWUxEAESEwoPU29tZUVudW1fVmFsdWUyEAISEwoPU29tZUVudW1fVmFs", + "dWUzEAMqPwoNU29tZUVudW1Bc0ludBIKCgZWYWx1ZTAQABIKCgZWYWx1ZTEQ", + "ARIKCgZWYWx1ZTIQAhIKCgZWYWx1ZTMQAzLbcgoMR3JwY1NlcnZpY2VzEiwK", + "DEdldEFkZEhlYWRlchIKLkFkZEhlYWRlchoOLkVtcHR5UmVzcG9uc2UiABIq", + "CgtHZXRBbnlIZWxsbxIJLkFueUhlbGxvGg4uSGVsbG9SZXNwb25zZSIAEisK", + "DFBvc3RBbnlIZWxsbxIJLkFueUhlbGxvGg4uSGVsbG9SZXNwb25zZSIAEioK", + "C1B1dEFueUhlbGxvEgkuQW55SGVsbG8aDi5IZWxsb1Jlc3BvbnNlIgASLQoO", + "RGVsZXRlQW55SGVsbG8SCS5BbnlIZWxsbxoOLkhlbGxvUmVzcG9uc2UiABI3", + "Cg9Qb3N0QXNzaWduUm9sZXMSDC5Bc3NpZ25Sb2xlcxoULkFzc2lnblJvbGVz", + "UmVzcG9uc2UiABI9ChNPcHRpb25zQXV0aGVudGljYXRlEg0uQXV0aGVudGlj", + "YXRlGhUuQXV0aGVudGljYXRlUmVzcG9uc2UiABI5Cg9HZXRBdXRoZW50aWNh", + "dGUSDS5BdXRoZW50aWNhdGUaFS5BdXRoZW50aWNhdGVSZXNwb25zZSIAEjoK", + "EFBvc3RBdXRoZW50aWNhdGUSDS5BdXRoZW50aWNhdGUaFS5BdXRoZW50aWNh", + "dGVSZXNwb25zZSIAEjwKEkRlbGV0ZUF1dGhlbnRpY2F0ZRINLkF1dGhlbnRp", + "Y2F0ZRoVLkF1dGhlbnRpY2F0ZVJlc3BvbnNlIgASRQoXR2V0Q2hhbmdlQ29u", + "bmVjdGlvbkluZm8SFS5DaGFuZ2VDb25uZWN0aW9uSW5mbxoRLkNoYW5nZURi", + "UmVzcG9uc2UiABItCgtHZXRDaGFuZ2VEYhIJLkNoYW5nZURiGhEuQ2hhbmdl", + "RGJSZXNwb25zZSIAElUKGVBvc3RDb252ZXJ0U2Vzc2lvblRvVG9rZW4SFi5D", + "b252ZXJ0U2Vzc2lvblRvVG9rZW4aHi5Db252ZXJ0U2Vzc2lvblRvVG9rZW5S", + "ZXNwb25zZSIAEkAKElBvc3RDcmVhdGVCb29rbWFyaxIPLkNyZWF0ZUJvb2tt", + "YXJrGhcuQ3JlYXRlQm9va21hcmtSZXNwb25zZSIAEmUKIFBvc3RDcmVhdGVD", + "b25uZWN0aW9uSW5mb1JvY2tzdGFyEh0uQ3JlYXRlQ29ubmVjdGlvbkluZm9S", + "b2Nrc3RhchogLlJvY2tzdGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2UiABJT", + "ChdQb3N0Q3JlYXRlTmFtZWRSb2Nrc3RhchIULkNyZWF0ZU5hbWVkUm9ja3N0", + "YXIaIC5Sb2Nrc3RhcldpdGhJZEFuZFJlc3VsdFJlc3BvbnNlIgASQAoSUG9z", + "dENyZWF0ZVJvY2tzdGFyEg8uQ3JlYXRlUm9ja3N0YXIaFy5DcmVhdGVSb2Nr", + "c3RhclJlc3BvbnNlIgASaQoiUG9zdENyZWF0ZVJvY2tzdGFyQWRob2NOb25E", + "ZWZhdWx0cxIfLkNyZWF0ZVJvY2tzdGFyQWRob2NOb25EZWZhdWx0cxogLlJv", + "Y2tzdGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2UiABJKChdQb3N0Q3JlYXRl", + "Um9ja3N0YXJBdWRpdBIULkNyZWF0ZVJvY2tzdGFyQXVkaXQaFy5Sb2Nrc3Rh", + "cldpdGhJZFJlc3BvbnNlIgASWAoeUG9zdENyZWF0ZVJvY2tzdGFyQXVkaXRN", + "cVRva2VuEhsuQ3JlYXRlUm9ja3N0YXJBdWRpdE1xVG9rZW4aFy5Sb2Nrc3Rh", + "cldpdGhJZFJlc3BvbnNlIgASXwodUG9zdENyZWF0ZVJvY2tzdGFyQXVkaXRU", + "ZW5hbnQSGi5DcmVhdGVSb2Nrc3RhckF1ZGl0VGVuYW50GiAuUm9ja3N0YXJX", + "aXRoSWRBbmRSZXN1bHRSZXNwb25zZSIAEm0KJFBvc3RDcmVhdGVSb2Nrc3Rh", + "ckF1ZGl0VGVuYW50R2F0ZXdheRIhLkNyZWF0ZVJvY2tzdGFyQXVkaXRUZW5h", + "bnRHYXRld2F5GiAuUm9ja3N0YXJXaXRoSWRBbmRSZXN1bHRSZXNwb25zZSIA", + "ElAKHkdldENyZWF0ZVJvY2tzdGFyQXVkaXRUZW5hbnRNcRIcLkNyZWF0ZVJv", + "Y2tzdGFyQXVkaXRUZW5hbnRNcRoOLkVtcHR5UmVzcG9uc2UiABJRCh9Qb3N0", + "Q3JlYXRlUm9ja3N0YXJBdWRpdFRlbmFudE1xEhwuQ3JlYXRlUm9ja3N0YXJB", + "dWRpdFRlbmFudE1xGg4uRW1wdHlSZXNwb25zZSIAElAKHlB1dENyZWF0ZVJv", + "Y2tzdGFyQXVkaXRUZW5hbnRNcRIcLkNyZWF0ZVJvY2tzdGFyQXVkaXRUZW5h", + "bnRNcRoOLkVtcHR5UmVzcG9uc2UiABJTCiFEZWxldGVDcmVhdGVSb2Nrc3Rh", + "ckF1ZGl0VGVuYW50TXESHC5DcmVhdGVSb2Nrc3RhckF1ZGl0VGVuYW50TXEa", + "Di5FbXB0eVJlc3BvbnNlIgASVwoZUG9zdENyZWF0ZVJvY2tzdGFyQXV0b01h", + "cBIWLkNyZWF0ZVJvY2tzdGFyQXV0b01hcBogLlJvY2tzdGFyV2l0aElkQW5k", + "UmVzdWx0UmVzcG9uc2UiABJbChlQb3N0Q3JlYXRlUm9ja3N0YXJWZXJzaW9u", + "EhYuQ3JlYXRlUm9ja3N0YXJWZXJzaW9uGiQuUm9ja3N0YXJXaXRoSWRBbmRS", + "b3dWZXJzaW9uUmVzcG9uc2UiABJmCh5Qb3N0Q3JlYXRlUm9ja3N0YXJXaXRo", + "QXV0b0d1aWQSGy5DcmVhdGVSb2Nrc3RhcldpdGhBdXRvR3VpZBolLkNyZWF0", + "ZVJvY2tzdGFyV2l0aFJldHVybkd1aWRSZXNwb25zZSIAEl0KHFBvc3RDcmVh", + "dGVSb2Nrc3RhcldpdGhSZXR1cm4SGS5DcmVhdGVSb2Nrc3RhcldpdGhSZXR1", + "cm4aIC5Sb2Nrc3RhcldpdGhJZEFuZFJlc3VsdFJlc3BvbnNlIgASUwogUG9z", + "dENyZWF0ZVJvY2tzdGFyV2l0aFZvaWRSZXR1cm4SHS5DcmVhdGVSb2Nrc3Rh", + "cldpdGhWb2lkUmV0dXJuGg4uRW1wdHlSZXNwb25zZSIAEjQKDlBvc3RDcmVh", + "dGVUb2RvEgsuQ3JlYXRlVG9kbxoTLkNyZWF0ZVRvZG9SZXNwb25zZSIAElAK", + "GlBvc3RDdXN0b21WYWxpZGF0aW9uRXJyb3JzEhcuQ3VzdG9tVmFsaWRhdGlv", + "bkVycm9ycxoXLlJvY2tzdGFyV2l0aElkUmVzcG9uc2UiABI3ChJDYWxsRGVs", + "ZXRlUm9ja3N0YXISDy5EZWxldGVSb2Nrc3RhchoOLkVtcHR5UmVzcG9uc2Ui", + "ABJSChdDYWxsRGVsZXRlUm9ja3N0YXJBdWRpdBIULkRlbGV0ZVJvY2tzdGFy", + "QXVkaXQaHy5Sb2Nrc3RhcldpdGhJZEFuZENvdW50UmVzcG9uc2UiABJTChlD", + "YWxsRGVsZXRlUm9ja3N0YXJGaWx0ZXJzEhYuRGVsZXRlUm9ja3N0YXJGaWx0", + "ZXJzGhwuRGVsZXRlUm9ja3N0YXJDb3VudFJlc3BvbnNlIgASLwoOQ2FsbERl", + "bGV0ZVRvZG8SCy5EZWxldGVUb2RvGg4uRW1wdHlSZXNwb25zZSIAEjEKD0Nh", + "bGxEZWxldGVUb2RvcxIMLkRlbGV0ZVRvZG9zGg4uRW1wdHlSZXNwb25zZSIA", + "ElAKIkdldER5bmFtaWNRdWVyeUdldFJvY2tzdGFyc0R5bmFtaWMSDy5EeW5h", + "bWljUmVxdWVzdBoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJeCiRHZXRE", + "eW5hbWljUXVlcnlDdXN0b21Sb2Nrc3RhcnNTY2hlbWESDy5EeW5hbWljUmVx", + "dWVzdBojLlF1ZXJ5UmVzcG9uc2VfQ3VzdG9tUm9ja3N0YXJTY2hlbWEiABJB", + "ChZHZXREeW5hbWljU2VhcmNoTW92aWVzEg8uRHluYW1pY1JlcXVlc3QaFC5R", + "dWVyeVJlc3BvbnNlX01vdmllIgASQAoVR2V0RHluYW1pY1F1ZXJ5TW92aWVz", + "Eg8uRHluYW1pY1JlcXVlc3QaFC5RdWVyeVJlc3BvbnNlX01vdmllIgASTQof", + "R2V0RHluYW1pY1F1ZXJ5VW5rbm93blJvY2tzdGFycxIPLkR5bmFtaWNSZXF1", + "ZXN0GhcuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIAEl0KJkdldER5bmFtaWNR", + "dWVyeVJvY2tzdGFyc1dpdGhSZWZlcmVuY2VzEg8uRHluYW1pY1JlcXVlc3Qa", + "IC5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyUmVmZXJlbmNlIgASRwoYR2V0RHlu", + "YW1pY1F1ZXJ5QWxsRmllbGRzEg8uRHluYW1pY1JlcXVlc3QaGC5RdWVyeVJl", + "c3BvbnNlX0FsbEZpZWxkcyIAEk4KHEdldER5bmFtaWNRdWVyeVR5cGVXaXRo", + "RW51bXMSDy5EeW5hbWljUmVxdWVzdBobLlF1ZXJ5UmVzcG9uc2VfVHlwZVdp", + "dGhFbnVtIgASSwodR2V0RHluYW1pY1F1ZXJ5QWRob2NSb2Nrc3RhcnMSDy5E", + "eW5hbWljUmVxdWVzdBoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABI/ChRH", + "ZXREeW5hbWljUXVlcnlBZGhvYxIPLkR5bmFtaWNSZXF1ZXN0GhQuUXVlcnlS", + "ZXNwb25zZV9BZGhvYyIAEkUKF0dldER5bmFtaWNRdWVyeUNoYW5nZURiEg8u", + "RHluYW1pY1JlcXVlc3QaFy5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyIgASaQov", + "R2V0RHluYW1pY1F1ZXJ5Sm9pbmVkUm9ja3N0YXJBbGJ1bXNDdXN0b21TZWxl", + "Y3QSDy5EeW5hbWljUmVxdWVzdBojLlF1ZXJ5UmVzcG9uc2VfQ3VzdG9tU2Vs", + "ZWN0Um9ja3N0YXIiABJ5CjdHZXREeW5hbWljUXVlcnlKb2luZWRSb2Nrc3Rh", + "ckFsYnVtc0N1c3RvbVNlbGVjdFJlc3BvbnNlEg8uRHluYW1pY1JlcXVlc3Qa", + "Ky5RdWVyeVJlc3BvbnNlX0N1c3RvbVNlbGVjdFJvY2tzdGFyUmVzcG9uc2Ui", + "ABI8ChNHZXREeW5hbWljUXVlcnlGb29zEg8uRHluYW1pY1JlcXVlc3QaEi5R", + "dWVyeVJlc3BvbnNlX0ZvbyIAEk8KIUdldER5bmFtaWNRdWVyeU92ZXJyaWRl", + "ZFJvY2tzdGFycxIPLkR5bmFtaWNSZXF1ZXN0GhcuUXVlcnlSZXNwb25zZV9S", + "b2Nrc3RhciIAElsKJ0dldER5bmFtaWNRdWVyeU92ZXJyaWRlZEN1c3RvbVJv", + "Y2tzdGFycxIPLkR5bmFtaWNSZXF1ZXN0Gh0uUXVlcnlSZXNwb25zZV9DdXN0", + "b21Sb2Nrc3RhciIAElMKJUdldER5bmFtaWNRdWVyeUNhc2VJbnNlbnNpdGl2", + "ZU9yZGVyQnkSDy5EeW5hbWljUmVxdWVzdBoXLlF1ZXJ5UmVzcG9uc2VfUm9j", + "a3N0YXIiABJBChZHZXREeW5hbWljU3RyZWFtTW92aWVzEg8uRHluYW1pY1Jl", + "cXVlc3QaFC5RdWVyeVJlc3BvbnNlX01vdmllIgASXwooR2V0RHluYW1pY1F1", + "ZXJ5Q3VzdG9tUm9ja3N0YXJzUmVmZXJlbmNlcxIPLkR5bmFtaWNSZXF1ZXN0", + "GiAuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhclJlZmVyZW5jZSIAEl8KK0dldER5", + "bmFtaWNRdWVyeVJvY2tzdGFyQWxidW1zQ3VzdG9tTGVmdEpvaW4SDy5EeW5h", + "bWljUmVxdWVzdBodLlF1ZXJ5UmVzcG9uc2VfQ3VzdG9tUm9ja3N0YXIiABJR", + "CiNHZXREeW5hbWljUXVlcnlDaGFuZ2VDb25uZWN0aW9uSW5mbxIPLkR5bmFt", + "aWNSZXF1ZXN0GhcuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIAEk4KHEdldER5", + "bmFtaWNRdWVyeVJvY2tzdGFyQXVkaXQSDy5EeW5hbWljUmVxdWVzdBobLlF1", + "ZXJ5UmVzcG9uc2VfUm9ja3N0YXJBdXRvIgASUwohR2V0RHluYW1pY1F1ZXJ5", + "Um9ja3N0YXJBdWRpdFN1Yk9yEg8uRHluYW1pY1JlcXVlc3QaGy5RdWVyeVJl", + "c3BvbnNlX1JvY2tzdGFyQXV0byIAEkYKGEdldER5bmFtaWNRdWVyeUJvb2tt", + "YXJrcxIPLkR5bmFtaWNSZXF1ZXN0GhcuUXVlcnlSZXNwb25zZV9Cb29rbWFy", + "ayIAElAKHUdldER5bmFtaWNRdWVyeU5hbWVkUm9ja3N0YXJzEg8uRHluYW1p", + "Y1JlcXVlc3QaHC5RdWVyeVJlc3BvbnNlX05hbWVkUm9ja3N0YXIiABJGChhH", + "ZXREeW5hbWljUXVlcnlSb2Nrc3RhcnMSDy5EeW5hbWljUmVxdWVzdBoXLlF1", + "ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJQCh1HZXREeW5hbWljUXVlcnlSb2Nr", + "c3RhckFsYnVtcxIPLkR5bmFtaWNSZXF1ZXN0GhwuUXVlcnlSZXNwb25zZV9S", + "b2Nrc3RhckFsYnVtIgASSQoZR2V0RHluYW1pY1F1ZXJ5UGFnaW5nVGVzdBIP", + "LkR5bmFtaWNSZXF1ZXN0GhkuUXVlcnlSZXNwb25zZV9QYWdpbmdUZXN0IgAS", + "UQojR2V0RHluYW1pY1F1ZXJ5Um9ja3N0YXJzQ29udmVudGlvbnMSDy5EeW5h", + "bWljUmVxdWVzdBoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJSCh5HZXRE", + "eW5hbWljUXVlcnlDdXN0b21Sb2Nrc3RhcnMSDy5EeW5hbWljUmVxdWVzdBod", + "LlF1ZXJ5UmVzcG9uc2VfQ3VzdG9tUm9ja3N0YXIiABJXCiNHZXREeW5hbWlj", + "UXVlcnlKb2luZWRSb2Nrc3RhckFsYnVtcxIPLkR5bmFtaWNSZXF1ZXN0Gh0u", + "UXVlcnlSZXNwb25zZV9DdXN0b21Sb2Nrc3RhciIAElkKJUdldER5bmFtaWNR", + "dWVyeVJvY2tzdGFyQWxidW1zSW1wbGljaXQSDy5EeW5hbWljUmVxdWVzdBod", + "LlF1ZXJ5UmVzcG9uc2VfQ3VzdG9tUm9ja3N0YXIiABJZCiVHZXREeW5hbWlj", + "UXVlcnlSb2Nrc3RhckFsYnVtc0xlZnRKb2luEg8uRHluYW1pY1JlcXVlc3Qa", + "HS5RdWVyeVJlc3BvbnNlX0N1c3RvbVJvY2tzdGFyIgASVAogR2V0RHluYW1p", + "Y1F1ZXJ5TXVsdGlKb2luUm9ja3N0YXISDy5EeW5hbWljUmVxdWVzdBodLlF1", + "ZXJ5UmVzcG9uc2VfQ3VzdG9tUm9ja3N0YXIiABJLCh1HZXREeW5hbWljUXVl", + "cnlGaWVsZFJvY2tzdGFycxIPLkR5bmFtaWNSZXF1ZXN0GhcuUXVlcnlSZXNw", + "b25zZV9Sb2Nrc3RhciIAEk8KHEdldER5bmFtaWNRdWVyeVJvY2tzdGFyQWxp", + "YXMSDy5EeW5hbWljUmVxdWVzdBocLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJB", + "bGlhcyIAElIKJEdldER5bmFtaWNRdWVyeUZpZWxkUm9ja3N0YXJzRHluYW1p", + "YxIPLkR5bmFtaWNSZXF1ZXN0GhcuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIA", + "EkwKHkdldER5bmFtaWNRdWVyeVJvY2tzdGFyc0ZpbHRlchIPLkR5bmFtaWNS", + "ZXF1ZXN0GhcuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIAElgKJEdldER5bmFt", + "aWNRdWVyeUN1c3RvbVJvY2tzdGFyc0ZpbHRlchIPLkR5bmFtaWNSZXF1ZXN0", + "Gh0uUXVlcnlSZXNwb25zZV9DdXN0b21Sb2Nrc3RhciIAEk0KH0dldER5bmFt", + "aWNRdWVyeVJvY2tzdGFyc0lGaWx0ZXISDy5EeW5hbWljUmVxdWVzdBoXLlF1", + "ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJIChpHZXREeW5hbWljUXVlcnlPclJv", + "Y2tzdGFycxIPLkR5bmFtaWNSZXF1ZXN0GhcuUXVlcnlSZXNwb25zZV9Sb2Nr", + "c3RhciIAEk4KIEdldER5bmFtaWNRdWVyeVJvY2tzdGFyc0ltcGxpY2l0Eg8u", + "RHluYW1pY1JlcXVlc3QaFy5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyIgASTgog", + "R2V0RHluYW1pY1F1ZXJ5T3JSb2Nrc3RhcnNGaWVsZHMSDy5EeW5hbWljUmVx", + "dWVzdBoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJWCihHZXREeW5hbWlj", + "UXVlcnlGaWVsZHNJbXBsaWNpdENvbnZlbnRpb25zEg8uRHluYW1pY1JlcXVl", + "c3QaFy5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyIgASSQobR2V0RHluYW1pY1F1", + "ZXJ5R2V0Um9ja3N0YXJzEg8uRHluYW1pY1JlcXVlc3QaFy5RdWVyeVJlc3Bv", + "bnNlX1JvY2tzdGFyIgASTAoeR2V0RHluYW1pY1F1ZXJ5Um9ja3N0YXJGaWx0", + "ZXJzEg8uRHluYW1pY1JlcXVlc3QaFy5RdWVyeVJlc3BvbnNlX1JvY2tzdGFy", + "IgASUAoaUG9zdER5bmFtaWNWYWxpZGF0aW9uUnVsZXMSFy5EeW5hbWljVmFs", + "aWRhdGlvblJ1bGVzGhcuUm9ja3N0YXJXaXRoSWRSZXNwb25zZSIAEkIKE1Bv", + "c3RFbXB0eVZhbGlkYXRvcnMSEC5FbXB0eVZhbGlkYXRvcnMaFy5Sb2Nrc3Rh", + "cldpdGhJZFJlc3BvbnNlIgASTQoYR2V0RW5kc1dpdGhTdWZmaXhSZXF1ZXN0", + "EhYuRW5kc1dpdGhTdWZmaXhSZXF1ZXN0GhcuRW5kc1dpdGhTdWZmaXhSZXNw", + "b25zZSIAEk4KGVBvc3RFbmRzV2l0aFN1ZmZpeFJlcXVlc3QSFi5FbmRzV2l0", + "aFN1ZmZpeFJlcXVlc3QaFy5FbmRzV2l0aFN1ZmZpeFJlc3BvbnNlIgASTQoY", + "UHV0RW5kc1dpdGhTdWZmaXhSZXF1ZXN0EhYuRW5kc1dpdGhTdWZmaXhSZXF1", + "ZXN0GhcuRW5kc1dpdGhTdWZmaXhSZXNwb25zZSIAElAKG0RlbGV0ZUVuZHNX", + "aXRoU3VmZml4UmVxdWVzdBIWLkVuZHNXaXRoU3VmZml4UmVxdWVzdBoXLkVu", + "ZHNXaXRoU3VmZml4UmVzcG9uc2UiABJAChJQb3N0R2V0QWNjZXNzVG9rZW4S", + "Dy5HZXRBY2Nlc3NUb2tlbhoXLkdldEFjY2Vzc1Rva2VuUmVzcG9uc2UiABI0", + "Cg5DYWxsR2V0QXBpS2V5cxILLkdldEFwaUtleXMaEy5HZXRBcGlLZXlzUmVz", + "cG9uc2UiABInCgtDYWxsR2V0RmlsZRIILkdldEZpbGUaDC5GaWxlQ29udGVu", + "dCIAEisKDENhbGxHZXRIZWxsbxIJLkdldEhlbGxvGg4uSGVsbG9SZXNwb25z", + "ZSIAEisKC0NhbGxHZXRUb2RvEgguR2V0VG9kbxoQLkdldFRvZG9SZXNwb25z", + "ZSIAEi4KDENhbGxHZXRUb2RvcxIJLkdldFRvZG9zGhEuR2V0VG9kb3NSZXNw", + "b25zZSIAEi0KC0dldEhlbGxvSnd0EgkuSGVsbG9Kd3QaES5IZWxsb0p3dFJl", + "c3BvbnNlIgASLgoMUG9zdEhlbGxvSnd0EgkuSGVsbG9Kd3QaES5IZWxsb0p3", + "dFJlc3BvbnNlIgASLQoLUHV0SGVsbG9Kd3QSCS5IZWxsb0p3dBoRLkhlbGxv", + "Snd0UmVzcG9uc2UiABIwCg5EZWxldGVIZWxsb0p3dBIJLkhlbGxvSnd0GhEu", + "SGVsbG9Kd3RSZXNwb25zZSIAEiIKB0dldEluY3ISBS5JbmNyGg4uRW1wdHlS", + "ZXNwb25zZSIAEiMKCFBvc3RJbmNyEgUuSW5jchoOLkVtcHR5UmVzcG9uc2Ui", + "ABIiCgdQdXRJbmNyEgUuSW5jchoOLkVtcHR5UmVzcG9uc2UiABIlCgpEZWxl", + "dGVJbmNyEgUuSW5jchoOLkVtcHR5UmVzcG9uc2UiABIuCgxQb3N0TXVsdGlw", + "bHkSCS5NdWx0aXBseRoRLk11bHRpcGx5UmVzcG9uc2UiABJKChdQb3N0Tm9B", + "YnN0cmFjdFZhbGlkYXRvchIULk5vQWJzdHJhY3RWYWxpZGF0b3IaFy5Sb2Nr", + "c3RhcldpdGhJZFJlc3BvbnNlIgASTAoYUG9zdE9ubHlWYWxpZGF0ZXNSZXF1", + "ZXN0EhUuT25seVZhbGlkYXRlc1JlcXVlc3QaFy5Sb2Nrc3RhcldpdGhJZFJl", + "c3BvbnNlIgASNQoRQ2FsbFBhdGNoUm9ja3N0YXISDi5QYXRjaFJvY2tzdGFy", + "Gg4uRW1wdHlSZXNwb25zZSIAEl0KHENhbGxQYXRjaFJvY2tzdGFyQXVkaXRU", + "ZW5hbnQSGS5QYXRjaFJvY2tzdGFyQXVkaXRUZW5hbnQaIC5Sb2Nrc3Rhcldp", + "dGhJZEFuZFJlc3VsdFJlc3BvbnNlIgASawojQ2FsbFBhdGNoUm9ja3N0YXJB", + "dWRpdFRlbmFudEdhdGV3YXkSIC5QYXRjaFJvY2tzdGFyQXVkaXRUZW5hbnRH", + "YXRld2F5GiAuUm9ja3N0YXJXaXRoSWRBbmRSZXN1bHRSZXNwb25zZSIAEk8K", + "HkNhbGxQYXRjaFJvY2tzdGFyQXVkaXRUZW5hbnRNcRIbLlBhdGNoUm9ja3N0", + "YXJBdWRpdFRlbmFudE1xGg4uRW1wdHlSZXNwb25zZSIAEjsKFUNhbGxQb3N0", + "Q2hhdFRvQ2hhbm5lbBISLlBvc3RDaGF0VG9DaGFubmVsGgwuQ2hhdE1lc3Nh", + "Z2UiABI0Cg1HZXRRdWVyeUFkaG9jEgsuUXVlcnlBZGhvYxoULlF1ZXJ5UmVz", + "cG9uc2VfQWRob2MiABJJChZHZXRRdWVyeUFkaG9jUm9ja3N0YXJzEhQuUXVl", + "cnlBZGhvY1JvY2tzdGFycxoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJA", + "ChFHZXRRdWVyeUFsbEZpZWxkcxIPLlF1ZXJ5QWxsRmllbGRzGhguUXVlcnlS", + "ZXNwb25zZV9BbGxGaWVsZHMiABI/ChFHZXRRdWVyeUJvb2ttYXJrcxIPLlF1", + "ZXJ5Qm9va21hcmtzGhcuUXVlcnlSZXNwb25zZV9Cb29rbWFyayIAElkKHkdl", + "dFF1ZXJ5Q2FzZUluc2Vuc2l0aXZlT3JkZXJCeRIcLlF1ZXJ5Q2FzZUluc2Vu", + "c2l0aXZlT3JkZXJCeRoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJVChxH", + "ZXRRdWVyeUNoYW5nZUNvbm5lY3Rpb25JbmZvEhouUXVlcnlDaGFuZ2VDb25u", + "ZWN0aW9uSW5mbxoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABI9ChBHZXRR", + "dWVyeUNoYW5nZURiEg4uUXVlcnlDaGFuZ2VEYhoXLlF1ZXJ5UmVzcG9uc2Vf", + "Um9ja3N0YXIiABJRChdHZXRRdWVyeUN1c3RvbVJvY2tzdGFycxIVLlF1ZXJ5", + "Q3VzdG9tUm9ja3N0YXJzGh0uUXVlcnlSZXNwb25zZV9DdXN0b21Sb2Nrc3Rh", + "ciIAEl0KHUdldFF1ZXJ5Q3VzdG9tUm9ja3N0YXJzRmlsdGVyEhsuUXVlcnlD", + "dXN0b21Sb2Nrc3RhcnNGaWx0ZXIaHS5RdWVyeVJlc3BvbnNlX0N1c3RvbVJv", + "Y2tzdGFyIgASaAohR2V0UXVlcnlDdXN0b21Sb2Nrc3RhcnNSZWZlcmVuY2Vz", + "Eh8uUXVlcnlDdXN0b21Sb2Nrc3RhcnNSZWZlcmVuY2VzGiAuUXVlcnlSZXNw", + "b25zZV9Sb2Nrc3RhclJlZmVyZW5jZSIAEmMKHUdldFF1ZXJ5Q3VzdG9tUm9j", + "a3N0YXJzU2NoZW1hEhsuUXVlcnlDdXN0b21Sb2Nrc3RhcnNTY2hlbWEaIy5R", + "dWVyeVJlc3BvbnNlX0N1c3RvbVJvY2tzdGFyU2NoZW1hIgASSQoWR2V0UXVl", + "cnlGaWVsZFJvY2tzdGFycxIULlF1ZXJ5RmllbGRSb2Nrc3RhcnMaFy5RdWVy", + "eVJlc3BvbnNlX1JvY2tzdGFyIgASVwodR2V0UXVlcnlGaWVsZFJvY2tzdGFy", + "c0R5bmFtaWMSGy5RdWVyeUZpZWxkUm9ja3N0YXJzRHluYW1pYxoXLlF1ZXJ5", + "UmVzcG9uc2VfUm9ja3N0YXIiABJfCiFHZXRRdWVyeUZpZWxkc0ltcGxpY2l0", + "Q29udmVudGlvbnMSHy5RdWVyeUZpZWxkc0ltcGxpY2l0Q29udmVudGlvbnMa", + "Fy5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyIgASMAoMR2V0UXVlcnlGb29zEgou", + "UXVlcnlGb29zGhIuUXVlcnlSZXNwb25zZV9Gb28iABJFChRHZXRRdWVyeUdl", + "dFJvY2tzdGFycxISLlF1ZXJ5R2V0Um9ja3N0YXJzGhcuUXVlcnlSZXNwb25z", + "ZV9Sb2Nrc3RhciIAElMKG0dldFF1ZXJ5R2V0Um9ja3N0YXJzRHluYW1pYxIZ", + "LlF1ZXJ5R2V0Um9ja3N0YXJzRHluYW1pYxoXLlF1ZXJ5UmVzcG9uc2VfUm9j", + "a3N0YXIiABJbChxHZXRRdWVyeUpvaW5lZFJvY2tzdGFyQWxidW1zEhouUXVl", + "cnlKb2luZWRSb2Nrc3RhckFsYnVtcxodLlF1ZXJ5UmVzcG9uc2VfQ3VzdG9t", + "Um9ja3N0YXIiABJ5CihHZXRRdWVyeUpvaW5lZFJvY2tzdGFyQWxidW1zQ3Vz", + "dG9tU2VsZWN0EiYuUXVlcnlKb2luZWRSb2Nrc3RhckFsYnVtc0N1c3RvbVNl", + "bGVjdBojLlF1ZXJ5UmVzcG9uc2VfQ3VzdG9tU2VsZWN0Um9ja3N0YXIiABKR", + "AQowR2V0UXVlcnlKb2luZWRSb2Nrc3RhckFsYnVtc0N1c3RvbVNlbGVjdFJl", + "c3BvbnNlEi4uUXVlcnlKb2luZWRSb2Nrc3RhckFsYnVtc0N1c3RvbVNlbGVj", + "dFJlc3BvbnNlGisuUXVlcnlSZXNwb25zZV9DdXN0b21TZWxlY3RSb2Nrc3Rh", + "clJlc3BvbnNlIgASNgoOR2V0UXVlcnlNb3ZpZXMSDC5RdWVyeU1vdmllcxoU", + "LlF1ZXJ5UmVzcG9uc2VfTW92aWUiABJVChlHZXRRdWVyeU11bHRpSm9pblJv", + "Y2tzdGFyEhcuUXVlcnlNdWx0aUpvaW5Sb2Nrc3RhchodLlF1ZXJ5UmVzcG9u", + "c2VfQ3VzdG9tUm9ja3N0YXIiABJOChZHZXRRdWVyeU5hbWVkUm9ja3N0YXJz", + "EhQuUXVlcnlOYW1lZFJvY2tzdGFycxocLlF1ZXJ5UmVzcG9uc2VfTmFtZWRS", + "b2Nrc3RhciIAEkMKE0dldFF1ZXJ5T3JSb2Nrc3RhcnMSES5RdWVyeU9yUm9j", + "a3N0YXJzGhcuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIAEk8KGUdldFF1ZXJ5", + "T3JSb2Nrc3RhcnNGaWVsZHMSFy5RdWVyeU9yUm9ja3N0YXJzRmllbGRzGhcu", + "UXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIAEmMKIEdldFF1ZXJ5T3ZlcnJpZGVk", + "Q3VzdG9tUm9ja3N0YXJzEh4uUXVlcnlPdmVycmlkZWRDdXN0b21Sb2Nrc3Rh", + "cnMaHS5RdWVyeVJlc3BvbnNlX0N1c3RvbVJvY2tzdGFyIgASUQoaR2V0UXVl", + "cnlPdmVycmlkZWRSb2Nrc3RhcnMSGC5RdWVyeU92ZXJyaWRlZFJvY2tzdGFy", + "cxoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABJDChJHZXRRdWVyeVBhZ2lu", + "Z1Rlc3QSEC5RdWVyeVBhZ2luZ1Rlc3QaGS5RdWVyeVJlc3BvbnNlX1BhZ2lu", + "Z1Rlc3QiABJOChZHZXRRdWVyeVJvY2tzdGFyQWxidW1zEhQuUXVlcnlSb2Nr", + "c3RhckFsYnVtcxocLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJBbGJ1bSIAEmsK", + "JEdldFF1ZXJ5Um9ja3N0YXJBbGJ1bXNDdXN0b21MZWZ0Sm9pbhIiLlF1ZXJ5", + "Um9ja3N0YXJBbGJ1bXNDdXN0b21MZWZ0Sm9pbhodLlF1ZXJ5UmVzcG9uc2Vf", + "Q3VzdG9tUm9ja3N0YXIiABJfCh5HZXRRdWVyeVJvY2tzdGFyQWxidW1zSW1w", + "bGljaXQSHC5RdWVyeVJvY2tzdGFyQWxidW1zSW1wbGljaXQaHS5RdWVyeVJl", + "c3BvbnNlX0N1c3RvbVJvY2tzdGFyIgASXwoeR2V0UXVlcnlSb2Nrc3RhckFs", + "YnVtc0xlZnRKb2luEhwuUXVlcnlSb2Nrc3RhckFsYnVtc0xlZnRKb2luGh0u", + "UXVlcnlSZXNwb25zZV9DdXN0b21Sb2Nrc3RhciIAEkwKFUdldFF1ZXJ5Um9j", + "a3N0YXJBbGlhcxITLlF1ZXJ5Um9ja3N0YXJBbGlhcxocLlF1ZXJ5UmVzcG9u", + "c2VfUm9ja3N0YXJBbGlhcyIAEksKFUdldFF1ZXJ5Um9ja3N0YXJBdWRpdBIT", + "LlF1ZXJ5Um9ja3N0YXJBdWRpdBobLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJB", + "dXRvIgASVQoaR2V0UXVlcnlSb2Nrc3RhckF1ZGl0U3ViT3ISGC5RdWVyeVJv", + "Y2tzdGFyQXVkaXRTdWJPchobLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXJBdXRv", + "IgASSwoXR2V0UXVlcnlSb2Nrc3RhckZpbHRlcnMSFS5RdWVyeVJvY2tzdGFy", + "RmlsdGVycxoXLlF1ZXJ5UmVzcG9uc2VfUm9ja3N0YXIiABI/ChFHZXRRdWVy", + "eVJvY2tzdGFycxIPLlF1ZXJ5Um9ja3N0YXJzGhcuUXVlcnlSZXNwb25zZV9S", + "b2Nrc3RhciIAElUKHEdldFF1ZXJ5Um9ja3N0YXJzQ29udmVudGlvbnMSGi5R", + "dWVyeVJvY2tzdGFyc0NvbnZlbnRpb25zGhcuUXVlcnlSZXNwb25zZV9Sb2Nr", + "c3RhciIAEksKF0dldFF1ZXJ5Um9ja3N0YXJzRmlsdGVyEhUuUXVlcnlSb2Nr", + "c3RhcnNGaWx0ZXIaFy5RdWVyeVJlc3BvbnNlX1JvY2tzdGFyIgASTQoYR2V0", + "UXVlcnlSb2Nrc3RhcnNJRmlsdGVyEhYuUXVlcnlSb2Nrc3RhcnNJRmlsdGVy", + "GhcuUXVlcnlSZXNwb25zZV9Sb2Nrc3RhciIAEk8KGUdldFF1ZXJ5Um9ja3N0", + "YXJzSW1wbGljaXQSFy5RdWVyeVJvY2tzdGFyc0ltcGxpY2l0GhcuUXVlcnlS", + "ZXNwb25zZV9Sb2Nrc3RhciIAEmQKH0dldFF1ZXJ5Um9ja3N0YXJzV2l0aFJl", + "ZmVyZW5jZXMSHS5RdWVyeVJvY2tzdGFyc1dpdGhSZWZlcmVuY2VzGiAuUXVl", + "cnlSZXNwb25zZV9Sb2Nrc3RhclJlZmVyZW5jZSIAEksKFUdldFF1ZXJ5VHlw", + "ZVdpdGhFbnVtcxITLlF1ZXJ5VHlwZVdpdGhFbnVtcxobLlF1ZXJ5UmVzcG9u", + "c2VfVHlwZVdpdGhFbnVtIgASTQoYR2V0UXVlcnlVbmtub3duUm9ja3N0YXJz", + "EhYuUXVlcnlVbmtub3duUm9ja3N0YXJzGhcuUXVlcnlSZXNwb25zZV9Sb2Nr", + "c3RhciIAElgKG0RlbGV0ZVJlYWxEZWxldGVBdWRpdFRlbmFudBIWLlJlYWxE", + "ZWxldGVBdWRpdFRlbmFudBofLlJvY2tzdGFyV2l0aElkQW5kQ291bnRSZXNw", + "b25zZSIAEmYKIkRlbGV0ZVJlYWxEZWxldGVBdWRpdFRlbmFudEdhdGV3YXkS", + "HS5SZWFsRGVsZXRlQXVkaXRUZW5hbnRHYXRld2F5Gh8uUm9ja3N0YXJXaXRo", + "SWRBbmRDb3VudFJlc3BvbnNlIgASSwodRGVsZXRlUmVhbERlbGV0ZUF1ZGl0", + "VGVuYW50TXESGC5SZWFsRGVsZXRlQXVkaXRUZW5hbnRNcRoOLkVtcHR5UmVz", + "cG9uc2UiABJJChVQb3N0UmVnZW5lcmF0ZUFwaUtleXMSEi5SZWdlbmVyYXRl", + "QXBpS2V5cxoaLlJlZ2VuZXJhdGVBcGlLZXlzUmVzcG9uc2UiABItCgtQdXRS", + "ZWdpc3RlchIJLlJlZ2lzdGVyGhEuUmVnaXN0ZXJSZXNwb25zZSIAEi4KDFBv", + "c3RSZWdpc3RlchIJLlJlZ2lzdGVyGhEuUmVnaXN0ZXJSZXNwb25zZSIAEjEK", + "D0dldFJlcXVpcmVzQXV0aBINLlJlcXVpcmVzQXV0aBoNLlJlcXVpcmVzQXV0", + "aCIAEjIKEFBvc3RSZXF1aXJlc0F1dGgSDS5SZXF1aXJlc0F1dGgaDS5SZXF1", + "aXJlc0F1dGgiABIxCg9QdXRSZXF1aXJlc0F1dGgSDS5SZXF1aXJlc0F1dGga", + "DS5SZXF1aXJlc0F1dGgiABI0ChJEZWxldGVSZXF1aXJlc0F1dGgSDS5SZXF1", + "aXJlc0F1dGgaDS5SZXF1aXJlc0F1dGgiABIvCg5Qb3N0UmVzZXRUb2RvcxIL", + "LlJlc2V0VG9kb3MaDi5FbXB0eVJlc3BvbnNlIgASOAoPR2V0U2VhcmNoTW92", + "aWVzEg0uU2VhcmNoTW92aWVzGhQuUXVlcnlSZXNwb25zZV9Nb3ZpZSIAEisK", + "C1Bvc3RTZWN1cmVkEgguU2VjdXJlZBoQLlNlY3VyZWRSZXNwb25zZSIAElYK", + "GFB1dFNvZnREZWxldGVBdWRpdFRlbmFudBIWLlNvZnREZWxldGVBdWRpdFRl", + "bmFudBogLlJvY2tzdGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2UiABIzChFT", + "ZXJ2ZXJTdHJlYW1GaWxlcxIMLlN0cmVhbUZpbGVzGgwuRmlsZUNvbnRlbnQi", + "ADABEjgKD0dldFN0cmVhbU1vdmllcxINLlN0cmVhbU1vdmllcxoULlF1ZXJ5", + "UmVzcG9uc2VfTW92aWUiABJQChhTZXJ2ZXJTdHJlYW1TZXJ2ZXJFdmVudHMS", + "Ey5TdHJlYW1TZXJ2ZXJFdmVudHMaGy5TdHJlYW1TZXJ2ZXJFdmVudHNSZXNw", + "b25zZSIAMAESSAoWUG9zdFRlc3RBdXRoVmFsaWRhdG9ycxITLlRlc3RBdXRo", + "VmFsaWRhdG9ycxoXLlJvY2tzdGFyV2l0aElkUmVzcG9uc2UiABJCChNQb3N0", + "VGVzdERiQ29uZGl0aW9uEhAuVGVzdERiQ29uZGl0aW9uGhcuUm9ja3N0YXJX", + "aXRoSWRSZXNwb25zZSIAEkIKE1Bvc3RUZXN0RGJWYWxpZGF0b3ISEC5UZXN0", + "RGJWYWxpZGF0b3IaFy5Sb2Nrc3RhcldpdGhJZFJlc3BvbnNlIgASOgoPUG9z", + "dFRlc3RJc0FkbWluEgwuVGVzdElzQWRtaW4aFy5Sb2Nrc3RhcldpdGhJZFJl", + "c3BvbnNlIgASUgobUG9zdFRlc3RNdWx0aUF1dGhWYWxpZGF0b3JzEhguVGVz", + "dE11bHRpQXV0aFZhbGlkYXRvcnMaFy5Sb2Nrc3RhcldpdGhJZFJlc3BvbnNl", + "IgASJAoIR2V0VGhyb3cSBi5UaHJvdxoOLkhlbGxvUmVzcG9uc2UiABI2Cg5H", + "ZXRUaHJvd0N1c3RvbRIMLlRocm93Q3VzdG9tGhQuVGhyb3dDdXN0b21SZXNw", + "b25zZSIAEiwKDEdldFRocm93Vm9pZBIKLlRocm93Vm9pZBoOLkVtcHR5UmVz", + "cG9uc2UiABJMChhQb3N0VHJpZ2dlckFsbFZhbGlkYXRvcnMSFS5UcmlnZ2Vy", + "QWxsVmFsaWRhdG9ycxoXLlJvY2tzdGFyV2l0aElkUmVzcG9uc2UiABI9ChVQ", + "b3N0VHJpZ2dlclZhbGlkYXRvcnMSEi5UcmlnZ2VyVmFsaWRhdG9ycxoOLkVt", + "cHR5UmVzcG9uc2UiABI9ChFQb3N0VW5Bc3NpZ25Sb2xlcxIOLlVuQXNzaWdu", + "Um9sZXMaFi5VbkFzc2lnblJvbGVzUmVzcG9uc2UiABJkCh9QdXRVcGRhdGVD", + "b25uZWN0aW9uSW5mb1JvY2tzdGFyEh0uVXBkYXRlQ29ubmVjdGlvbkluZm9S", + "b2Nrc3RhchogLlJvY2tzdGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2UiABJS", + "ChZQdXRVcGRhdGVOYW1lZFJvY2tzdGFyEhQuVXBkYXRlTmFtZWRSb2Nrc3Rh", + "chogLlJvY2tzdGFyV2l0aElkQW5kUmVzdWx0UmVzcG9uc2UiABI2ChFQdXRV", + "cGRhdGVSb2Nrc3RhchIPLlVwZGF0ZVJvY2tzdGFyGg4uRW1wdHlSZXNwb25z", + "ZSIAElYKIVB1dFVwZGF0ZVJvY2tzdGFyQWRob2NOb25EZWZhdWx0cxIfLlVw", + "ZGF0ZVJvY2tzdGFyQWRob2NOb25EZWZhdWx0cxoOLkVtcHR5UmVzcG9uc2Ui", + "ABJCChhQYXRjaFVwZGF0ZVJvY2tzdGFyQXVkaXQSFC5VcGRhdGVSb2Nrc3Rh", + "ckF1ZGl0Gg4uRW1wdHlSZXNwb25zZSIAEl4KHFB1dFVwZGF0ZVJvY2tzdGFy", + "QXVkaXRUZW5hbnQSGi5VcGRhdGVSb2Nrc3RhckF1ZGl0VGVuYW50GiAuUm9j", + "a3N0YXJXaXRoSWRBbmRSZXN1bHRSZXNwb25zZSIAEmwKI1B1dFVwZGF0ZVJv", + "Y2tzdGFyQXVkaXRUZW5hbnRHYXRld2F5EiEuVXBkYXRlUm9ja3N0YXJBdWRp", + "dFRlbmFudEdhdGV3YXkaIC5Sb2Nrc3RhcldpdGhJZEFuZFJlc3VsdFJlc3Bv", + "bnNlIgASUAoeUHV0VXBkYXRlUm9ja3N0YXJBdWRpdFRlbmFudE1xEhwuVXBk", + "YXRlUm9ja3N0YXJBdWRpdFRlbmFudE1xGg4uRW1wdHlSZXNwb25zZSIAElwK", + "GlBhdGNoVXBkYXRlUm9ja3N0YXJWZXJzaW9uEhYuVXBkYXRlUm9ja3N0YXJW", + "ZXJzaW9uGiQuUm9ja3N0YXJXaXRoSWRBbmRSb3dWZXJzaW9uUmVzcG9uc2Ui", + "ABIuCg1QdXRVcGRhdGVUb2RvEgsuVXBkYXRlVG9kbxoOLkVtcHR5UmVzcG9u", + "c2UiABJQChpQb3N0VmFsaWRhdGVDcmVhdGVSb2Nrc3RhchIXLlZhbGlkYXRl", + "Q3JlYXRlUm9ja3N0YXIaFy5Sb2Nrc3RhcldpdGhJZFJlc3BvbnNlIgBCTqoC", + "JFNlcnZpY2VTdGFjay5FeHRlbnNpb25zLlRlc3RzLlByb3RvY8oCJFNlcnZp", + "Y2VTdGFjay5FeHRlbnNpb25zLlRlc3RzLlByb3RvY2IGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode), typeof(global::ServiceStack.Extensions.Tests.Protoc.LivingStatus), typeof(global::ServiceStack.Extensions.Tests.Protoc.SomeEnum), typeof(global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt), }, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AddHeader), global::ServiceStack.Extensions.Tests.Protoc.AddHeader.Parser, new[]{ "Name", "Value" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Adhoc), global::ServiceStack.Extensions.Tests.Protoc.Adhoc.Parser, new[]{ "Id", "FirstName", "LastName" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AllFields), global::ServiceStack.Extensions.Tests.Protoc.AllFields.Parser, new[]{ "Id", "NullableId", "Byte", "Short", "Int", "Long", "UShort", "UInt", "ULong", "Float", "Double", "Decimal", "String", "DateTime", "TimeSpan", "Guid", "NullableDateTime", "NullableTimeSpan", "NullableGuid", "Enum", "NullableEnum" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AnyHello), global::ServiceStack.Extensions.Tests.Protoc.AnyHello.Parser, new[]{ "Name" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AssignRoles), global::ServiceStack.Extensions.Tests.Protoc.AssignRoles.Parser, new[]{ "UserName", "Permissions", "Roles", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AssignRolesResponse), global::ServiceStack.Extensions.Tests.Protoc.AssignRolesResponse.Parser, new[]{ "AllRoles", "AllPermissions", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AuditBase), global::ServiceStack.Extensions.Tests.Protoc.AuditBase.Parser, new[]{ "CreatedDate", "CreatedBy", "CreatedInfo", "ModifiedDate", "ModifiedBy", "ModifiedInfo", "SoftDeletedDate", "SoftDeletedBy", "SoftDeletedInfo", "RockstarAuditTenant" }, new[]{ "Subtype" }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Authenticate), global::ServiceStack.Extensions.Tests.Protoc.Authenticate.Parser, new[]{ "Provider", "State", "OauthToken", "OauthVerifier", "UserName", "Password", "RememberMe", "ErrorView", "Nonce", "Uri", "Response", "Qop", "Nc", "Cnonce", "UseTokenCookie", "AccessToken", "AccessTokenSecret", "Scope", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse), global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse.Parser, new[]{ "UserId", "SessionId", "UserName", "DisplayName", "ReferrerUrl", "BearerToken", "RefreshToken", "ProfileUrl", "Roles", "Permissions", "ResponseStatus", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Bar), global::ServiceStack.Extensions.Tests.Protoc.Bar.Parser, new[]{ "Y" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Bookmark), global::ServiceStack.Extensions.Tests.Protoc.Bookmark.Parser, new[]{ "Slug", "Title", "Description", "Url" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo), global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ChangeDb), global::ServiceStack.Extensions.Tests.Protoc.ChangeDb.Parser, new[]{ "NamedConnection", "ConnectionString", "ProviderName" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse), global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse.Parser, new[]{ "Results" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ChatMessage), global::ServiceStack.Extensions.Tests.Protoc.ChatMessage.Parser, new[]{ "Id", "Channel", "FromUserId", "FromName", "DisplayName", "Message", "UserAuthId", "Private" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken), global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken.Parser, new[]{ "PreserveSession", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToTokenResponse), global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToTokenResponse.Parser, new[]{ "Meta", "AccessToken", "RefreshToken", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark), global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark.Parser, new[]{ "Slug", "Title", "Description", "Url" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmarkResponse), global::ServiceStack.Extensions.Tests.Protoc.CreateBookmarkResponse.Parser, new[]{ "Id", "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar), global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar), global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "BearerToken" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant.Parser, new[]{ "BearerToken", "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap.Parser, new[]{ "MapFirstName", "MapLastName", "MapAge", "MapDateOfBirth", "MapDateDied", "MapLivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarResponse), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarResponse.Parser, new[]{ "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturnGuidResponse), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturnGuidResponse.Parser, new[]{ "Id", "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateTodo), global::ServiceStack.Extensions.Tests.Protoc.CreateTodo.Parser, new[]{ "Title", "Order" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CreateTodoResponse), global::ServiceStack.Extensions.Tests.Protoc.CreateTodoResponse.Parser, new[]{ "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CustomRockstar), global::ServiceStack.Extensions.Tests.Protoc.CustomRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "RockstarAlbumName", "RockstarGenreName" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CustomRockstarSchema), global::ServiceStack.Extensions.Tests.Protoc.CustomRockstarSchema.Parser, new[]{ "FirstName", "LastName", "Age", "RockstarAlbumName", "RockstarGenreName" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CustomSelectRockstar), global::ServiceStack.Extensions.Tests.Protoc.CustomSelectRockstar.Parser, new[]{ "Id", "FirstName", "LastName", "Age" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CustomSelectRockstarResponse), global::ServiceStack.Extensions.Tests.Protoc.CustomSelectRockstarResponse.Parser, new[]{ "Id", "FirstName", "Age" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors), global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors.Parser, new[]{ "CustomErrorCode", "CustomErrorCodeAndMessage", "ErrorCodeRule", "IsOddCondition", "IsOddAndOverTwoDigitsCondition", "IsOddOrOverTwoDigitsCondition" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DaoBase), global::ServiceStack.Extensions.Tests.Protoc.DaoBase.Parser, new[]{ "Id", "CreateDate", "CreatedBy", "ModifiedDate", "ModifiedBy", "Bookmark" }, new[]{ "Subtype" }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarCountResponse), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarCountResponse.Parser, new[]{ "Count", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters.Parser, new[]{ "FirstName", "LastName", "Age" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo), global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos), global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos.Parser, new[]{ "Ids" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest), global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest.Parser, new[]{ "Params" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules), global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse), global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse.Parser, new[]{ "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators), global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators.Parser, new[]{ "Int", "NInt", "TimeSpan", "NTimeSpan", "String", "IntArray", "StringList" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest), global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest.Parser, new[]{ "Suffix" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse), global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse.Parser, new[]{ "Result", "Count", "Words" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Entry), global::ServiceStack.Extensions.Tests.Protoc.Entry.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.FileContent), global::ServiceStack.Extensions.Tests.Protoc.FileContent.Parser, new[]{ "Name", "Type", "Length", "Body", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Foo), global::ServiceStack.Extensions.Tests.Protoc.Foo.Parser, new[]{ "X", "Bar" }, new[]{ "Subtype" }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken), global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken.Parser, new[]{ "RefreshToken", "UseTokenCookie", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetAccessTokenResponse), global::ServiceStack.Extensions.Tests.Protoc.GetAccessTokenResponse.Parser, new[]{ "AccessToken", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys), global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys.Parser, new[]{ "Environment", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeysResponse), global::ServiceStack.Extensions.Tests.Protoc.GetApiKeysResponse.Parser, new[]{ "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetFile), global::ServiceStack.Extensions.Tests.Protoc.GetFile.Parser, new[]{ "Path" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetHello), global::ServiceStack.Extensions.Tests.Protoc.GetHello.Parser, new[]{ "Name" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetTodo), global::ServiceStack.Extensions.Tests.Protoc.GetTodo.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetTodoResponse), global::ServiceStack.Extensions.Tests.Protoc.GetTodoResponse.Parser, new[]{ "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetTodos), global::ServiceStack.Extensions.Tests.Protoc.GetTodos.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.GetTodosResponse), global::ServiceStack.Extensions.Tests.Protoc.GetTodosResponse.Parser, new[]{ "Results", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt), global::ServiceStack.Extensions.Tests.Protoc.HelloJwt.Parser, new[]{ "Name", "BearerToken" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse), global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse.Parser, new[]{ "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.HelloResponse), global::ServiceStack.Extensions.Tests.Protoc.HelloResponse.Parser, new[]{ "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Incr), global::ServiceStack.Extensions.Tests.Protoc.Incr.Parser, new[]{ "Amount" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Movie), global::ServiceStack.Extensions.Tests.Protoc.Movie.Parser, new[]{ "Id", "ImdbId", "Title", "Rating", "Score", "Director", "ReleaseDate", "TagLine", "Genres" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Multiply), global::ServiceStack.Extensions.Tests.Protoc.Multiply.Parser, new[]{ "X", "Y" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.MultiplyResponse), global::ServiceStack.Extensions.Tests.Protoc.MultiplyResponse.Parser, new[]{ "Result" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar), global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator), global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest), global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest.Parser, new[]{ "Test", "NotNull" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PagingTest), global::ServiceStack.Extensions.Tests.Protoc.PagingTest.Parser, new[]{ "Id", "Name", "Value" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant.Parser, new[]{ "BearerToken", "Id", "FirstName", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway.Parser, new[]{ "Id", "FirstName", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq.Parser, new[]{ "Id", "FirstName", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel), global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel.Parser, new[]{ "From", "ToUserId", "Channel", "Message", "Selector" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc), global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "FirstName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields), global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Guid" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks), global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy), global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo), global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb), global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "NamedConnection", "ConnectionString", "ProviderName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryDbTenant_RockstarAuditTenant_RockstarAuto), global::ServiceStack.Extensions.Tests.Protoc.QueryDbTenant_RockstarAuditTenant_RockstarAuto.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "FirstName", "FirstNames", "Age", "FirstNameCaseInsensitive", "FirstNameStartsWith", "LastNameEndsWith", "FirstNameBetween", "OrLastName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic), global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions), global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "FirstNameContains", "LastNameEndsWith" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryFoos), global::ServiceStack.Extensions.Tests.Protoc.QueryFoos.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "X" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Ids", "Ages", "FirstNames", "IdsBetween" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic), global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums), global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "RockstarAlbumName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect), global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "RockstarAlbumName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse), global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "RockstarAlbumName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryMovies), global::ServiceStack.Extensions.Tests.Protoc.QueryMovies.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Ids", "ImdbIds", "Ratings" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar), global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "RockstarAlbumName", "RockstarGenreName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "FirstName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields), global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "FirstName", "LastName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest), global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Id", "Name", "Value" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum.Parser, new[]{ "Offset", "Total", "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Id", "RockstarId", "Name", "Genre", "IdBetween" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "AlbumName", "IdNotEqualTo" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "AlbumName", "IdNotEqualTo" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age", "RockstarAlbumName" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Id" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "FirstNameStartsWith", "AgeOlderThan" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Ids", "Ages", "FirstNames", "IdsBetween" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "DateOfBirthGreaterThan", "DateDiedLessThan", "Ids", "AgeOlderThan", "AgeGreaterThanOrEqualTo", "AgeGreaterThan", "GreaterThanAge", "FirstNameStartsWith", "LastNameEndsWith", "LastNameContains", "RockstarAlbumNameContains", "RockstarIdAfter", "RockstarIdOnOrAfter" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Age" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums), global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars), global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "UnknownInt", "UnknownProperty" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant), global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant.Parser, new[]{ "BearerToken", "Id", "Age" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway), global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq), global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys), global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys.Parser, new[]{ "Environment", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeysResponse), global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeysResponse.Parser, new[]{ "Results", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Register), global::ServiceStack.Extensions.Tests.Protoc.Register.Parser, new[]{ "UserName", "FirstName", "LastName", "DisplayName", "Email", "Password", "ConfirmPassword", "AutoLogin", "ErrorView", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse), global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse.Parser, new[]{ "UserId", "SessionId", "UserName", "ReferrerUrl", "BearerToken", "RefreshToken", "ResponseStatus", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth), global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth.Parser, new[]{ "Name", "BearerToken" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ResetTodos), global::ServiceStack.Extensions.Tests.Protoc.ResetTodos.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ResponseError), global::ServiceStack.Extensions.Tests.Protoc.ResponseError.Parser, new[]{ "ErrorCode", "FieldName", "Message", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus), global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus.Parser, new[]{ "ErrorCode", "Message", "StackTrace", "Errors", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Rockstar), global::ServiceStack.Extensions.Tests.Protoc.Rockstar.Parser, new[]{ "Id", "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "NamedRockstar" }, new[]{ "Subtype" }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarAlbum), global::ServiceStack.Extensions.Tests.Protoc.RockstarAlbum.Parser, new[]{ "Id", "RockstarId", "Name", "Genre" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarAlias), global::ServiceStack.Extensions.Tests.Protoc.RockstarAlias.Parser, new[]{ "RockstarId", "FirstName", "Surname", "Album" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit), global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit.Parser, new[]{ "Id", "CreatedDate", "CreatedBy", "CreatedInfo", "ModifiedDate", "ModifiedBy", "ModifiedInfo" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant), global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant.Parser, new[]{ "TenantId", "Id", "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto), global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid), global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarBase), global::ServiceStack.Extensions.Tests.Protoc.RockstarBase.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "RockstarAutoGuid", "RockstarAuto", "RockstarAudit", "RockstarVersion" }, new[]{ "Subtype" }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarGenre), global::ServiceStack.Extensions.Tests.Protoc.RockstarGenre.Parser, new[]{ "Id", "RockstarId", "Name" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarReference), global::ServiceStack.Extensions.Tests.Protoc.RockstarReference.Parser, new[]{ "Id", "FirstName", "LastName", "Age", "Albums" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion), global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion.Parser, new[]{ "Id", "RowVersion" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse.Parser, new[]{ "Id", "Count", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse.Parser, new[]{ "Id", "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse.Parser, new[]{ "Id", "RowVersion", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse.Parser, new[]{ "Id", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.SearchMovies), global::ServiceStack.Extensions.Tests.Protoc.SearchMovies.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.SearchResult), global::ServiceStack.Extensions.Tests.Protoc.SearchResult.Parser, new[]{ "Id", "Suffix" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Secured), global::ServiceStack.Extensions.Tests.Protoc.Secured.Parser, new[]{ "Name" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.SecuredResponse), global::ServiceStack.Extensions.Tests.Protoc.SecuredResponse.Parser, new[]{ "Result", "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant), global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant.Parser, new[]{ "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.StreamFiles), global::ServiceStack.Extensions.Tests.Protoc.StreamFiles.Parser, new[]{ "Paths" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.StreamMovies), global::ServiceStack.Extensions.Tests.Protoc.StreamMovies.Parser, new[]{ "Skip", "Take", "OrderBy", "OrderByDesc", "Include", "Fields", "Meta", "Ratings" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.StreamServerEvents), global::ServiceStack.Extensions.Tests.Protoc.StreamServerEvents.Parser, new[]{ "Channels" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.StreamServerEventsResponse), global::ServiceStack.Extensions.Tests.Protoc.StreamServerEventsResponse.Parser, new[]{ "EventId", "Channel", "Selector", "Json", "Op", "Target", "CssSelector", "Meta", "UserId", "DisplayName", "ProfileUrl", "IsAuthenticated", "Channels", "CreatedAt", "Id", "UnRegisterUrl", "UpdateSubscriberUrl", "HeartbeatUrl", "HeartbeatIntervalMs", "IdleTimeoutMs", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators), global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators.Parser, new[]{ "NotNull" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition), global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition.Parser, new[]{ "Id", "NotNull" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator), global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator.Parser, new[]{ "Id", "NotNull" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin), global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin.Parser, new[]{ "NotNull" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators), global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators.Parser, new[]{ "NotNull" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Throw), global::ServiceStack.Extensions.Tests.Protoc.Throw.Parser, new[]{ "Message" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom), global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustomResponse), global::ServiceStack.Extensions.Tests.Protoc.ThrowCustomResponse.Parser, new[]{ "ResponseStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid), global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid.Parser, new[]{ "Message" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.Todo), global::ServiceStack.Extensions.Tests.Protoc.Todo.Parser, new[]{ "Id", "Title", "Order", "Completed" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators), global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators.Parser, new[]{ "CreditCard", "Email", "Empty", "Equal", "ExclusiveBetween", "GreaterThanOrEqual", "GreaterThan", "InclusiveBetween", "Length", "LessThanOrEqual", "LessThan", "NotEmpty", "NotEqual", "Null", "RegularExpression", "ScalePrecision" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators), global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators.Parser, new[]{ "CreditCard", "Email", "Empty", "Equal", "ExclusiveBetween", "GreaterThanOrEqual", "GreaterThan", "InclusiveBetween", "Length", "LessThanOrEqual", "LessThan", "NotEmpty", "NotEqual", "Null", "RegularExpression", "ScalePrecision" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.TypeWithEnum), global::ServiceStack.Extensions.Tests.Protoc.TypeWithEnum.Parser, new[]{ "Id", "Name", "SomeEnum", "SomeEnumAsInt", "NSomeEnum", "NSomeEnumAsInt" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles), global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles.Parser, new[]{ "UserName", "Permissions", "Roles", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRolesResponse), global::ServiceStack.Extensions.Tests.Protoc.UnAssignRolesResponse.Parser, new[]{ "AllRoles", "AllPermissions", "Meta", "ResponseStatus" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse), global::ServiceStack.Extensions.Tests.Protoc.UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar), global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar), global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults.Parser, new[]{ "Id", "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant.Parser, new[]{ "BearerToken", "Id", "FirstName", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway.Parser, new[]{ "Id", "FirstName", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq.Parser, new[]{ "Id", "FirstName", "LivingStatus" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus", "Id", "RowVersion" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo), global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo.Parser, new[]{ "Id", "Title", "Order", "Completed" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.UserApiKey), global::ServiceStack.Extensions.Tests.Protoc.UserApiKey.Parser, new[]{ "Key", "KeyType", "ExpiryDate", "Meta" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar), global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar.Parser, new[]{ "FirstName", "LastName", "Age", "DateOfBirth", "DateDied", "LivingStatus" }, null, null, null) + })); + } + #endregion + + } + #region Enums + public enum HttpStatusCode { + /// + /// proto3 requires a zero value as the first item (it can be named anything) + /// + [pbr::OriginalName("ZERO")] Zero = 0, + [pbr::OriginalName("Continue")] Continue = 100, + [pbr::OriginalName("SwitchingProtocols")] SwitchingProtocols = 101, + [pbr::OriginalName("Processing")] Processing = 102, + [pbr::OriginalName("EarlyHints")] EarlyHints = 103, + [pbr::OriginalName("OK")] Ok = 200, + [pbr::OriginalName("Created")] Created = 201, + [pbr::OriginalName("Accepted")] Accepted = 202, + [pbr::OriginalName("NonAuthoritativeInformation")] NonAuthoritativeInformation = 203, + [pbr::OriginalName("NoContent")] NoContent = 204, + [pbr::OriginalName("ResetContent")] ResetContent = 205, + [pbr::OriginalName("PartialContent")] PartialContent = 206, + [pbr::OriginalName("MultiStatus")] MultiStatus = 207, + [pbr::OriginalName("AlreadyReported")] AlreadyReported = 208, + [pbr::OriginalName("IMUsed")] Imused = 226, + [pbr::OriginalName("MultipleChoices")] MultipleChoices = 300, + [pbr::OriginalName("Ambiguous", PreferredAlias = false)] Ambiguous = 300, + [pbr::OriginalName("MovedPermanently")] MovedPermanently = 301, + [pbr::OriginalName("Moved", PreferredAlias = false)] Moved = 301, + [pbr::OriginalName("Found")] Found = 302, + [pbr::OriginalName("Redirect", PreferredAlias = false)] Redirect = 302, + [pbr::OriginalName("SeeOther")] SeeOther = 303, + [pbr::OriginalName("RedirectMethod", PreferredAlias = false)] RedirectMethod = 303, + [pbr::OriginalName("NotModified")] NotModified = 304, + [pbr::OriginalName("UseProxy")] UseProxy = 305, + [pbr::OriginalName("Unused")] Unused = 306, + [pbr::OriginalName("TemporaryRedirect")] TemporaryRedirect = 307, + [pbr::OriginalName("RedirectKeepVerb", PreferredAlias = false)] RedirectKeepVerb = 307, + [pbr::OriginalName("PermanentRedirect")] PermanentRedirect = 308, + [pbr::OriginalName("BadRequest")] BadRequest = 400, + [pbr::OriginalName("Unauthorized")] Unauthorized = 401, + [pbr::OriginalName("PaymentRequired")] PaymentRequired = 402, + [pbr::OriginalName("Forbidden")] Forbidden = 403, + [pbr::OriginalName("NotFound")] NotFound = 404, + [pbr::OriginalName("MethodNotAllowed")] MethodNotAllowed = 405, + [pbr::OriginalName("NotAcceptable")] NotAcceptable = 406, + [pbr::OriginalName("ProxyAuthenticationRequired")] ProxyAuthenticationRequired = 407, + [pbr::OriginalName("RequestTimeout")] RequestTimeout = 408, + [pbr::OriginalName("Conflict")] Conflict = 409, + [pbr::OriginalName("Gone")] Gone = 410, + [pbr::OriginalName("LengthRequired")] LengthRequired = 411, + [pbr::OriginalName("PreconditionFailed")] PreconditionFailed = 412, + [pbr::OriginalName("RequestEntityTooLarge")] RequestEntityTooLarge = 413, + [pbr::OriginalName("RequestUriTooLong")] RequestUriTooLong = 414, + [pbr::OriginalName("UnsupportedMediaType")] UnsupportedMediaType = 415, + [pbr::OriginalName("RequestedRangeNotSatisfiable")] RequestedRangeNotSatisfiable = 416, + [pbr::OriginalName("ExpectationFailed")] ExpectationFailed = 417, + [pbr::OriginalName("MisdirectedRequest")] MisdirectedRequest = 421, + [pbr::OriginalName("UnprocessableEntity")] UnprocessableEntity = 422, + [pbr::OriginalName("Locked")] Locked = 423, + [pbr::OriginalName("FailedDependency")] FailedDependency = 424, + [pbr::OriginalName("UpgradeRequired")] UpgradeRequired = 426, + [pbr::OriginalName("PreconditionRequired")] PreconditionRequired = 428, + [pbr::OriginalName("TooManyRequests")] TooManyRequests = 429, + [pbr::OriginalName("RequestHeaderFieldsTooLarge")] RequestHeaderFieldsTooLarge = 431, + [pbr::OriginalName("UnavailableForLegalReasons")] UnavailableForLegalReasons = 451, + [pbr::OriginalName("InternalServerError")] InternalServerError = 500, + [pbr::OriginalName("NotImplemented")] NotImplemented = 501, + [pbr::OriginalName("BadGateway")] BadGateway = 502, + [pbr::OriginalName("ServiceUnavailable")] ServiceUnavailable = 503, + [pbr::OriginalName("GatewayTimeout")] GatewayTimeout = 504, + [pbr::OriginalName("HttpVersionNotSupported")] HttpVersionNotSupported = 505, + [pbr::OriginalName("VariantAlsoNegotiates")] VariantAlsoNegotiates = 506, + [pbr::OriginalName("InsufficientStorage")] InsufficientStorage = 507, + [pbr::OriginalName("LoopDetected")] LoopDetected = 508, + [pbr::OriginalName("NotExtended")] NotExtended = 510, + [pbr::OriginalName("NetworkAuthenticationRequired")] NetworkAuthenticationRequired = 511, + } + + public enum LivingStatus { + [pbr::OriginalName("Alive")] Alive = 0, + [pbr::OriginalName("Dead")] Dead = 1, + } + + public enum SomeEnum { + [pbr::OriginalName("SomeEnum_Value0")] Value0 = 0, + [pbr::OriginalName("SomeEnum_Value1")] Value1 = 1, + [pbr::OriginalName("SomeEnum_Value2")] Value2 = 2, + [pbr::OriginalName("SomeEnum_Value3")] Value3 = 3, + } + + public enum SomeEnumAsInt { + [pbr::OriginalName("Value0")] Value0 = 0, + [pbr::OriginalName("Value1")] Value1 = 1, + [pbr::OriginalName("Value2")] Value2 = 2, + [pbr::OriginalName("Value3")] Value3 = 3, + } + + #endregion + + #region Messages + public sealed partial class AddHeader : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AddHeader()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddHeader() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddHeader(AddHeader other) : this() { + name_ = other.name_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddHeader Clone() { + return new AddHeader(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Value" field. + public const int ValueFieldNumber = 2; + private string value_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Value { + get { return value_; } + set { + value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AddHeader); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AddHeader other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Value.Length != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (Value.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Value.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AddHeader other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Value.Length != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + case 18: { + Value = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class Adhoc : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Adhoc()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Adhoc() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Adhoc(Adhoc other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Adhoc Clone() { + return new Adhoc(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "first_name" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 3; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Adhoc); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Adhoc other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(LastName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Adhoc other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + LastName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class AllFields : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AllFields()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AllFields() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AllFields(AllFields other) : this() { + id_ = other.id_; + nullableId_ = other.nullableId_; + byte_ = other.byte_; + short_ = other.short_; + int_ = other.int_; + long_ = other.long_; + uShort_ = other.uShort_; + uInt_ = other.uInt_; + uLong_ = other.uLong_; + float_ = other.float_; + double_ = other.double_; + decimal_ = other.decimal_; + string_ = other.string_; + dateTime_ = other.dateTime_ != null ? other.dateTime_.Clone() : null; + timeSpan_ = other.timeSpan_ != null ? other.timeSpan_.Clone() : null; + guid_ = other.guid_; + nullableDateTime_ = other.nullableDateTime_ != null ? other.nullableDateTime_.Clone() : null; + nullableTimeSpan_ = other.nullableTimeSpan_ != null ? other.nullableTimeSpan_.Clone() : null; + nullableGuid_ = other.nullableGuid_; + enum_ = other.enum_; + nullableEnum_ = other.nullableEnum_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AllFields Clone() { + return new AllFields(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "NullableId" field. + public const int NullableIdFieldNumber = 2; + private int nullableId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NullableId { + get { return nullableId_; } + set { + nullableId_ = value; + } + } + + /// Field number for the "Byte" field. + public const int ByteFieldNumber = 3; + private uint byte_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Byte { + get { return byte_; } + set { + byte_ = value; + } + } + + /// Field number for the "Short" field. + public const int ShortFieldNumber = 4; + private int short_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Short { + get { return short_; } + set { + short_ = value; + } + } + + /// Field number for the "Int" field. + public const int IntFieldNumber = 5; + private int int_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Int { + get { return int_; } + set { + int_ = value; + } + } + + /// Field number for the "Long" field. + public const int LongFieldNumber = 6; + private long long_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Long { + get { return long_; } + set { + long_ = value; + } + } + + /// Field number for the "UShort" field. + public const int UShortFieldNumber = 7; + private uint uShort_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint UShort { + get { return uShort_; } + set { + uShort_ = value; + } + } + + /// Field number for the "UInt" field. + public const int UIntFieldNumber = 8; + private uint uInt_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint UInt { + get { return uInt_; } + set { + uInt_ = value; + } + } + + /// Field number for the "ULong" field. + public const int ULongFieldNumber = 9; + private ulong uLong_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong ULong { + get { return uLong_; } + set { + uLong_ = value; + } + } + + /// Field number for the "Float" field. + public const int FloatFieldNumber = 10; + private float float_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public float Float { + get { return float_; } + set { + float_ = value; + } + } + + /// Field number for the "Double" field. + public const int DoubleFieldNumber = 11; + private double double_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double Double { + get { return double_; } + set { + double_ = value; + } + } + + /// Field number for the "Decimal" field. + public const int DecimalFieldNumber = 12; + private string decimal_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Decimal { + get { return decimal_; } + set { + decimal_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "String" field. + public const int StringFieldNumber = 13; + private string string_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string String { + get { return string_; } + set { + string_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "DateTime" field. + public const int DateTimeFieldNumber = 14; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateTime { + get { return dateTime_; } + set { + dateTime_ = value; + } + } + + /// Field number for the "TimeSpan" field. + public const int TimeSpanFieldNumber = 15; + private global::Google.Protobuf.WellKnownTypes.Duration timeSpan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Duration TimeSpan { + get { return timeSpan_; } + set { + timeSpan_ = value; + } + } + + /// Field number for the "Guid" field. + public const int GuidFieldNumber = 16; + private string guid_ = ""; + /// + /// default value could not be applied: 00000000-0000-0000-0000-000000000000 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Guid { + get { return guid_; } + set { + guid_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "NullableDateTime" field. + public const int NullableDateTimeFieldNumber = 17; + private global::Google.Protobuf.WellKnownTypes.Timestamp nullableDateTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp NullableDateTime { + get { return nullableDateTime_; } + set { + nullableDateTime_ = value; + } + } + + /// Field number for the "NullableTimeSpan" field. + public const int NullableTimeSpanFieldNumber = 18; + private global::Google.Protobuf.WellKnownTypes.Duration nullableTimeSpan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Duration NullableTimeSpan { + get { return nullableTimeSpan_; } + set { + nullableTimeSpan_ = value; + } + } + + /// Field number for the "NullableGuid" field. + public const int NullableGuidFieldNumber = 19; + private string nullableGuid_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NullableGuid { + get { return nullableGuid_; } + set { + nullableGuid_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Enum" field. + public const int EnumFieldNumber = 20; + private global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode enum_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode Enum { + get { return enum_; } + set { + enum_ = value; + } + } + + /// Field number for the "NullableEnum" field. + public const int NullableEnumFieldNumber = 21; + private global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode nullableEnum_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode NullableEnum { + get { return nullableEnum_; } + set { + nullableEnum_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AllFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AllFields other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (NullableId != other.NullableId) return false; + if (Byte != other.Byte) return false; + if (Short != other.Short) return false; + if (Int != other.Int) return false; + if (Long != other.Long) return false; + if (UShort != other.UShort) return false; + if (UInt != other.UInt) return false; + if (ULong != other.ULong) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(Float, other.Float)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(Double, other.Double)) return false; + if (Decimal != other.Decimal) return false; + if (String != other.String) return false; + if (!object.Equals(DateTime, other.DateTime)) return false; + if (!object.Equals(TimeSpan, other.TimeSpan)) return false; + if (Guid != other.Guid) return false; + if (!object.Equals(NullableDateTime, other.NullableDateTime)) return false; + if (!object.Equals(NullableTimeSpan, other.NullableTimeSpan)) return false; + if (NullableGuid != other.NullableGuid) return false; + if (Enum != other.Enum) return false; + if (NullableEnum != other.NullableEnum) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (NullableId != 0) hash ^= NullableId.GetHashCode(); + if (Byte != 0) hash ^= Byte.GetHashCode(); + if (Short != 0) hash ^= Short.GetHashCode(); + if (Int != 0) hash ^= Int.GetHashCode(); + if (Long != 0L) hash ^= Long.GetHashCode(); + if (UShort != 0) hash ^= UShort.GetHashCode(); + if (UInt != 0) hash ^= UInt.GetHashCode(); + if (ULong != 0UL) hash ^= ULong.GetHashCode(); + if (Float != 0F) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(Float); + if (Double != 0D) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(Double); + if (Decimal.Length != 0) hash ^= Decimal.GetHashCode(); + if (String.Length != 0) hash ^= String.GetHashCode(); + if (dateTime_ != null) hash ^= DateTime.GetHashCode(); + if (timeSpan_ != null) hash ^= TimeSpan.GetHashCode(); + if (Guid.Length != 0) hash ^= Guid.GetHashCode(); + if (nullableDateTime_ != null) hash ^= NullableDateTime.GetHashCode(); + if (nullableTimeSpan_ != null) hash ^= NullableTimeSpan.GetHashCode(); + if (NullableGuid.Length != 0) hash ^= NullableGuid.GetHashCode(); + if (Enum != 0) hash ^= Enum.GetHashCode(); + if (NullableEnum != 0) hash ^= NullableEnum.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (NullableId != 0) { + output.WriteRawTag(16); + output.WriteInt32(NullableId); + } + if (Byte != 0) { + output.WriteRawTag(24); + output.WriteUInt32(Byte); + } + if (Short != 0) { + output.WriteRawTag(32); + output.WriteInt32(Short); + } + if (Int != 0) { + output.WriteRawTag(40); + output.WriteInt32(Int); + } + if (Long != 0L) { + output.WriteRawTag(48); + output.WriteInt64(Long); + } + if (UShort != 0) { + output.WriteRawTag(56); + output.WriteUInt32(UShort); + } + if (UInt != 0) { + output.WriteRawTag(64); + output.WriteUInt32(UInt); + } + if (ULong != 0UL) { + output.WriteRawTag(72); + output.WriteUInt64(ULong); + } + if (Float != 0F) { + output.WriteRawTag(85); + output.WriteFloat(Float); + } + if (Double != 0D) { + output.WriteRawTag(89); + output.WriteDouble(Double); + } + if (Decimal.Length != 0) { + output.WriteRawTag(98); + output.WriteString(Decimal); + } + if (String.Length != 0) { + output.WriteRawTag(106); + output.WriteString(String); + } + if (dateTime_ != null) { + output.WriteRawTag(114); + output.WriteMessage(DateTime); + } + if (timeSpan_ != null) { + output.WriteRawTag(122); + output.WriteMessage(TimeSpan); + } + if (Guid.Length != 0) { + output.WriteRawTag(130, 1); + output.WriteString(Guid); + } + if (nullableDateTime_ != null) { + output.WriteRawTag(138, 1); + output.WriteMessage(NullableDateTime); + } + if (nullableTimeSpan_ != null) { + output.WriteRawTag(146, 1); + output.WriteMessage(NullableTimeSpan); + } + if (NullableGuid.Length != 0) { + output.WriteRawTag(154, 1); + output.WriteString(NullableGuid); + } + if (Enum != 0) { + output.WriteRawTag(160, 1); + output.WriteEnum((int) Enum); + } + if (NullableEnum != 0) { + output.WriteRawTag(168, 1); + output.WriteEnum((int) NullableEnum); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (NullableId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NullableId); + } + if (Byte != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Byte); + } + if (Short != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Short); + } + if (Int != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Int); + } + if (Long != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Long); + } + if (UShort != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(UShort); + } + if (UInt != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(UInt); + } + if (ULong != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(ULong); + } + if (Float != 0F) { + size += 1 + 4; + } + if (Double != 0D) { + size += 1 + 8; + } + if (Decimal.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Decimal); + } + if (String.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(String); + } + if (dateTime_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateTime); + } + if (timeSpan_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TimeSpan); + } + if (Guid.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Guid); + } + if (nullableDateTime_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NullableDateTime); + } + if (nullableTimeSpan_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NullableTimeSpan); + } + if (NullableGuid.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(NullableGuid); + } + if (Enum != 0) { + size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) Enum); + } + if (NullableEnum != 0) { + size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) NullableEnum); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AllFields other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.NullableId != 0) { + NullableId = other.NullableId; + } + if (other.Byte != 0) { + Byte = other.Byte; + } + if (other.Short != 0) { + Short = other.Short; + } + if (other.Int != 0) { + Int = other.Int; + } + if (other.Long != 0L) { + Long = other.Long; + } + if (other.UShort != 0) { + UShort = other.UShort; + } + if (other.UInt != 0) { + UInt = other.UInt; + } + if (other.ULong != 0UL) { + ULong = other.ULong; + } + if (other.Float != 0F) { + Float = other.Float; + } + if (other.Double != 0D) { + Double = other.Double; + } + if (other.Decimal.Length != 0) { + Decimal = other.Decimal; + } + if (other.String.Length != 0) { + String = other.String; + } + if (other.dateTime_ != null) { + if (dateTime_ == null) { + DateTime = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateTime.MergeFrom(other.DateTime); + } + if (other.timeSpan_ != null) { + if (timeSpan_ == null) { + TimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + TimeSpan.MergeFrom(other.TimeSpan); + } + if (other.Guid.Length != 0) { + Guid = other.Guid; + } + if (other.nullableDateTime_ != null) { + if (nullableDateTime_ == null) { + NullableDateTime = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + NullableDateTime.MergeFrom(other.NullableDateTime); + } + if (other.nullableTimeSpan_ != null) { + if (nullableTimeSpan_ == null) { + NullableTimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + NullableTimeSpan.MergeFrom(other.NullableTimeSpan); + } + if (other.NullableGuid.Length != 0) { + NullableGuid = other.NullableGuid; + } + if (other.Enum != 0) { + Enum = other.Enum; + } + if (other.NullableEnum != 0) { + NullableEnum = other.NullableEnum; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 16: { + NullableId = input.ReadInt32(); + break; + } + case 24: { + Byte = input.ReadUInt32(); + break; + } + case 32: { + Short = input.ReadInt32(); + break; + } + case 40: { + Int = input.ReadInt32(); + break; + } + case 48: { + Long = input.ReadInt64(); + break; + } + case 56: { + UShort = input.ReadUInt32(); + break; + } + case 64: { + UInt = input.ReadUInt32(); + break; + } + case 72: { + ULong = input.ReadUInt64(); + break; + } + case 85: { + Float = input.ReadFloat(); + break; + } + case 89: { + Double = input.ReadDouble(); + break; + } + case 98: { + Decimal = input.ReadString(); + break; + } + case 106: { + String = input.ReadString(); + break; + } + case 114: { + if (dateTime_ == null) { + DateTime = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateTime); + break; + } + case 122: { + if (timeSpan_ == null) { + TimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + input.ReadMessage(TimeSpan); + break; + } + case 130: { + Guid = input.ReadString(); + break; + } + case 138: { + if (nullableDateTime_ == null) { + NullableDateTime = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(NullableDateTime); + break; + } + case 146: { + if (nullableTimeSpan_ == null) { + NullableTimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + input.ReadMessage(NullableTimeSpan); + break; + } + case 154: { + NullableGuid = input.ReadString(); + break; + } + case 160: { + Enum = (global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode) input.ReadEnum(); + break; + } + case 168: { + NullableEnum = (global::ServiceStack.Extensions.Tests.Protoc.HttpStatusCode) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class AnyHello : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AnyHello()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AnyHello() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AnyHello(AnyHello other) : this() { + name_ = other.name_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AnyHello Clone() { + return new AnyHello(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AnyHello); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AnyHello other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AnyHello other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class AssignRoles : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AssignRoles()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AssignRoles() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AssignRoles(AssignRoles other) : this() { + userName_ = other.userName_; + permissions_ = other.permissions_.Clone(); + roles_ = other.roles_.Clone(); + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AssignRoles Clone() { + return new AssignRoles(this); + } + + /// Field number for the "UserName" field. + public const int UserNameFieldNumber = 1; + private string userName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserName { + get { return userName_; } + set { + userName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Permissions" field. + public const int PermissionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_permissions_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField permissions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Permissions { + get { return permissions_; } + } + + /// Field number for the "Roles" field. + public const int RolesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_roles_codec + = pb::FieldCodec.ForString(26); + private readonly pbc::RepeatedField roles_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Roles { + get { return roles_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AssignRoles); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AssignRoles other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (UserName != other.UserName) return false; + if(!permissions_.Equals(other.permissions_)) return false; + if(!roles_.Equals(other.roles_)) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (UserName.Length != 0) hash ^= UserName.GetHashCode(); + hash ^= permissions_.GetHashCode(); + hash ^= roles_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (UserName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(UserName); + } + permissions_.WriteTo(output, _repeated_permissions_codec); + roles_.WriteTo(output, _repeated_roles_codec); + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (UserName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserName); + } + size += permissions_.CalculateSize(_repeated_permissions_codec); + size += roles_.CalculateSize(_repeated_roles_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AssignRoles other) { + if (other == null) { + return; + } + if (other.UserName.Length != 0) { + UserName = other.UserName; + } + permissions_.Add(other.permissions_); + roles_.Add(other.roles_); + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + UserName = input.ReadString(); + break; + } + case 18: { + permissions_.AddEntriesFrom(input, _repeated_permissions_codec); + break; + } + case 26: { + roles_.AddEntriesFrom(input, _repeated_roles_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class AssignRolesResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AssignRolesResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AssignRolesResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AssignRolesResponse(AssignRolesResponse other) : this() { + allRoles_ = other.allRoles_.Clone(); + allPermissions_ = other.allPermissions_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AssignRolesResponse Clone() { + return new AssignRolesResponse(this); + } + + /// Field number for the "AllRoles" field. + public const int AllRolesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_allRoles_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField allRoles_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AllRoles { + get { return allRoles_; } + } + + /// Field number for the "AllPermissions" field. + public const int AllPermissionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_allPermissions_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField allPermissions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AllPermissions { + get { return allPermissions_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 3; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 26); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 4; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AssignRolesResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AssignRolesResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!allRoles_.Equals(other.allRoles_)) return false; + if(!allPermissions_.Equals(other.allPermissions_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= allRoles_.GetHashCode(); + hash ^= allPermissions_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + allRoles_.WriteTo(output, _repeated_allRoles_codec); + allPermissions_.WriteTo(output, _repeated_allPermissions_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(34); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += allRoles_.CalculateSize(_repeated_allRoles_codec); + size += allPermissions_.CalculateSize(_repeated_allPermissions_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AssignRolesResponse other) { + if (other == null) { + return; + } + allRoles_.Add(other.allRoles_); + allPermissions_.Add(other.allPermissions_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + allRoles_.AddEntriesFrom(input, _repeated_allRoles_codec); + break; + } + case 18: { + allPermissions_.AddEntriesFrom(input, _repeated_allPermissions_codec); + break; + } + case 26: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 34: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class AuditBase : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuditBase()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AuditBase() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AuditBase(AuditBase other) : this() { + createdDate_ = other.createdDate_ != null ? other.createdDate_.Clone() : null; + createdBy_ = other.createdBy_; + createdInfo_ = other.createdInfo_; + modifiedDate_ = other.modifiedDate_ != null ? other.modifiedDate_.Clone() : null; + modifiedBy_ = other.modifiedBy_; + modifiedInfo_ = other.modifiedInfo_; + softDeletedDate_ = other.softDeletedDate_ != null ? other.softDeletedDate_.Clone() : null; + softDeletedBy_ = other.softDeletedBy_; + softDeletedInfo_ = other.softDeletedInfo_; + switch (other.SubtypeCase) { + case SubtypeOneofCase.RockstarAuditTenant: + RockstarAuditTenant = other.RockstarAuditTenant.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AuditBase Clone() { + return new AuditBase(this); + } + + /// Field number for the "CreatedDate" field. + public const int CreatedDateFieldNumber = 1; + private global::Google.Protobuf.WellKnownTypes.Timestamp createdDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp CreatedDate { + get { return createdDate_; } + set { + createdDate_ = value; + } + } + + /// Field number for the "CreatedBy" field. + public const int CreatedByFieldNumber = 2; + private string createdBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreatedBy { + get { return createdBy_; } + set { + createdBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "CreatedInfo" field. + public const int CreatedInfoFieldNumber = 3; + private string createdInfo_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreatedInfo { + get { return createdInfo_; } + set { + createdInfo_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ModifiedDate" field. + public const int ModifiedDateFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp modifiedDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp ModifiedDate { + get { return modifiedDate_; } + set { + modifiedDate_ = value; + } + } + + /// Field number for the "ModifiedBy" field. + public const int ModifiedByFieldNumber = 5; + private string modifiedBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ModifiedBy { + get { return modifiedBy_; } + set { + modifiedBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ModifiedInfo" field. + public const int ModifiedInfoFieldNumber = 6; + private string modifiedInfo_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ModifiedInfo { + get { return modifiedInfo_; } + set { + modifiedInfo_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "SoftDeletedDate" field. + public const int SoftDeletedDateFieldNumber = 7; + private global::Google.Protobuf.WellKnownTypes.Timestamp softDeletedDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp SoftDeletedDate { + get { return softDeletedDate_; } + set { + softDeletedDate_ = value; + } + } + + /// Field number for the "SoftDeletedBy" field. + public const int SoftDeletedByFieldNumber = 8; + private string softDeletedBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SoftDeletedBy { + get { return softDeletedBy_; } + set { + softDeletedBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "SoftDeletedInfo" field. + public const int SoftDeletedInfoFieldNumber = 9; + private string softDeletedInfo_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SoftDeletedInfo { + get { return softDeletedInfo_; } + set { + softDeletedInfo_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RockstarAuditTenant" field. + public const int RockstarAuditTenantFieldNumber = 252248706; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant RockstarAuditTenant { + get { return subtypeCase_ == SubtypeOneofCase.RockstarAuditTenant ? (global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.RockstarAuditTenant; + } + } + + private object subtype_; + /// Enum of possible cases for the "subtype" oneof. + public enum SubtypeOneofCase { + None = 0, + RockstarAuditTenant = 252248706, + } + private SubtypeOneofCase subtypeCase_ = SubtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubtypeOneofCase SubtypeCase { + get { return subtypeCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearSubtype() { + subtypeCase_ = SubtypeOneofCase.None; + subtype_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AuditBase); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AuditBase other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(CreatedDate, other.CreatedDate)) return false; + if (CreatedBy != other.CreatedBy) return false; + if (CreatedInfo != other.CreatedInfo) return false; + if (!object.Equals(ModifiedDate, other.ModifiedDate)) return false; + if (ModifiedBy != other.ModifiedBy) return false; + if (ModifiedInfo != other.ModifiedInfo) return false; + if (!object.Equals(SoftDeletedDate, other.SoftDeletedDate)) return false; + if (SoftDeletedBy != other.SoftDeletedBy) return false; + if (SoftDeletedInfo != other.SoftDeletedInfo) return false; + if (!object.Equals(RockstarAuditTenant, other.RockstarAuditTenant)) return false; + if (SubtypeCase != other.SubtypeCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (createdDate_ != null) hash ^= CreatedDate.GetHashCode(); + if (CreatedBy.Length != 0) hash ^= CreatedBy.GetHashCode(); + if (CreatedInfo.Length != 0) hash ^= CreatedInfo.GetHashCode(); + if (modifiedDate_ != null) hash ^= ModifiedDate.GetHashCode(); + if (ModifiedBy.Length != 0) hash ^= ModifiedBy.GetHashCode(); + if (ModifiedInfo.Length != 0) hash ^= ModifiedInfo.GetHashCode(); + if (softDeletedDate_ != null) hash ^= SoftDeletedDate.GetHashCode(); + if (SoftDeletedBy.Length != 0) hash ^= SoftDeletedBy.GetHashCode(); + if (SoftDeletedInfo.Length != 0) hash ^= SoftDeletedInfo.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAuditTenant) hash ^= RockstarAuditTenant.GetHashCode(); + hash ^= (int) subtypeCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (createdDate_ != null) { + output.WriteRawTag(10); + output.WriteMessage(CreatedDate); + } + if (CreatedBy.Length != 0) { + output.WriteRawTag(18); + output.WriteString(CreatedBy); + } + if (CreatedInfo.Length != 0) { + output.WriteRawTag(26); + output.WriteString(CreatedInfo); + } + if (modifiedDate_ != null) { + output.WriteRawTag(34); + output.WriteMessage(ModifiedDate); + } + if (ModifiedBy.Length != 0) { + output.WriteRawTag(42); + output.WriteString(ModifiedBy); + } + if (ModifiedInfo.Length != 0) { + output.WriteRawTag(50); + output.WriteString(ModifiedInfo); + } + if (softDeletedDate_ != null) { + output.WriteRawTag(58); + output.WriteMessage(SoftDeletedDate); + } + if (SoftDeletedBy.Length != 0) { + output.WriteRawTag(66); + output.WriteString(SoftDeletedBy); + } + if (SoftDeletedInfo.Length != 0) { + output.WriteRawTag(74); + output.WriteString(SoftDeletedInfo); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAuditTenant) { + output.WriteRawTag(146, 168, 160, 194, 7); + output.WriteMessage(RockstarAuditTenant); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (createdDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(CreatedDate); + } + if (CreatedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreatedBy); + } + if (CreatedInfo.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreatedInfo); + } + if (modifiedDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ModifiedDate); + } + if (ModifiedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ModifiedBy); + } + if (ModifiedInfo.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ModifiedInfo); + } + if (softDeletedDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SoftDeletedDate); + } + if (SoftDeletedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SoftDeletedBy); + } + if (SoftDeletedInfo.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SoftDeletedInfo); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAuditTenant) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(RockstarAuditTenant); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AuditBase other) { + if (other == null) { + return; + } + if (other.createdDate_ != null) { + if (createdDate_ == null) { + CreatedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + CreatedDate.MergeFrom(other.CreatedDate); + } + if (other.CreatedBy.Length != 0) { + CreatedBy = other.CreatedBy; + } + if (other.CreatedInfo.Length != 0) { + CreatedInfo = other.CreatedInfo; + } + if (other.modifiedDate_ != null) { + if (modifiedDate_ == null) { + ModifiedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + ModifiedDate.MergeFrom(other.ModifiedDate); + } + if (other.ModifiedBy.Length != 0) { + ModifiedBy = other.ModifiedBy; + } + if (other.ModifiedInfo.Length != 0) { + ModifiedInfo = other.ModifiedInfo; + } + if (other.softDeletedDate_ != null) { + if (softDeletedDate_ == null) { + SoftDeletedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + SoftDeletedDate.MergeFrom(other.SoftDeletedDate); + } + if (other.SoftDeletedBy.Length != 0) { + SoftDeletedBy = other.SoftDeletedBy; + } + if (other.SoftDeletedInfo.Length != 0) { + SoftDeletedInfo = other.SoftDeletedInfo; + } + switch (other.SubtypeCase) { + case SubtypeOneofCase.RockstarAuditTenant: + if (RockstarAuditTenant == null) { + RockstarAuditTenant = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant(); + } + RockstarAuditTenant.MergeFrom(other.RockstarAuditTenant); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (createdDate_ == null) { + CreatedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(CreatedDate); + break; + } + case 18: { + CreatedBy = input.ReadString(); + break; + } + case 26: { + CreatedInfo = input.ReadString(); + break; + } + case 34: { + if (modifiedDate_ == null) { + ModifiedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(ModifiedDate); + break; + } + case 42: { + ModifiedBy = input.ReadString(); + break; + } + case 50: { + ModifiedInfo = input.ReadString(); + break; + } + case 58: { + if (softDeletedDate_ == null) { + SoftDeletedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(SoftDeletedDate); + break; + } + case 66: { + SoftDeletedBy = input.ReadString(); + break; + } + case 74: { + SoftDeletedInfo = input.ReadString(); + break; + } + case 2017989650: { + global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAuditTenant(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAuditTenant) { + subBuilder.MergeFrom(RockstarAuditTenant); + } + input.ReadMessage(subBuilder); + RockstarAuditTenant = subBuilder; + break; + } + } + } + } + + } + + public sealed partial class Authenticate : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Authenticate()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Authenticate() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Authenticate(Authenticate other) : this() { + provider_ = other.provider_; + state_ = other.state_; + oauthToken_ = other.oauthToken_; + oauthVerifier_ = other.oauthVerifier_; + userName_ = other.userName_; + password_ = other.password_; + rememberMe_ = other.rememberMe_; + errorView_ = other.errorView_; + nonce_ = other.nonce_; + uri_ = other.uri_; + response_ = other.response_; + qop_ = other.qop_; + nc_ = other.nc_; + cnonce_ = other.cnonce_; + useTokenCookie_ = other.useTokenCookie_; + accessToken_ = other.accessToken_; + accessTokenSecret_ = other.accessTokenSecret_; + scope_ = other.scope_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Authenticate Clone() { + return new Authenticate(this); + } + + /// Field number for the "provider" field. + public const int ProviderFieldNumber = 1; + private string provider_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Provider { + get { return provider_; } + set { + provider_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "State" field. + public const int StateFieldNumber = 2; + private string state_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string State { + get { return state_; } + set { + state_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "oauth_token" field. + public const int OauthTokenFieldNumber = 3; + private string oauthToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OauthToken { + get { return oauthToken_; } + set { + oauthToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "oauth_verifier" field. + public const int OauthVerifierFieldNumber = 4; + private string oauthVerifier_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OauthVerifier { + get { return oauthVerifier_; } + set { + oauthVerifier_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UserName" field. + public const int UserNameFieldNumber = 5; + private string userName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserName { + get { return userName_; } + set { + userName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Password" field. + public const int PasswordFieldNumber = 6; + private string password_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Password { + get { return password_; } + set { + password_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RememberMe" field. + public const int RememberMeFieldNumber = 7; + private bool rememberMe_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool RememberMe { + get { return rememberMe_; } + set { + rememberMe_ = value; + } + } + + /// Field number for the "ErrorView" field. + public const int ErrorViewFieldNumber = 9; + private string errorView_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ErrorView { + get { return errorView_; } + set { + errorView_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "nonce" field. + public const int NonceFieldNumber = 10; + private string nonce_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Nonce { + get { return nonce_; } + set { + nonce_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "uri" field. + public const int UriFieldNumber = 11; + private string uri_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Uri { + get { return uri_; } + set { + uri_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "response" field. + public const int ResponseFieldNumber = 12; + private string response_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Response { + get { return response_; } + set { + response_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "qop" field. + public const int QopFieldNumber = 13; + private string qop_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Qop { + get { return qop_; } + set { + qop_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "nc" field. + public const int NcFieldNumber = 14; + private string nc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Nc { + get { return nc_; } + set { + nc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "cnonce" field. + public const int CnonceFieldNumber = 15; + private string cnonce_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Cnonce { + get { return cnonce_; } + set { + cnonce_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UseTokenCookie" field. + public const int UseTokenCookieFieldNumber = 16; + private bool useTokenCookie_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool UseTokenCookie { + get { return useTokenCookie_; } + set { + useTokenCookie_ = value; + } + } + + /// Field number for the "AccessToken" field. + public const int AccessTokenFieldNumber = 17; + private string accessToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AccessToken { + get { return accessToken_; } + set { + accessToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "AccessTokenSecret" field. + public const int AccessTokenSecretFieldNumber = 18; + private string accessTokenSecret_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AccessTokenSecret { + get { return accessTokenSecret_; } + set { + accessTokenSecret_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "scope" field. + public const int ScopeFieldNumber = 19; + private string scope_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Scope { + get { return scope_; } + set { + scope_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 20; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 162); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Authenticate); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Authenticate other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Provider != other.Provider) return false; + if (State != other.State) return false; + if (OauthToken != other.OauthToken) return false; + if (OauthVerifier != other.OauthVerifier) return false; + if (UserName != other.UserName) return false; + if (Password != other.Password) return false; + if (RememberMe != other.RememberMe) return false; + if (ErrorView != other.ErrorView) return false; + if (Nonce != other.Nonce) return false; + if (Uri != other.Uri) return false; + if (Response != other.Response) return false; + if (Qop != other.Qop) return false; + if (Nc != other.Nc) return false; + if (Cnonce != other.Cnonce) return false; + if (UseTokenCookie != other.UseTokenCookie) return false; + if (AccessToken != other.AccessToken) return false; + if (AccessTokenSecret != other.AccessTokenSecret) return false; + if (Scope != other.Scope) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Provider.Length != 0) hash ^= Provider.GetHashCode(); + if (State.Length != 0) hash ^= State.GetHashCode(); + if (OauthToken.Length != 0) hash ^= OauthToken.GetHashCode(); + if (OauthVerifier.Length != 0) hash ^= OauthVerifier.GetHashCode(); + if (UserName.Length != 0) hash ^= UserName.GetHashCode(); + if (Password.Length != 0) hash ^= Password.GetHashCode(); + if (RememberMe != false) hash ^= RememberMe.GetHashCode(); + if (ErrorView.Length != 0) hash ^= ErrorView.GetHashCode(); + if (Nonce.Length != 0) hash ^= Nonce.GetHashCode(); + if (Uri.Length != 0) hash ^= Uri.GetHashCode(); + if (Response.Length != 0) hash ^= Response.GetHashCode(); + if (Qop.Length != 0) hash ^= Qop.GetHashCode(); + if (Nc.Length != 0) hash ^= Nc.GetHashCode(); + if (Cnonce.Length != 0) hash ^= Cnonce.GetHashCode(); + if (UseTokenCookie != false) hash ^= UseTokenCookie.GetHashCode(); + if (AccessToken.Length != 0) hash ^= AccessToken.GetHashCode(); + if (AccessTokenSecret.Length != 0) hash ^= AccessTokenSecret.GetHashCode(); + if (Scope.Length != 0) hash ^= Scope.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Provider.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Provider); + } + if (State.Length != 0) { + output.WriteRawTag(18); + output.WriteString(State); + } + if (OauthToken.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OauthToken); + } + if (OauthVerifier.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OauthVerifier); + } + if (UserName.Length != 0) { + output.WriteRawTag(42); + output.WriteString(UserName); + } + if (Password.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Password); + } + if (RememberMe != false) { + output.WriteRawTag(56); + output.WriteBool(RememberMe); + } + if (ErrorView.Length != 0) { + output.WriteRawTag(74); + output.WriteString(ErrorView); + } + if (Nonce.Length != 0) { + output.WriteRawTag(82); + output.WriteString(Nonce); + } + if (Uri.Length != 0) { + output.WriteRawTag(90); + output.WriteString(Uri); + } + if (Response.Length != 0) { + output.WriteRawTag(98); + output.WriteString(Response); + } + if (Qop.Length != 0) { + output.WriteRawTag(106); + output.WriteString(Qop); + } + if (Nc.Length != 0) { + output.WriteRawTag(114); + output.WriteString(Nc); + } + if (Cnonce.Length != 0) { + output.WriteRawTag(122); + output.WriteString(Cnonce); + } + if (UseTokenCookie != false) { + output.WriteRawTag(128, 1); + output.WriteBool(UseTokenCookie); + } + if (AccessToken.Length != 0) { + output.WriteRawTag(138, 1); + output.WriteString(AccessToken); + } + if (AccessTokenSecret.Length != 0) { + output.WriteRawTag(146, 1); + output.WriteString(AccessTokenSecret); + } + if (Scope.Length != 0) { + output.WriteRawTag(154, 1); + output.WriteString(Scope); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Provider.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Provider); + } + if (State.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(State); + } + if (OauthToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OauthToken); + } + if (OauthVerifier.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OauthVerifier); + } + if (UserName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserName); + } + if (Password.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Password); + } + if (RememberMe != false) { + size += 1 + 1; + } + if (ErrorView.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorView); + } + if (Nonce.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Nonce); + } + if (Uri.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Uri); + } + if (Response.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Response); + } + if (Qop.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Qop); + } + if (Nc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Nc); + } + if (Cnonce.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Cnonce); + } + if (UseTokenCookie != false) { + size += 2 + 1; + } + if (AccessToken.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(AccessToken); + } + if (AccessTokenSecret.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(AccessTokenSecret); + } + if (Scope.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Scope); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Authenticate other) { + if (other == null) { + return; + } + if (other.Provider.Length != 0) { + Provider = other.Provider; + } + if (other.State.Length != 0) { + State = other.State; + } + if (other.OauthToken.Length != 0) { + OauthToken = other.OauthToken; + } + if (other.OauthVerifier.Length != 0) { + OauthVerifier = other.OauthVerifier; + } + if (other.UserName.Length != 0) { + UserName = other.UserName; + } + if (other.Password.Length != 0) { + Password = other.Password; + } + if (other.RememberMe != false) { + RememberMe = other.RememberMe; + } + if (other.ErrorView.Length != 0) { + ErrorView = other.ErrorView; + } + if (other.Nonce.Length != 0) { + Nonce = other.Nonce; + } + if (other.Uri.Length != 0) { + Uri = other.Uri; + } + if (other.Response.Length != 0) { + Response = other.Response; + } + if (other.Qop.Length != 0) { + Qop = other.Qop; + } + if (other.Nc.Length != 0) { + Nc = other.Nc; + } + if (other.Cnonce.Length != 0) { + Cnonce = other.Cnonce; + } + if (other.UseTokenCookie != false) { + UseTokenCookie = other.UseTokenCookie; + } + if (other.AccessToken.Length != 0) { + AccessToken = other.AccessToken; + } + if (other.AccessTokenSecret.Length != 0) { + AccessTokenSecret = other.AccessTokenSecret; + } + if (other.Scope.Length != 0) { + Scope = other.Scope; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Provider = input.ReadString(); + break; + } + case 18: { + State = input.ReadString(); + break; + } + case 26: { + OauthToken = input.ReadString(); + break; + } + case 34: { + OauthVerifier = input.ReadString(); + break; + } + case 42: { + UserName = input.ReadString(); + break; + } + case 50: { + Password = input.ReadString(); + break; + } + case 56: { + RememberMe = input.ReadBool(); + break; + } + case 74: { + ErrorView = input.ReadString(); + break; + } + case 82: { + Nonce = input.ReadString(); + break; + } + case 90: { + Uri = input.ReadString(); + break; + } + case 98: { + Response = input.ReadString(); + break; + } + case 106: { + Qop = input.ReadString(); + break; + } + case 114: { + Nc = input.ReadString(); + break; + } + case 122: { + Cnonce = input.ReadString(); + break; + } + case 128: { + UseTokenCookie = input.ReadBool(); + break; + } + case 138: { + AccessToken = input.ReadString(); + break; + } + case 146: { + AccessTokenSecret = input.ReadString(); + break; + } + case 154: { + Scope = input.ReadString(); + break; + } + case 162: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class AuthenticateResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AuthenticateResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AuthenticateResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AuthenticateResponse(AuthenticateResponse other) : this() { + userId_ = other.userId_; + sessionId_ = other.sessionId_; + userName_ = other.userName_; + displayName_ = other.displayName_; + referrerUrl_ = other.referrerUrl_; + bearerToken_ = other.bearerToken_; + refreshToken_ = other.refreshToken_; + profileUrl_ = other.profileUrl_; + roles_ = other.roles_.Clone(); + permissions_ = other.permissions_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AuthenticateResponse Clone() { + return new AuthenticateResponse(this); + } + + /// Field number for the "UserId" field. + public const int UserIdFieldNumber = 1; + private string userId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserId { + get { return userId_; } + set { + userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "SessionId" field. + public const int SessionIdFieldNumber = 2; + private string sessionId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SessionId { + get { return sessionId_; } + set { + sessionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UserName" field. + public const int UserNameFieldNumber = 3; + private string userName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserName { + get { return userName_; } + set { + userName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "DisplayName" field. + public const int DisplayNameFieldNumber = 4; + private string displayName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string DisplayName { + get { return displayName_; } + set { + displayName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ReferrerUrl" field. + public const int ReferrerUrlFieldNumber = 5; + private string referrerUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ReferrerUrl { + get { return referrerUrl_; } + set { + referrerUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 6; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RefreshToken" field. + public const int RefreshTokenFieldNumber = 7; + private string refreshToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RefreshToken { + get { return refreshToken_; } + set { + refreshToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ProfileUrl" field. + public const int ProfileUrlFieldNumber = 8; + private string profileUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ProfileUrl { + get { return profileUrl_; } + set { + profileUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Roles" field. + public const int RolesFieldNumber = 9; + private static readonly pb::FieldCodec _repeated_roles_codec + = pb::FieldCodec.ForString(74); + private readonly pbc::RepeatedField roles_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Roles { + get { return roles_; } + } + + /// Field number for the "Permissions" field. + public const int PermissionsFieldNumber = 10; + private static readonly pb::FieldCodec _repeated_permissions_codec + = pb::FieldCodec.ForString(82); + private readonly pbc::RepeatedField permissions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Permissions { + get { return permissions_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 11; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 12; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 98); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AuthenticateResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AuthenticateResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (UserId != other.UserId) return false; + if (SessionId != other.SessionId) return false; + if (UserName != other.UserName) return false; + if (DisplayName != other.DisplayName) return false; + if (ReferrerUrl != other.ReferrerUrl) return false; + if (BearerToken != other.BearerToken) return false; + if (RefreshToken != other.RefreshToken) return false; + if (ProfileUrl != other.ProfileUrl) return false; + if(!roles_.Equals(other.roles_)) return false; + if(!permissions_.Equals(other.permissions_)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (UserId.Length != 0) hash ^= UserId.GetHashCode(); + if (SessionId.Length != 0) hash ^= SessionId.GetHashCode(); + if (UserName.Length != 0) hash ^= UserName.GetHashCode(); + if (DisplayName.Length != 0) hash ^= DisplayName.GetHashCode(); + if (ReferrerUrl.Length != 0) hash ^= ReferrerUrl.GetHashCode(); + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (RefreshToken.Length != 0) hash ^= RefreshToken.GetHashCode(); + if (ProfileUrl.Length != 0) hash ^= ProfileUrl.GetHashCode(); + hash ^= roles_.GetHashCode(); + hash ^= permissions_.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (UserId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(UserId); + } + if (SessionId.Length != 0) { + output.WriteRawTag(18); + output.WriteString(SessionId); + } + if (UserName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(UserName); + } + if (DisplayName.Length != 0) { + output.WriteRawTag(34); + output.WriteString(DisplayName); + } + if (ReferrerUrl.Length != 0) { + output.WriteRawTag(42); + output.WriteString(ReferrerUrl); + } + if (BearerToken.Length != 0) { + output.WriteRawTag(50); + output.WriteString(BearerToken); + } + if (RefreshToken.Length != 0) { + output.WriteRawTag(58); + output.WriteString(RefreshToken); + } + if (ProfileUrl.Length != 0) { + output.WriteRawTag(66); + output.WriteString(ProfileUrl); + } + roles_.WriteTo(output, _repeated_roles_codec); + permissions_.WriteTo(output, _repeated_permissions_codec); + if (responseStatus_ != null) { + output.WriteRawTag(90); + output.WriteMessage(ResponseStatus); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (UserId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId); + } + if (SessionId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SessionId); + } + if (UserName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserName); + } + if (DisplayName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(DisplayName); + } + if (ReferrerUrl.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ReferrerUrl); + } + if (BearerToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (RefreshToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RefreshToken); + } + if (ProfileUrl.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ProfileUrl); + } + size += roles_.CalculateSize(_repeated_roles_codec); + size += permissions_.CalculateSize(_repeated_permissions_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AuthenticateResponse other) { + if (other == null) { + return; + } + if (other.UserId.Length != 0) { + UserId = other.UserId; + } + if (other.SessionId.Length != 0) { + SessionId = other.SessionId; + } + if (other.UserName.Length != 0) { + UserName = other.UserName; + } + if (other.DisplayName.Length != 0) { + DisplayName = other.DisplayName; + } + if (other.ReferrerUrl.Length != 0) { + ReferrerUrl = other.ReferrerUrl; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + if (other.RefreshToken.Length != 0) { + RefreshToken = other.RefreshToken; + } + if (other.ProfileUrl.Length != 0) { + ProfileUrl = other.ProfileUrl; + } + roles_.Add(other.roles_); + permissions_.Add(other.permissions_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + UserId = input.ReadString(); + break; + } + case 18: { + SessionId = input.ReadString(); + break; + } + case 26: { + UserName = input.ReadString(); + break; + } + case 34: { + DisplayName = input.ReadString(); + break; + } + case 42: { + ReferrerUrl = input.ReadString(); + break; + } + case 50: { + BearerToken = input.ReadString(); + break; + } + case 58: { + RefreshToken = input.ReadString(); + break; + } + case 66: { + ProfileUrl = input.ReadString(); + break; + } + case 74: { + roles_.AddEntriesFrom(input, _repeated_roles_codec); + break; + } + case 82: { + permissions_.AddEntriesFrom(input, _repeated_permissions_codec); + break; + } + case 90: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + case 98: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class Bar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Bar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Bar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Bar(Bar other) : this() { + y_ = other.y_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Bar Clone() { + return new Bar(this); + } + + /// Field number for the "Y" field. + public const int YFieldNumber = 2; + private string y_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Y { + get { return y_; } + set { + y_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Bar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Bar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Y != other.Y) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Y.Length != 0) hash ^= Y.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Y.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Y); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Y.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Y); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Bar other) { + if (other == null) { + return; + } + if (other.Y.Length != 0) { + Y = other.Y; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 18: { + Y = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class Bookmark : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Bookmark()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Bookmark() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Bookmark(Bookmark other) : this() { + slug_ = other.slug_; + title_ = other.title_; + description_ = other.description_; + url_ = other.url_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Bookmark Clone() { + return new Bookmark(this); + } + + /// Field number for the "Slug" field. + public const int SlugFieldNumber = 1; + private string slug_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Slug { + get { return slug_; } + set { + slug_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Title" field. + public const int TitleFieldNumber = 2; + private string title_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Title { + get { return title_; } + set { + title_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Description" field. + public const int DescriptionFieldNumber = 3; + private string description_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Description { + get { return description_; } + set { + description_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Url" field. + public const int UrlFieldNumber = 4; + private string url_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Url { + get { return url_; } + set { + url_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Bookmark); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Bookmark other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Slug != other.Slug) return false; + if (Title != other.Title) return false; + if (Description != other.Description) return false; + if (Url != other.Url) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Slug.Length != 0) hash ^= Slug.GetHashCode(); + if (Title.Length != 0) hash ^= Title.GetHashCode(); + if (Description.Length != 0) hash ^= Description.GetHashCode(); + if (Url.Length != 0) hash ^= Url.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Slug.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Slug); + } + if (Title.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Title); + } + if (Description.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Description); + } + if (Url.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Url); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Slug.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Slug); + } + if (Title.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Title); + } + if (Description.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Description); + } + if (Url.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Url); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Bookmark other) { + if (other == null) { + return; + } + if (other.Slug.Length != 0) { + Slug = other.Slug; + } + if (other.Title.Length != 0) { + Title = other.Title; + } + if (other.Description.Length != 0) { + Description = other.Description; + } + if (other.Url.Length != 0) { + Url = other.Url; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Slug = input.ReadString(); + break; + } + case 18: { + Title = input.ReadString(); + break; + } + case 26: { + Description = input.ReadString(); + break; + } + case 34: { + Url = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class ChangeConnectionInfo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ChangeConnectionInfo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeConnectionInfo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeConnectionInfo(ChangeConnectionInfo other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeConnectionInfo Clone() { + return new ChangeConnectionInfo(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ChangeConnectionInfo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ChangeConnectionInfo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ChangeConnectionInfo other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class ChangeDb : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ChangeDb()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeDb() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeDb(ChangeDb other) : this() { + namedConnection_ = other.namedConnection_; + connectionString_ = other.connectionString_; + providerName_ = other.providerName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeDb Clone() { + return new ChangeDb(this); + } + + /// Field number for the "NamedConnection" field. + public const int NamedConnectionFieldNumber = 1; + private string namedConnection_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NamedConnection { + get { return namedConnection_; } + set { + namedConnection_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ConnectionString" field. + public const int ConnectionStringFieldNumber = 2; + private string connectionString_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ConnectionString { + get { return connectionString_; } + set { + connectionString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ProviderName" field. + public const int ProviderNameFieldNumber = 3; + private string providerName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ProviderName { + get { return providerName_; } + set { + providerName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ChangeDb); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ChangeDb other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NamedConnection != other.NamedConnection) return false; + if (ConnectionString != other.ConnectionString) return false; + if (ProviderName != other.ProviderName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NamedConnection.Length != 0) hash ^= NamedConnection.GetHashCode(); + if (ConnectionString.Length != 0) hash ^= ConnectionString.GetHashCode(); + if (ProviderName.Length != 0) hash ^= ProviderName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (NamedConnection.Length != 0) { + output.WriteRawTag(10); + output.WriteString(NamedConnection); + } + if (ConnectionString.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ConnectionString); + } + if (ProviderName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(ProviderName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NamedConnection.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NamedConnection); + } + if (ConnectionString.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ConnectionString); + } + if (ProviderName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ProviderName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ChangeDb other) { + if (other == null) { + return; + } + if (other.NamedConnection.Length != 0) { + NamedConnection = other.NamedConnection; + } + if (other.ConnectionString.Length != 0) { + ConnectionString = other.ConnectionString; + } + if (other.ProviderName.Length != 0) { + ProviderName = other.ProviderName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + NamedConnection = input.ReadString(); + break; + } + case 18: { + ConnectionString = input.ReadString(); + break; + } + case 26: { + ProviderName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class ChangeDbResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ChangeDbResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeDbResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeDbResponse(ChangeDbResponse other) : this() { + results_ = other.results_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChangeDbResponse Clone() { + return new ChangeDbResponse(this); + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(10, global::ServiceStack.Extensions.Tests.Protoc.Rockstar.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ChangeDbResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ChangeDbResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!results_.Equals(other.results_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= results_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + results_.WriteTo(output, _repeated_results_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += results_.CalculateSize(_repeated_results_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ChangeDbResponse other) { + if (other == null) { + return; + } + results_.Add(other.results_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + } + } + } + + } + + public sealed partial class ChatMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ChatMessage()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[14]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChatMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChatMessage(ChatMessage other) : this() { + id_ = other.id_; + channel_ = other.channel_; + fromUserId_ = other.fromUserId_; + fromName_ = other.fromName_; + displayName_ = other.displayName_; + message_ = other.message_; + userAuthId_ = other.userAuthId_; + private_ = other.private_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ChatMessage Clone() { + return new ChatMessage(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Channel" field. + public const int ChannelFieldNumber = 2; + private string channel_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Channel { + get { return channel_; } + set { + channel_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FromUserId" field. + public const int FromUserIdFieldNumber = 3; + private string fromUserId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FromUserId { + get { return fromUserId_; } + set { + fromUserId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FromName" field. + public const int FromNameFieldNumber = 4; + private string fromName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FromName { + get { return fromName_; } + set { + fromName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "DisplayName" field. + public const int DisplayNameFieldNumber = 5; + private string displayName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string DisplayName { + get { return displayName_; } + set { + displayName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Message" field. + public const int MessageFieldNumber = 6; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UserAuthId" field. + public const int UserAuthIdFieldNumber = 7; + private string userAuthId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserAuthId { + get { return userAuthId_; } + set { + userAuthId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Private" field. + public const int PrivateFieldNumber = 8; + private bool private_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Private { + get { return private_; } + set { + private_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ChatMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ChatMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Channel != other.Channel) return false; + if (FromUserId != other.FromUserId) return false; + if (FromName != other.FromName) return false; + if (DisplayName != other.DisplayName) return false; + if (Message != other.Message) return false; + if (UserAuthId != other.UserAuthId) return false; + if (Private != other.Private) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (Channel.Length != 0) hash ^= Channel.GetHashCode(); + if (FromUserId.Length != 0) hash ^= FromUserId.GetHashCode(); + if (FromName.Length != 0) hash ^= FromName.GetHashCode(); + if (DisplayName.Length != 0) hash ^= DisplayName.GetHashCode(); + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (UserAuthId.Length != 0) hash ^= UserAuthId.GetHashCode(); + if (Private != false) hash ^= Private.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Channel.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Channel); + } + if (FromUserId.Length != 0) { + output.WriteRawTag(26); + output.WriteString(FromUserId); + } + if (FromName.Length != 0) { + output.WriteRawTag(34); + output.WriteString(FromName); + } + if (DisplayName.Length != 0) { + output.WriteRawTag(42); + output.WriteString(DisplayName); + } + if (Message.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Message); + } + if (UserAuthId.Length != 0) { + output.WriteRawTag(58); + output.WriteString(UserAuthId); + } + if (Private != false) { + output.WriteRawTag(64); + output.WriteBool(Private); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (Channel.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Channel); + } + if (FromUserId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FromUserId); + } + if (FromName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FromName); + } + if (DisplayName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(DisplayName); + } + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (UserAuthId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserAuthId); + } + if (Private != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ChatMessage other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + if (other.Channel.Length != 0) { + Channel = other.Channel; + } + if (other.FromUserId.Length != 0) { + FromUserId = other.FromUserId; + } + if (other.FromName.Length != 0) { + FromName = other.FromName; + } + if (other.DisplayName.Length != 0) { + DisplayName = other.DisplayName; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + if (other.UserAuthId.Length != 0) { + UserAuthId = other.UserAuthId; + } + if (other.Private != false) { + Private = other.Private; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 18: { + Channel = input.ReadString(); + break; + } + case 26: { + FromUserId = input.ReadString(); + break; + } + case 34: { + FromName = input.ReadString(); + break; + } + case 42: { + DisplayName = input.ReadString(); + break; + } + case 50: { + Message = input.ReadString(); + break; + } + case 58: { + UserAuthId = input.ReadString(); + break; + } + case 64: { + Private = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class ConvertSessionToToken : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ConvertSessionToToken()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[15]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ConvertSessionToToken() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ConvertSessionToToken(ConvertSessionToToken other) : this() { + preserveSession_ = other.preserveSession_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ConvertSessionToToken Clone() { + return new ConvertSessionToToken(this); + } + + /// Field number for the "PreserveSession" field. + public const int PreserveSessionFieldNumber = 1; + private bool preserveSession_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool PreserveSession { + get { return preserveSession_; } + set { + preserveSession_ = value; + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 2; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 18); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ConvertSessionToToken); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ConvertSessionToToken other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (PreserveSession != other.PreserveSession) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (PreserveSession != false) hash ^= PreserveSession.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (PreserveSession != false) { + output.WriteRawTag(8); + output.WriteBool(PreserveSession); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (PreserveSession != false) { + size += 1 + 1; + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ConvertSessionToToken other) { + if (other == null) { + return; + } + if (other.PreserveSession != false) { + PreserveSession = other.PreserveSession; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + PreserveSession = input.ReadBool(); + break; + } + case 18: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class ConvertSessionToTokenResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ConvertSessionToTokenResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ConvertSessionToTokenResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ConvertSessionToTokenResponse(ConvertSessionToTokenResponse other) : this() { + meta_ = other.meta_.Clone(); + accessToken_ = other.accessToken_; + refreshToken_ = other.refreshToken_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ConvertSessionToTokenResponse Clone() { + return new ConvertSessionToTokenResponse(this); + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 1; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 10); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "AccessToken" field. + public const int AccessTokenFieldNumber = 2; + private string accessToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AccessToken { + get { return accessToken_; } + set { + accessToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RefreshToken" field. + public const int RefreshTokenFieldNumber = 3; + private string refreshToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RefreshToken { + get { return refreshToken_; } + set { + refreshToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 4; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ConvertSessionToTokenResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ConvertSessionToTokenResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!Meta.Equals(other.Meta)) return false; + if (AccessToken != other.AccessToken) return false; + if (RefreshToken != other.RefreshToken) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= Meta.GetHashCode(); + if (AccessToken.Length != 0) hash ^= AccessToken.GetHashCode(); + if (RefreshToken.Length != 0) hash ^= RefreshToken.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + meta_.WriteTo(output, _map_meta_codec); + if (AccessToken.Length != 0) { + output.WriteRawTag(18); + output.WriteString(AccessToken); + } + if (RefreshToken.Length != 0) { + output.WriteRawTag(26); + output.WriteString(RefreshToken); + } + if (responseStatus_ != null) { + output.WriteRawTag(34); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += meta_.CalculateSize(_map_meta_codec); + if (AccessToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AccessToken); + } + if (RefreshToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RefreshToken); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ConvertSessionToTokenResponse other) { + if (other == null) { + return; + } + meta_.Add(other.meta_); + if (other.AccessToken.Length != 0) { + AccessToken = other.AccessToken; + } + if (other.RefreshToken.Length != 0) { + RefreshToken = other.RefreshToken; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 18: { + AccessToken = input.ReadString(); + break; + } + case 26: { + RefreshToken = input.ReadString(); + break; + } + case 34: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[17]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[18]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class CreateBookmark : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateBookmark()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[19]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateBookmark() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateBookmark(CreateBookmark other) : this() { + slug_ = other.slug_; + title_ = other.title_; + description_ = other.description_; + url_ = other.url_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateBookmark Clone() { + return new CreateBookmark(this); + } + + /// Field number for the "Slug" field. + public const int SlugFieldNumber = 1; + private string slug_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Slug { + get { return slug_; } + set { + slug_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Title" field. + public const int TitleFieldNumber = 2; + private string title_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Title { + get { return title_; } + set { + title_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Description" field. + public const int DescriptionFieldNumber = 3; + private string description_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Description { + get { return description_; } + set { + description_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Url" field. + public const int UrlFieldNumber = 4; + private string url_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Url { + get { return url_; } + set { + url_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateBookmark); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateBookmark other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Slug != other.Slug) return false; + if (Title != other.Title) return false; + if (Description != other.Description) return false; + if (Url != other.Url) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Slug.Length != 0) hash ^= Slug.GetHashCode(); + if (Title.Length != 0) hash ^= Title.GetHashCode(); + if (Description.Length != 0) hash ^= Description.GetHashCode(); + if (Url.Length != 0) hash ^= Url.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Slug.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Slug); + } + if (Title.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Title); + } + if (Description.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Description); + } + if (Url.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Url); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Slug.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Slug); + } + if (Title.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Title); + } + if (Description.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Description); + } + if (Url.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Url); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateBookmark other) { + if (other == null) { + return; + } + if (other.Slug.Length != 0) { + Slug = other.Slug; + } + if (other.Title.Length != 0) { + Title = other.Title; + } + if (other.Description.Length != 0) { + Description = other.Description; + } + if (other.Url.Length != 0) { + Url = other.Url; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Slug = input.ReadString(); + break; + } + case 18: { + Title = input.ReadString(); + break; + } + case 26: { + Description = input.ReadString(); + break; + } + case 34: { + Url = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class CreateBookmarkResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateBookmarkResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[20]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateBookmarkResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateBookmarkResponse(CreateBookmarkResponse other) : this() { + id_ = other.id_; + result_ = other.result_ != null ? other.result_.Clone() : null; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateBookmarkResponse Clone() { + return new CreateBookmarkResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private string id_ = ""; + /// + /// default value could not be applied: 00000000-0000-0000-0000-000000000000 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.DaoBase result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.DaoBase Result { + get { return result_; } + set { + result_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateBookmarkResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateBookmarkResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (!object.Equals(Result, other.Result)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (result_ != null) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Id); + } + if (result_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); + } + if (result_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateBookmarkResponse other) { + if (other == null) { + return; + } + if (other.Id.Length != 0) { + Id = other.Id; + } + if (other.result_ != null) { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.DaoBase(); + } + Result.MergeFrom(other.Result); + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Id = input.ReadString(); + break; + } + case 18: { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.DaoBase(); + } + input.ReadMessage(Result); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class CreateConnectionInfoRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateConnectionInfoRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[21]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateConnectionInfoRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateConnectionInfoRockstar(CreateConnectionInfoRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateConnectionInfoRockstar Clone() { + return new CreateConnectionInfoRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateConnectionInfoRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateConnectionInfoRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateConnectionInfoRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class CreateNamedRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateNamedRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[22]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateNamedRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateNamedRockstar(CreateNamedRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateNamedRockstar Clone() { + return new CreateNamedRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateNamedRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateNamedRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateNamedRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[23]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstar(CreateRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstar Clone() { + return new CreateRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAdhocNonDefaults : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAdhocNonDefaults()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[24]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAdhocNonDefaults() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAdhocNonDefaults(CreateRockstarAdhocNonDefaults other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAdhocNonDefaults Clone() { + return new CreateRockstarAdhocNonDefaults(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAdhocNonDefaults); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAdhocNonDefaults other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAdhocNonDefaults other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAudit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAudit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[25]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAudit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAudit(CreateRockstarAudit other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAudit Clone() { + return new CreateRockstarAudit(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAudit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAudit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAudit other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAuditMqToken : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAuditMqToken()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[26]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditMqToken() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditMqToken(CreateRockstarAuditMqToken other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + bearerToken_ = other.bearerToken_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditMqToken Clone() { + return new CreateRockstarAuditMqToken(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 101; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAuditMqToken); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAuditMqToken other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (BearerToken != other.BearerToken) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (BearerToken.Length != 0) { + output.WriteRawTag(170, 6); + output.WriteString(BearerToken); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (BearerToken.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAuditMqToken other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 810: { + BearerToken = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAuditTenant : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAuditTenant()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[27]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenant() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenant(CreateRockstarAuditTenant other) : this() { + bearerToken_ = other.bearerToken_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenant Clone() { + return new CreateRockstarAuditTenant(this); + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 201; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 202; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 203; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 204; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 205; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 206; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 207; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAuditTenant); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAuditTenant other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BearerToken != other.BearerToken) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (BearerToken.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(BearerToken); + } + if (FirstName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(218, 12); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(224, 12); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(234, 12); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(242, 12); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(248, 12); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BearerToken.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAuditTenant other) { + if (other == null) { + return; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 1610: { + BearerToken = input.ReadString(); + break; + } + case 1618: { + FirstName = input.ReadString(); + break; + } + case 1626: { + LastName = input.ReadString(); + break; + } + case 1632: { + Age = input.ReadInt32(); + break; + } + case 1642: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 1650: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 1656: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAuditTenantGateway : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAuditTenantGateway()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[28]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenantGateway() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenantGateway(CreateRockstarAuditTenantGateway other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenantGateway Clone() { + return new CreateRockstarAuditTenantGateway(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAuditTenantGateway); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAuditTenantGateway other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAuditTenantGateway other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAuditTenantMq : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAuditTenantMq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[29]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenantMq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenantMq(CreateRockstarAuditTenantMq other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAuditTenantMq Clone() { + return new CreateRockstarAuditTenantMq(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAuditTenantMq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAuditTenantMq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAuditTenantMq other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarAutoMap : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarAutoMap()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[30]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAutoMap() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAutoMap(CreateRockstarAutoMap other) : this() { + mapFirstName_ = other.mapFirstName_; + mapLastName_ = other.mapLastName_; + mapAge_ = other.mapAge_; + mapDateOfBirth_ = other.mapDateOfBirth_ != null ? other.mapDateOfBirth_.Clone() : null; + mapDateDied_ = other.mapDateDied_ != null ? other.mapDateDied_.Clone() : null; + mapLivingStatus_ = other.mapLivingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarAutoMap Clone() { + return new CreateRockstarAutoMap(this); + } + + /// Field number for the "MapFirstName" field. + public const int MapFirstNameFieldNumber = 1; + private string mapFirstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string MapFirstName { + get { return mapFirstName_; } + set { + mapFirstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "MapLastName" field. + public const int MapLastNameFieldNumber = 2; + private string mapLastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string MapLastName { + get { return mapLastName_; } + set { + mapLastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "MapAge" field. + public const int MapAgeFieldNumber = 3; + private int mapAge_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int MapAge { + get { return mapAge_; } + set { + mapAge_ = value; + } + } + + /// Field number for the "MapDateOfBirth" field. + public const int MapDateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp mapDateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp MapDateOfBirth { + get { return mapDateOfBirth_; } + set { + mapDateOfBirth_ = value; + } + } + + /// Field number for the "MapDateDied" field. + public const int MapDateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp mapDateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp MapDateDied { + get { return mapDateDied_; } + set { + mapDateDied_ = value; + } + } + + /// Field number for the "MapLivingStatus" field. + public const int MapLivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus mapLivingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus MapLivingStatus { + get { return mapLivingStatus_; } + set { + mapLivingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarAutoMap); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarAutoMap other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (MapFirstName != other.MapFirstName) return false; + if (MapLastName != other.MapLastName) return false; + if (MapAge != other.MapAge) return false; + if (!object.Equals(MapDateOfBirth, other.MapDateOfBirth)) return false; + if (!object.Equals(MapDateDied, other.MapDateDied)) return false; + if (MapLivingStatus != other.MapLivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (MapFirstName.Length != 0) hash ^= MapFirstName.GetHashCode(); + if (MapLastName.Length != 0) hash ^= MapLastName.GetHashCode(); + if (MapAge != 0) hash ^= MapAge.GetHashCode(); + if (mapDateOfBirth_ != null) hash ^= MapDateOfBirth.GetHashCode(); + if (mapDateDied_ != null) hash ^= MapDateDied.GetHashCode(); + if (MapLivingStatus != 0) hash ^= MapLivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (MapFirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(MapFirstName); + } + if (MapLastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(MapLastName); + } + if (MapAge != 0) { + output.WriteRawTag(24); + output.WriteInt32(MapAge); + } + if (mapDateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(MapDateOfBirth); + } + if (mapDateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(MapDateDied); + } + if (MapLivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) MapLivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (MapFirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(MapFirstName); + } + if (MapLastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(MapLastName); + } + if (MapAge != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(MapAge); + } + if (mapDateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(MapDateOfBirth); + } + if (mapDateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(MapDateDied); + } + if (MapLivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) MapLivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarAutoMap other) { + if (other == null) { + return; + } + if (other.MapFirstName.Length != 0) { + MapFirstName = other.MapFirstName; + } + if (other.MapLastName.Length != 0) { + MapLastName = other.MapLastName; + } + if (other.MapAge != 0) { + MapAge = other.MapAge; + } + if (other.mapDateOfBirth_ != null) { + if (mapDateOfBirth_ == null) { + MapDateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + MapDateOfBirth.MergeFrom(other.MapDateOfBirth); + } + if (other.mapDateDied_ != null) { + if (mapDateDied_ == null) { + MapDateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + MapDateDied.MergeFrom(other.MapDateDied); + } + if (other.MapLivingStatus != 0) { + MapLivingStatus = other.MapLivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + MapFirstName = input.ReadString(); + break; + } + case 18: { + MapLastName = input.ReadString(); + break; + } + case 24: { + MapAge = input.ReadInt32(); + break; + } + case 34: { + if (mapDateOfBirth_ == null) { + MapDateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(MapDateOfBirth); + break; + } + case 42: { + if (mapDateDied_ == null) { + MapDateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(MapDateDied); + break; + } + case 48: { + MapLivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[31]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarResponse(CreateRockstarResponse other) : this() { + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarResponse Clone() { + return new CreateRockstarResponse(this); + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 1; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (responseStatus_ != null) { + output.WriteRawTag(10); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarResponse other) { + if (other == null) { + return; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarVersion : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarVersion()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[32]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarVersion() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarVersion(CreateRockstarVersion other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarVersion Clone() { + return new CreateRockstarVersion(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarVersion); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarVersion other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarVersion other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarWithAutoGuid : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarWithAutoGuid()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[33]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithAutoGuid() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithAutoGuid(CreateRockstarWithAutoGuid other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithAutoGuid Clone() { + return new CreateRockstarWithAutoGuid(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarWithAutoGuid); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarWithAutoGuid other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarWithAutoGuid other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarWithReturn : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarWithReturn()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[34]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithReturn() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithReturn(CreateRockstarWithReturn other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithReturn Clone() { + return new CreateRockstarWithReturn(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarWithReturn); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarWithReturn other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarWithReturn other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarWithReturnGuidResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarWithReturnGuidResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[35]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithReturnGuidResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithReturnGuidResponse(CreateRockstarWithReturnGuidResponse other) : this() { + id_ = other.id_; + result_ = other.result_ != null ? other.result_.Clone() : null; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithReturnGuidResponse Clone() { + return new CreateRockstarWithReturnGuidResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private string id_ = ""; + /// + /// default value could not be applied: 00000000-0000-0000-0000-000000000000 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.RockstarBase result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarBase Result { + get { return result_; } + set { + result_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarWithReturnGuidResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarWithReturnGuidResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (!object.Equals(Result, other.Result)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (result_ != null) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Id); + } + if (result_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); + } + if (result_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarWithReturnGuidResponse other) { + if (other == null) { + return; + } + if (other.Id.Length != 0) { + Id = other.Id; + } + if (other.result_ != null) { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.RockstarBase(); + } + Result.MergeFrom(other.Result); + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Id = input.ReadString(); + break; + } + case 18: { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.RockstarBase(); + } + input.ReadMessage(Result); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class CreateRockstarWithVoidReturn : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateRockstarWithVoidReturn()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[36]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithVoidReturn() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithVoidReturn(CreateRockstarWithVoidReturn other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateRockstarWithVoidReturn Clone() { + return new CreateRockstarWithVoidReturn(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateRockstarWithVoidReturn); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateRockstarWithVoidReturn other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateRockstarWithVoidReturn other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class CreateTodo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateTodo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[37]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateTodo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateTodo(CreateTodo other) : this() { + title_ = other.title_; + order_ = other.order_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateTodo Clone() { + return new CreateTodo(this); + } + + /// Field number for the "Title" field. + public const int TitleFieldNumber = 1; + private string title_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Title { + get { return title_; } + set { + title_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Order" field. + public const int OrderFieldNumber = 2; + private int order_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Order { + get { return order_; } + set { + order_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateTodo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateTodo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Title != other.Title) return false; + if (Order != other.Order) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Title.Length != 0) hash ^= Title.GetHashCode(); + if (Order != 0) hash ^= Order.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Title.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Title); + } + if (Order != 0) { + output.WriteRawTag(16); + output.WriteInt32(Order); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Title.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Title); + } + if (Order != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Order); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateTodo other) { + if (other == null) { + return; + } + if (other.Title.Length != 0) { + Title = other.Title; + } + if (other.Order != 0) { + Order = other.Order; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Title = input.ReadString(); + break; + } + case 16: { + Order = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class CreateTodoResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateTodoResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[38]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateTodoResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateTodoResponse(CreateTodoResponse other) : this() { + result_ = other.result_ != null ? other.result_.Clone() : null; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateTodoResponse Clone() { + return new CreateTodoResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private global::ServiceStack.Extensions.Tests.Protoc.Todo result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.Todo Result { + get { return result_; } + set { + result_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateTodoResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateTodoResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Result, other.Result)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (result_ != null) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (result_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (result_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateTodoResponse other) { + if (other == null) { + return; + } + if (other.result_ != null) { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.Todo(); + } + Result.MergeFrom(other.Result); + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.Todo(); + } + input.ReadMessage(Result); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class CustomRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CustomRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[39]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomRockstar(CustomRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + rockstarGenreName_ = other.rockstarGenreName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomRockstar Clone() { + return new CustomRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 4; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RockstarGenreName" field. + public const int RockstarGenreNameFieldNumber = 5; + private string rockstarGenreName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarGenreName { + get { return rockstarGenreName_; } + set { + rockstarGenreName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CustomRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CustomRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + if (RockstarGenreName != other.RockstarGenreName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (RockstarGenreName.Length != 0) hash ^= RockstarGenreName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(34); + output.WriteString(RockstarAlbumName); + } + if (RockstarGenreName.Length != 0) { + output.WriteRawTag(42); + output.WriteString(RockstarGenreName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (RockstarGenreName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RockstarGenreName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CustomRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + if (other.RockstarGenreName.Length != 0) { + RockstarGenreName = other.RockstarGenreName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + RockstarAlbumName = input.ReadString(); + break; + } + case 42: { + RockstarGenreName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class CustomRockstarSchema : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CustomRockstarSchema()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[40]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomRockstarSchema() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomRockstarSchema(CustomRockstarSchema other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + rockstarGenreName_ = other.rockstarGenreName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomRockstarSchema Clone() { + return new CustomRockstarSchema(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 4; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RockstarGenreName" field. + public const int RockstarGenreNameFieldNumber = 5; + private string rockstarGenreName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarGenreName { + get { return rockstarGenreName_; } + set { + rockstarGenreName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CustomRockstarSchema); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CustomRockstarSchema other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + if (RockstarGenreName != other.RockstarGenreName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (RockstarGenreName.Length != 0) hash ^= RockstarGenreName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(34); + output.WriteString(RockstarAlbumName); + } + if (RockstarGenreName.Length != 0) { + output.WriteRawTag(42); + output.WriteString(RockstarGenreName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (RockstarGenreName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RockstarGenreName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CustomRockstarSchema other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + if (other.RockstarGenreName.Length != 0) { + RockstarGenreName = other.RockstarGenreName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + RockstarAlbumName = input.ReadString(); + break; + } + case 42: { + RockstarGenreName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class CustomSelectRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CustomSelectRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[41]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomSelectRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomSelectRockstar(CustomSelectRockstar other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomSelectRockstar Clone() { + return new CustomSelectRockstar(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 3; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 4; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CustomSelectRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CustomSelectRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(32); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CustomSelectRockstar other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + LastName = input.ReadString(); + break; + } + case 32: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class CustomSelectRockstarResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CustomSelectRockstarResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[42]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomSelectRockstarResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomSelectRockstarResponse(CustomSelectRockstarResponse other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomSelectRockstarResponse Clone() { + return new CustomSelectRockstarResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CustomSelectRockstarResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CustomSelectRockstarResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CustomSelectRockstarResponse other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class CustomValidationErrors : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CustomValidationErrors()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[43]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomValidationErrors() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomValidationErrors(CustomValidationErrors other) : this() { + customErrorCode_ = other.customErrorCode_; + customErrorCodeAndMessage_ = other.customErrorCodeAndMessage_; + errorCodeRule_ = other.errorCodeRule_; + isOddCondition_ = other.isOddCondition_; + isOddAndOverTwoDigitsCondition_ = other.isOddAndOverTwoDigitsCondition_; + isOddOrOverTwoDigitsCondition_ = other.isOddOrOverTwoDigitsCondition_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CustomValidationErrors Clone() { + return new CustomValidationErrors(this); + } + + /// Field number for the "CustomErrorCode" field. + public const int CustomErrorCodeFieldNumber = 1; + private string customErrorCode_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CustomErrorCode { + get { return customErrorCode_; } + set { + customErrorCode_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "CustomErrorCodeAndMessage" field. + public const int CustomErrorCodeAndMessageFieldNumber = 2; + private int customErrorCodeAndMessage_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CustomErrorCodeAndMessage { + get { return customErrorCodeAndMessage_; } + set { + customErrorCodeAndMessage_ = value; + } + } + + /// Field number for the "ErrorCodeRule" field. + public const int ErrorCodeRuleFieldNumber = 3; + private string errorCodeRule_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ErrorCodeRule { + get { return errorCodeRule_; } + set { + errorCodeRule_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "IsOddCondition" field. + public const int IsOddConditionFieldNumber = 4; + private int isOddCondition_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int IsOddCondition { + get { return isOddCondition_; } + set { + isOddCondition_ = value; + } + } + + /// Field number for the "IsOddAndOverTwoDigitsCondition" field. + public const int IsOddAndOverTwoDigitsConditionFieldNumber = 5; + private int isOddAndOverTwoDigitsCondition_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int IsOddAndOverTwoDigitsCondition { + get { return isOddAndOverTwoDigitsCondition_; } + set { + isOddAndOverTwoDigitsCondition_ = value; + } + } + + /// Field number for the "IsOddOrOverTwoDigitsCondition" field. + public const int IsOddOrOverTwoDigitsConditionFieldNumber = 6; + private int isOddOrOverTwoDigitsCondition_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int IsOddOrOverTwoDigitsCondition { + get { return isOddOrOverTwoDigitsCondition_; } + set { + isOddOrOverTwoDigitsCondition_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CustomValidationErrors); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CustomValidationErrors other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (CustomErrorCode != other.CustomErrorCode) return false; + if (CustomErrorCodeAndMessage != other.CustomErrorCodeAndMessage) return false; + if (ErrorCodeRule != other.ErrorCodeRule) return false; + if (IsOddCondition != other.IsOddCondition) return false; + if (IsOddAndOverTwoDigitsCondition != other.IsOddAndOverTwoDigitsCondition) return false; + if (IsOddOrOverTwoDigitsCondition != other.IsOddOrOverTwoDigitsCondition) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (CustomErrorCode.Length != 0) hash ^= CustomErrorCode.GetHashCode(); + if (CustomErrorCodeAndMessage != 0) hash ^= CustomErrorCodeAndMessage.GetHashCode(); + if (ErrorCodeRule.Length != 0) hash ^= ErrorCodeRule.GetHashCode(); + if (IsOddCondition != 0) hash ^= IsOddCondition.GetHashCode(); + if (IsOddAndOverTwoDigitsCondition != 0) hash ^= IsOddAndOverTwoDigitsCondition.GetHashCode(); + if (IsOddOrOverTwoDigitsCondition != 0) hash ^= IsOddOrOverTwoDigitsCondition.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (CustomErrorCode.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CustomErrorCode); + } + if (CustomErrorCodeAndMessage != 0) { + output.WriteRawTag(16); + output.WriteInt32(CustomErrorCodeAndMessage); + } + if (ErrorCodeRule.Length != 0) { + output.WriteRawTag(26); + output.WriteString(ErrorCodeRule); + } + if (IsOddCondition != 0) { + output.WriteRawTag(32); + output.WriteInt32(IsOddCondition); + } + if (IsOddAndOverTwoDigitsCondition != 0) { + output.WriteRawTag(40); + output.WriteInt32(IsOddAndOverTwoDigitsCondition); + } + if (IsOddOrOverTwoDigitsCondition != 0) { + output.WriteRawTag(48); + output.WriteInt32(IsOddOrOverTwoDigitsCondition); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (CustomErrorCode.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CustomErrorCode); + } + if (CustomErrorCodeAndMessage != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(CustomErrorCodeAndMessage); + } + if (ErrorCodeRule.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorCodeRule); + } + if (IsOddCondition != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(IsOddCondition); + } + if (IsOddAndOverTwoDigitsCondition != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(IsOddAndOverTwoDigitsCondition); + } + if (IsOddOrOverTwoDigitsCondition != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(IsOddOrOverTwoDigitsCondition); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CustomValidationErrors other) { + if (other == null) { + return; + } + if (other.CustomErrorCode.Length != 0) { + CustomErrorCode = other.CustomErrorCode; + } + if (other.CustomErrorCodeAndMessage != 0) { + CustomErrorCodeAndMessage = other.CustomErrorCodeAndMessage; + } + if (other.ErrorCodeRule.Length != 0) { + ErrorCodeRule = other.ErrorCodeRule; + } + if (other.IsOddCondition != 0) { + IsOddCondition = other.IsOddCondition; + } + if (other.IsOddAndOverTwoDigitsCondition != 0) { + IsOddAndOverTwoDigitsCondition = other.IsOddAndOverTwoDigitsCondition; + } + if (other.IsOddOrOverTwoDigitsCondition != 0) { + IsOddOrOverTwoDigitsCondition = other.IsOddOrOverTwoDigitsCondition; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + CustomErrorCode = input.ReadString(); + break; + } + case 16: { + CustomErrorCodeAndMessage = input.ReadInt32(); + break; + } + case 26: { + ErrorCodeRule = input.ReadString(); + break; + } + case 32: { + IsOddCondition = input.ReadInt32(); + break; + } + case 40: { + IsOddAndOverTwoDigitsCondition = input.ReadInt32(); + break; + } + case 48: { + IsOddOrOverTwoDigitsCondition = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class DaoBase : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DaoBase()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[44]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaoBase() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaoBase(DaoBase other) : this() { + id_ = other.id_; + createDate_ = other.createDate_ != null ? other.createDate_.Clone() : null; + createdBy_ = other.createdBy_; + modifiedDate_ = other.modifiedDate_ != null ? other.modifiedDate_.Clone() : null; + modifiedBy_ = other.modifiedBy_; + switch (other.SubtypeCase) { + case SubtypeOneofCase.Bookmark: + Bookmark = other.Bookmark.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaoBase Clone() { + return new DaoBase(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private string id_ = ""; + /// + /// default value could not be applied: 00000000-0000-0000-0000-000000000000 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "CreateDate" field. + public const int CreateDateFieldNumber = 2; + private global::Google.Protobuf.WellKnownTypes.Timestamp createDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp CreateDate { + get { return createDate_; } + set { + createDate_ = value; + } + } + + /// Field number for the "CreatedBy" field. + public const int CreatedByFieldNumber = 3; + private string createdBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreatedBy { + get { return createdBy_; } + set { + createdBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ModifiedDate" field. + public const int ModifiedDateFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp modifiedDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp ModifiedDate { + get { return modifiedDate_; } + set { + modifiedDate_ = value; + } + } + + /// Field number for the "ModifiedBy" field. + public const int ModifiedByFieldNumber = 5; + private string modifiedBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ModifiedBy { + get { return modifiedBy_; } + set { + modifiedBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Bookmark" field. + public const int BookmarkFieldNumber = 439450339; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.Bookmark Bookmark { + get { return subtypeCase_ == SubtypeOneofCase.Bookmark ? (global::ServiceStack.Extensions.Tests.Protoc.Bookmark) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.Bookmark; + } + } + + private object subtype_; + /// Enum of possible cases for the "subtype" oneof. + public enum SubtypeOneofCase { + None = 0, + Bookmark = 439450339, + } + private SubtypeOneofCase subtypeCase_ = SubtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubtypeOneofCase SubtypeCase { + get { return subtypeCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearSubtype() { + subtypeCase_ = SubtypeOneofCase.None; + subtype_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DaoBase); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DaoBase other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (!object.Equals(CreateDate, other.CreateDate)) return false; + if (CreatedBy != other.CreatedBy) return false; + if (!object.Equals(ModifiedDate, other.ModifiedDate)) return false; + if (ModifiedBy != other.ModifiedBy) return false; + if (!object.Equals(Bookmark, other.Bookmark)) return false; + if (SubtypeCase != other.SubtypeCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (createDate_ != null) hash ^= CreateDate.GetHashCode(); + if (CreatedBy.Length != 0) hash ^= CreatedBy.GetHashCode(); + if (modifiedDate_ != null) hash ^= ModifiedDate.GetHashCode(); + if (ModifiedBy.Length != 0) hash ^= ModifiedBy.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.Bookmark) hash ^= Bookmark.GetHashCode(); + hash ^= (int) subtypeCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Id); + } + if (createDate_ != null) { + output.WriteRawTag(18); + output.WriteMessage(CreateDate); + } + if (CreatedBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(CreatedBy); + } + if (modifiedDate_ != null) { + output.WriteRawTag(34); + output.WriteMessage(ModifiedDate); + } + if (ModifiedBy.Length != 0) { + output.WriteRawTag(42); + output.WriteString(ModifiedBy); + } + if (subtypeCase_ == SubtypeOneofCase.Bookmark) { + output.WriteRawTag(154, 174, 175, 140, 13); + output.WriteMessage(Bookmark); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); + } + if (createDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(CreateDate); + } + if (CreatedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreatedBy); + } + if (modifiedDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ModifiedDate); + } + if (ModifiedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ModifiedBy); + } + if (subtypeCase_ == SubtypeOneofCase.Bookmark) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(Bookmark); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DaoBase other) { + if (other == null) { + return; + } + if (other.Id.Length != 0) { + Id = other.Id; + } + if (other.createDate_ != null) { + if (createDate_ == null) { + CreateDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + CreateDate.MergeFrom(other.CreateDate); + } + if (other.CreatedBy.Length != 0) { + CreatedBy = other.CreatedBy; + } + if (other.modifiedDate_ != null) { + if (modifiedDate_ == null) { + ModifiedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + ModifiedDate.MergeFrom(other.ModifiedDate); + } + if (other.ModifiedBy.Length != 0) { + ModifiedBy = other.ModifiedBy; + } + switch (other.SubtypeCase) { + case SubtypeOneofCase.Bookmark: + if (Bookmark == null) { + Bookmark = new global::ServiceStack.Extensions.Tests.Protoc.Bookmark(); + } + Bookmark.MergeFrom(other.Bookmark); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Id = input.ReadString(); + break; + } + case 18: { + if (createDate_ == null) { + CreateDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(CreateDate); + break; + } + case 26: { + CreatedBy = input.ReadString(); + break; + } + case 34: { + if (modifiedDate_ == null) { + ModifiedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(ModifiedDate); + break; + } + case 42: { + ModifiedBy = input.ReadString(); + break; + } + case 3515602714: { + global::ServiceStack.Extensions.Tests.Protoc.Bookmark subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.Bookmark(); + if (subtypeCase_ == SubtypeOneofCase.Bookmark) { + subBuilder.MergeFrom(Bookmark); + } + input.ReadMessage(subBuilder); + Bookmark = subBuilder; + break; + } + } + } + } + + } + + public sealed partial class DeleteRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeleteRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[45]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstar(DeleteRockstar other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstar Clone() { + return new DeleteRockstar(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeleteRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeleteRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeleteRockstar other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class DeleteRockstarAudit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeleteRockstarAudit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[46]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarAudit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarAudit(DeleteRockstarAudit other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarAudit Clone() { + return new DeleteRockstarAudit(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeleteRockstarAudit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeleteRockstarAudit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeleteRockstarAudit other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class DeleteRockstarCountResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeleteRockstarCountResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[47]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarCountResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarCountResponse(DeleteRockstarCountResponse other) : this() { + count_ = other.count_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarCountResponse Clone() { + return new DeleteRockstarCountResponse(this); + } + + /// Field number for the "Count" field. + public const int CountFieldNumber = 1; + private int count_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Count { + get { return count_; } + set { + count_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeleteRockstarCountResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeleteRockstarCountResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Count != other.Count) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Count != 0) hash ^= Count.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Count != 0) { + output.WriteRawTag(8); + output.WriteInt32(Count); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Count != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Count); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeleteRockstarCountResponse other) { + if (other == null) { + return; + } + if (other.Count != 0) { + Count = other.Count; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Count = input.ReadInt32(); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class DeleteRockstarFilters : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeleteRockstarFilters()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[48]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarFilters() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarFilters(DeleteRockstarFilters other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteRockstarFilters Clone() { + return new DeleteRockstarFilters(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeleteRockstarFilters); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeleteRockstarFilters other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeleteRockstarFilters other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class DeleteTodo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeleteTodo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[49]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteTodo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteTodo(DeleteTodo other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteTodo Clone() { + return new DeleteTodo(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeleteTodo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeleteTodo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeleteTodo other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + } + } + } + + } + + public sealed partial class DeleteTodos : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeleteTodos()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[50]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteTodos() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteTodos(DeleteTodos other) : this() { + ids_ = other.ids_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeleteTodos Clone() { + return new DeleteTodos(this); + } + + /// Field number for the "Ids" field. + public const int IdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForInt64(8); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeleteTodos); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeleteTodos other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!ids_.Equals(other.ids_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= ids_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + ids_.WriteTo(output, _repeated_ids_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += ids_.CalculateSize(_repeated_ids_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeleteTodos other) { + if (other == null) { + return; + } + ids_.Add(other.ids_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: + case 8: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + } + } + } + + } + + public sealed partial class DynamicRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DynamicRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[51]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DynamicRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DynamicRequest(DynamicRequest other) : this() { + params_ = other.params_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DynamicRequest Clone() { + return new DynamicRequest(this); + } + + /// Field number for the "Params" field. + public const int ParamsFieldNumber = 1; + private static readonly pbc::MapField.Codec _map_params_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 10); + private readonly pbc::MapField params_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Params { + get { return params_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DynamicRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DynamicRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!Params.Equals(other.Params)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= Params.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + params_.WriteTo(output, _map_params_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += params_.CalculateSize(_map_params_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DynamicRequest other) { + if (other == null) { + return; + } + params_.Add(other.params_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + params_.AddEntriesFrom(input, _map_params_codec); + break; + } + } + } + } + + } + + public sealed partial class DynamicValidationRules : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DynamicValidationRules()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[52]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DynamicValidationRules() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DynamicValidationRules(DynamicValidationRules other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DynamicValidationRules Clone() { + return new DynamicValidationRules(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DynamicValidationRules); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DynamicValidationRules other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (LivingStatus != 0) { + output.WriteRawTag(40); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DynamicValidationRules other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 40: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class EmptyResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EmptyResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[53]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EmptyResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EmptyResponse(EmptyResponse other) : this() { + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EmptyResponse Clone() { + return new EmptyResponse(this); + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 1; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EmptyResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EmptyResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (responseStatus_ != null) { + output.WriteRawTag(10); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EmptyResponse other) { + if (other == null) { + return; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class EmptyValidators : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EmptyValidators()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[54]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EmptyValidators() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EmptyValidators(EmptyValidators other) : this() { + int_ = other.int_; + nInt_ = other.nInt_; + timeSpan_ = other.timeSpan_ != null ? other.timeSpan_.Clone() : null; + nTimeSpan_ = other.nTimeSpan_ != null ? other.nTimeSpan_.Clone() : null; + string_ = other.string_; + intArray_ = other.intArray_.Clone(); + stringList_ = other.stringList_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EmptyValidators Clone() { + return new EmptyValidators(this); + } + + /// Field number for the "Int" field. + public const int IntFieldNumber = 1; + private int int_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Int { + get { return int_; } + set { + int_ = value; + } + } + + /// Field number for the "NInt" field. + public const int NIntFieldNumber = 2; + private int nInt_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NInt { + get { return nInt_; } + set { + nInt_ = value; + } + } + + /// Field number for the "TimeSpan" field. + public const int TimeSpanFieldNumber = 3; + private global::Google.Protobuf.WellKnownTypes.Duration timeSpan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Duration TimeSpan { + get { return timeSpan_; } + set { + timeSpan_ = value; + } + } + + /// Field number for the "NTimeSpan" field. + public const int NTimeSpanFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Duration nTimeSpan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Duration NTimeSpan { + get { return nTimeSpan_; } + set { + nTimeSpan_ = value; + } + } + + /// Field number for the "String" field. + public const int StringFieldNumber = 5; + private string string_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string String { + get { return string_; } + set { + string_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "IntArray" field. + public const int IntArrayFieldNumber = 6; + private static readonly pb::FieldCodec _repeated_intArray_codec + = pb::FieldCodec.ForInt32(48); + private readonly pbc::RepeatedField intArray_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField IntArray { + get { return intArray_; } + } + + /// Field number for the "StringList" field. + public const int StringListFieldNumber = 7; + private static readonly pb::FieldCodec _repeated_stringList_codec + = pb::FieldCodec.ForString(58); + private readonly pbc::RepeatedField stringList_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField StringList { + get { return stringList_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EmptyValidators); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EmptyValidators other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Int != other.Int) return false; + if (NInt != other.NInt) return false; + if (!object.Equals(TimeSpan, other.TimeSpan)) return false; + if (!object.Equals(NTimeSpan, other.NTimeSpan)) return false; + if (String != other.String) return false; + if(!intArray_.Equals(other.intArray_)) return false; + if(!stringList_.Equals(other.stringList_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Int != 0) hash ^= Int.GetHashCode(); + if (NInt != 0) hash ^= NInt.GetHashCode(); + if (timeSpan_ != null) hash ^= TimeSpan.GetHashCode(); + if (nTimeSpan_ != null) hash ^= NTimeSpan.GetHashCode(); + if (String.Length != 0) hash ^= String.GetHashCode(); + hash ^= intArray_.GetHashCode(); + hash ^= stringList_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Int != 0) { + output.WriteRawTag(8); + output.WriteInt32(Int); + } + if (NInt != 0) { + output.WriteRawTag(16); + output.WriteInt32(NInt); + } + if (timeSpan_ != null) { + output.WriteRawTag(26); + output.WriteMessage(TimeSpan); + } + if (nTimeSpan_ != null) { + output.WriteRawTag(34); + output.WriteMessage(NTimeSpan); + } + if (String.Length != 0) { + output.WriteRawTag(42); + output.WriteString(String); + } + intArray_.WriteTo(output, _repeated_intArray_codec); + stringList_.WriteTo(output, _repeated_stringList_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Int != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Int); + } + if (NInt != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NInt); + } + if (timeSpan_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TimeSpan); + } + if (nTimeSpan_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(NTimeSpan); + } + if (String.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(String); + } + size += intArray_.CalculateSize(_repeated_intArray_codec); + size += stringList_.CalculateSize(_repeated_stringList_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EmptyValidators other) { + if (other == null) { + return; + } + if (other.Int != 0) { + Int = other.Int; + } + if (other.NInt != 0) { + NInt = other.NInt; + } + if (other.timeSpan_ != null) { + if (timeSpan_ == null) { + TimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + TimeSpan.MergeFrom(other.TimeSpan); + } + if (other.nTimeSpan_ != null) { + if (nTimeSpan_ == null) { + NTimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + NTimeSpan.MergeFrom(other.NTimeSpan); + } + if (other.String.Length != 0) { + String = other.String; + } + intArray_.Add(other.intArray_); + stringList_.Add(other.stringList_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Int = input.ReadInt32(); + break; + } + case 16: { + NInt = input.ReadInt32(); + break; + } + case 26: { + if (timeSpan_ == null) { + TimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + input.ReadMessage(TimeSpan); + break; + } + case 34: { + if (nTimeSpan_ == null) { + NTimeSpan = new global::Google.Protobuf.WellKnownTypes.Duration(); + } + input.ReadMessage(NTimeSpan); + break; + } + case 42: { + String = input.ReadString(); + break; + } + case 50: + case 48: { + intArray_.AddEntriesFrom(input, _repeated_intArray_codec); + break; + } + case 58: { + stringList_.AddEntriesFrom(input, _repeated_stringList_codec); + break; + } + } + } + } + + } + + public sealed partial class EndsWithSuffixRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EndsWithSuffixRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[55]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndsWithSuffixRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndsWithSuffixRequest(EndsWithSuffixRequest other) : this() { + suffix_ = other.suffix_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndsWithSuffixRequest Clone() { + return new EndsWithSuffixRequest(this); + } + + /// Field number for the "Suffix" field. + public const int SuffixFieldNumber = 1; + private string suffix_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Suffix { + get { return suffix_; } + set { + suffix_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EndsWithSuffixRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EndsWithSuffixRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Suffix != other.Suffix) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Suffix.Length != 0) hash ^= Suffix.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Suffix.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Suffix); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Suffix.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Suffix); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EndsWithSuffixRequest other) { + if (other == null) { + return; + } + if (other.Suffix.Length != 0) { + Suffix = other.Suffix; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Suffix = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class EndsWithSuffixResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EndsWithSuffixResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[56]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndsWithSuffixResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndsWithSuffixResponse(EndsWithSuffixResponse other) : this() { + result_ = other.result_ != null ? other.result_.Clone() : null; + count_ = other.count_; + words_ = other.words_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndsWithSuffixResponse Clone() { + return new EndsWithSuffixResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private global::ServiceStack.Extensions.Tests.Protoc.SearchResult result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.SearchResult Result { + get { return result_; } + set { + result_ = value; + } + } + + /// Field number for the "Count" field. + public const int CountFieldNumber = 2; + private int count_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Count { + get { return count_; } + set { + count_ = value; + } + } + + /// Field number for the "Words" field. + public const int WordsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_words_codec + = pb::FieldCodec.ForString(26); + private readonly pbc::RepeatedField words_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Words { + get { return words_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EndsWithSuffixResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EndsWithSuffixResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Result, other.Result)) return false; + if (Count != other.Count) return false; + if(!words_.Equals(other.words_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (result_ != null) hash ^= Result.GetHashCode(); + if (Count != 0) hash ^= Count.GetHashCode(); + hash ^= words_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (result_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Result); + } + if (Count != 0) { + output.WriteRawTag(16); + output.WriteInt32(Count); + } + words_.WriteTo(output, _repeated_words_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (result_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Result); + } + if (Count != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Count); + } + size += words_.CalculateSize(_repeated_words_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EndsWithSuffixResponse other) { + if (other == null) { + return; + } + if (other.result_ != null) { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.SearchResult(); + } + Result.MergeFrom(other.Result); + } + if (other.Count != 0) { + Count = other.Count; + } + words_.Add(other.words_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.SearchResult(); + } + input.ReadMessage(Result); + break; + } + case 16: { + Count = input.ReadInt32(); + break; + } + case 26: { + words_.AddEntriesFrom(input, _repeated_words_codec); + break; + } + } + } + } + + } + + public sealed partial class Entry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Entry()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[57]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Entry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Entry(Entry other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Entry Clone() { + return new Entry(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Entry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Entry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Entry other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class FileContent : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FileContent()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[58]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FileContent() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FileContent(FileContent other) : this() { + name_ = other.name_; + type_ = other.type_; + length_ = other.length_; + body_ = other.body_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FileContent Clone() { + return new FileContent(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Type" field. + public const int TypeFieldNumber = 2; + private string type_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Type { + get { return type_; } + set { + type_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Length" field. + public const int LengthFieldNumber = 3; + private int length_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Length { + get { return length_; } + set { + length_ = value; + } + } + + /// Field number for the "Body" field. + public const int BodyFieldNumber = 4; + private pb::ByteString body_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Body { + get { return body_; } + set { + body_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as FileContent); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(FileContent other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + if (Type != other.Type) return false; + if (Length != other.Length) return false; + if (Body != other.Body) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Type.Length != 0) hash ^= Type.GetHashCode(); + if (Length != 0) hash ^= Length.GetHashCode(); + if (Body.Length != 0) hash ^= Body.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (Type.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Type); + } + if (Length != 0) { + output.WriteRawTag(24); + output.WriteInt32(Length); + } + if (Body.Length != 0) { + output.WriteRawTag(34); + output.WriteBytes(Body); + } + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Type.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Type); + } + if (Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Length); + } + if (Body.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Body); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(FileContent other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Type.Length != 0) { + Type = other.Type; + } + if (other.Length != 0) { + Length = other.Length; + } + if (other.Body.Length != 0) { + Body = other.Body; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + case 18: { + Type = input.ReadString(); + break; + } + case 24: { + Length = input.ReadInt32(); + break; + } + case 34: { + Body = input.ReadBytes(); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class Foo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Foo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[59]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Foo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Foo(Foo other) : this() { + x_ = other.x_; + switch (other.SubtypeCase) { + case SubtypeOneofCase.Bar: + Bar = other.Bar.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Foo Clone() { + return new Foo(this); + } + + /// Field number for the "X" field. + public const int XFieldNumber = 1; + private string x_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string X { + get { return x_; } + set { + x_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Bar" field. + public const int BarFieldNumber = 210304982; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.Bar Bar { + get { return subtypeCase_ == SubtypeOneofCase.Bar ? (global::ServiceStack.Extensions.Tests.Protoc.Bar) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.Bar; + } + } + + private object subtype_; + /// Enum of possible cases for the "subtype" oneof. + public enum SubtypeOneofCase { + None = 0, + Bar = 210304982, + } + private SubtypeOneofCase subtypeCase_ = SubtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubtypeOneofCase SubtypeCase { + get { return subtypeCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearSubtype() { + subtypeCase_ = SubtypeOneofCase.None; + subtype_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Foo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Foo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (X != other.X) return false; + if (!object.Equals(Bar, other.Bar)) return false; + if (SubtypeCase != other.SubtypeCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (X.Length != 0) hash ^= X.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.Bar) hash ^= Bar.GetHashCode(); + hash ^= (int) subtypeCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (X.Length != 0) { + output.WriteRawTag(10); + output.WriteString(X); + } + if (subtypeCase_ == SubtypeOneofCase.Bar) { + output.WriteRawTag(178, 253, 159, 162, 6); + output.WriteMessage(Bar); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (X.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(X); + } + if (subtypeCase_ == SubtypeOneofCase.Bar) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(Bar); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Foo other) { + if (other == null) { + return; + } + if (other.X.Length != 0) { + X = other.X; + } + switch (other.SubtypeCase) { + case SubtypeOneofCase.Bar: + if (Bar == null) { + Bar = new global::ServiceStack.Extensions.Tests.Protoc.Bar(); + } + Bar.MergeFrom(other.Bar); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + X = input.ReadString(); + break; + } + case 1682439858: { + global::ServiceStack.Extensions.Tests.Protoc.Bar subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.Bar(); + if (subtypeCase_ == SubtypeOneofCase.Bar) { + subBuilder.MergeFrom(Bar); + } + input.ReadMessage(subBuilder); + Bar = subBuilder; + break; + } + } + } + } + + } + + public sealed partial class GetAccessToken : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetAccessToken()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[60]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetAccessToken() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetAccessToken(GetAccessToken other) : this() { + refreshToken_ = other.refreshToken_; + useTokenCookie_ = other.useTokenCookie_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetAccessToken Clone() { + return new GetAccessToken(this); + } + + /// Field number for the "RefreshToken" field. + public const int RefreshTokenFieldNumber = 1; + private string refreshToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RefreshToken { + get { return refreshToken_; } + set { + refreshToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UseTokenCookie" field. + public const int UseTokenCookieFieldNumber = 2; + private bool useTokenCookie_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool UseTokenCookie { + get { return useTokenCookie_; } + set { + useTokenCookie_ = value; + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 3; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 26); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetAccessToken); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetAccessToken other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (RefreshToken != other.RefreshToken) return false; + if (UseTokenCookie != other.UseTokenCookie) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (RefreshToken.Length != 0) hash ^= RefreshToken.GetHashCode(); + if (UseTokenCookie != false) hash ^= UseTokenCookie.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (RefreshToken.Length != 0) { + output.WriteRawTag(10); + output.WriteString(RefreshToken); + } + if (UseTokenCookie != false) { + output.WriteRawTag(16); + output.WriteBool(UseTokenCookie); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (RefreshToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RefreshToken); + } + if (UseTokenCookie != false) { + size += 1 + 1; + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetAccessToken other) { + if (other == null) { + return; + } + if (other.RefreshToken.Length != 0) { + RefreshToken = other.RefreshToken; + } + if (other.UseTokenCookie != false) { + UseTokenCookie = other.UseTokenCookie; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + RefreshToken = input.ReadString(); + break; + } + case 16: { + UseTokenCookie = input.ReadBool(); + break; + } + case 26: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class GetAccessTokenResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetAccessTokenResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[61]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetAccessTokenResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetAccessTokenResponse(GetAccessTokenResponse other) : this() { + accessToken_ = other.accessToken_; + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetAccessTokenResponse Clone() { + return new GetAccessTokenResponse(this); + } + + /// Field number for the "AccessToken" field. + public const int AccessTokenFieldNumber = 1; + private string accessToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AccessToken { + get { return accessToken_; } + set { + accessToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 2; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 18); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetAccessTokenResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetAccessTokenResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (AccessToken != other.AccessToken) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (AccessToken.Length != 0) hash ^= AccessToken.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (AccessToken.Length != 0) { + output.WriteRawTag(10); + output.WriteString(AccessToken); + } + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (AccessToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AccessToken); + } + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetAccessTokenResponse other) { + if (other == null) { + return; + } + if (other.AccessToken.Length != 0) { + AccessToken = other.AccessToken; + } + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + AccessToken = input.ReadString(); + break; + } + case 18: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class GetApiKeys : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetApiKeys()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[62]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetApiKeys() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetApiKeys(GetApiKeys other) : this() { + environment_ = other.environment_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetApiKeys Clone() { + return new GetApiKeys(this); + } + + /// Field number for the "Environment" field. + public const int EnvironmentFieldNumber = 1; + private string environment_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Environment { + get { return environment_; } + set { + environment_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 2; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 18); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetApiKeys); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetApiKeys other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Environment != other.Environment) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Environment.Length != 0) hash ^= Environment.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Environment.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Environment); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Environment.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Environment); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetApiKeys other) { + if (other == null) { + return; + } + if (other.Environment.Length != 0) { + Environment = other.Environment; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Environment = input.ReadString(); + break; + } + case 18: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class GetApiKeysResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetApiKeysResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[63]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetApiKeysResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetApiKeysResponse(GetApiKeysResponse other) : this() { + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetApiKeysResponse Clone() { + return new GetApiKeysResponse(this); + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(10, global::ServiceStack.Extensions.Tests.Protoc.UserApiKey.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 2; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 18); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetApiKeysResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetApiKeysResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetApiKeysResponse other) { + if (other == null) { + return; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 18: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class GetFile : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetFile()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[64]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetFile() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetFile(GetFile other) : this() { + path_ = other.path_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetFile Clone() { + return new GetFile(this); + } + + /// Field number for the "Path" field. + public const int PathFieldNumber = 1; + private string path_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Path { + get { return path_; } + set { + path_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetFile); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetFile other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Path != other.Path) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Path.Length != 0) hash ^= Path.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Path.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Path); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Path.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Path); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetFile other) { + if (other == null) { + return; + } + if (other.Path.Length != 0) { + Path = other.Path; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Path = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class GetHello : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetHello()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[65]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHello() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHello(GetHello other) : this() { + name_ = other.name_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHello Clone() { + return new GetHello(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetHello); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetHello other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetHello other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class GetTodo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetTodo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[66]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodo(GetTodo other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodo Clone() { + return new GetTodo(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetTodo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetTodo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetTodo other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + } + } + } + + } + + public sealed partial class GetTodoResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetTodoResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[67]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodoResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodoResponse(GetTodoResponse other) : this() { + result_ = other.result_ != null ? other.result_.Clone() : null; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodoResponse Clone() { + return new GetTodoResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private global::ServiceStack.Extensions.Tests.Protoc.Todo result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.Todo Result { + get { return result_; } + set { + result_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetTodoResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetTodoResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Result, other.Result)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (result_ != null) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (result_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (result_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetTodoResponse other) { + if (other == null) { + return; + } + if (other.result_ != null) { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.Todo(); + } + Result.MergeFrom(other.Result); + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.Todo(); + } + input.ReadMessage(Result); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class GetTodos : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetTodos()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[68]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodos() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodos(GetTodos other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodos Clone() { + return new GetTodos(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetTodos); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetTodos other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetTodos other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class GetTodosResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetTodosResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[69]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodosResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodosResponse(GetTodosResponse other) : this() { + results_ = other.results_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetTodosResponse Clone() { + return new GetTodosResponse(this); + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(10, global::ServiceStack.Extensions.Tests.Protoc.Todo.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetTodosResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetTodosResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!results_.Equals(other.results_)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= results_.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + results_.WriteTo(output, _repeated_results_codec); + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += results_.CalculateSize(_repeated_results_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetTodosResponse other) { + if (other == null) { + return; + } + results_.Add(other.results_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class HelloJwt : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloJwt()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[70]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloJwt() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloJwt(HelloJwt other) : this() { + name_ = other.name_; + bearerToken_ = other.bearerToken_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloJwt Clone() { + return new HelloJwt(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 2; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as HelloJwt); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(HelloJwt other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + if (BearerToken != other.BearerToken) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (BearerToken.Length != 0) { + output.WriteRawTag(18); + output.WriteString(BearerToken); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (BearerToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(HelloJwt other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + case 18: { + BearerToken = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class HelloJwtResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloJwtResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[71]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloJwtResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloJwtResponse(HelloJwtResponse other) : this() { + result_ = other.result_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloJwtResponse Clone() { + return new HelloJwtResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private string result_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Result { + get { return result_; } + set { + result_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as HelloJwtResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(HelloJwtResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Result != other.Result) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Result.Length != 0) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Result.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Result.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(HelloJwtResponse other) { + if (other == null) { + return; + } + if (other.Result.Length != 0) { + Result = other.Result; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Result = input.ReadString(); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class HelloResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HelloResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[72]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloResponse(HelloResponse other) : this() { + result_ = other.result_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public HelloResponse Clone() { + return new HelloResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private string result_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Result { + get { return result_; } + set { + result_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as HelloResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(HelloResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Result != other.Result) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Result.Length != 0) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Result.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Result.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(HelloResponse other) { + if (other == null) { + return; + } + if (other.Result.Length != 0) { + Result = other.Result; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Result = input.ReadString(); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class Incr : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Incr()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[73]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Incr() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Incr(Incr other) : this() { + amount_ = other.amount_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Incr Clone() { + return new Incr(this); + } + + /// Field number for the "Amount" field. + public const int AmountFieldNumber = 1; + private int amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Incr); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Incr other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Amount != other.Amount) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Amount != 0) hash ^= Amount.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Amount != 0) { + output.WriteRawTag(8); + output.WriteInt32(Amount); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Amount != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Amount); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Incr other) { + if (other == null) { + return; + } + if (other.Amount != 0) { + Amount = other.Amount; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Amount = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class Movie : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Movie()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[74]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Movie() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Movie(Movie other) : this() { + id_ = other.id_; + imdbId_ = other.imdbId_; + title_ = other.title_; + rating_ = other.rating_; + score_ = other.score_; + director_ = other.director_; + releaseDate_ = other.releaseDate_ != null ? other.releaseDate_.Clone() : null; + tagLine_ = other.tagLine_; + genres_ = other.genres_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Movie Clone() { + return new Movie(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "ImdbId" field. + public const int ImdbIdFieldNumber = 2; + private string imdbId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ImdbId { + get { return imdbId_; } + set { + imdbId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Title" field. + public const int TitleFieldNumber = 3; + private string title_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Title { + get { return title_; } + set { + title_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Rating" field. + public const int RatingFieldNumber = 4; + private string rating_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Rating { + get { return rating_; } + set { + rating_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Score" field. + public const int ScoreFieldNumber = 5; + private string score_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Score { + get { return score_; } + set { + score_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Director" field. + public const int DirectorFieldNumber = 6; + private string director_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Director { + get { return director_; } + set { + director_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ReleaseDate" field. + public const int ReleaseDateFieldNumber = 7; + private global::Google.Protobuf.WellKnownTypes.Timestamp releaseDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp ReleaseDate { + get { return releaseDate_; } + set { + releaseDate_ = value; + } + } + + /// Field number for the "TagLine" field. + public const int TagLineFieldNumber = 8; + private string tagLine_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TagLine { + get { return tagLine_; } + set { + tagLine_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Genres" field. + public const int GenresFieldNumber = 9; + private static readonly pb::FieldCodec _repeated_genres_codec + = pb::FieldCodec.ForString(74); + private readonly pbc::RepeatedField genres_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Genres { + get { return genres_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Movie); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Movie other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (ImdbId != other.ImdbId) return false; + if (Title != other.Title) return false; + if (Rating != other.Rating) return false; + if (Score != other.Score) return false; + if (Director != other.Director) return false; + if (!object.Equals(ReleaseDate, other.ReleaseDate)) return false; + if (TagLine != other.TagLine) return false; + if(!genres_.Equals(other.genres_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (ImdbId.Length != 0) hash ^= ImdbId.GetHashCode(); + if (Title.Length != 0) hash ^= Title.GetHashCode(); + if (Rating.Length != 0) hash ^= Rating.GetHashCode(); + if (Score.Length != 0) hash ^= Score.GetHashCode(); + if (Director.Length != 0) hash ^= Director.GetHashCode(); + if (releaseDate_ != null) hash ^= ReleaseDate.GetHashCode(); + if (TagLine.Length != 0) hash ^= TagLine.GetHashCode(); + hash ^= genres_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (ImdbId.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ImdbId); + } + if (Title.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Title); + } + if (Rating.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Rating); + } + if (Score.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Score); + } + if (Director.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Director); + } + if (releaseDate_ != null) { + output.WriteRawTag(58); + output.WriteMessage(ReleaseDate); + } + if (TagLine.Length != 0) { + output.WriteRawTag(66); + output.WriteString(TagLine); + } + genres_.WriteTo(output, _repeated_genres_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (ImdbId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ImdbId); + } + if (Title.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Title); + } + if (Rating.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Rating); + } + if (Score.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Score); + } + if (Director.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Director); + } + if (releaseDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ReleaseDate); + } + if (TagLine.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TagLine); + } + size += genres_.CalculateSize(_repeated_genres_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Movie other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.ImdbId.Length != 0) { + ImdbId = other.ImdbId; + } + if (other.Title.Length != 0) { + Title = other.Title; + } + if (other.Rating.Length != 0) { + Rating = other.Rating; + } + if (other.Score.Length != 0) { + Score = other.Score; + } + if (other.Director.Length != 0) { + Director = other.Director; + } + if (other.releaseDate_ != null) { + if (releaseDate_ == null) { + ReleaseDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + ReleaseDate.MergeFrom(other.ReleaseDate); + } + if (other.TagLine.Length != 0) { + TagLine = other.TagLine; + } + genres_.Add(other.genres_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + ImdbId = input.ReadString(); + break; + } + case 26: { + Title = input.ReadString(); + break; + } + case 34: { + Rating = input.ReadString(); + break; + } + case 42: { + Score = input.ReadString(); + break; + } + case 50: { + Director = input.ReadString(); + break; + } + case 58: { + if (releaseDate_ == null) { + ReleaseDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(ReleaseDate); + break; + } + case 66: { + TagLine = input.ReadString(); + break; + } + case 74: { + genres_.AddEntriesFrom(input, _repeated_genres_codec); + break; + } + } + } + } + + } + + public sealed partial class Multiply : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Multiply()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[75]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Multiply() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Multiply(Multiply other) : this() { + x_ = other.x_; + y_ = other.y_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Multiply Clone() { + return new Multiply(this); + } + + /// Field number for the "X" field. + public const int XFieldNumber = 1; + private int x_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int X { + get { return x_; } + set { + x_ = value; + } + } + + /// Field number for the "Y" field. + public const int YFieldNumber = 2; + private int y_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Y { + get { return y_; } + set { + y_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Multiply); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Multiply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (X != other.X) return false; + if (Y != other.Y) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (X != 0) hash ^= X.GetHashCode(); + if (Y != 0) hash ^= Y.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (X != 0) { + output.WriteRawTag(8); + output.WriteInt32(X); + } + if (Y != 0) { + output.WriteRawTag(16); + output.WriteInt32(Y); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (X != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(X); + } + if (Y != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Y); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Multiply other) { + if (other == null) { + return; + } + if (other.X != 0) { + X = other.X; + } + if (other.Y != 0) { + Y = other.Y; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + X = input.ReadInt32(); + break; + } + case 16: { + Y = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class MultiplyResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MultiplyResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[76]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MultiplyResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MultiplyResponse(MultiplyResponse other) : this() { + result_ = other.result_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MultiplyResponse Clone() { + return new MultiplyResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private int result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Result { + get { return result_; } + set { + result_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as MultiplyResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(MultiplyResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Result != other.Result) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Result != 0) hash ^= Result.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Result != 0) { + output.WriteRawTag(8); + output.WriteInt32(Result); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Result != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Result); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(MultiplyResponse other) { + if (other == null) { + return; + } + if (other.Result != 0) { + Result = other.Result; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Result = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class NamedRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NamedRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[77]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NamedRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NamedRockstar(NamedRockstar other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NamedRockstar Clone() { + return new NamedRockstar(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NamedRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NamedRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NamedRockstar other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class NoAbstractValidator : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NoAbstractValidator()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[78]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NoAbstractValidator() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NoAbstractValidator(NoAbstractValidator other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NoAbstractValidator Clone() { + return new NoAbstractValidator(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NoAbstractValidator); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NoAbstractValidator other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (LivingStatus != 0) { + output.WriteRawTag(40); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NoAbstractValidator other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 40: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class OnlyValidatesRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OnlyValidatesRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[79]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OnlyValidatesRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OnlyValidatesRequest(OnlyValidatesRequest other) : this() { + test_ = other.test_; + notNull_ = other.notNull_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OnlyValidatesRequest Clone() { + return new OnlyValidatesRequest(this); + } + + /// Field number for the "Test" field. + public const int TestFieldNumber = 1; + private int test_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Test { + get { return test_; } + set { + test_ = value; + } + } + + /// Field number for the "NotNull" field. + public const int NotNullFieldNumber = 2; + private string notNull_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotNull { + get { return notNull_; } + set { + notNull_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as OnlyValidatesRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(OnlyValidatesRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Test != other.Test) return false; + if (NotNull != other.NotNull) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Test != 0) hash ^= Test.GetHashCode(); + if (NotNull.Length != 0) hash ^= NotNull.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Test != 0) { + output.WriteRawTag(8); + output.WriteInt32(Test); + } + if (NotNull.Length != 0) { + output.WriteRawTag(18); + output.WriteString(NotNull); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Test != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Test); + } + if (NotNull.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotNull); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(OnlyValidatesRequest other) { + if (other == null) { + return; + } + if (other.Test != 0) { + Test = other.Test; + } + if (other.NotNull.Length != 0) { + NotNull = other.NotNull; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Test = input.ReadInt32(); + break; + } + case 18: { + NotNull = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class PagingTest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PagingTest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[80]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PagingTest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PagingTest(PagingTest other) : this() { + id_ = other.id_; + name_ = other.name_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PagingTest Clone() { + return new PagingTest(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 2; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Value" field. + public const int ValueFieldNumber = 3; + private int value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PagingTest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PagingTest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Name != other.Name) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Value != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (Name.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Name); + } + if (Value != 0) { + output.WriteRawTag(24); + output.WriteInt32(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Value != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PagingTest other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Value != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + Name = input.ReadString(); + break; + } + case 24: { + Value = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[81]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[82]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class PatchRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PatchRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[83]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstar(PatchRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstar Clone() { + return new PatchRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PatchRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PatchRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PatchRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class PatchRockstarAuditTenant : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PatchRockstarAuditTenant()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[84]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenant() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenant(PatchRockstarAuditTenant other) : this() { + bearerToken_ = other.bearerToken_; + id_ = other.id_; + firstName_ = other.firstName_; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenant Clone() { + return new PatchRockstarAuditTenant(this); + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 201; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 202; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 203; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 204; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PatchRockstarAuditTenant); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PatchRockstarAuditTenant other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BearerToken != other.BearerToken) return false; + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (BearerToken.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(BearerToken); + } + if (Id != 0) { + output.WriteRawTag(208, 12); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(218, 12); + output.WriteString(FirstName); + } + if (LivingStatus != 0) { + output.WriteRawTag(224, 12); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BearerToken.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LivingStatus != 0) { + size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PatchRockstarAuditTenant other) { + if (other == null) { + return; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 1610: { + BearerToken = input.ReadString(); + break; + } + case 1616: { + Id = input.ReadInt32(); + break; + } + case 1626: { + FirstName = input.ReadString(); + break; + } + case 1632: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class PatchRockstarAuditTenantGateway : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PatchRockstarAuditTenantGateway()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[85]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenantGateway() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenantGateway(PatchRockstarAuditTenantGateway other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenantGateway Clone() { + return new PatchRockstarAuditTenantGateway(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PatchRockstarAuditTenantGateway); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PatchRockstarAuditTenantGateway other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LivingStatus != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PatchRockstarAuditTenantGateway other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 24: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class PatchRockstarAuditTenantMq : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PatchRockstarAuditTenantMq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[86]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenantMq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenantMq(PatchRockstarAuditTenantMq other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PatchRockstarAuditTenantMq Clone() { + return new PatchRockstarAuditTenantMq(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PatchRockstarAuditTenantMq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PatchRockstarAuditTenantMq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LivingStatus != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PatchRockstarAuditTenantMq other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 24: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class PostChatToChannel : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PostChatToChannel()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[87]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PostChatToChannel() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PostChatToChannel(PostChatToChannel other) : this() { + from_ = other.from_; + toUserId_ = other.toUserId_; + channel_ = other.channel_; + message_ = other.message_; + selector_ = other.selector_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PostChatToChannel Clone() { + return new PostChatToChannel(this); + } + + /// Field number for the "From" field. + public const int FromFieldNumber = 1; + private string from_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string From { + get { return from_; } + set { + from_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ToUserId" field. + public const int ToUserIdFieldNumber = 2; + private string toUserId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ToUserId { + get { return toUserId_; } + set { + toUserId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Channel" field. + public const int ChannelFieldNumber = 3; + private string channel_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Channel { + get { return channel_; } + set { + channel_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Message" field. + public const int MessageFieldNumber = 4; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Selector" field. + public const int SelectorFieldNumber = 5; + private string selector_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Selector { + get { return selector_; } + set { + selector_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PostChatToChannel); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PostChatToChannel other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (From != other.From) return false; + if (ToUserId != other.ToUserId) return false; + if (Channel != other.Channel) return false; + if (Message != other.Message) return false; + if (Selector != other.Selector) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (From.Length != 0) hash ^= From.GetHashCode(); + if (ToUserId.Length != 0) hash ^= ToUserId.GetHashCode(); + if (Channel.Length != 0) hash ^= Channel.GetHashCode(); + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (Selector.Length != 0) hash ^= Selector.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (From.Length != 0) { + output.WriteRawTag(10); + output.WriteString(From); + } + if (ToUserId.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ToUserId); + } + if (Channel.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Channel); + } + if (Message.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Message); + } + if (Selector.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Selector); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (From.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(From); + } + if (ToUserId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ToUserId); + } + if (Channel.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Channel); + } + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (Selector.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Selector); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PostChatToChannel other) { + if (other == null) { + return; + } + if (other.From.Length != 0) { + From = other.From; + } + if (other.ToUserId.Length != 0) { + ToUserId = other.ToUserId; + } + if (other.Channel.Length != 0) { + Channel = other.Channel; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + if (other.Selector.Length != 0) { + Selector = other.Selector; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + From = input.ReadString(); + break; + } + case 18: { + ToUserId = input.ReadString(); + break; + } + case 26: { + Channel = input.ReadString(); + break; + } + case 34: { + Message = input.ReadString(); + break; + } + case 42: { + Selector = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryAdhoc : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryAdhoc()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[88]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAdhoc() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAdhoc(QueryAdhoc other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAdhoc Clone() { + return new QueryAdhoc(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryAdhoc); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryAdhoc other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryAdhoc other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryAdhocRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryAdhocRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[89]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAdhocRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAdhocRockstars(QueryAdhocRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + firstName_ = other.firstName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAdhocRockstars Clone() { + return new QueryAdhocRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "first_name" field. + public const int FirstNameFieldNumber = 201; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryAdhocRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryAdhocRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (FirstName != other.FirstName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (FirstName.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(FirstName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryAdhocRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + FirstName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryAllFields : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryAllFields()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[90]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAllFields() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAllFields(QueryAllFields other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + guid_ = other.guid_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryAllFields Clone() { + return new QueryAllFields(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Guid" field. + public const int GuidFieldNumber = 201; + private string guid_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Guid { + get { return guid_; } + set { + guid_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryAllFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryAllFields other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Guid != other.Guid) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Guid.Length != 0) hash ^= Guid.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Guid.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(Guid); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Guid.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Guid); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryAllFields other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Guid.Length != 0) { + Guid = other.Guid; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + Guid = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryBookmarks : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryBookmarks()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[91]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryBookmarks() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryBookmarks(QueryBookmarks other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryBookmarks Clone() { + return new QueryBookmarks(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryBookmarks); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryBookmarks other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryBookmarks other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryCaseInsensitiveOrderBy : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryCaseInsensitiveOrderBy()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[92]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCaseInsensitiveOrderBy() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCaseInsensitiveOrderBy(QueryCaseInsensitiveOrderBy other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCaseInsensitiveOrderBy Clone() { + return new QueryCaseInsensitiveOrderBy(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryCaseInsensitiveOrderBy); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryCaseInsensitiveOrderBy other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryCaseInsensitiveOrderBy other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryChangeConnectionInfo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryChangeConnectionInfo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[93]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryChangeConnectionInfo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryChangeConnectionInfo(QueryChangeConnectionInfo other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryChangeConnectionInfo Clone() { + return new QueryChangeConnectionInfo(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryChangeConnectionInfo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryChangeConnectionInfo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryChangeConnectionInfo other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryChangeDb : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryChangeDb()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[94]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryChangeDb() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryChangeDb(QueryChangeDb other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + namedConnection_ = other.namedConnection_; + connectionString_ = other.connectionString_; + providerName_ = other.providerName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryChangeDb Clone() { + return new QueryChangeDb(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "NamedConnection" field. + public const int NamedConnectionFieldNumber = 201; + private string namedConnection_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NamedConnection { + get { return namedConnection_; } + set { + namedConnection_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ConnectionString" field. + public const int ConnectionStringFieldNumber = 202; + private string connectionString_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ConnectionString { + get { return connectionString_; } + set { + connectionString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ProviderName" field. + public const int ProviderNameFieldNumber = 203; + private string providerName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ProviderName { + get { return providerName_; } + set { + providerName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryChangeDb); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryChangeDb other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (NamedConnection != other.NamedConnection) return false; + if (ConnectionString != other.ConnectionString) return false; + if (ProviderName != other.ProviderName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (NamedConnection.Length != 0) hash ^= NamedConnection.GetHashCode(); + if (ConnectionString.Length != 0) hash ^= ConnectionString.GetHashCode(); + if (ProviderName.Length != 0) hash ^= ProviderName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (NamedConnection.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(NamedConnection); + } + if (ConnectionString.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(ConnectionString); + } + if (ProviderName.Length != 0) { + output.WriteRawTag(218, 12); + output.WriteString(ProviderName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (NamedConnection.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(NamedConnection); + } + if (ConnectionString.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(ConnectionString); + } + if (ProviderName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(ProviderName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryChangeDb other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.NamedConnection.Length != 0) { + NamedConnection = other.NamedConnection; + } + if (other.ConnectionString.Length != 0) { + ConnectionString = other.ConnectionString; + } + if (other.ProviderName.Length != 0) { + ProviderName = other.ProviderName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + NamedConnection = input.ReadString(); + break; + } + case 1618: { + ConnectionString = input.ReadString(); + break; + } + case 1626: { + ProviderName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryCustomRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryCustomRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[95]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstars(QueryCustomRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstars Clone() { + return new QueryCustomRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryCustomRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryCustomRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryCustomRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryCustomRockstarsFilter : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryCustomRockstarsFilter()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[96]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsFilter() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsFilter(QueryCustomRockstarsFilter other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsFilter Clone() { + return new QueryCustomRockstarsFilter(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryCustomRockstarsFilter); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryCustomRockstarsFilter other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryCustomRockstarsFilter other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryCustomRockstarsReferences : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryCustomRockstarsReferences()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[97]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsReferences() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsReferences(QueryCustomRockstarsReferences other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsReferences Clone() { + return new QueryCustomRockstarsReferences(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryCustomRockstarsReferences); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryCustomRockstarsReferences other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryCustomRockstarsReferences other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryCustomRockstarsSchema : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryCustomRockstarsSchema()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[98]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsSchema() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsSchema(QueryCustomRockstarsSchema other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryCustomRockstarsSchema Clone() { + return new QueryCustomRockstarsSchema(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryCustomRockstarsSchema); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryCustomRockstarsSchema other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryCustomRockstarsSchema other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryDbTenant_RockstarAuditTenant_RockstarAuto : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryDbTenant_RockstarAuditTenant_RockstarAuto()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[99]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryDbTenant_RockstarAuditTenant_RockstarAuto() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryDbTenant_RockstarAuditTenant_RockstarAuto(QueryDbTenant_RockstarAuditTenant_RockstarAuto other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryDbTenant_RockstarAuditTenant_RockstarAuto Clone() { + return new QueryDbTenant_RockstarAuditTenant_RockstarAuto(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryDbTenant_RockstarAuditTenant_RockstarAuto); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryDbTenant_RockstarAuditTenant_RockstarAuto other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryDbTenant_RockstarAuditTenant_RockstarAuto other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class QueryFieldRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryFieldRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[100]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldRockstars(QueryFieldRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + firstName_ = other.firstName_; + firstNames_ = other.firstNames_.Clone(); + age_ = other.age_; + firstNameCaseInsensitive_ = other.firstNameCaseInsensitive_; + firstNameStartsWith_ = other.firstNameStartsWith_; + lastNameEndsWith_ = other.lastNameEndsWith_; + firstNameBetween_ = other.firstNameBetween_.Clone(); + orLastName_ = other.orLastName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldRockstars Clone() { + return new QueryFieldRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 201; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FirstNames" field. + public const int FirstNamesFieldNumber = 202; + private static readonly pb::FieldCodec _repeated_firstNames_codec + = pb::FieldCodec.ForString(1618); + private readonly pbc::RepeatedField firstNames_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField FirstNames { + get { return firstNames_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 203; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "FirstNameCaseInsensitive" field. + public const int FirstNameCaseInsensitiveFieldNumber = 204; + private string firstNameCaseInsensitive_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstNameCaseInsensitive { + get { return firstNameCaseInsensitive_; } + set { + firstNameCaseInsensitive_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FirstNameStartsWith" field. + public const int FirstNameStartsWithFieldNumber = 205; + private string firstNameStartsWith_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstNameStartsWith { + get { return firstNameStartsWith_; } + set { + firstNameStartsWith_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastNameEndsWith" field. + public const int LastNameEndsWithFieldNumber = 206; + private string lastNameEndsWith_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastNameEndsWith { + get { return lastNameEndsWith_; } + set { + lastNameEndsWith_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FirstNameBetween" field. + public const int FirstNameBetweenFieldNumber = 207; + private static readonly pb::FieldCodec _repeated_firstNameBetween_codec + = pb::FieldCodec.ForString(1658); + private readonly pbc::RepeatedField firstNameBetween_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField FirstNameBetween { + get { return firstNameBetween_; } + } + + /// Field number for the "OrLastName" field. + public const int OrLastNameFieldNumber = 208; + private string orLastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrLastName { + get { return orLastName_; } + set { + orLastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryFieldRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryFieldRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (FirstName != other.FirstName) return false; + if(!firstNames_.Equals(other.firstNames_)) return false; + if (Age != other.Age) return false; + if (FirstNameCaseInsensitive != other.FirstNameCaseInsensitive) return false; + if (FirstNameStartsWith != other.FirstNameStartsWith) return false; + if (LastNameEndsWith != other.LastNameEndsWith) return false; + if(!firstNameBetween_.Equals(other.firstNameBetween_)) return false; + if (OrLastName != other.OrLastName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + hash ^= firstNames_.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (FirstNameCaseInsensitive.Length != 0) hash ^= FirstNameCaseInsensitive.GetHashCode(); + if (FirstNameStartsWith.Length != 0) hash ^= FirstNameStartsWith.GetHashCode(); + if (LastNameEndsWith.Length != 0) hash ^= LastNameEndsWith.GetHashCode(); + hash ^= firstNameBetween_.GetHashCode(); + if (OrLastName.Length != 0) hash ^= OrLastName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (FirstName.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(FirstName); + } + firstNames_.WriteTo(output, _repeated_firstNames_codec); + if (Age != 0) { + output.WriteRawTag(216, 12); + output.WriteInt32(Age); + } + if (FirstNameCaseInsensitive.Length != 0) { + output.WriteRawTag(226, 12); + output.WriteString(FirstNameCaseInsensitive); + } + if (FirstNameStartsWith.Length != 0) { + output.WriteRawTag(234, 12); + output.WriteString(FirstNameStartsWith); + } + if (LastNameEndsWith.Length != 0) { + output.WriteRawTag(242, 12); + output.WriteString(LastNameEndsWith); + } + firstNameBetween_.WriteTo(output, _repeated_firstNameBetween_codec); + if (OrLastName.Length != 0) { + output.WriteRawTag(130, 13); + output.WriteString(OrLastName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + size += firstNames_.CalculateSize(_repeated_firstNames_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (FirstNameCaseInsensitive.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstNameCaseInsensitive); + } + if (FirstNameStartsWith.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstNameStartsWith); + } + if (LastNameEndsWith.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(LastNameEndsWith); + } + size += firstNameBetween_.CalculateSize(_repeated_firstNameBetween_codec); + if (OrLastName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(OrLastName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryFieldRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + firstNames_.Add(other.firstNames_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.FirstNameCaseInsensitive.Length != 0) { + FirstNameCaseInsensitive = other.FirstNameCaseInsensitive; + } + if (other.FirstNameStartsWith.Length != 0) { + FirstNameStartsWith = other.FirstNameStartsWith; + } + if (other.LastNameEndsWith.Length != 0) { + LastNameEndsWith = other.LastNameEndsWith; + } + firstNameBetween_.Add(other.firstNameBetween_); + if (other.OrLastName.Length != 0) { + OrLastName = other.OrLastName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + FirstName = input.ReadString(); + break; + } + case 1618: { + firstNames_.AddEntriesFrom(input, _repeated_firstNames_codec); + break; + } + case 1624: { + Age = input.ReadInt32(); + break; + } + case 1634: { + FirstNameCaseInsensitive = input.ReadString(); + break; + } + case 1642: { + FirstNameStartsWith = input.ReadString(); + break; + } + case 1650: { + LastNameEndsWith = input.ReadString(); + break; + } + case 1658: { + firstNameBetween_.AddEntriesFrom(input, _repeated_firstNameBetween_codec); + break; + } + case 1666: { + OrLastName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryFieldRockstarsDynamic : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryFieldRockstarsDynamic()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[101]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldRockstarsDynamic() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldRockstarsDynamic(QueryFieldRockstarsDynamic other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldRockstarsDynamic Clone() { + return new QueryFieldRockstarsDynamic(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryFieldRockstarsDynamic); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryFieldRockstarsDynamic other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryFieldRockstarsDynamic other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryFieldsImplicitConventions : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryFieldsImplicitConventions()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[102]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldsImplicitConventions() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldsImplicitConventions(QueryFieldsImplicitConventions other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + firstNameContains_ = other.firstNameContains_; + lastNameEndsWith_ = other.lastNameEndsWith_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFieldsImplicitConventions Clone() { + return new QueryFieldsImplicitConventions(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "FirstNameContains" field. + public const int FirstNameContainsFieldNumber = 201; + private string firstNameContains_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstNameContains { + get { return firstNameContains_; } + set { + firstNameContains_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastNameEndsWith" field. + public const int LastNameEndsWithFieldNumber = 202; + private string lastNameEndsWith_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastNameEndsWith { + get { return lastNameEndsWith_; } + set { + lastNameEndsWith_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryFieldsImplicitConventions); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryFieldsImplicitConventions other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (FirstNameContains != other.FirstNameContains) return false; + if (LastNameEndsWith != other.LastNameEndsWith) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (FirstNameContains.Length != 0) hash ^= FirstNameContains.GetHashCode(); + if (LastNameEndsWith.Length != 0) hash ^= LastNameEndsWith.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (FirstNameContains.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(FirstNameContains); + } + if (LastNameEndsWith.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(LastNameEndsWith); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (FirstNameContains.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstNameContains); + } + if (LastNameEndsWith.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(LastNameEndsWith); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryFieldsImplicitConventions other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.FirstNameContains.Length != 0) { + FirstNameContains = other.FirstNameContains; + } + if (other.LastNameEndsWith.Length != 0) { + LastNameEndsWith = other.LastNameEndsWith; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + FirstNameContains = input.ReadString(); + break; + } + case 1618: { + LastNameEndsWith = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryFoos : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryFoos()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[103]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFoos() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFoos(QueryFoos other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + x_ = other.x_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryFoos Clone() { + return new QueryFoos(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "X" field. + public const int XFieldNumber = 201; + private string x_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string X { + get { return x_; } + set { + x_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryFoos); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryFoos other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (X != other.X) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (X.Length != 0) hash ^= X.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (X.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(X); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (X.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(X); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryFoos other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.X.Length != 0) { + X = other.X; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + X = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryGetRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryGetRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[104]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryGetRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryGetRockstars(QueryGetRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + ids_ = other.ids_.Clone(); + ages_ = other.ages_.Clone(); + firstNames_ = other.firstNames_.Clone(); + idsBetween_ = other.idsBetween_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryGetRockstars Clone() { + return new QueryGetRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Ids" field. + public const int IdsFieldNumber = 201; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForInt32(1608); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + /// Field number for the "Ages" field. + public const int AgesFieldNumber = 202; + private static readonly pb::FieldCodec _repeated_ages_codec + = pb::FieldCodec.ForInt32(1616); + private readonly pbc::RepeatedField ages_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ages { + get { return ages_; } + } + + /// Field number for the "FirstNames" field. + public const int FirstNamesFieldNumber = 203; + private static readonly pb::FieldCodec _repeated_firstNames_codec + = pb::FieldCodec.ForString(1626); + private readonly pbc::RepeatedField firstNames_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField FirstNames { + get { return firstNames_; } + } + + /// Field number for the "IdsBetween" field. + public const int IdsBetweenFieldNumber = 204; + private static readonly pb::FieldCodec _repeated_idsBetween_codec + = pb::FieldCodec.ForInt32(1632); + private readonly pbc::RepeatedField idsBetween_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField IdsBetween { + get { return idsBetween_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryGetRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryGetRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if(!ids_.Equals(other.ids_)) return false; + if(!ages_.Equals(other.ages_)) return false; + if(!firstNames_.Equals(other.firstNames_)) return false; + if(!idsBetween_.Equals(other.idsBetween_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + hash ^= ids_.GetHashCode(); + hash ^= ages_.GetHashCode(); + hash ^= firstNames_.GetHashCode(); + hash ^= idsBetween_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + ids_.WriteTo(output, _repeated_ids_codec); + ages_.WriteTo(output, _repeated_ages_codec); + firstNames_.WriteTo(output, _repeated_firstNames_codec); + idsBetween_.WriteTo(output, _repeated_idsBetween_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + size += ids_.CalculateSize(_repeated_ids_codec); + size += ages_.CalculateSize(_repeated_ages_codec); + size += firstNames_.CalculateSize(_repeated_firstNames_codec); + size += idsBetween_.CalculateSize(_repeated_idsBetween_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryGetRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + ids_.Add(other.ids_); + ages_.Add(other.ages_); + firstNames_.Add(other.firstNames_); + idsBetween_.Add(other.idsBetween_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: + case 1608: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + case 1618: + case 1616: { + ages_.AddEntriesFrom(input, _repeated_ages_codec); + break; + } + case 1626: { + firstNames_.AddEntriesFrom(input, _repeated_firstNames_codec); + break; + } + case 1634: + case 1632: { + idsBetween_.AddEntriesFrom(input, _repeated_idsBetween_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryGetRockstarsDynamic : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryGetRockstarsDynamic()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[105]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryGetRockstarsDynamic() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryGetRockstarsDynamic(QueryGetRockstarsDynamic other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryGetRockstarsDynamic Clone() { + return new QueryGetRockstarsDynamic(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryGetRockstarsDynamic); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryGetRockstarsDynamic other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryGetRockstarsDynamic other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryJoinedRockstarAlbums : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryJoinedRockstarAlbums()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[106]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbums() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbums(QueryJoinedRockstarAlbums other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbums Clone() { + return new QueryJoinedRockstarAlbums(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 202; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryJoinedRockstarAlbums); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryJoinedRockstarAlbums other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(RockstarAlbumName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryJoinedRockstarAlbums other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + RockstarAlbumName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryJoinedRockstarAlbumsCustomSelect : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryJoinedRockstarAlbumsCustomSelect()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[107]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbumsCustomSelect() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbumsCustomSelect(QueryJoinedRockstarAlbumsCustomSelect other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbumsCustomSelect Clone() { + return new QueryJoinedRockstarAlbumsCustomSelect(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 202; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryJoinedRockstarAlbumsCustomSelect); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryJoinedRockstarAlbumsCustomSelect other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(RockstarAlbumName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryJoinedRockstarAlbumsCustomSelect other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + RockstarAlbumName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryJoinedRockstarAlbumsCustomSelectResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryJoinedRockstarAlbumsCustomSelectResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[108]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbumsCustomSelectResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbumsCustomSelectResponse(QueryJoinedRockstarAlbumsCustomSelectResponse other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryJoinedRockstarAlbumsCustomSelectResponse Clone() { + return new QueryJoinedRockstarAlbumsCustomSelectResponse(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 202; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryJoinedRockstarAlbumsCustomSelectResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryJoinedRockstarAlbumsCustomSelectResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(RockstarAlbumName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryJoinedRockstarAlbumsCustomSelectResponse other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + RockstarAlbumName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryMovies : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryMovies()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[109]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryMovies() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryMovies(QueryMovies other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + ids_ = other.ids_.Clone(); + imdbIds_ = other.imdbIds_.Clone(); + ratings_ = other.ratings_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryMovies Clone() { + return new QueryMovies(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Ids" field. + public const int IdsFieldNumber = 201; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForInt32(1608); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + /// Field number for the "ImdbIds" field. + public const int ImdbIdsFieldNumber = 202; + private static readonly pb::FieldCodec _repeated_imdbIds_codec + = pb::FieldCodec.ForString(1618); + private readonly pbc::RepeatedField imdbIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField ImdbIds { + get { return imdbIds_; } + } + + /// Field number for the "Ratings" field. + public const int RatingsFieldNumber = 203; + private static readonly pb::FieldCodec _repeated_ratings_codec + = pb::FieldCodec.ForString(1626); + private readonly pbc::RepeatedField ratings_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ratings { + get { return ratings_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryMovies); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryMovies other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if(!ids_.Equals(other.ids_)) return false; + if(!imdbIds_.Equals(other.imdbIds_)) return false; + if(!ratings_.Equals(other.ratings_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + hash ^= ids_.GetHashCode(); + hash ^= imdbIds_.GetHashCode(); + hash ^= ratings_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + ids_.WriteTo(output, _repeated_ids_codec); + imdbIds_.WriteTo(output, _repeated_imdbIds_codec); + ratings_.WriteTo(output, _repeated_ratings_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + size += ids_.CalculateSize(_repeated_ids_codec); + size += imdbIds_.CalculateSize(_repeated_imdbIds_codec); + size += ratings_.CalculateSize(_repeated_ratings_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryMovies other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + ids_.Add(other.ids_); + imdbIds_.Add(other.imdbIds_); + ratings_.Add(other.ratings_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: + case 1608: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + case 1618: { + imdbIds_.AddEntriesFrom(input, _repeated_imdbIds_codec); + break; + } + case 1626: { + ratings_.AddEntriesFrom(input, _repeated_ratings_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryMultiJoinRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryMultiJoinRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[110]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryMultiJoinRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryMultiJoinRockstar(QueryMultiJoinRockstar other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + rockstarGenreName_ = other.rockstarGenreName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryMultiJoinRockstar Clone() { + return new QueryMultiJoinRockstar(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 202; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RockstarGenreName" field. + public const int RockstarGenreNameFieldNumber = 203; + private string rockstarGenreName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarGenreName { + get { return rockstarGenreName_; } + set { + rockstarGenreName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryMultiJoinRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryMultiJoinRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + if (RockstarGenreName != other.RockstarGenreName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (RockstarGenreName.Length != 0) hash ^= RockstarGenreName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(RockstarAlbumName); + } + if (RockstarGenreName.Length != 0) { + output.WriteRawTag(218, 12); + output.WriteString(RockstarGenreName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (RockstarGenreName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarGenreName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryMultiJoinRockstar other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + if (other.RockstarGenreName.Length != 0) { + RockstarGenreName = other.RockstarGenreName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + RockstarAlbumName = input.ReadString(); + break; + } + case 1626: { + RockstarGenreName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryNamedRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryNamedRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[111]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryNamedRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryNamedRockstars(QueryNamedRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryNamedRockstars Clone() { + return new QueryNamedRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryNamedRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryNamedRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryNamedRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryOrRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryOrRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[112]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOrRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOrRockstars(QueryOrRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + firstName_ = other.firstName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOrRockstars Clone() { + return new QueryOrRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 202; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryOrRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryOrRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (FirstName != other.FirstName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (FirstName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(FirstName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryOrRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + FirstName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryOrRockstarsFields : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryOrRockstarsFields()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[113]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOrRockstarsFields() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOrRockstarsFields(QueryOrRockstarsFields other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + firstName_ = other.firstName_; + lastName_ = other.lastName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOrRockstarsFields Clone() { + return new QueryOrRockstarsFields(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 201; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 202; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryOrRockstarsFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryOrRockstarsFields other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (FirstName.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(LastName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryOrRockstarsFields other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + FirstName = input.ReadString(); + break; + } + case 1618: { + LastName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryOverridedCustomRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryOverridedCustomRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[114]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOverridedCustomRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOverridedCustomRockstars(QueryOverridedCustomRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOverridedCustomRockstars Clone() { + return new QueryOverridedCustomRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryOverridedCustomRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryOverridedCustomRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryOverridedCustomRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryOverridedRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryOverridedRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[115]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOverridedRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOverridedRockstars(QueryOverridedRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryOverridedRockstars Clone() { + return new QueryOverridedRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryOverridedRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryOverridedRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryOverridedRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryPagingTest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryPagingTest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[116]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryPagingTest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryPagingTest(QueryPagingTest other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + id_ = other.id_; + name_ = other.name_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryPagingTest Clone() { + return new QueryPagingTest(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 201; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 202; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Value" field. + public const int ValueFieldNumber = 203; + private int value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryPagingTest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryPagingTest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Id != other.Id) return false; + if (Name != other.Name) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Value != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Id != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Id); + } + if (Name.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(Name); + } + if (Value != 0) { + output.WriteRawTag(216, 12); + output.WriteInt32(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (Name.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Value != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryPagingTest other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Id != 0) { + Id = other.Id; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Value != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Id = input.ReadInt32(); + break; + } + case 1618: { + Name = input.ReadString(); + break; + } + case 1624: { + Value = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_Adhoc : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_Adhoc()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[117]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Adhoc() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Adhoc(QueryResponse_Adhoc other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Adhoc Clone() { + return new QueryResponse_Adhoc(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.Adhoc.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_Adhoc); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_Adhoc other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_Adhoc other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_AllFields : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_AllFields()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[118]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_AllFields() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_AllFields(QueryResponse_AllFields other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_AllFields Clone() { + return new QueryResponse_AllFields(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.AllFields.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_AllFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_AllFields other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_AllFields other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_Bookmark : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_Bookmark()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[119]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Bookmark() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Bookmark(QueryResponse_Bookmark other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Bookmark Clone() { + return new QueryResponse_Bookmark(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.DaoBase.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_Bookmark); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_Bookmark other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_Bookmark other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_CustomRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_CustomRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[120]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomRockstar(QueryResponse_CustomRockstar other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomRockstar Clone() { + return new QueryResponse_CustomRockstar(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.CustomRockstar.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_CustomRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_CustomRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_CustomRockstar other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_CustomRockstarSchema : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_CustomRockstarSchema()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[121]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomRockstarSchema() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomRockstarSchema(QueryResponse_CustomRockstarSchema other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomRockstarSchema Clone() { + return new QueryResponse_CustomRockstarSchema(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.CustomRockstarSchema.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_CustomRockstarSchema); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_CustomRockstarSchema other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_CustomRockstarSchema other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_CustomSelectRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_CustomSelectRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[122]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomSelectRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomSelectRockstar(QueryResponse_CustomSelectRockstar other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomSelectRockstar Clone() { + return new QueryResponse_CustomSelectRockstar(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.CustomSelectRockstar.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_CustomSelectRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_CustomSelectRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_CustomSelectRockstar other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_CustomSelectRockstarResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_CustomSelectRockstarResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[123]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomSelectRockstarResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomSelectRockstarResponse(QueryResponse_CustomSelectRockstarResponse other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_CustomSelectRockstarResponse Clone() { + return new QueryResponse_CustomSelectRockstarResponse(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.CustomSelectRockstarResponse.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_CustomSelectRockstarResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_CustomSelectRockstarResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_CustomSelectRockstarResponse other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_Foo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_Foo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[124]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Foo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Foo(QueryResponse_Foo other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Foo Clone() { + return new QueryResponse_Foo(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.Foo.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_Foo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_Foo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_Foo other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_Movie : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_Movie()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[125]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Movie() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Movie(QueryResponse_Movie other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Movie Clone() { + return new QueryResponse_Movie(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.Movie.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_Movie); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_Movie other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_Movie other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_NamedRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_NamedRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[126]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_NamedRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_NamedRockstar(QueryResponse_NamedRockstar other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_NamedRockstar Clone() { + return new QueryResponse_NamedRockstar(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.Rockstar.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_NamedRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_NamedRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_NamedRockstar other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_PagingTest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_PagingTest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[127]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_PagingTest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_PagingTest(QueryResponse_PagingTest other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_PagingTest Clone() { + return new QueryResponse_PagingTest(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.PagingTest.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_PagingTest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_PagingTest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_PagingTest other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_Rockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_Rockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[128]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Rockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Rockstar(QueryResponse_Rockstar other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_Rockstar Clone() { + return new QueryResponse_Rockstar(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.Rockstar.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_Rockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_Rockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_Rockstar other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_RockstarAlbum : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_RockstarAlbum()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[129]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAlbum() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAlbum(QueryResponse_RockstarAlbum other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAlbum Clone() { + return new QueryResponse_RockstarAlbum(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.RockstarAlbum.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_RockstarAlbum); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_RockstarAlbum other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_RockstarAlbum other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_RockstarAlias : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_RockstarAlias()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[130]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAlias() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAlias(QueryResponse_RockstarAlias other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAlias Clone() { + return new QueryResponse_RockstarAlias(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.RockstarAlias.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_RockstarAlias); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_RockstarAlias other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_RockstarAlias other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_RockstarAuto : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_RockstarAuto()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[131]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAuto() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAuto(QueryResponse_RockstarAuto other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarAuto Clone() { + return new QueryResponse_RockstarAuto(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.RockstarBase.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_RockstarAuto); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_RockstarAuto other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_RockstarAuto other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_RockstarReference : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_RockstarReference()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[132]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarReference() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarReference(QueryResponse_RockstarReference other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_RockstarReference Clone() { + return new QueryResponse_RockstarReference(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.RockstarReference.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_RockstarReference); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_RockstarReference other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_RockstarReference other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryResponse_TypeWithEnum : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryResponse_TypeWithEnum()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[133]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_TypeWithEnum() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_TypeWithEnum(QueryResponse_TypeWithEnum other) : this() { + offset_ = other.offset_; + total_ = other.total_; + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryResponse_TypeWithEnum Clone() { + return new QueryResponse_TypeWithEnum(this); + } + + /// Field number for the "Offset" field. + public const int OffsetFieldNumber = 1; + private int offset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Offset { + get { return offset_; } + set { + offset_ = value; + } + } + + /// Field number for the "Total" field. + public const int TotalFieldNumber = 2; + private int total_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Total { + get { return total_; } + set { + total_ = value; + } + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(26, global::ServiceStack.Extensions.Tests.Protoc.TypeWithEnum.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryResponse_TypeWithEnum); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryResponse_TypeWithEnum other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Offset != other.Offset) return false; + if (Total != other.Total) return false; + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Offset != 0) hash ^= Offset.GetHashCode(); + if (Total != 0) hash ^= Total.GetHashCode(); + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Offset != 0) { + output.WriteRawTag(8); + output.WriteInt32(Offset); + } + if (Total != 0) { + output.WriteRawTag(16); + output.WriteInt32(Total); + } + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Offset != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Offset); + } + if (Total != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Total); + } + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryResponse_TypeWithEnum other) { + if (other == null) { + return; + } + if (other.Offset != 0) { + Offset = other.Offset; + } + if (other.Total != 0) { + Total = other.Total; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Offset = input.ReadInt32(); + break; + } + case 16: { + Total = input.ReadInt32(); + break; + } + case 26: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 42: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAlbums : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAlbums()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[134]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbums() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbums(QueryRockstarAlbums other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + id_ = other.id_; + rockstarId_ = other.rockstarId_; + name_ = other.name_; + genre_ = other.genre_; + idBetween_ = other.idBetween_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbums Clone() { + return new QueryRockstarAlbums(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 201; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "RockstarId" field. + public const int RockstarIdFieldNumber = 202; + private int rockstarId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int RockstarId { + get { return rockstarId_; } + set { + rockstarId_ = value; + } + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 203; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Genre" field. + public const int GenreFieldNumber = 204; + private string genre_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Genre { + get { return genre_; } + set { + genre_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "IdBetween" field. + public const int IdBetweenFieldNumber = 205; + private static readonly pb::FieldCodec _repeated_idBetween_codec + = pb::FieldCodec.ForInt32(1640); + private readonly pbc::RepeatedField idBetween_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField IdBetween { + get { return idBetween_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAlbums); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAlbums other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Id != other.Id) return false; + if (RockstarId != other.RockstarId) return false; + if (Name != other.Name) return false; + if (Genre != other.Genre) return false; + if(!idBetween_.Equals(other.idBetween_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (RockstarId != 0) hash ^= RockstarId.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Genre.Length != 0) hash ^= Genre.GetHashCode(); + hash ^= idBetween_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Id != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Id); + } + if (RockstarId != 0) { + output.WriteRawTag(208, 12); + output.WriteInt32(RockstarId); + } + if (Name.Length != 0) { + output.WriteRawTag(218, 12); + output.WriteString(Name); + } + if (Genre.Length != 0) { + output.WriteRawTag(226, 12); + output.WriteString(Genre); + } + idBetween_.WriteTo(output, _repeated_idBetween_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (RockstarId != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(RockstarId); + } + if (Name.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Genre.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Genre); + } + size += idBetween_.CalculateSize(_repeated_idBetween_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAlbums other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Id != 0) { + Id = other.Id; + } + if (other.RockstarId != 0) { + RockstarId = other.RockstarId; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Genre.Length != 0) { + Genre = other.Genre; + } + idBetween_.Add(other.idBetween_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Id = input.ReadInt32(); + break; + } + case 1616: { + RockstarId = input.ReadInt32(); + break; + } + case 1626: { + Name = input.ReadString(); + break; + } + case 1634: { + Genre = input.ReadString(); + break; + } + case 1642: + case 1640: { + idBetween_.AddEntriesFrom(input, _repeated_idBetween_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAlbumsCustomLeftJoin : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAlbumsCustomLeftJoin()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[135]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsCustomLeftJoin() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsCustomLeftJoin(QueryRockstarAlbumsCustomLeftJoin other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + albumName_ = other.albumName_; + idNotEqualTo_ = other.idNotEqualTo_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsCustomLeftJoin Clone() { + return new QueryRockstarAlbumsCustomLeftJoin(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "AlbumName" field. + public const int AlbumNameFieldNumber = 202; + private string albumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AlbumName { + get { return albumName_; } + set { + albumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "IdNotEqualTo" field. + public const int IdNotEqualToFieldNumber = 203; + private int idNotEqualTo_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int IdNotEqualTo { + get { return idNotEqualTo_; } + set { + idNotEqualTo_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAlbumsCustomLeftJoin); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAlbumsCustomLeftJoin other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (AlbumName != other.AlbumName) return false; + if (IdNotEqualTo != other.IdNotEqualTo) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (AlbumName.Length != 0) hash ^= AlbumName.GetHashCode(); + if (IdNotEqualTo != 0) hash ^= IdNotEqualTo.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (AlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(AlbumName); + } + if (IdNotEqualTo != 0) { + output.WriteRawTag(216, 12); + output.WriteInt32(IdNotEqualTo); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (AlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(AlbumName); + } + if (IdNotEqualTo != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(IdNotEqualTo); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAlbumsCustomLeftJoin other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.AlbumName.Length != 0) { + AlbumName = other.AlbumName; + } + if (other.IdNotEqualTo != 0) { + IdNotEqualTo = other.IdNotEqualTo; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + AlbumName = input.ReadString(); + break; + } + case 1624: { + IdNotEqualTo = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAlbumsImplicit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAlbumsImplicit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[136]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsImplicit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsImplicit(QueryRockstarAlbumsImplicit other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsImplicit Clone() { + return new QueryRockstarAlbumsImplicit(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAlbumsImplicit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAlbumsImplicit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAlbumsImplicit other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAlbumsLeftJoin : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAlbumsLeftJoin()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[137]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsLeftJoin() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsLeftJoin(QueryRockstarAlbumsLeftJoin other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + albumName_ = other.albumName_; + idNotEqualTo_ = other.idNotEqualTo_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlbumsLeftJoin Clone() { + return new QueryRockstarAlbumsLeftJoin(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "AlbumName" field. + public const int AlbumNameFieldNumber = 202; + private string albumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AlbumName { + get { return albumName_; } + set { + albumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "IdNotEqualTo" field. + public const int IdNotEqualToFieldNumber = 203; + private int idNotEqualTo_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int IdNotEqualTo { + get { return idNotEqualTo_; } + set { + idNotEqualTo_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAlbumsLeftJoin); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAlbumsLeftJoin other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (AlbumName != other.AlbumName) return false; + if (IdNotEqualTo != other.IdNotEqualTo) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (AlbumName.Length != 0) hash ^= AlbumName.GetHashCode(); + if (IdNotEqualTo != 0) hash ^= IdNotEqualTo.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (AlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(AlbumName); + } + if (IdNotEqualTo != 0) { + output.WriteRawTag(216, 12); + output.WriteInt32(IdNotEqualTo); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (AlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(AlbumName); + } + if (IdNotEqualTo != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(IdNotEqualTo); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAlbumsLeftJoin other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.AlbumName.Length != 0) { + AlbumName = other.AlbumName; + } + if (other.IdNotEqualTo != 0) { + IdNotEqualTo = other.IdNotEqualTo; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + AlbumName = input.ReadString(); + break; + } + case 1624: { + IdNotEqualTo = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAlias : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAlias()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[138]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlias() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlias(QueryRockstarAlias other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + rockstarAlbumName_ = other.rockstarAlbumName_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAlias Clone() { + return new QueryRockstarAlias(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "RockstarAlbumName" field. + public const int RockstarAlbumNameFieldNumber = 202; + private string rockstarAlbumName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumName { + get { return rockstarAlbumName_; } + set { + rockstarAlbumName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAlias); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAlias other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + if (RockstarAlbumName != other.RockstarAlbumName) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (RockstarAlbumName.Length != 0) hash ^= RockstarAlbumName.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (RockstarAlbumName.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(RockstarAlbumName); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (RockstarAlbumName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumName); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAlias other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + if (other.RockstarAlbumName.Length != 0) { + RockstarAlbumName = other.RockstarAlbumName; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + case 1618: { + RockstarAlbumName = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAudit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAudit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[139]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAudit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAudit(QueryRockstarAudit other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAudit Clone() { + return new QueryRockstarAudit(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 301; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAudit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAudit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Id != 0) { + output.WriteRawTag(232, 18); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAudit other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 2408: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarAuditSubOr : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarAuditSubOr()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[140]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAuditSubOr() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAuditSubOr(QueryRockstarAuditSubOr other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + firstNameStartsWith_ = other.firstNameStartsWith_; + ageOlderThan_ = other.ageOlderThan_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarAuditSubOr Clone() { + return new QueryRockstarAuditSubOr(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "FirstNameStartsWith" field. + public const int FirstNameStartsWithFieldNumber = 201; + private string firstNameStartsWith_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstNameStartsWith { + get { return firstNameStartsWith_; } + set { + firstNameStartsWith_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "AgeOlderThan" field. + public const int AgeOlderThanFieldNumber = 202; + private int ageOlderThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int AgeOlderThan { + get { return ageOlderThan_; } + set { + ageOlderThan_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarAuditSubOr); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarAuditSubOr other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (FirstNameStartsWith != other.FirstNameStartsWith) return false; + if (AgeOlderThan != other.AgeOlderThan) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (FirstNameStartsWith.Length != 0) hash ^= FirstNameStartsWith.GetHashCode(); + if (AgeOlderThan != 0) hash ^= AgeOlderThan.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (FirstNameStartsWith.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(FirstNameStartsWith); + } + if (AgeOlderThan != 0) { + output.WriteRawTag(208, 12); + output.WriteInt32(AgeOlderThan); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (FirstNameStartsWith.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstNameStartsWith); + } + if (AgeOlderThan != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(AgeOlderThan); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarAuditSubOr other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.FirstNameStartsWith.Length != 0) { + FirstNameStartsWith = other.FirstNameStartsWith; + } + if (other.AgeOlderThan != 0) { + AgeOlderThan = other.AgeOlderThan; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + FirstNameStartsWith = input.ReadString(); + break; + } + case 1616: { + AgeOlderThan = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarFilters : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarFilters()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[141]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarFilters() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarFilters(QueryRockstarFilters other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + ids_ = other.ids_.Clone(); + ages_ = other.ages_.Clone(); + firstNames_ = other.firstNames_.Clone(); + idsBetween_ = other.idsBetween_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarFilters Clone() { + return new QueryRockstarFilters(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Ids" field. + public const int IdsFieldNumber = 201; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForInt32(1608); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + /// Field number for the "Ages" field. + public const int AgesFieldNumber = 202; + private static readonly pb::FieldCodec _repeated_ages_codec + = pb::FieldCodec.ForInt32(1616); + private readonly pbc::RepeatedField ages_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ages { + get { return ages_; } + } + + /// Field number for the "FirstNames" field. + public const int FirstNamesFieldNumber = 203; + private static readonly pb::FieldCodec _repeated_firstNames_codec + = pb::FieldCodec.ForString(1626); + private readonly pbc::RepeatedField firstNames_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField FirstNames { + get { return firstNames_; } + } + + /// Field number for the "IdsBetween" field. + public const int IdsBetweenFieldNumber = 204; + private static readonly pb::FieldCodec _repeated_idsBetween_codec + = pb::FieldCodec.ForInt32(1632); + private readonly pbc::RepeatedField idsBetween_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField IdsBetween { + get { return idsBetween_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarFilters); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarFilters other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if(!ids_.Equals(other.ids_)) return false; + if(!ages_.Equals(other.ages_)) return false; + if(!firstNames_.Equals(other.firstNames_)) return false; + if(!idsBetween_.Equals(other.idsBetween_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + hash ^= ids_.GetHashCode(); + hash ^= ages_.GetHashCode(); + hash ^= firstNames_.GetHashCode(); + hash ^= idsBetween_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + ids_.WriteTo(output, _repeated_ids_codec); + ages_.WriteTo(output, _repeated_ages_codec); + firstNames_.WriteTo(output, _repeated_firstNames_codec); + idsBetween_.WriteTo(output, _repeated_idsBetween_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + size += ids_.CalculateSize(_repeated_ids_codec); + size += ages_.CalculateSize(_repeated_ages_codec); + size += firstNames_.CalculateSize(_repeated_firstNames_codec); + size += idsBetween_.CalculateSize(_repeated_idsBetween_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarFilters other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + ids_.Add(other.ids_); + ages_.Add(other.ages_); + firstNames_.Add(other.firstNames_); + idsBetween_.Add(other.idsBetween_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: + case 1608: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + case 1618: + case 1616: { + ages_.AddEntriesFrom(input, _repeated_ages_codec); + break; + } + case 1626: { + firstNames_.AddEntriesFrom(input, _repeated_firstNames_codec); + break; + } + case 1634: + case 1632: { + idsBetween_.AddEntriesFrom(input, _repeated_idsBetween_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[142]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstars(QueryRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstars Clone() { + return new QueryRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarsConventions : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarsConventions()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[143]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsConventions() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsConventions(QueryRockstarsConventions other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + dateOfBirthGreaterThan_ = other.dateOfBirthGreaterThan_ != null ? other.dateOfBirthGreaterThan_.Clone() : null; + dateDiedLessThan_ = other.dateDiedLessThan_ != null ? other.dateDiedLessThan_.Clone() : null; + ids_ = other.ids_.Clone(); + ageOlderThan_ = other.ageOlderThan_; + ageGreaterThanOrEqualTo_ = other.ageGreaterThanOrEqualTo_; + ageGreaterThan_ = other.ageGreaterThan_; + greaterThanAge_ = other.greaterThanAge_; + firstNameStartsWith_ = other.firstNameStartsWith_; + lastNameEndsWith_ = other.lastNameEndsWith_; + lastNameContains_ = other.lastNameContains_; + rockstarAlbumNameContains_ = other.rockstarAlbumNameContains_; + rockstarIdAfter_ = other.rockstarIdAfter_; + rockstarIdOnOrAfter_ = other.rockstarIdOnOrAfter_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsConventions Clone() { + return new QueryRockstarsConventions(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "DateOfBirthGreaterThan" field. + public const int DateOfBirthGreaterThanFieldNumber = 201; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirthGreaterThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirthGreaterThan { + get { return dateOfBirthGreaterThan_; } + set { + dateOfBirthGreaterThan_ = value; + } + } + + /// Field number for the "DateDiedLessThan" field. + public const int DateDiedLessThanFieldNumber = 202; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDiedLessThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDiedLessThan { + get { return dateDiedLessThan_; } + set { + dateDiedLessThan_ = value; + } + } + + /// Field number for the "Ids" field. + public const int IdsFieldNumber = 203; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForInt32(1624); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + /// Field number for the "AgeOlderThan" field. + public const int AgeOlderThanFieldNumber = 204; + private int ageOlderThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int AgeOlderThan { + get { return ageOlderThan_; } + set { + ageOlderThan_ = value; + } + } + + /// Field number for the "AgeGreaterThanOrEqualTo" field. + public const int AgeGreaterThanOrEqualToFieldNumber = 205; + private int ageGreaterThanOrEqualTo_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int AgeGreaterThanOrEqualTo { + get { return ageGreaterThanOrEqualTo_; } + set { + ageGreaterThanOrEqualTo_ = value; + } + } + + /// Field number for the "AgeGreaterThan" field. + public const int AgeGreaterThanFieldNumber = 206; + private int ageGreaterThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int AgeGreaterThan { + get { return ageGreaterThan_; } + set { + ageGreaterThan_ = value; + } + } + + /// Field number for the "GreaterThanAge" field. + public const int GreaterThanAgeFieldNumber = 207; + private int greaterThanAge_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int GreaterThanAge { + get { return greaterThanAge_; } + set { + greaterThanAge_ = value; + } + } + + /// Field number for the "FirstNameStartsWith" field. + public const int FirstNameStartsWithFieldNumber = 208; + private string firstNameStartsWith_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstNameStartsWith { + get { return firstNameStartsWith_; } + set { + firstNameStartsWith_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastNameEndsWith" field. + public const int LastNameEndsWithFieldNumber = 209; + private string lastNameEndsWith_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastNameEndsWith { + get { return lastNameEndsWith_; } + set { + lastNameEndsWith_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastNameContains" field. + public const int LastNameContainsFieldNumber = 210; + private string lastNameContains_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastNameContains { + get { return lastNameContains_; } + set { + lastNameContains_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RockstarAlbumNameContains" field. + public const int RockstarAlbumNameContainsFieldNumber = 211; + private string rockstarAlbumNameContains_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RockstarAlbumNameContains { + get { return rockstarAlbumNameContains_; } + set { + rockstarAlbumNameContains_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RockstarIdAfter" field. + public const int RockstarIdAfterFieldNumber = 212; + private int rockstarIdAfter_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int RockstarIdAfter { + get { return rockstarIdAfter_; } + set { + rockstarIdAfter_ = value; + } + } + + /// Field number for the "RockstarIdOnOrAfter" field. + public const int RockstarIdOnOrAfterFieldNumber = 213; + private int rockstarIdOnOrAfter_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int RockstarIdOnOrAfter { + get { return rockstarIdOnOrAfter_; } + set { + rockstarIdOnOrAfter_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarsConventions); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarsConventions other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(DateOfBirthGreaterThan, other.DateOfBirthGreaterThan)) return false; + if (!object.Equals(DateDiedLessThan, other.DateDiedLessThan)) return false; + if(!ids_.Equals(other.ids_)) return false; + if (AgeOlderThan != other.AgeOlderThan) return false; + if (AgeGreaterThanOrEqualTo != other.AgeGreaterThanOrEqualTo) return false; + if (AgeGreaterThan != other.AgeGreaterThan) return false; + if (GreaterThanAge != other.GreaterThanAge) return false; + if (FirstNameStartsWith != other.FirstNameStartsWith) return false; + if (LastNameEndsWith != other.LastNameEndsWith) return false; + if (LastNameContains != other.LastNameContains) return false; + if (RockstarAlbumNameContains != other.RockstarAlbumNameContains) return false; + if (RockstarIdAfter != other.RockstarIdAfter) return false; + if (RockstarIdOnOrAfter != other.RockstarIdOnOrAfter) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (dateOfBirthGreaterThan_ != null) hash ^= DateOfBirthGreaterThan.GetHashCode(); + if (dateDiedLessThan_ != null) hash ^= DateDiedLessThan.GetHashCode(); + hash ^= ids_.GetHashCode(); + if (AgeOlderThan != 0) hash ^= AgeOlderThan.GetHashCode(); + if (AgeGreaterThanOrEqualTo != 0) hash ^= AgeGreaterThanOrEqualTo.GetHashCode(); + if (AgeGreaterThan != 0) hash ^= AgeGreaterThan.GetHashCode(); + if (GreaterThanAge != 0) hash ^= GreaterThanAge.GetHashCode(); + if (FirstNameStartsWith.Length != 0) hash ^= FirstNameStartsWith.GetHashCode(); + if (LastNameEndsWith.Length != 0) hash ^= LastNameEndsWith.GetHashCode(); + if (LastNameContains.Length != 0) hash ^= LastNameContains.GetHashCode(); + if (RockstarAlbumNameContains.Length != 0) hash ^= RockstarAlbumNameContains.GetHashCode(); + if (RockstarIdAfter != 0) hash ^= RockstarIdAfter.GetHashCode(); + if (RockstarIdOnOrAfter != 0) hash ^= RockstarIdOnOrAfter.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (dateOfBirthGreaterThan_ != null) { + output.WriteRawTag(202, 12); + output.WriteMessage(DateOfBirthGreaterThan); + } + if (dateDiedLessThan_ != null) { + output.WriteRawTag(210, 12); + output.WriteMessage(DateDiedLessThan); + } + ids_.WriteTo(output, _repeated_ids_codec); + if (AgeOlderThan != 0) { + output.WriteRawTag(224, 12); + output.WriteInt32(AgeOlderThan); + } + if (AgeGreaterThanOrEqualTo != 0) { + output.WriteRawTag(232, 12); + output.WriteInt32(AgeGreaterThanOrEqualTo); + } + if (AgeGreaterThan != 0) { + output.WriteRawTag(240, 12); + output.WriteInt32(AgeGreaterThan); + } + if (GreaterThanAge != 0) { + output.WriteRawTag(248, 12); + output.WriteInt32(GreaterThanAge); + } + if (FirstNameStartsWith.Length != 0) { + output.WriteRawTag(130, 13); + output.WriteString(FirstNameStartsWith); + } + if (LastNameEndsWith.Length != 0) { + output.WriteRawTag(138, 13); + output.WriteString(LastNameEndsWith); + } + if (LastNameContains.Length != 0) { + output.WriteRawTag(146, 13); + output.WriteString(LastNameContains); + } + if (RockstarAlbumNameContains.Length != 0) { + output.WriteRawTag(154, 13); + output.WriteString(RockstarAlbumNameContains); + } + if (RockstarIdAfter != 0) { + output.WriteRawTag(160, 13); + output.WriteInt32(RockstarIdAfter); + } + if (RockstarIdOnOrAfter != 0) { + output.WriteRawTag(168, 13); + output.WriteInt32(RockstarIdOnOrAfter); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (dateOfBirthGreaterThan_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirthGreaterThan); + } + if (dateDiedLessThan_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DateDiedLessThan); + } + size += ids_.CalculateSize(_repeated_ids_codec); + if (AgeOlderThan != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(AgeOlderThan); + } + if (AgeGreaterThanOrEqualTo != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(AgeGreaterThanOrEqualTo); + } + if (AgeGreaterThan != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(AgeGreaterThan); + } + if (GreaterThanAge != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(GreaterThanAge); + } + if (FirstNameStartsWith.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstNameStartsWith); + } + if (LastNameEndsWith.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(LastNameEndsWith); + } + if (LastNameContains.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(LastNameContains); + } + if (RockstarAlbumNameContains.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(RockstarAlbumNameContains); + } + if (RockstarIdAfter != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(RockstarIdAfter); + } + if (RockstarIdOnOrAfter != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(RockstarIdOnOrAfter); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarsConventions other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.dateOfBirthGreaterThan_ != null) { + if (dateOfBirthGreaterThan_ == null) { + DateOfBirthGreaterThan = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirthGreaterThan.MergeFrom(other.DateOfBirthGreaterThan); + } + if (other.dateDiedLessThan_ != null) { + if (dateDiedLessThan_ == null) { + DateDiedLessThan = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDiedLessThan.MergeFrom(other.DateDiedLessThan); + } + ids_.Add(other.ids_); + if (other.AgeOlderThan != 0) { + AgeOlderThan = other.AgeOlderThan; + } + if (other.AgeGreaterThanOrEqualTo != 0) { + AgeGreaterThanOrEqualTo = other.AgeGreaterThanOrEqualTo; + } + if (other.AgeGreaterThan != 0) { + AgeGreaterThan = other.AgeGreaterThan; + } + if (other.GreaterThanAge != 0) { + GreaterThanAge = other.GreaterThanAge; + } + if (other.FirstNameStartsWith.Length != 0) { + FirstNameStartsWith = other.FirstNameStartsWith; + } + if (other.LastNameEndsWith.Length != 0) { + LastNameEndsWith = other.LastNameEndsWith; + } + if (other.LastNameContains.Length != 0) { + LastNameContains = other.LastNameContains; + } + if (other.RockstarAlbumNameContains.Length != 0) { + RockstarAlbumNameContains = other.RockstarAlbumNameContains; + } + if (other.RockstarIdAfter != 0) { + RockstarIdAfter = other.RockstarIdAfter; + } + if (other.RockstarIdOnOrAfter != 0) { + RockstarIdOnOrAfter = other.RockstarIdOnOrAfter; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + if (dateOfBirthGreaterThan_ == null) { + DateOfBirthGreaterThan = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirthGreaterThan); + break; + } + case 1618: { + if (dateDiedLessThan_ == null) { + DateDiedLessThan = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDiedLessThan); + break; + } + case 1626: + case 1624: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + case 1632: { + AgeOlderThan = input.ReadInt32(); + break; + } + case 1640: { + AgeGreaterThanOrEqualTo = input.ReadInt32(); + break; + } + case 1648: { + AgeGreaterThan = input.ReadInt32(); + break; + } + case 1656: { + GreaterThanAge = input.ReadInt32(); + break; + } + case 1666: { + FirstNameStartsWith = input.ReadString(); + break; + } + case 1674: { + LastNameEndsWith = input.ReadString(); + break; + } + case 1682: { + LastNameContains = input.ReadString(); + break; + } + case 1690: { + RockstarAlbumNameContains = input.ReadString(); + break; + } + case 1696: { + RockstarIdAfter = input.ReadInt32(); + break; + } + case 1704: { + RockstarIdOnOrAfter = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarsFilter : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarsFilter()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[144]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsFilter() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsFilter(QueryRockstarsFilter other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsFilter Clone() { + return new QueryRockstarsFilter(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarsFilter); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarsFilter other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarsFilter other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarsIFilter : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarsIFilter()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[145]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsIFilter() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsIFilter(QueryRockstarsIFilter other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsIFilter Clone() { + return new QueryRockstarsIFilter(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarsIFilter); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarsIFilter other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarsIFilter other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarsImplicit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarsImplicit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[146]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsImplicit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsImplicit(QueryRockstarsImplicit other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsImplicit Clone() { + return new QueryRockstarsImplicit(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarsImplicit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarsImplicit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarsImplicit other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryRockstarsWithReferences : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryRockstarsWithReferences()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[147]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsWithReferences() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsWithReferences(QueryRockstarsWithReferences other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryRockstarsWithReferences Clone() { + return new QueryRockstarsWithReferences(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 201; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryRockstarsWithReferences); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryRockstarsWithReferences other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (Age != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (Age != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryRockstarsWithReferences other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class QueryTypeWithEnums : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryTypeWithEnums()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[148]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryTypeWithEnums() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryTypeWithEnums(QueryTypeWithEnums other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryTypeWithEnums Clone() { + return new QueryTypeWithEnums(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryTypeWithEnums); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryTypeWithEnums other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryTypeWithEnums other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class QueryUnknownRockstars : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new QueryUnknownRockstars()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[149]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryUnknownRockstars() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryUnknownRockstars(QueryUnknownRockstars other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + unknownInt_ = other.unknownInt_; + unknownProperty_ = other.unknownProperty_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public QueryUnknownRockstars Clone() { + return new QueryUnknownRockstars(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "UnknownInt" field. + public const int UnknownIntFieldNumber = 201; + private int unknownInt_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int UnknownInt { + get { return unknownInt_; } + set { + unknownInt_ = value; + } + } + + /// Field number for the "UnknownProperty" field. + public const int UnknownPropertyFieldNumber = 202; + private string unknownProperty_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UnknownProperty { + get { return unknownProperty_; } + set { + unknownProperty_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as QueryUnknownRockstars); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(QueryUnknownRockstars other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if (UnknownInt != other.UnknownInt) return false; + if (UnknownProperty != other.UnknownProperty) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (UnknownInt != 0) hash ^= UnknownInt.GetHashCode(); + if (UnknownProperty.Length != 0) hash ^= UnknownProperty.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (UnknownInt != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(UnknownInt); + } + if (UnknownProperty.Length != 0) { + output.WriteRawTag(210, 12); + output.WriteString(UnknownProperty); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (UnknownInt != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(UnknownInt); + } + if (UnknownProperty.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(UnknownProperty); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(QueryUnknownRockstars other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + if (other.UnknownInt != 0) { + UnknownInt = other.UnknownInt; + } + if (other.UnknownProperty.Length != 0) { + UnknownProperty = other.UnknownProperty; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1608: { + UnknownInt = input.ReadInt32(); + break; + } + case 1618: { + UnknownProperty = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RealDeleteAuditTenant : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RealDeleteAuditTenant()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[150]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenant() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenant(RealDeleteAuditTenant other) : this() { + bearerToken_ = other.bearerToken_; + id_ = other.id_; + age_ = other.age_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenant Clone() { + return new RealDeleteAuditTenant(this); + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 1; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 2; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RealDeleteAuditTenant); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RealDeleteAuditTenant other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BearerToken != other.BearerToken) return false; + if (Id != other.Id) return false; + if (Age != other.Age) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (BearerToken.Length != 0) { + output.WriteRawTag(10); + output.WriteString(BearerToken); + } + if (Id != 0) { + output.WriteRawTag(16); + output.WriteInt32(Id); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BearerToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RealDeleteAuditTenant other) { + if (other == null) { + return; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.Age != 0) { + Age = other.Age; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + BearerToken = input.ReadString(); + break; + } + case 16: { + Id = input.ReadInt32(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class RealDeleteAuditTenantGateway : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RealDeleteAuditTenantGateway()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[151]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenantGateway() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenantGateway(RealDeleteAuditTenantGateway other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenantGateway Clone() { + return new RealDeleteAuditTenantGateway(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RealDeleteAuditTenantGateway); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RealDeleteAuditTenantGateway other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RealDeleteAuditTenantGateway other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class RealDeleteAuditTenantMq : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RealDeleteAuditTenantMq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[152]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenantMq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenantMq(RealDeleteAuditTenantMq other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RealDeleteAuditTenantMq Clone() { + return new RealDeleteAuditTenantMq(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RealDeleteAuditTenantMq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RealDeleteAuditTenantMq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RealDeleteAuditTenantMq other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class RegenerateApiKeys : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RegenerateApiKeys()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[153]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegenerateApiKeys() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegenerateApiKeys(RegenerateApiKeys other) : this() { + environment_ = other.environment_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegenerateApiKeys Clone() { + return new RegenerateApiKeys(this); + } + + /// Field number for the "Environment" field. + public const int EnvironmentFieldNumber = 1; + private string environment_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Environment { + get { return environment_; } + set { + environment_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 2; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 18); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RegenerateApiKeys); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RegenerateApiKeys other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Environment != other.Environment) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Environment.Length != 0) hash ^= Environment.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Environment.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Environment); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Environment.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Environment); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RegenerateApiKeys other) { + if (other == null) { + return; + } + if (other.Environment.Length != 0) { + Environment = other.Environment; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Environment = input.ReadString(); + break; + } + case 18: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class RegenerateApiKeysResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RegenerateApiKeysResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[154]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegenerateApiKeysResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegenerateApiKeysResponse(RegenerateApiKeysResponse other) : this() { + results_ = other.results_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegenerateApiKeysResponse Clone() { + return new RegenerateApiKeysResponse(this); + } + + /// Field number for the "Results" field. + public const int ResultsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_results_codec + = pb::FieldCodec.ForMessage(10, global::ServiceStack.Extensions.Tests.Protoc.UserApiKey.Parser); + private readonly pbc::RepeatedField results_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Results { + get { return results_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 2; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 18); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RegenerateApiKeysResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RegenerateApiKeysResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!results_.Equals(other.results_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= results_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + results_.WriteTo(output, _repeated_results_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += results_.CalculateSize(_repeated_results_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RegenerateApiKeysResponse other) { + if (other == null) { + return; + } + results_.Add(other.results_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + results_.AddEntriesFrom(input, _repeated_results_codec); + break; + } + case 18: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class Register : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Register()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[155]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Register() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Register(Register other) : this() { + userName_ = other.userName_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + displayName_ = other.displayName_; + email_ = other.email_; + password_ = other.password_; + confirmPassword_ = other.confirmPassword_; + autoLogin_ = other.autoLogin_; + errorView_ = other.errorView_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Register Clone() { + return new Register(this); + } + + /// Field number for the "UserName" field. + public const int UserNameFieldNumber = 1; + private string userName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserName { + get { return userName_; } + set { + userName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 3; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "DisplayName" field. + public const int DisplayNameFieldNumber = 4; + private string displayName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string DisplayName { + get { return displayName_; } + set { + displayName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Email" field. + public const int EmailFieldNumber = 5; + private string email_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Email { + get { return email_; } + set { + email_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Password" field. + public const int PasswordFieldNumber = 6; + private string password_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Password { + get { return password_; } + set { + password_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ConfirmPassword" field. + public const int ConfirmPasswordFieldNumber = 7; + private string confirmPassword_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ConfirmPassword { + get { return confirmPassword_; } + set { + confirmPassword_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "AutoLogin" field. + public const int AutoLoginFieldNumber = 8; + private bool autoLogin_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool AutoLogin { + get { return autoLogin_; } + set { + autoLogin_ = value; + } + } + + /// Field number for the "ErrorView" field. + public const int ErrorViewFieldNumber = 10; + private string errorView_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ErrorView { + get { return errorView_; } + set { + errorView_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 11; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 90); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Register); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Register other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (UserName != other.UserName) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (DisplayName != other.DisplayName) return false; + if (Email != other.Email) return false; + if (Password != other.Password) return false; + if (ConfirmPassword != other.ConfirmPassword) return false; + if (AutoLogin != other.AutoLogin) return false; + if (ErrorView != other.ErrorView) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (UserName.Length != 0) hash ^= UserName.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (DisplayName.Length != 0) hash ^= DisplayName.GetHashCode(); + if (Email.Length != 0) hash ^= Email.GetHashCode(); + if (Password.Length != 0) hash ^= Password.GetHashCode(); + if (ConfirmPassword.Length != 0) hash ^= ConfirmPassword.GetHashCode(); + if (AutoLogin != false) hash ^= AutoLogin.GetHashCode(); + if (ErrorView.Length != 0) hash ^= ErrorView.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (UserName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(UserName); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(LastName); + } + if (DisplayName.Length != 0) { + output.WriteRawTag(34); + output.WriteString(DisplayName); + } + if (Email.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Email); + } + if (Password.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Password); + } + if (ConfirmPassword.Length != 0) { + output.WriteRawTag(58); + output.WriteString(ConfirmPassword); + } + if (AutoLogin != false) { + output.WriteRawTag(64); + output.WriteBool(AutoLogin); + } + if (ErrorView.Length != 0) { + output.WriteRawTag(82); + output.WriteString(ErrorView); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (UserName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserName); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (DisplayName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(DisplayName); + } + if (Email.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Email); + } + if (Password.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Password); + } + if (ConfirmPassword.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ConfirmPassword); + } + if (AutoLogin != false) { + size += 1 + 1; + } + if (ErrorView.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorView); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Register other) { + if (other == null) { + return; + } + if (other.UserName.Length != 0) { + UserName = other.UserName; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.DisplayName.Length != 0) { + DisplayName = other.DisplayName; + } + if (other.Email.Length != 0) { + Email = other.Email; + } + if (other.Password.Length != 0) { + Password = other.Password; + } + if (other.ConfirmPassword.Length != 0) { + ConfirmPassword = other.ConfirmPassword; + } + if (other.AutoLogin != false) { + AutoLogin = other.AutoLogin; + } + if (other.ErrorView.Length != 0) { + ErrorView = other.ErrorView; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + UserName = input.ReadString(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + LastName = input.ReadString(); + break; + } + case 34: { + DisplayName = input.ReadString(); + break; + } + case 42: { + Email = input.ReadString(); + break; + } + case 50: { + Password = input.ReadString(); + break; + } + case 58: { + ConfirmPassword = input.ReadString(); + break; + } + case 64: { + AutoLogin = input.ReadBool(); + break; + } + case 82: { + ErrorView = input.ReadString(); + break; + } + case 90: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class RegisterResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RegisterResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[156]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegisterResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegisterResponse(RegisterResponse other) : this() { + userId_ = other.userId_; + sessionId_ = other.sessionId_; + userName_ = other.userName_; + referrerUrl_ = other.referrerUrl_; + bearerToken_ = other.bearerToken_; + refreshToken_ = other.refreshToken_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RegisterResponse Clone() { + return new RegisterResponse(this); + } + + /// Field number for the "UserId" field. + public const int UserIdFieldNumber = 1; + private string userId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserId { + get { return userId_; } + set { + userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "SessionId" field. + public const int SessionIdFieldNumber = 2; + private string sessionId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SessionId { + get { return sessionId_; } + set { + sessionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UserName" field. + public const int UserNameFieldNumber = 3; + private string userName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserName { + get { return userName_; } + set { + userName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ReferrerUrl" field. + public const int ReferrerUrlFieldNumber = 4; + private string referrerUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ReferrerUrl { + get { return referrerUrl_; } + set { + referrerUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 5; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RefreshToken" field. + public const int RefreshTokenFieldNumber = 6; + private string refreshToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RefreshToken { + get { return refreshToken_; } + set { + refreshToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 7; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 8; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 66); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RegisterResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RegisterResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (UserId != other.UserId) return false; + if (SessionId != other.SessionId) return false; + if (UserName != other.UserName) return false; + if (ReferrerUrl != other.ReferrerUrl) return false; + if (BearerToken != other.BearerToken) return false; + if (RefreshToken != other.RefreshToken) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (UserId.Length != 0) hash ^= UserId.GetHashCode(); + if (SessionId.Length != 0) hash ^= SessionId.GetHashCode(); + if (UserName.Length != 0) hash ^= UserName.GetHashCode(); + if (ReferrerUrl.Length != 0) hash ^= ReferrerUrl.GetHashCode(); + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (RefreshToken.Length != 0) hash ^= RefreshToken.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (UserId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(UserId); + } + if (SessionId.Length != 0) { + output.WriteRawTag(18); + output.WriteString(SessionId); + } + if (UserName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(UserName); + } + if (ReferrerUrl.Length != 0) { + output.WriteRawTag(34); + output.WriteString(ReferrerUrl); + } + if (BearerToken.Length != 0) { + output.WriteRawTag(42); + output.WriteString(BearerToken); + } + if (RefreshToken.Length != 0) { + output.WriteRawTag(50); + output.WriteString(RefreshToken); + } + if (responseStatus_ != null) { + output.WriteRawTag(58); + output.WriteMessage(ResponseStatus); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (UserId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId); + } + if (SessionId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SessionId); + } + if (UserName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserName); + } + if (ReferrerUrl.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ReferrerUrl); + } + if (BearerToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (RefreshToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RefreshToken); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RegisterResponse other) { + if (other == null) { + return; + } + if (other.UserId.Length != 0) { + UserId = other.UserId; + } + if (other.SessionId.Length != 0) { + SessionId = other.SessionId; + } + if (other.UserName.Length != 0) { + UserName = other.UserName; + } + if (other.ReferrerUrl.Length != 0) { + ReferrerUrl = other.ReferrerUrl; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + if (other.RefreshToken.Length != 0) { + RefreshToken = other.RefreshToken; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + UserId = input.ReadString(); + break; + } + case 18: { + SessionId = input.ReadString(); + break; + } + case 26: { + UserName = input.ReadString(); + break; + } + case 34: { + ReferrerUrl = input.ReadString(); + break; + } + case 42: { + BearerToken = input.ReadString(); + break; + } + case 50: { + RefreshToken = input.ReadString(); + break; + } + case 58: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + case 66: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class RequiresAuth : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequiresAuth()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[157]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequiresAuth() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequiresAuth(RequiresAuth other) : this() { + name_ = other.name_; + bearerToken_ = other.bearerToken_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequiresAuth Clone() { + return new RequiresAuth(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 2; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequiresAuth); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequiresAuth other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + if (BearerToken != other.BearerToken) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (BearerToken.Length != 0) { + output.WriteRawTag(18); + output.WriteString(BearerToken); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (BearerToken.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequiresAuth other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + case 18: { + BearerToken = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class ResetTodos : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResetTodos()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[158]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResetTodos() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResetTodos(ResetTodos other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResetTodos Clone() { + return new ResetTodos(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ResetTodos); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ResetTodos other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ResetTodos other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class ResponseError : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResponseError()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[159]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResponseError() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResponseError(ResponseError other) : this() { + errorCode_ = other.errorCode_; + fieldName_ = other.fieldName_; + message_ = other.message_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResponseError Clone() { + return new ResponseError(this); + } + + /// Field number for the "ErrorCode" field. + public const int ErrorCodeFieldNumber = 1; + private string errorCode_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ErrorCode { + get { return errorCode_; } + set { + errorCode_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "FieldName" field. + public const int FieldNameFieldNumber = 2; + private string fieldName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FieldName { + get { return fieldName_; } + set { + fieldName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Message" field. + public const int MessageFieldNumber = 3; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ResponseError); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ResponseError other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ErrorCode != other.ErrorCode) return false; + if (FieldName != other.FieldName) return false; + if (Message != other.Message) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ErrorCode.Length != 0) hash ^= ErrorCode.GetHashCode(); + if (FieldName.Length != 0) hash ^= FieldName.GetHashCode(); + if (Message.Length != 0) hash ^= Message.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ErrorCode.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ErrorCode); + } + if (FieldName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FieldName); + } + if (Message.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Message); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ErrorCode.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorCode); + } + if (FieldName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FieldName); + } + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ResponseError other) { + if (other == null) { + return; + } + if (other.ErrorCode.Length != 0) { + ErrorCode = other.ErrorCode; + } + if (other.FieldName.Length != 0) { + FieldName = other.FieldName; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + ErrorCode = input.ReadString(); + break; + } + case 18: { + FieldName = input.ReadString(); + break; + } + case 26: { + Message = input.ReadString(); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class ResponseStatus : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResponseStatus()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[160]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResponseStatus() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResponseStatus(ResponseStatus other) : this() { + errorCode_ = other.errorCode_; + message_ = other.message_; + stackTrace_ = other.stackTrace_; + errors_ = other.errors_.Clone(); + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResponseStatus Clone() { + return new ResponseStatus(this); + } + + /// Field number for the "ErrorCode" field. + public const int ErrorCodeFieldNumber = 1; + private string errorCode_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ErrorCode { + get { return errorCode_; } + set { + errorCode_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Message" field. + public const int MessageFieldNumber = 2; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "StackTrace" field. + public const int StackTraceFieldNumber = 3; + private string stackTrace_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string StackTrace { + get { return stackTrace_; } + set { + stackTrace_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Errors" field. + public const int ErrorsFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_errors_codec + = pb::FieldCodec.ForMessage(34, global::ServiceStack.Extensions.Tests.Protoc.ResponseError.Parser); + private readonly pbc::RepeatedField errors_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Errors { + get { return errors_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 5; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 42); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ResponseStatus); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ResponseStatus other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ErrorCode != other.ErrorCode) return false; + if (Message != other.Message) return false; + if (StackTrace != other.StackTrace) return false; + if(!errors_.Equals(other.errors_)) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ErrorCode.Length != 0) hash ^= ErrorCode.GetHashCode(); + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (StackTrace.Length != 0) hash ^= StackTrace.GetHashCode(); + hash ^= errors_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ErrorCode.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ErrorCode); + } + if (Message.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Message); + } + if (StackTrace.Length != 0) { + output.WriteRawTag(26); + output.WriteString(StackTrace); + } + errors_.WriteTo(output, _repeated_errors_codec); + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ErrorCode.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorCode); + } + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (StackTrace.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(StackTrace); + } + size += errors_.CalculateSize(_repeated_errors_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ResponseStatus other) { + if (other == null) { + return; + } + if (other.ErrorCode.Length != 0) { + ErrorCode = other.ErrorCode; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + if (other.StackTrace.Length != 0) { + StackTrace = other.StackTrace; + } + errors_.Add(other.errors_); + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + ErrorCode = input.ReadString(); + break; + } + case 18: { + Message = input.ReadString(); + break; + } + case 26: { + StackTrace = input.ReadString(); + break; + } + case 34: { + errors_.AddEntriesFrom(input, _repeated_errors_codec); + break; + } + case 42: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class Rockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Rockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[161]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Rockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Rockstar(Rockstar other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + switch (other.SubtypeCase) { + case SubtypeOneofCase.NamedRockstar: + NamedRockstar = other.NamedRockstar.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Rockstar Clone() { + return new Rockstar(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 3; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 4; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 6; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 7; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "NamedRockstar" field. + public const int NamedRockstarFieldNumber = 345091624; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar NamedRockstar { + get { return subtypeCase_ == SubtypeOneofCase.NamedRockstar ? (global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.NamedRockstar; + } + } + + private object subtype_; + /// Enum of possible cases for the "subtype" oneof. + public enum SubtypeOneofCase { + None = 0, + NamedRockstar = 345091624, + } + private SubtypeOneofCase subtypeCase_ = SubtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubtypeOneofCase SubtypeCase { + get { return subtypeCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearSubtype() { + subtypeCase_ = SubtypeOneofCase.None; + subtype_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Rockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Rockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (!object.Equals(NamedRockstar, other.NamedRockstar)) return false; + if (SubtypeCase != other.SubtypeCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.NamedRockstar) hash ^= NamedRockstar.GetHashCode(); + hash ^= (int) subtypeCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(32); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(50); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(56); + output.WriteEnum((int) LivingStatus); + } + if (subtypeCase_ == SubtypeOneofCase.NamedRockstar) { + output.WriteRawTag(194, 226, 181, 164, 10); + output.WriteMessage(NamedRockstar); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (subtypeCase_ == SubtypeOneofCase.NamedRockstar) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(NamedRockstar); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Rockstar other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + switch (other.SubtypeCase) { + case SubtypeOneofCase.NamedRockstar: + if (NamedRockstar == null) { + NamedRockstar = new global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar(); + } + NamedRockstar.MergeFrom(other.NamedRockstar); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + LastName = input.ReadString(); + break; + } + case 32: { + Age = input.ReadInt32(); + break; + } + case 42: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 50: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 56: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 2760732994: { + global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.NamedRockstar(); + if (subtypeCase_ == SubtypeOneofCase.NamedRockstar) { + subBuilder.MergeFrom(NamedRockstar); + } + input.ReadMessage(subBuilder); + NamedRockstar = subBuilder; + break; + } + } + } + } + + } + + public sealed partial class RockstarAlbum : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarAlbum()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[162]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAlbum() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAlbum(RockstarAlbum other) : this() { + id_ = other.id_; + rockstarId_ = other.rockstarId_; + name_ = other.name_; + genre_ = other.genre_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAlbum Clone() { + return new RockstarAlbum(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "RockstarId" field. + public const int RockstarIdFieldNumber = 2; + private int rockstarId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int RockstarId { + get { return rockstarId_; } + set { + rockstarId_ = value; + } + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 3; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Genre" field. + public const int GenreFieldNumber = 4; + private string genre_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Genre { + get { return genre_; } + set { + genre_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarAlbum); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarAlbum other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (RockstarId != other.RockstarId) return false; + if (Name != other.Name) return false; + if (Genre != other.Genre) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (RockstarId != 0) hash ^= RockstarId.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Genre.Length != 0) hash ^= Genre.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (RockstarId != 0) { + output.WriteRawTag(16); + output.WriteInt32(RockstarId); + } + if (Name.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Name); + } + if (Genre.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Genre); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (RockstarId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RockstarId); + } + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Genre.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Genre); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarAlbum other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.RockstarId != 0) { + RockstarId = other.RockstarId; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Genre.Length != 0) { + Genre = other.Genre; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 16: { + RockstarId = input.ReadInt32(); + break; + } + case 26: { + Name = input.ReadString(); + break; + } + case 34: { + Genre = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RockstarAlias : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarAlias()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[163]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAlias() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAlias(RockstarAlias other) : this() { + rockstarId_ = other.rockstarId_; + firstName_ = other.firstName_; + surname_ = other.surname_; + album_ = other.album_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAlias Clone() { + return new RockstarAlias(this); + } + + /// Field number for the "RockstarId" field. + public const int RockstarIdFieldNumber = 1; + private int rockstarId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int RockstarId { + get { return rockstarId_; } + set { + rockstarId_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Surname" field. + public const int SurnameFieldNumber = 3; + private string surname_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Surname { + get { return surname_; } + set { + surname_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "album" field. + public const int AlbumFieldNumber = 4; + private string album_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Album { + get { return album_; } + set { + album_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarAlias); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarAlias other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (RockstarId != other.RockstarId) return false; + if (FirstName != other.FirstName) return false; + if (Surname != other.Surname) return false; + if (Album != other.Album) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (RockstarId != 0) hash ^= RockstarId.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (Surname.Length != 0) hash ^= Surname.GetHashCode(); + if (Album.Length != 0) hash ^= Album.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (RockstarId != 0) { + output.WriteRawTag(8); + output.WriteInt32(RockstarId); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (Surname.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Surname); + } + if (Album.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Album); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (RockstarId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RockstarId); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (Surname.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Surname); + } + if (Album.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Album); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarAlias other) { + if (other == null) { + return; + } + if (other.RockstarId != 0) { + RockstarId = other.RockstarId; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.Surname.Length != 0) { + Surname = other.Surname; + } + if (other.Album.Length != 0) { + Album = other.Album; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + RockstarId = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + Surname = input.ReadString(); + break; + } + case 34: { + Album = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RockstarAudit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarAudit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[164]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAudit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAudit(RockstarAudit other) : this() { + id_ = other.id_; + createdDate_ = other.createdDate_ != null ? other.createdDate_.Clone() : null; + createdBy_ = other.createdBy_; + createdInfo_ = other.createdInfo_; + modifiedDate_ = other.modifiedDate_ != null ? other.modifiedDate_.Clone() : null; + modifiedBy_ = other.modifiedBy_; + modifiedInfo_ = other.modifiedInfo_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAudit Clone() { + return new RockstarAudit(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "CreatedDate" field. + public const int CreatedDateFieldNumber = 2; + private global::Google.Protobuf.WellKnownTypes.Timestamp createdDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp CreatedDate { + get { return createdDate_; } + set { + createdDate_ = value; + } + } + + /// Field number for the "CreatedBy" field. + public const int CreatedByFieldNumber = 3; + private string createdBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreatedBy { + get { return createdBy_; } + set { + createdBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "CreatedInfo" field. + public const int CreatedInfoFieldNumber = 4; + private string createdInfo_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreatedInfo { + get { return createdInfo_; } + set { + createdInfo_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ModifiedDate" field. + public const int ModifiedDateFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp modifiedDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp ModifiedDate { + get { return modifiedDate_; } + set { + modifiedDate_ = value; + } + } + + /// Field number for the "ModifiedBy" field. + public const int ModifiedByFieldNumber = 6; + private string modifiedBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ModifiedBy { + get { return modifiedBy_; } + set { + modifiedBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ModifiedInfo" field. + public const int ModifiedInfoFieldNumber = 7; + private string modifiedInfo_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ModifiedInfo { + get { return modifiedInfo_; } + set { + modifiedInfo_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarAudit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarAudit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (!object.Equals(CreatedDate, other.CreatedDate)) return false; + if (CreatedBy != other.CreatedBy) return false; + if (CreatedInfo != other.CreatedInfo) return false; + if (!object.Equals(ModifiedDate, other.ModifiedDate)) return false; + if (ModifiedBy != other.ModifiedBy) return false; + if (ModifiedInfo != other.ModifiedInfo) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (createdDate_ != null) hash ^= CreatedDate.GetHashCode(); + if (CreatedBy.Length != 0) hash ^= CreatedBy.GetHashCode(); + if (CreatedInfo.Length != 0) hash ^= CreatedInfo.GetHashCode(); + if (modifiedDate_ != null) hash ^= ModifiedDate.GetHashCode(); + if (ModifiedBy.Length != 0) hash ^= ModifiedBy.GetHashCode(); + if (ModifiedInfo.Length != 0) hash ^= ModifiedInfo.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (createdDate_ != null) { + output.WriteRawTag(18); + output.WriteMessage(CreatedDate); + } + if (CreatedBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(CreatedBy); + } + if (CreatedInfo.Length != 0) { + output.WriteRawTag(34); + output.WriteString(CreatedInfo); + } + if (modifiedDate_ != null) { + output.WriteRawTag(42); + output.WriteMessage(ModifiedDate); + } + if (ModifiedBy.Length != 0) { + output.WriteRawTag(50); + output.WriteString(ModifiedBy); + } + if (ModifiedInfo.Length != 0) { + output.WriteRawTag(58); + output.WriteString(ModifiedInfo); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (createdDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(CreatedDate); + } + if (CreatedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreatedBy); + } + if (CreatedInfo.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreatedInfo); + } + if (modifiedDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ModifiedDate); + } + if (ModifiedBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ModifiedBy); + } + if (ModifiedInfo.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ModifiedInfo); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarAudit other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.createdDate_ != null) { + if (createdDate_ == null) { + CreatedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + CreatedDate.MergeFrom(other.CreatedDate); + } + if (other.CreatedBy.Length != 0) { + CreatedBy = other.CreatedBy; + } + if (other.CreatedInfo.Length != 0) { + CreatedInfo = other.CreatedInfo; + } + if (other.modifiedDate_ != null) { + if (modifiedDate_ == null) { + ModifiedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + ModifiedDate.MergeFrom(other.ModifiedDate); + } + if (other.ModifiedBy.Length != 0) { + ModifiedBy = other.ModifiedBy; + } + if (other.ModifiedInfo.Length != 0) { + ModifiedInfo = other.ModifiedInfo; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + if (createdDate_ == null) { + CreatedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(CreatedDate); + break; + } + case 26: { + CreatedBy = input.ReadString(); + break; + } + case 34: { + CreatedInfo = input.ReadString(); + break; + } + case 42: { + if (modifiedDate_ == null) { + ModifiedDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(ModifiedDate); + break; + } + case 50: { + ModifiedBy = input.ReadString(); + break; + } + case 58: { + ModifiedInfo = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RockstarAuditTenant : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarAuditTenant()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[165]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAuditTenant() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAuditTenant(RockstarAuditTenant other) : this() { + tenantId_ = other.tenantId_; + id_ = other.id_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAuditTenant Clone() { + return new RockstarAuditTenant(this); + } + + /// Field number for the "TenantId" field. + public const int TenantIdFieldNumber = 1; + private int tenantId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int TenantId { + get { return tenantId_; } + set { + tenantId_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 2; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 3; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 4; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 5; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 6; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 7; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 8; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarAuditTenant); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarAuditTenant other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TenantId != other.TenantId) return false; + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (TenantId != 0) hash ^= TenantId.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (TenantId != 0) { + output.WriteRawTag(8); + output.WriteInt32(TenantId); + } + if (Id != 0) { + output.WriteRawTag(16); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(34); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(40); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(50); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(58); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(64); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (TenantId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(TenantId); + } + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarAuditTenant other) { + if (other == null) { + return; + } + if (other.TenantId != 0) { + TenantId = other.TenantId; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + TenantId = input.ReadInt32(); + break; + } + case 16: { + Id = input.ReadInt32(); + break; + } + case 26: { + FirstName = input.ReadString(); + break; + } + case 34: { + LastName = input.ReadString(); + break; + } + case 40: { + Age = input.ReadInt32(); + break; + } + case 50: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 58: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 64: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class RockstarAuto : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarAuto()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[166]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAuto() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAuto(RockstarAuto other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAuto Clone() { + return new RockstarAuto(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarAuto); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarAuto other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarAuto other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class RockstarAutoGuid : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarAutoGuid()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[167]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAutoGuid() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAutoGuid(RockstarAutoGuid other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarAutoGuid Clone() { + return new RockstarAutoGuid(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private string id_ = ""; + /// + /// default value could not be applied: 00000000-0000-0000-0000-000000000000 + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarAutoGuid); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarAutoGuid other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarAutoGuid other) { + if (other == null) { + return; + } + if (other.Id.Length != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Id = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RockstarBase : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarBase()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[168]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarBase() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarBase(RockstarBase other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + switch (other.SubtypeCase) { + case SubtypeOneofCase.RockstarAutoGuid: + RockstarAutoGuid = other.RockstarAutoGuid.Clone(); + break; + case SubtypeOneofCase.RockstarAuto: + RockstarAuto = other.RockstarAuto.Clone(); + break; + case SubtypeOneofCase.RockstarAudit: + RockstarAudit = other.RockstarAudit.Clone(); + break; + case SubtypeOneofCase.RockstarVersion: + RockstarVersion = other.RockstarVersion.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarBase Clone() { + return new RockstarBase(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "RockstarAutoGuid" field. + public const int RockstarAutoGuidFieldNumber = 92000829; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid RockstarAutoGuid { + get { return subtypeCase_ == SubtypeOneofCase.RockstarAutoGuid ? (global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.RockstarAutoGuid; + } + } + + /// Field number for the "RockstarAuto" field. + public const int RockstarAutoFieldNumber = 92257311; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto RockstarAuto { + get { return subtypeCase_ == SubtypeOneofCase.RockstarAuto ? (global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.RockstarAuto; + } + } + + /// Field number for the "RockstarAudit" field. + public const int RockstarAuditFieldNumber = 119875064; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit RockstarAudit { + get { return subtypeCase_ == SubtypeOneofCase.RockstarAudit ? (global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.RockstarAudit; + } + } + + /// Field number for the "RockstarVersion" field. + public const int RockstarVersionFieldNumber = 320656675; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion RockstarVersion { + get { return subtypeCase_ == SubtypeOneofCase.RockstarVersion ? (global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion) subtype_ : null; } + set { + subtype_ = value; + subtypeCase_ = value == null ? SubtypeOneofCase.None : SubtypeOneofCase.RockstarVersion; + } + } + + private object subtype_; + /// Enum of possible cases for the "subtype" oneof. + public enum SubtypeOneofCase { + None = 0, + RockstarAutoGuid = 92000829, + RockstarAuto = 92257311, + RockstarAudit = 119875064, + RockstarVersion = 320656675, + } + private SubtypeOneofCase subtypeCase_ = SubtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubtypeOneofCase SubtypeCase { + get { return subtypeCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearSubtype() { + subtypeCase_ = SubtypeOneofCase.None; + subtype_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarBase); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarBase other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (!object.Equals(RockstarAutoGuid, other.RockstarAutoGuid)) return false; + if (!object.Equals(RockstarAuto, other.RockstarAuto)) return false; + if (!object.Equals(RockstarAudit, other.RockstarAudit)) return false; + if (!object.Equals(RockstarVersion, other.RockstarVersion)) return false; + if (SubtypeCase != other.SubtypeCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAutoGuid) hash ^= RockstarAutoGuid.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAuto) hash ^= RockstarAuto.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAudit) hash ^= RockstarAudit.GetHashCode(); + if (subtypeCase_ == SubtypeOneofCase.RockstarVersion) hash ^= RockstarVersion.GetHashCode(); + hash ^= (int) subtypeCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAutoGuid) { + output.WriteRawTag(234, 163, 250, 222, 2); + output.WriteMessage(RockstarAutoGuid); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAuto) { + output.WriteRawTag(250, 193, 247, 223, 2); + output.WriteMessage(RockstarAuto); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAudit) { + output.WriteRawTag(194, 223, 164, 201, 3); + output.WriteMessage(RockstarAudit); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarVersion) { + output.WriteRawTag(154, 210, 154, 199, 9); + output.WriteMessage(RockstarVersion); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAutoGuid) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(RockstarAutoGuid); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAuto) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(RockstarAuto); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarAudit) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(RockstarAudit); + } + if (subtypeCase_ == SubtypeOneofCase.RockstarVersion) { + size += 5 + pb::CodedOutputStream.ComputeMessageSize(RockstarVersion); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarBase other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + switch (other.SubtypeCase) { + case SubtypeOneofCase.RockstarAutoGuid: + if (RockstarAutoGuid == null) { + RockstarAutoGuid = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid(); + } + RockstarAutoGuid.MergeFrom(other.RockstarAutoGuid); + break; + case SubtypeOneofCase.RockstarAuto: + if (RockstarAuto == null) { + RockstarAuto = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto(); + } + RockstarAuto.MergeFrom(other.RockstarAuto); + break; + case SubtypeOneofCase.RockstarAudit: + if (RockstarAudit == null) { + RockstarAudit = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit(); + } + RockstarAudit.MergeFrom(other.RockstarAudit); + break; + case SubtypeOneofCase.RockstarVersion: + if (RockstarVersion == null) { + RockstarVersion = new global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion(); + } + RockstarVersion.MergeFrom(other.RockstarVersion); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 736006634: { + global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAutoGuid(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAutoGuid) { + subBuilder.MergeFrom(RockstarAutoGuid); + } + input.ReadMessage(subBuilder); + RockstarAutoGuid = subBuilder; + break; + } + case 738058490: { + global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAuto(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAuto) { + subBuilder.MergeFrom(RockstarAuto); + } + input.ReadMessage(subBuilder); + RockstarAuto = subBuilder; + break; + } + case 959000514: { + global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.RockstarAudit(); + if (subtypeCase_ == SubtypeOneofCase.RockstarAudit) { + subBuilder.MergeFrom(RockstarAudit); + } + input.ReadMessage(subBuilder); + RockstarAudit = subBuilder; + break; + } + case 2565253402: { + global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion subBuilder = new global::ServiceStack.Extensions.Tests.Protoc.RockstarVersion(); + if (subtypeCase_ == SubtypeOneofCase.RockstarVersion) { + subBuilder.MergeFrom(RockstarVersion); + } + input.ReadMessage(subBuilder); + RockstarVersion = subBuilder; + break; + } + } + } + } + + } + + public sealed partial class RockstarGenre : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarGenre()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[169]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarGenre() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarGenre(RockstarGenre other) : this() { + id_ = other.id_; + rockstarId_ = other.rockstarId_; + name_ = other.name_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarGenre Clone() { + return new RockstarGenre(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "RockstarId" field. + public const int RockstarIdFieldNumber = 2; + private int rockstarId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int RockstarId { + get { return rockstarId_; } + set { + rockstarId_ = value; + } + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 3; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarGenre); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarGenre other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (RockstarId != other.RockstarId) return false; + if (Name != other.Name) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (RockstarId != 0) hash ^= RockstarId.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (RockstarId != 0) { + output.WriteRawTag(16); + output.WriteInt32(RockstarId); + } + if (Name.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (RockstarId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(RockstarId); + } + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarGenre other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.RockstarId != 0) { + RockstarId = other.RockstarId; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 16: { + RockstarId = input.ReadInt32(); + break; + } + case 26: { + Name = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RockstarReference : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarReference()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[170]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarReference() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarReference(RockstarReference other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + albums_ = other.albums_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarReference Clone() { + return new RockstarReference(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 3; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 4; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "Albums" field. + public const int AlbumsFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_albums_codec + = pb::FieldCodec.ForMessage(42, global::ServiceStack.Extensions.Tests.Protoc.RockstarAlbum.Parser); + private readonly pbc::RepeatedField albums_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Albums { + get { return albums_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarReference); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarReference other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if(!albums_.Equals(other.albums_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + hash ^= albums_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(32); + output.WriteInt32(Age); + } + albums_.WriteTo(output, _repeated_albums_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + size += albums_.CalculateSize(_repeated_albums_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarReference other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + albums_.Add(other.albums_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + LastName = input.ReadString(); + break; + } + case 32: { + Age = input.ReadInt32(); + break; + } + case 42: { + albums_.AddEntriesFrom(input, _repeated_albums_codec); + break; + } + } + } + } + + } + + public sealed partial class RockstarVersion : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarVersion()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[171]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarVersion() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarVersion(RockstarVersion other) : this() { + id_ = other.id_; + rowVersion_ = other.rowVersion_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarVersion Clone() { + return new RockstarVersion(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "RowVersion" field. + public const int RowVersionFieldNumber = 2; + private ulong rowVersion_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong RowVersion { + get { return rowVersion_; } + set { + rowVersion_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarVersion); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarVersion other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (RowVersion != other.RowVersion) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (RowVersion != 0UL) hash ^= RowVersion.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (RowVersion != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(RowVersion); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (RowVersion != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(RowVersion); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarVersion other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.RowVersion != 0UL) { + RowVersion = other.RowVersion; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 16: { + RowVersion = input.ReadUInt64(); + break; + } + } + } + } + + } + + public sealed partial class RockstarWithIdAndCountResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarWithIdAndCountResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[172]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndCountResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndCountResponse(RockstarWithIdAndCountResponse other) : this() { + id_ = other.id_; + count_ = other.count_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndCountResponse Clone() { + return new RockstarWithIdAndCountResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Count" field. + public const int CountFieldNumber = 2; + private int count_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Count { + get { return count_; } + set { + count_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarWithIdAndCountResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarWithIdAndCountResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Count != other.Count) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (Count != 0) hash ^= Count.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (Count != 0) { + output.WriteRawTag(16); + output.WriteInt32(Count); + } + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (Count != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Count); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarWithIdAndCountResponse other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.Count != 0) { + Count = other.Count; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 16: { + Count = input.ReadInt32(); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[173]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndResultResponse(RockstarWithIdAndResultResponse other) : this() { + id_ = other.id_; + result_ = other.result_ != null ? other.result_.Clone() : null; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndResultResponse Clone() { + return new RockstarWithIdAndResultResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.RockstarBase result_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.RockstarBase Result { + get { return result_; } + set { + result_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (!object.Equals(Result, other.Result)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (result_ != null) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (result_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (result_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.result_ != null) { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.RockstarBase(); + } + Result.MergeFrom(other.Result); + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + if (result_ == null) { + Result = new global::ServiceStack.Extensions.Tests.Protoc.RockstarBase(); + } + input.ReadMessage(Result); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class RockstarWithIdAndRowVersionResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarWithIdAndRowVersionResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[174]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndRowVersionResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndRowVersionResponse(RockstarWithIdAndRowVersionResponse other) : this() { + id_ = other.id_; + rowVersion_ = other.rowVersion_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdAndRowVersionResponse Clone() { + return new RockstarWithIdAndRowVersionResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "RowVersion" field. + public const int RowVersionFieldNumber = 2; + private uint rowVersion_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint RowVersion { + get { return rowVersion_; } + set { + rowVersion_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarWithIdAndRowVersionResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarWithIdAndRowVersionResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (RowVersion != other.RowVersion) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (RowVersion != 0) hash ^= RowVersion.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (RowVersion != 0) { + output.WriteRawTag(16); + output.WriteUInt32(RowVersion); + } + if (responseStatus_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (RowVersion != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(RowVersion); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarWithIdAndRowVersionResponse other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.RowVersion != 0) { + RowVersion = other.RowVersion; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 16: { + RowVersion = input.ReadUInt32(); + break; + } + case 26: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class RockstarWithIdResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RockstarWithIdResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[175]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdResponse(RockstarWithIdResponse other) : this() { + id_ = other.id_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RockstarWithIdResponse Clone() { + return new RockstarWithIdResponse(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RockstarWithIdResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RockstarWithIdResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RockstarWithIdResponse other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class SearchMovies : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SearchMovies()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[176]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SearchMovies() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SearchMovies(SearchMovies other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SearchMovies Clone() { + return new SearchMovies(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SearchMovies); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SearchMovies other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SearchMovies other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class SearchResult : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SearchResult()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[177]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SearchResult() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SearchResult(SearchResult other) : this() { + id_ = other.id_; + suffix_ = other.suffix_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SearchResult Clone() { + return new SearchResult(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Suffix" field. + public const int SuffixFieldNumber = 2; + private string suffix_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Suffix { + get { return suffix_; } + set { + suffix_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SearchResult); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SearchResult other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Suffix != other.Suffix) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (Suffix.Length != 0) hash ^= Suffix.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (Suffix.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Suffix); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (Suffix.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Suffix); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SearchResult other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.Suffix.Length != 0) { + Suffix = other.Suffix; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + Suffix = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class Secured : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Secured()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[178]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Secured() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Secured(Secured other) : this() { + name_ = other.name_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Secured Clone() { + return new Secured(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Secured); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Secured other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Secured other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Name = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class SecuredResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SecuredResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[179]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SecuredResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SecuredResponse(SecuredResponse other) : this() { + result_ = other.result_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SecuredResponse Clone() { + return new SecuredResponse(this); + } + + /// Field number for the "Result" field. + public const int ResultFieldNumber = 1; + private string result_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Result { + get { return result_; } + set { + result_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 2; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SecuredResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SecuredResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Result != other.Result) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Result.Length != 0) hash ^= Result.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Result.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Result); + } + if (responseStatus_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Result.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Result); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SecuredResponse other) { + if (other == null) { + return; + } + if (other.Result.Length != 0) { + Result = other.Result; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Result = input.ReadString(); + break; + } + case 18: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[180]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class SoftDeleteAuditTenant : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SoftDeleteAuditTenant()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[181]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditTenant() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditTenant(SoftDeleteAuditTenant other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditTenant Clone() { + return new SoftDeleteAuditTenant(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 201; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SoftDeleteAuditTenant); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SoftDeleteAuditTenant other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(200, 12); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SoftDeleteAuditTenant other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 1608: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[182]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class StreamFiles : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamFiles()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[183]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamFiles() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamFiles(StreamFiles other) : this() { + paths_ = other.paths_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamFiles Clone() { + return new StreamFiles(this); + } + + /// Field number for the "Paths" field. + public const int PathsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_paths_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField paths_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Paths { + get { return paths_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StreamFiles); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StreamFiles other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!paths_.Equals(other.paths_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= paths_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + paths_.WriteTo(output, _repeated_paths_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += paths_.CalculateSize(_repeated_paths_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StreamFiles other) { + if (other == null) { + return; + } + paths_.Add(other.paths_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + paths_.AddEntriesFrom(input, _repeated_paths_codec); + break; + } + } + } + } + + } + + public sealed partial class StreamMovies : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamMovies()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[184]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamMovies() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamMovies(StreamMovies other) : this() { + skip_ = other.skip_; + take_ = other.take_; + orderBy_ = other.orderBy_; + orderByDesc_ = other.orderByDesc_; + include_ = other.include_; + fields_ = other.fields_; + meta_ = other.meta_.Clone(); + ratings_ = other.ratings_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamMovies Clone() { + return new StreamMovies(this); + } + + /// Field number for the "Skip" field. + public const int SkipFieldNumber = 1; + private int skip_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Skip { + get { return skip_; } + set { + skip_ = value; + } + } + + /// Field number for the "Take" field. + public const int TakeFieldNumber = 2; + private int take_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Take { + get { return take_; } + set { + take_ = value; + } + } + + /// Field number for the "OrderBy" field. + public const int OrderByFieldNumber = 3; + private string orderBy_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderBy { + get { return orderBy_; } + set { + orderBy_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "OrderByDesc" field. + public const int OrderByDescFieldNumber = 4; + private string orderByDesc_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OrderByDesc { + get { return orderByDesc_; } + set { + orderByDesc_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Include" field. + public const int IncludeFieldNumber = 5; + private string include_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Include { + get { return include_; } + set { + include_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Fields" field. + public const int FieldsFieldNumber = 6; + private string fields_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Fields { + get { return fields_; } + set { + fields_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 7; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 58); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "Ratings" field. + public const int RatingsFieldNumber = 201; + private static readonly pb::FieldCodec _repeated_ratings_codec + = pb::FieldCodec.ForString(1610); + private readonly pbc::RepeatedField ratings_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ratings { + get { return ratings_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StreamMovies); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StreamMovies other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Skip != other.Skip) return false; + if (Take != other.Take) return false; + if (OrderBy != other.OrderBy) return false; + if (OrderByDesc != other.OrderByDesc) return false; + if (Include != other.Include) return false; + if (Fields != other.Fields) return false; + if (!Meta.Equals(other.Meta)) return false; + if(!ratings_.Equals(other.ratings_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Skip != 0) hash ^= Skip.GetHashCode(); + if (Take != 0) hash ^= Take.GetHashCode(); + if (OrderBy.Length != 0) hash ^= OrderBy.GetHashCode(); + if (OrderByDesc.Length != 0) hash ^= OrderByDesc.GetHashCode(); + if (Include.Length != 0) hash ^= Include.GetHashCode(); + if (Fields.Length != 0) hash ^= Fields.GetHashCode(); + hash ^= Meta.GetHashCode(); + hash ^= ratings_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Skip != 0) { + output.WriteRawTag(8); + output.WriteInt32(Skip); + } + if (Take != 0) { + output.WriteRawTag(16); + output.WriteInt32(Take); + } + if (OrderBy.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OrderBy); + } + if (OrderByDesc.Length != 0) { + output.WriteRawTag(34); + output.WriteString(OrderByDesc); + } + if (Include.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Include); + } + if (Fields.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Fields); + } + meta_.WriteTo(output, _map_meta_codec); + ratings_.WriteTo(output, _repeated_ratings_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Skip != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Skip); + } + if (Take != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Take); + } + if (OrderBy.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderBy); + } + if (OrderByDesc.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OrderByDesc); + } + if (Include.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Include); + } + if (Fields.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Fields); + } + size += meta_.CalculateSize(_map_meta_codec); + size += ratings_.CalculateSize(_repeated_ratings_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StreamMovies other) { + if (other == null) { + return; + } + if (other.Skip != 0) { + Skip = other.Skip; + } + if (other.Take != 0) { + Take = other.Take; + } + if (other.OrderBy.Length != 0) { + OrderBy = other.OrderBy; + } + if (other.OrderByDesc.Length != 0) { + OrderByDesc = other.OrderByDesc; + } + if (other.Include.Length != 0) { + Include = other.Include; + } + if (other.Fields.Length != 0) { + Fields = other.Fields; + } + meta_.Add(other.meta_); + ratings_.Add(other.ratings_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Skip = input.ReadInt32(); + break; + } + case 16: { + Take = input.ReadInt32(); + break; + } + case 26: { + OrderBy = input.ReadString(); + break; + } + case 34: { + OrderByDesc = input.ReadString(); + break; + } + case 42: { + Include = input.ReadString(); + break; + } + case 50: { + Fields = input.ReadString(); + break; + } + case 58: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 1610: { + ratings_.AddEntriesFrom(input, _repeated_ratings_codec); + break; + } + } + } + } + + } + + public sealed partial class StreamServerEvents : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamServerEvents()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[185]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamServerEvents() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamServerEvents(StreamServerEvents other) : this() { + channels_ = other.channels_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamServerEvents Clone() { + return new StreamServerEvents(this); + } + + /// Field number for the "Channels" field. + public const int ChannelsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_channels_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField channels_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Channels { + get { return channels_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StreamServerEvents); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StreamServerEvents other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!channels_.Equals(other.channels_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= channels_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + channels_.WriteTo(output, _repeated_channels_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += channels_.CalculateSize(_repeated_channels_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StreamServerEvents other) { + if (other == null) { + return; + } + channels_.Add(other.channels_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + channels_.AddEntriesFrom(input, _repeated_channels_codec); + break; + } + } + } + } + + } + + public sealed partial class StreamServerEventsResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamServerEventsResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[186]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamServerEventsResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamServerEventsResponse(StreamServerEventsResponse other) : this() { + eventId_ = other.eventId_; + channel_ = other.channel_; + selector_ = other.selector_; + json_ = other.json_; + op_ = other.op_; + target_ = other.target_; + cssSelector_ = other.cssSelector_; + meta_ = other.meta_.Clone(); + userId_ = other.userId_; + displayName_ = other.displayName_; + profileUrl_ = other.profileUrl_; + isAuthenticated_ = other.isAuthenticated_; + channels_ = other.channels_.Clone(); + createdAt_ = other.createdAt_; + id_ = other.id_; + unRegisterUrl_ = other.unRegisterUrl_; + updateSubscriberUrl_ = other.updateSubscriberUrl_; + heartbeatUrl_ = other.heartbeatUrl_; + heartbeatIntervalMs_ = other.heartbeatIntervalMs_; + idleTimeoutMs_ = other.idleTimeoutMs_; + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StreamServerEventsResponse Clone() { + return new StreamServerEventsResponse(this); + } + + /// Field number for the "EventId" field. + public const int EventIdFieldNumber = 1; + private long eventId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long EventId { + get { return eventId_; } + set { + eventId_ = value; + } + } + + /// Field number for the "Channel" field. + public const int ChannelFieldNumber = 2; + private string channel_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Channel { + get { return channel_; } + set { + channel_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Selector" field. + public const int SelectorFieldNumber = 4; + private string selector_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Selector { + get { return selector_; } + set { + selector_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Json" field. + public const int JsonFieldNumber = 5; + private string json_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Json { + get { return json_; } + set { + json_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Op" field. + public const int OpFieldNumber = 6; + private string op_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Op { + get { return op_; } + set { + op_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Target" field. + public const int TargetFieldNumber = 7; + private string target_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Target { + get { return target_; } + set { + target_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "CssSelector" field. + public const int CssSelectorFieldNumber = 8; + private string cssSelector_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CssSelector { + get { return cssSelector_; } + set { + cssSelector_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 9; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 74); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "UserId" field. + public const int UserIdFieldNumber = 10; + private string userId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserId { + get { return userId_; } + set { + userId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "DisplayName" field. + public const int DisplayNameFieldNumber = 11; + private string displayName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string DisplayName { + get { return displayName_; } + set { + displayName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ProfileUrl" field. + public const int ProfileUrlFieldNumber = 12; + private string profileUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ProfileUrl { + get { return profileUrl_; } + set { + profileUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "IsAuthenticated" field. + public const int IsAuthenticatedFieldNumber = 13; + private bool isAuthenticated_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsAuthenticated { + get { return isAuthenticated_; } + set { + isAuthenticated_ = value; + } + } + + /// Field number for the "Channels" field. + public const int ChannelsFieldNumber = 14; + private static readonly pb::FieldCodec _repeated_channels_codec + = pb::FieldCodec.ForString(114); + private readonly pbc::RepeatedField channels_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Channels { + get { return channels_; } + } + + /// Field number for the "CreatedAt" field. + public const int CreatedAtFieldNumber = 15; + private long createdAt_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long CreatedAt { + get { return createdAt_; } + set { + createdAt_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 21; + private string id_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UnRegisterUrl" field. + public const int UnRegisterUrlFieldNumber = 22; + private string unRegisterUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UnRegisterUrl { + get { return unRegisterUrl_; } + set { + unRegisterUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "UpdateSubscriberUrl" field. + public const int UpdateSubscriberUrlFieldNumber = 23; + private string updateSubscriberUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UpdateSubscriberUrl { + get { return updateSubscriberUrl_; } + set { + updateSubscriberUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "HeartbeatUrl" field. + public const int HeartbeatUrlFieldNumber = 24; + private string heartbeatUrl_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string HeartbeatUrl { + get { return heartbeatUrl_; } + set { + heartbeatUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "HeartbeatIntervalMs" field. + public const int HeartbeatIntervalMsFieldNumber = 25; + private long heartbeatIntervalMs_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long HeartbeatIntervalMs { + get { return heartbeatIntervalMs_; } + set { + heartbeatIntervalMs_ = value; + } + } + + /// Field number for the "IdleTimeoutMs" field. + public const int IdleTimeoutMsFieldNumber = 26; + private long idleTimeoutMs_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long IdleTimeoutMs { + get { return idleTimeoutMs_; } + set { + idleTimeoutMs_ = value; + } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 30; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StreamServerEventsResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StreamServerEventsResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (EventId != other.EventId) return false; + if (Channel != other.Channel) return false; + if (Selector != other.Selector) return false; + if (Json != other.Json) return false; + if (Op != other.Op) return false; + if (Target != other.Target) return false; + if (CssSelector != other.CssSelector) return false; + if (!Meta.Equals(other.Meta)) return false; + if (UserId != other.UserId) return false; + if (DisplayName != other.DisplayName) return false; + if (ProfileUrl != other.ProfileUrl) return false; + if (IsAuthenticated != other.IsAuthenticated) return false; + if(!channels_.Equals(other.channels_)) return false; + if (CreatedAt != other.CreatedAt) return false; + if (Id != other.Id) return false; + if (UnRegisterUrl != other.UnRegisterUrl) return false; + if (UpdateSubscriberUrl != other.UpdateSubscriberUrl) return false; + if (HeartbeatUrl != other.HeartbeatUrl) return false; + if (HeartbeatIntervalMs != other.HeartbeatIntervalMs) return false; + if (IdleTimeoutMs != other.IdleTimeoutMs) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (EventId != 0L) hash ^= EventId.GetHashCode(); + if (Channel.Length != 0) hash ^= Channel.GetHashCode(); + if (Selector.Length != 0) hash ^= Selector.GetHashCode(); + if (Json.Length != 0) hash ^= Json.GetHashCode(); + if (Op.Length != 0) hash ^= Op.GetHashCode(); + if (Target.Length != 0) hash ^= Target.GetHashCode(); + if (CssSelector.Length != 0) hash ^= CssSelector.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (UserId.Length != 0) hash ^= UserId.GetHashCode(); + if (DisplayName.Length != 0) hash ^= DisplayName.GetHashCode(); + if (ProfileUrl.Length != 0) hash ^= ProfileUrl.GetHashCode(); + if (IsAuthenticated != false) hash ^= IsAuthenticated.GetHashCode(); + hash ^= channels_.GetHashCode(); + if (CreatedAt != 0L) hash ^= CreatedAt.GetHashCode(); + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (UnRegisterUrl.Length != 0) hash ^= UnRegisterUrl.GetHashCode(); + if (UpdateSubscriberUrl.Length != 0) hash ^= UpdateSubscriberUrl.GetHashCode(); + if (HeartbeatUrl.Length != 0) hash ^= HeartbeatUrl.GetHashCode(); + if (HeartbeatIntervalMs != 0L) hash ^= HeartbeatIntervalMs.GetHashCode(); + if (IdleTimeoutMs != 0L) hash ^= IdleTimeoutMs.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (EventId != 0L) { + output.WriteRawTag(8); + output.WriteInt64(EventId); + } + if (Channel.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Channel); + } + if (Selector.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Selector); + } + if (Json.Length != 0) { + output.WriteRawTag(42); + output.WriteString(Json); + } + if (Op.Length != 0) { + output.WriteRawTag(50); + output.WriteString(Op); + } + if (Target.Length != 0) { + output.WriteRawTag(58); + output.WriteString(Target); + } + if (CssSelector.Length != 0) { + output.WriteRawTag(66); + output.WriteString(CssSelector); + } + meta_.WriteTo(output, _map_meta_codec); + if (UserId.Length != 0) { + output.WriteRawTag(82); + output.WriteString(UserId); + } + if (DisplayName.Length != 0) { + output.WriteRawTag(90); + output.WriteString(DisplayName); + } + if (ProfileUrl.Length != 0) { + output.WriteRawTag(98); + output.WriteString(ProfileUrl); + } + if (IsAuthenticated != false) { + output.WriteRawTag(104); + output.WriteBool(IsAuthenticated); + } + channels_.WriteTo(output, _repeated_channels_codec); + if (CreatedAt != 0L) { + output.WriteRawTag(120); + output.WriteInt64(CreatedAt); + } + if (Id.Length != 0) { + output.WriteRawTag(170, 1); + output.WriteString(Id); + } + if (UnRegisterUrl.Length != 0) { + output.WriteRawTag(178, 1); + output.WriteString(UnRegisterUrl); + } + if (UpdateSubscriberUrl.Length != 0) { + output.WriteRawTag(186, 1); + output.WriteString(UpdateSubscriberUrl); + } + if (HeartbeatUrl.Length != 0) { + output.WriteRawTag(194, 1); + output.WriteString(HeartbeatUrl); + } + if (HeartbeatIntervalMs != 0L) { + output.WriteRawTag(200, 1); + output.WriteInt64(HeartbeatIntervalMs); + } + if (IdleTimeoutMs != 0L) { + output.WriteRawTag(208, 1); + output.WriteInt64(IdleTimeoutMs); + } + if (responseStatus_ != null) { + output.WriteRawTag(242, 1); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (EventId != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(EventId); + } + if (Channel.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Channel); + } + if (Selector.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Selector); + } + if (Json.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Json); + } + if (Op.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Op); + } + if (Target.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Target); + } + if (CssSelector.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CssSelector); + } + size += meta_.CalculateSize(_map_meta_codec); + if (UserId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserId); + } + if (DisplayName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(DisplayName); + } + if (ProfileUrl.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ProfileUrl); + } + if (IsAuthenticated != false) { + size += 1 + 1; + } + size += channels_.CalculateSize(_repeated_channels_codec); + if (CreatedAt != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(CreatedAt); + } + if (Id.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(Id); + } + if (UnRegisterUrl.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(UnRegisterUrl); + } + if (UpdateSubscriberUrl.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(UpdateSubscriberUrl); + } + if (HeartbeatUrl.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(HeartbeatUrl); + } + if (HeartbeatIntervalMs != 0L) { + size += 2 + pb::CodedOutputStream.ComputeInt64Size(HeartbeatIntervalMs); + } + if (IdleTimeoutMs != 0L) { + size += 2 + pb::CodedOutputStream.ComputeInt64Size(IdleTimeoutMs); + } + if (responseStatus_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StreamServerEventsResponse other) { + if (other == null) { + return; + } + if (other.EventId != 0L) { + EventId = other.EventId; + } + if (other.Channel.Length != 0) { + Channel = other.Channel; + } + if (other.Selector.Length != 0) { + Selector = other.Selector; + } + if (other.Json.Length != 0) { + Json = other.Json; + } + if (other.Op.Length != 0) { + Op = other.Op; + } + if (other.Target.Length != 0) { + Target = other.Target; + } + if (other.CssSelector.Length != 0) { + CssSelector = other.CssSelector; + } + meta_.Add(other.meta_); + if (other.UserId.Length != 0) { + UserId = other.UserId; + } + if (other.DisplayName.Length != 0) { + DisplayName = other.DisplayName; + } + if (other.ProfileUrl.Length != 0) { + ProfileUrl = other.ProfileUrl; + } + if (other.IsAuthenticated != false) { + IsAuthenticated = other.IsAuthenticated; + } + channels_.Add(other.channels_); + if (other.CreatedAt != 0L) { + CreatedAt = other.CreatedAt; + } + if (other.Id.Length != 0) { + Id = other.Id; + } + if (other.UnRegisterUrl.Length != 0) { + UnRegisterUrl = other.UnRegisterUrl; + } + if (other.UpdateSubscriberUrl.Length != 0) { + UpdateSubscriberUrl = other.UpdateSubscriberUrl; + } + if (other.HeartbeatUrl.Length != 0) { + HeartbeatUrl = other.HeartbeatUrl; + } + if (other.HeartbeatIntervalMs != 0L) { + HeartbeatIntervalMs = other.HeartbeatIntervalMs; + } + if (other.IdleTimeoutMs != 0L) { + IdleTimeoutMs = other.IdleTimeoutMs; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + EventId = input.ReadInt64(); + break; + } + case 18: { + Channel = input.ReadString(); + break; + } + case 34: { + Selector = input.ReadString(); + break; + } + case 42: { + Json = input.ReadString(); + break; + } + case 50: { + Op = input.ReadString(); + break; + } + case 58: { + Target = input.ReadString(); + break; + } + case 66: { + CssSelector = input.ReadString(); + break; + } + case 74: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 82: { + UserId = input.ReadString(); + break; + } + case 90: { + DisplayName = input.ReadString(); + break; + } + case 98: { + ProfileUrl = input.ReadString(); + break; + } + case 104: { + IsAuthenticated = input.ReadBool(); + break; + } + case 114: { + channels_.AddEntriesFrom(input, _repeated_channels_codec); + break; + } + case 120: { + CreatedAt = input.ReadInt64(); + break; + } + case 170: { + Id = input.ReadString(); + break; + } + case 178: { + UnRegisterUrl = input.ReadString(); + break; + } + case 186: { + UpdateSubscriberUrl = input.ReadString(); + break; + } + case 194: { + HeartbeatUrl = input.ReadString(); + break; + } + case 200: { + HeartbeatIntervalMs = input.ReadInt64(); + break; + } + case 208: { + IdleTimeoutMs = input.ReadInt64(); + break; + } + case 242: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class TestAuthValidators : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TestAuthValidators()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[187]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestAuthValidators() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestAuthValidators(TestAuthValidators other) : this() { + notNull_ = other.notNull_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestAuthValidators Clone() { + return new TestAuthValidators(this); + } + + /// Field number for the "NotNull" field. + public const int NotNullFieldNumber = 1; + private string notNull_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotNull { + get { return notNull_; } + set { + notNull_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TestAuthValidators); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TestAuthValidators other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NotNull != other.NotNull) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NotNull.Length != 0) hash ^= NotNull.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (NotNull.Length != 0) { + output.WriteRawTag(10); + output.WriteString(NotNull); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NotNull.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotNull); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TestAuthValidators other) { + if (other == null) { + return; + } + if (other.NotNull.Length != 0) { + NotNull = other.NotNull; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + NotNull = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class TestDbCondition : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TestDbCondition()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[188]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestDbCondition() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestDbCondition(TestDbCondition other) : this() { + id_ = other.id_; + notNull_ = other.notNull_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestDbCondition Clone() { + return new TestDbCondition(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "NotNull" field. + public const int NotNullFieldNumber = 2; + private string notNull_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotNull { + get { return notNull_; } + set { + notNull_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TestDbCondition); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TestDbCondition other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (NotNull != other.NotNull) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (NotNull.Length != 0) hash ^= NotNull.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (NotNull.Length != 0) { + output.WriteRawTag(18); + output.WriteString(NotNull); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (NotNull.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotNull); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TestDbCondition other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.NotNull.Length != 0) { + NotNull = other.NotNull; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + NotNull = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class TestDbValidator : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TestDbValidator()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[189]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestDbValidator() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestDbValidator(TestDbValidator other) : this() { + id_ = other.id_; + notNull_ = other.notNull_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestDbValidator Clone() { + return new TestDbValidator(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "NotNull" field. + public const int NotNullFieldNumber = 2; + private string notNull_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotNull { + get { return notNull_; } + set { + notNull_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TestDbValidator); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TestDbValidator other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (NotNull != other.NotNull) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (NotNull.Length != 0) hash ^= NotNull.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (NotNull.Length != 0) { + output.WriteRawTag(18); + output.WriteString(NotNull); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (NotNull.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotNull); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TestDbValidator other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.NotNull.Length != 0) { + NotNull = other.NotNull; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + NotNull = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class TestIsAdmin : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TestIsAdmin()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[190]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestIsAdmin() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestIsAdmin(TestIsAdmin other) : this() { + notNull_ = other.notNull_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestIsAdmin Clone() { + return new TestIsAdmin(this); + } + + /// Field number for the "NotNull" field. + public const int NotNullFieldNumber = 1; + private string notNull_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotNull { + get { return notNull_; } + set { + notNull_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TestIsAdmin); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TestIsAdmin other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NotNull != other.NotNull) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NotNull.Length != 0) hash ^= NotNull.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (NotNull.Length != 0) { + output.WriteRawTag(10); + output.WriteString(NotNull); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NotNull.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotNull); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TestIsAdmin other) { + if (other == null) { + return; + } + if (other.NotNull.Length != 0) { + NotNull = other.NotNull; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + NotNull = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class TestMultiAuthValidators : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TestMultiAuthValidators()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[191]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestMultiAuthValidators() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestMultiAuthValidators(TestMultiAuthValidators other) : this() { + notNull_ = other.notNull_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TestMultiAuthValidators Clone() { + return new TestMultiAuthValidators(this); + } + + /// Field number for the "NotNull" field. + public const int NotNullFieldNumber = 1; + private string notNull_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotNull { + get { return notNull_; } + set { + notNull_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TestMultiAuthValidators); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TestMultiAuthValidators other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NotNull != other.NotNull) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NotNull.Length != 0) hash ^= NotNull.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (NotNull.Length != 0) { + output.WriteRawTag(10); + output.WriteString(NotNull); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NotNull.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotNull); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TestMultiAuthValidators other) { + if (other == null) { + return; + } + if (other.NotNull.Length != 0) { + NotNull = other.NotNull; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + NotNull = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class Throw : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Throw()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[192]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Throw() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Throw(Throw other) : this() { + message_ = other.message_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Throw Clone() { + return new Throw(this); + } + + /// Field number for the "Message" field. + public const int MessageFieldNumber = 1; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Throw); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Throw other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Message != other.Message) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Message.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Message); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Throw other) { + if (other == null) { + return; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Message = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class ThrowCustom : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ThrowCustom()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[193]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowCustom() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowCustom(ThrowCustom other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowCustom Clone() { + return new ThrowCustom(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ThrowCustom); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ThrowCustom other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ThrowCustom other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class ThrowCustomResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ThrowCustomResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[194]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowCustomResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowCustomResponse(ThrowCustomResponse other) : this() { + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowCustomResponse Clone() { + return new ThrowCustomResponse(this); + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 1; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ThrowCustomResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ThrowCustomResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (responseStatus_ != null) { + output.WriteRawTag(10); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ThrowCustomResponse other) { + if (other == null) { + return; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class ThrowVoid : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ThrowVoid()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[195]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowVoid() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowVoid(ThrowVoid other) : this() { + message_ = other.message_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ThrowVoid Clone() { + return new ThrowVoid(this); + } + + /// Field number for the "Message" field. + public const int MessageFieldNumber = 1; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ThrowVoid); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ThrowVoid other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Message != other.Message) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Message.Length != 0) hash ^= Message.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Message.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Message); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ThrowVoid other) { + if (other == null) { + return; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Message = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class Todo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Todo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[196]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Todo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Todo(Todo other) : this() { + id_ = other.id_; + title_ = other.title_; + order_ = other.order_; + completed_ = other.completed_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Todo Clone() { + return new Todo(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Title" field. + public const int TitleFieldNumber = 2; + private string title_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Title { + get { return title_; } + set { + title_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Order" field. + public const int OrderFieldNumber = 3; + private int order_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Order { + get { return order_; } + set { + order_ = value; + } + } + + /// Field number for the "Completed" field. + public const int CompletedFieldNumber = 4; + private bool completed_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Completed { + get { return completed_; } + set { + completed_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Todo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Todo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Title != other.Title) return false; + if (Order != other.Order) return false; + if (Completed != other.Completed) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (Title.Length != 0) hash ^= Title.GetHashCode(); + if (Order != 0) hash ^= Order.GetHashCode(); + if (Completed != false) hash ^= Completed.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Title.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Title); + } + if (Order != 0) { + output.WriteRawTag(24); + output.WriteInt32(Order); + } + if (Completed != false) { + output.WriteRawTag(32); + output.WriteBool(Completed); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (Title.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Title); + } + if (Order != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Order); + } + if (Completed != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Todo other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + if (other.Title.Length != 0) { + Title = other.Title; + } + if (other.Order != 0) { + Order = other.Order; + } + if (other.Completed != false) { + Completed = other.Completed; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 18: { + Title = input.ReadString(); + break; + } + case 24: { + Order = input.ReadInt32(); + break; + } + case 32: { + Completed = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class TriggerAllValidators : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TriggerAllValidators()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[197]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TriggerAllValidators() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TriggerAllValidators(TriggerAllValidators other) : this() { + creditCard_ = other.creditCard_; + email_ = other.email_; + empty_ = other.empty_; + equal_ = other.equal_; + exclusiveBetween_ = other.exclusiveBetween_; + greaterThanOrEqual_ = other.greaterThanOrEqual_; + greaterThan_ = other.greaterThan_; + inclusiveBetween_ = other.inclusiveBetween_; + length_ = other.length_; + lessThanOrEqual_ = other.lessThanOrEqual_; + lessThan_ = other.lessThan_; + notEmpty_ = other.notEmpty_; + notEqual_ = other.notEqual_; + null_ = other.null_; + regularExpression_ = other.regularExpression_; + scalePrecision_ = other.scalePrecision_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TriggerAllValidators Clone() { + return new TriggerAllValidators(this); + } + + /// Field number for the "CreditCard" field. + public const int CreditCardFieldNumber = 1; + private string creditCard_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreditCard { + get { return creditCard_; } + set { + creditCard_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Email" field. + public const int EmailFieldNumber = 2; + private string email_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Email { + get { return email_; } + set { + email_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Empty" field. + public const int EmptyFieldNumber = 3; + private string empty_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Empty { + get { return empty_; } + set { + empty_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Equal" field. + public const int EqualFieldNumber = 4; + private string equal_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Equal { + get { return equal_; } + set { + equal_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ExclusiveBetween" field. + public const int ExclusiveBetweenFieldNumber = 5; + private int exclusiveBetween_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ExclusiveBetween { + get { return exclusiveBetween_; } + set { + exclusiveBetween_ = value; + } + } + + /// Field number for the "GreaterThanOrEqual" field. + public const int GreaterThanOrEqualFieldNumber = 6; + private int greaterThanOrEqual_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int GreaterThanOrEqual { + get { return greaterThanOrEqual_; } + set { + greaterThanOrEqual_ = value; + } + } + + /// Field number for the "GreaterThan" field. + public const int GreaterThanFieldNumber = 7; + private int greaterThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int GreaterThan { + get { return greaterThan_; } + set { + greaterThan_ = value; + } + } + + /// Field number for the "InclusiveBetween" field. + public const int InclusiveBetweenFieldNumber = 8; + private int inclusiveBetween_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int InclusiveBetween { + get { return inclusiveBetween_; } + set { + inclusiveBetween_ = value; + } + } + + /// Field number for the "Length" field. + public const int LengthFieldNumber = 9; + private string length_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Length { + get { return length_; } + set { + length_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LessThanOrEqual" field. + public const int LessThanOrEqualFieldNumber = 10; + private int lessThanOrEqual_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int LessThanOrEqual { + get { return lessThanOrEqual_; } + set { + lessThanOrEqual_ = value; + } + } + + /// Field number for the "LessThan" field. + public const int LessThanFieldNumber = 11; + private int lessThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int LessThan { + get { return lessThan_; } + set { + lessThan_ = value; + } + } + + /// Field number for the "NotEmpty" field. + public const int NotEmptyFieldNumber = 12; + private string notEmpty_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotEmpty { + get { return notEmpty_; } + set { + notEmpty_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "NotEqual" field. + public const int NotEqualFieldNumber = 13; + private string notEqual_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotEqual { + get { return notEqual_; } + set { + notEqual_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Null" field. + public const int NullFieldNumber = 14; + private string null_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Null { + get { return null_; } + set { + null_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RegularExpression" field. + public const int RegularExpressionFieldNumber = 15; + private string regularExpression_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RegularExpression { + get { return regularExpression_; } + set { + regularExpression_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ScalePrecision" field. + public const int ScalePrecisionFieldNumber = 16; + private string scalePrecision_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ScalePrecision { + get { return scalePrecision_; } + set { + scalePrecision_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TriggerAllValidators); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TriggerAllValidators other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (CreditCard != other.CreditCard) return false; + if (Email != other.Email) return false; + if (Empty != other.Empty) return false; + if (Equal != other.Equal) return false; + if (ExclusiveBetween != other.ExclusiveBetween) return false; + if (GreaterThanOrEqual != other.GreaterThanOrEqual) return false; + if (GreaterThan != other.GreaterThan) return false; + if (InclusiveBetween != other.InclusiveBetween) return false; + if (Length != other.Length) return false; + if (LessThanOrEqual != other.LessThanOrEqual) return false; + if (LessThan != other.LessThan) return false; + if (NotEmpty != other.NotEmpty) return false; + if (NotEqual != other.NotEqual) return false; + if (Null != other.Null) return false; + if (RegularExpression != other.RegularExpression) return false; + if (ScalePrecision != other.ScalePrecision) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (CreditCard.Length != 0) hash ^= CreditCard.GetHashCode(); + if (Email.Length != 0) hash ^= Email.GetHashCode(); + if (Empty.Length != 0) hash ^= Empty.GetHashCode(); + if (Equal.Length != 0) hash ^= Equal.GetHashCode(); + if (ExclusiveBetween != 0) hash ^= ExclusiveBetween.GetHashCode(); + if (GreaterThanOrEqual != 0) hash ^= GreaterThanOrEqual.GetHashCode(); + if (GreaterThan != 0) hash ^= GreaterThan.GetHashCode(); + if (InclusiveBetween != 0) hash ^= InclusiveBetween.GetHashCode(); + if (Length.Length != 0) hash ^= Length.GetHashCode(); + if (LessThanOrEqual != 0) hash ^= LessThanOrEqual.GetHashCode(); + if (LessThan != 0) hash ^= LessThan.GetHashCode(); + if (NotEmpty.Length != 0) hash ^= NotEmpty.GetHashCode(); + if (NotEqual.Length != 0) hash ^= NotEqual.GetHashCode(); + if (Null.Length != 0) hash ^= Null.GetHashCode(); + if (RegularExpression.Length != 0) hash ^= RegularExpression.GetHashCode(); + if (ScalePrecision.Length != 0) hash ^= ScalePrecision.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (CreditCard.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CreditCard); + } + if (Email.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Email); + } + if (Empty.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Empty); + } + if (Equal.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Equal); + } + if (ExclusiveBetween != 0) { + output.WriteRawTag(40); + output.WriteInt32(ExclusiveBetween); + } + if (GreaterThanOrEqual != 0) { + output.WriteRawTag(48); + output.WriteInt32(GreaterThanOrEqual); + } + if (GreaterThan != 0) { + output.WriteRawTag(56); + output.WriteInt32(GreaterThan); + } + if (InclusiveBetween != 0) { + output.WriteRawTag(64); + output.WriteInt32(InclusiveBetween); + } + if (Length.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Length); + } + if (LessThanOrEqual != 0) { + output.WriteRawTag(80); + output.WriteInt32(LessThanOrEqual); + } + if (LessThan != 0) { + output.WriteRawTag(88); + output.WriteInt32(LessThan); + } + if (NotEmpty.Length != 0) { + output.WriteRawTag(98); + output.WriteString(NotEmpty); + } + if (NotEqual.Length != 0) { + output.WriteRawTag(106); + output.WriteString(NotEqual); + } + if (Null.Length != 0) { + output.WriteRawTag(114); + output.WriteString(Null); + } + if (RegularExpression.Length != 0) { + output.WriteRawTag(122); + output.WriteString(RegularExpression); + } + if (ScalePrecision.Length != 0) { + output.WriteRawTag(130, 1); + output.WriteString(ScalePrecision); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (CreditCard.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreditCard); + } + if (Email.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Email); + } + if (Empty.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Empty); + } + if (Equal.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Equal); + } + if (ExclusiveBetween != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ExclusiveBetween); + } + if (GreaterThanOrEqual != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(GreaterThanOrEqual); + } + if (GreaterThan != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(GreaterThan); + } + if (InclusiveBetween != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(InclusiveBetween); + } + if (Length.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Length); + } + if (LessThanOrEqual != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(LessThanOrEqual); + } + if (LessThan != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(LessThan); + } + if (NotEmpty.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotEmpty); + } + if (NotEqual.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotEqual); + } + if (Null.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Null); + } + if (RegularExpression.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RegularExpression); + } + if (ScalePrecision.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(ScalePrecision); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TriggerAllValidators other) { + if (other == null) { + return; + } + if (other.CreditCard.Length != 0) { + CreditCard = other.CreditCard; + } + if (other.Email.Length != 0) { + Email = other.Email; + } + if (other.Empty.Length != 0) { + Empty = other.Empty; + } + if (other.Equal.Length != 0) { + Equal = other.Equal; + } + if (other.ExclusiveBetween != 0) { + ExclusiveBetween = other.ExclusiveBetween; + } + if (other.GreaterThanOrEqual != 0) { + GreaterThanOrEqual = other.GreaterThanOrEqual; + } + if (other.GreaterThan != 0) { + GreaterThan = other.GreaterThan; + } + if (other.InclusiveBetween != 0) { + InclusiveBetween = other.InclusiveBetween; + } + if (other.Length.Length != 0) { + Length = other.Length; + } + if (other.LessThanOrEqual != 0) { + LessThanOrEqual = other.LessThanOrEqual; + } + if (other.LessThan != 0) { + LessThan = other.LessThan; + } + if (other.NotEmpty.Length != 0) { + NotEmpty = other.NotEmpty; + } + if (other.NotEqual.Length != 0) { + NotEqual = other.NotEqual; + } + if (other.Null.Length != 0) { + Null = other.Null; + } + if (other.RegularExpression.Length != 0) { + RegularExpression = other.RegularExpression; + } + if (other.ScalePrecision.Length != 0) { + ScalePrecision = other.ScalePrecision; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + CreditCard = input.ReadString(); + break; + } + case 18: { + Email = input.ReadString(); + break; + } + case 26: { + Empty = input.ReadString(); + break; + } + case 34: { + Equal = input.ReadString(); + break; + } + case 40: { + ExclusiveBetween = input.ReadInt32(); + break; + } + case 48: { + GreaterThanOrEqual = input.ReadInt32(); + break; + } + case 56: { + GreaterThan = input.ReadInt32(); + break; + } + case 64: { + InclusiveBetween = input.ReadInt32(); + break; + } + case 74: { + Length = input.ReadString(); + break; + } + case 80: { + LessThanOrEqual = input.ReadInt32(); + break; + } + case 88: { + LessThan = input.ReadInt32(); + break; + } + case 98: { + NotEmpty = input.ReadString(); + break; + } + case 106: { + NotEqual = input.ReadString(); + break; + } + case 114: { + Null = input.ReadString(); + break; + } + case 122: { + RegularExpression = input.ReadString(); + break; + } + case 130: { + ScalePrecision = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class TriggerValidators : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TriggerValidators()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[198]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TriggerValidators() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TriggerValidators(TriggerValidators other) : this() { + creditCard_ = other.creditCard_; + email_ = other.email_; + empty_ = other.empty_; + equal_ = other.equal_; + exclusiveBetween_ = other.exclusiveBetween_; + greaterThanOrEqual_ = other.greaterThanOrEqual_; + greaterThan_ = other.greaterThan_; + inclusiveBetween_ = other.inclusiveBetween_; + length_ = other.length_; + lessThanOrEqual_ = other.lessThanOrEqual_; + lessThan_ = other.lessThan_; + notEmpty_ = other.notEmpty_; + notEqual_ = other.notEqual_; + null_ = other.null_; + regularExpression_ = other.regularExpression_; + scalePrecision_ = other.scalePrecision_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TriggerValidators Clone() { + return new TriggerValidators(this); + } + + /// Field number for the "CreditCard" field. + public const int CreditCardFieldNumber = 1; + private string creditCard_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CreditCard { + get { return creditCard_; } + set { + creditCard_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Email" field. + public const int EmailFieldNumber = 2; + private string email_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Email { + get { return email_; } + set { + email_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Empty" field. + public const int EmptyFieldNumber = 3; + private string empty_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Empty { + get { return empty_; } + set { + empty_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Equal" field. + public const int EqualFieldNumber = 4; + private string equal_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Equal { + get { return equal_; } + set { + equal_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ExclusiveBetween" field. + public const int ExclusiveBetweenFieldNumber = 5; + private int exclusiveBetween_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ExclusiveBetween { + get { return exclusiveBetween_; } + set { + exclusiveBetween_ = value; + } + } + + /// Field number for the "GreaterThanOrEqual" field. + public const int GreaterThanOrEqualFieldNumber = 6; + private int greaterThanOrEqual_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int GreaterThanOrEqual { + get { return greaterThanOrEqual_; } + set { + greaterThanOrEqual_ = value; + } + } + + /// Field number for the "GreaterThan" field. + public const int GreaterThanFieldNumber = 7; + private int greaterThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int GreaterThan { + get { return greaterThan_; } + set { + greaterThan_ = value; + } + } + + /// Field number for the "InclusiveBetween" field. + public const int InclusiveBetweenFieldNumber = 8; + private int inclusiveBetween_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int InclusiveBetween { + get { return inclusiveBetween_; } + set { + inclusiveBetween_ = value; + } + } + + /// Field number for the "Length" field. + public const int LengthFieldNumber = 9; + private string length_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Length { + get { return length_; } + set { + length_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LessThanOrEqual" field. + public const int LessThanOrEqualFieldNumber = 10; + private int lessThanOrEqual_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int LessThanOrEqual { + get { return lessThanOrEqual_; } + set { + lessThanOrEqual_ = value; + } + } + + /// Field number for the "LessThan" field. + public const int LessThanFieldNumber = 11; + private int lessThan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int LessThan { + get { return lessThan_; } + set { + lessThan_ = value; + } + } + + /// Field number for the "NotEmpty" field. + public const int NotEmptyFieldNumber = 12; + private string notEmpty_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotEmpty { + get { return notEmpty_; } + set { + notEmpty_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "NotEqual" field. + public const int NotEqualFieldNumber = 13; + private string notEqual_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NotEqual { + get { return notEqual_; } + set { + notEqual_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Null" field. + public const int NullFieldNumber = 14; + private string null_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Null { + get { return null_; } + set { + null_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "RegularExpression" field. + public const int RegularExpressionFieldNumber = 15; + private string regularExpression_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string RegularExpression { + get { return regularExpression_; } + set { + regularExpression_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ScalePrecision" field. + public const int ScalePrecisionFieldNumber = 16; + private string scalePrecision_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ScalePrecision { + get { return scalePrecision_; } + set { + scalePrecision_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TriggerValidators); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TriggerValidators other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (CreditCard != other.CreditCard) return false; + if (Email != other.Email) return false; + if (Empty != other.Empty) return false; + if (Equal != other.Equal) return false; + if (ExclusiveBetween != other.ExclusiveBetween) return false; + if (GreaterThanOrEqual != other.GreaterThanOrEqual) return false; + if (GreaterThan != other.GreaterThan) return false; + if (InclusiveBetween != other.InclusiveBetween) return false; + if (Length != other.Length) return false; + if (LessThanOrEqual != other.LessThanOrEqual) return false; + if (LessThan != other.LessThan) return false; + if (NotEmpty != other.NotEmpty) return false; + if (NotEqual != other.NotEqual) return false; + if (Null != other.Null) return false; + if (RegularExpression != other.RegularExpression) return false; + if (ScalePrecision != other.ScalePrecision) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (CreditCard.Length != 0) hash ^= CreditCard.GetHashCode(); + if (Email.Length != 0) hash ^= Email.GetHashCode(); + if (Empty.Length != 0) hash ^= Empty.GetHashCode(); + if (Equal.Length != 0) hash ^= Equal.GetHashCode(); + if (ExclusiveBetween != 0) hash ^= ExclusiveBetween.GetHashCode(); + if (GreaterThanOrEqual != 0) hash ^= GreaterThanOrEqual.GetHashCode(); + if (GreaterThan != 0) hash ^= GreaterThan.GetHashCode(); + if (InclusiveBetween != 0) hash ^= InclusiveBetween.GetHashCode(); + if (Length.Length != 0) hash ^= Length.GetHashCode(); + if (LessThanOrEqual != 0) hash ^= LessThanOrEqual.GetHashCode(); + if (LessThan != 0) hash ^= LessThan.GetHashCode(); + if (NotEmpty.Length != 0) hash ^= NotEmpty.GetHashCode(); + if (NotEqual.Length != 0) hash ^= NotEqual.GetHashCode(); + if (Null.Length != 0) hash ^= Null.GetHashCode(); + if (RegularExpression.Length != 0) hash ^= RegularExpression.GetHashCode(); + if (ScalePrecision.Length != 0) hash ^= ScalePrecision.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (CreditCard.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CreditCard); + } + if (Email.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Email); + } + if (Empty.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Empty); + } + if (Equal.Length != 0) { + output.WriteRawTag(34); + output.WriteString(Equal); + } + if (ExclusiveBetween != 0) { + output.WriteRawTag(40); + output.WriteInt32(ExclusiveBetween); + } + if (GreaterThanOrEqual != 0) { + output.WriteRawTag(48); + output.WriteInt32(GreaterThanOrEqual); + } + if (GreaterThan != 0) { + output.WriteRawTag(56); + output.WriteInt32(GreaterThan); + } + if (InclusiveBetween != 0) { + output.WriteRawTag(64); + output.WriteInt32(InclusiveBetween); + } + if (Length.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Length); + } + if (LessThanOrEqual != 0) { + output.WriteRawTag(80); + output.WriteInt32(LessThanOrEqual); + } + if (LessThan != 0) { + output.WriteRawTag(88); + output.WriteInt32(LessThan); + } + if (NotEmpty.Length != 0) { + output.WriteRawTag(98); + output.WriteString(NotEmpty); + } + if (NotEqual.Length != 0) { + output.WriteRawTag(106); + output.WriteString(NotEqual); + } + if (Null.Length != 0) { + output.WriteRawTag(114); + output.WriteString(Null); + } + if (RegularExpression.Length != 0) { + output.WriteRawTag(122); + output.WriteString(RegularExpression); + } + if (ScalePrecision.Length != 0) { + output.WriteRawTag(130, 1); + output.WriteString(ScalePrecision); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (CreditCard.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CreditCard); + } + if (Email.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Email); + } + if (Empty.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Empty); + } + if (Equal.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Equal); + } + if (ExclusiveBetween != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ExclusiveBetween); + } + if (GreaterThanOrEqual != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(GreaterThanOrEqual); + } + if (GreaterThan != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(GreaterThan); + } + if (InclusiveBetween != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(InclusiveBetween); + } + if (Length.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Length); + } + if (LessThanOrEqual != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(LessThanOrEqual); + } + if (LessThan != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(LessThan); + } + if (NotEmpty.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotEmpty); + } + if (NotEqual.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NotEqual); + } + if (Null.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Null); + } + if (RegularExpression.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(RegularExpression); + } + if (ScalePrecision.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(ScalePrecision); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TriggerValidators other) { + if (other == null) { + return; + } + if (other.CreditCard.Length != 0) { + CreditCard = other.CreditCard; + } + if (other.Email.Length != 0) { + Email = other.Email; + } + if (other.Empty.Length != 0) { + Empty = other.Empty; + } + if (other.Equal.Length != 0) { + Equal = other.Equal; + } + if (other.ExclusiveBetween != 0) { + ExclusiveBetween = other.ExclusiveBetween; + } + if (other.GreaterThanOrEqual != 0) { + GreaterThanOrEqual = other.GreaterThanOrEqual; + } + if (other.GreaterThan != 0) { + GreaterThan = other.GreaterThan; + } + if (other.InclusiveBetween != 0) { + InclusiveBetween = other.InclusiveBetween; + } + if (other.Length.Length != 0) { + Length = other.Length; + } + if (other.LessThanOrEqual != 0) { + LessThanOrEqual = other.LessThanOrEqual; + } + if (other.LessThan != 0) { + LessThan = other.LessThan; + } + if (other.NotEmpty.Length != 0) { + NotEmpty = other.NotEmpty; + } + if (other.NotEqual.Length != 0) { + NotEqual = other.NotEqual; + } + if (other.Null.Length != 0) { + Null = other.Null; + } + if (other.RegularExpression.Length != 0) { + RegularExpression = other.RegularExpression; + } + if (other.ScalePrecision.Length != 0) { + ScalePrecision = other.ScalePrecision; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + CreditCard = input.ReadString(); + break; + } + case 18: { + Email = input.ReadString(); + break; + } + case 26: { + Empty = input.ReadString(); + break; + } + case 34: { + Equal = input.ReadString(); + break; + } + case 40: { + ExclusiveBetween = input.ReadInt32(); + break; + } + case 48: { + GreaterThanOrEqual = input.ReadInt32(); + break; + } + case 56: { + GreaterThan = input.ReadInt32(); + break; + } + case 64: { + InclusiveBetween = input.ReadInt32(); + break; + } + case 74: { + Length = input.ReadString(); + break; + } + case 80: { + LessThanOrEqual = input.ReadInt32(); + break; + } + case 88: { + LessThan = input.ReadInt32(); + break; + } + case 98: { + NotEmpty = input.ReadString(); + break; + } + case 106: { + NotEqual = input.ReadString(); + break; + } + case 114: { + Null = input.ReadString(); + break; + } + case 122: { + RegularExpression = input.ReadString(); + break; + } + case 130: { + ScalePrecision = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class TypeWithEnum : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TypeWithEnum()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[199]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TypeWithEnum() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TypeWithEnum(TypeWithEnum other) : this() { + id_ = other.id_; + name_ = other.name_; + someEnum_ = other.someEnum_; + someEnumAsInt_ = other.someEnumAsInt_; + nSomeEnum_ = other.nSomeEnum_; + nSomeEnumAsInt_ = other.nSomeEnumAsInt_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TypeWithEnum Clone() { + return new TypeWithEnum(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 2; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "SomeEnum" field. + public const int SomeEnumFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.SomeEnum someEnum_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.SomeEnum SomeEnum { + get { return someEnum_; } + set { + someEnum_ = value; + } + } + + /// Field number for the "SomeEnumAsInt" field. + public const int SomeEnumAsIntFieldNumber = 4; + private global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt someEnumAsInt_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt SomeEnumAsInt { + get { return someEnumAsInt_; } + set { + someEnumAsInt_ = value; + } + } + + /// Field number for the "NSomeEnum" field. + public const int NSomeEnumFieldNumber = 5; + private global::ServiceStack.Extensions.Tests.Protoc.SomeEnum nSomeEnum_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.SomeEnum NSomeEnum { + get { return nSomeEnum_; } + set { + nSomeEnum_ = value; + } + } + + /// Field number for the "NSomeEnumAsInt" field. + public const int NSomeEnumAsIntFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt nSomeEnumAsInt_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt NSomeEnumAsInt { + get { return nSomeEnumAsInt_; } + set { + nSomeEnumAsInt_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TypeWithEnum); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TypeWithEnum other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Name != other.Name) return false; + if (SomeEnum != other.SomeEnum) return false; + if (SomeEnumAsInt != other.SomeEnumAsInt) return false; + if (NSomeEnum != other.NSomeEnum) return false; + if (NSomeEnumAsInt != other.NSomeEnumAsInt) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (SomeEnum != 0) hash ^= SomeEnum.GetHashCode(); + if (SomeEnumAsInt != 0) hash ^= SomeEnumAsInt.GetHashCode(); + if (NSomeEnum != 0) hash ^= NSomeEnum.GetHashCode(); + if (NSomeEnumAsInt != 0) hash ^= NSomeEnumAsInt.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (Name.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Name); + } + if (SomeEnum != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) SomeEnum); + } + if (SomeEnumAsInt != 0) { + output.WriteRawTag(32); + output.WriteEnum((int) SomeEnumAsInt); + } + if (NSomeEnum != 0) { + output.WriteRawTag(40); + output.WriteEnum((int) NSomeEnum); + } + if (NSomeEnumAsInt != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) NSomeEnumAsInt); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (SomeEnum != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SomeEnum); + } + if (SomeEnumAsInt != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SomeEnumAsInt); + } + if (NSomeEnum != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NSomeEnum); + } + if (NSomeEnumAsInt != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NSomeEnumAsInt); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TypeWithEnum other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.SomeEnum != 0) { + SomeEnum = other.SomeEnum; + } + if (other.SomeEnumAsInt != 0) { + SomeEnumAsInt = other.SomeEnumAsInt; + } + if (other.NSomeEnum != 0) { + NSomeEnum = other.NSomeEnum; + } + if (other.NSomeEnumAsInt != 0) { + NSomeEnumAsInt = other.NSomeEnumAsInt; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + Name = input.ReadString(); + break; + } + case 24: { + SomeEnum = (global::ServiceStack.Extensions.Tests.Protoc.SomeEnum) input.ReadEnum(); + break; + } + case 32: { + SomeEnumAsInt = (global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt) input.ReadEnum(); + break; + } + case 40: { + NSomeEnum = (global::ServiceStack.Extensions.Tests.Protoc.SomeEnum) input.ReadEnum(); + break; + } + case 48: { + NSomeEnumAsInt = (global::ServiceStack.Extensions.Tests.Protoc.SomeEnumAsInt) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class UnAssignRoles : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UnAssignRoles()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[200]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnAssignRoles() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnAssignRoles(UnAssignRoles other) : this() { + userName_ = other.userName_; + permissions_ = other.permissions_.Clone(); + roles_ = other.roles_.Clone(); + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnAssignRoles Clone() { + return new UnAssignRoles(this); + } + + /// Field number for the "UserName" field. + public const int UserNameFieldNumber = 1; + private string userName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserName { + get { return userName_; } + set { + userName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Permissions" field. + public const int PermissionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_permissions_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField permissions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Permissions { + get { return permissions_; } + } + + /// Field number for the "Roles" field. + public const int RolesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_roles_codec + = pb::FieldCodec.ForString(26); + private readonly pbc::RepeatedField roles_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Roles { + get { return roles_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UnAssignRoles); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UnAssignRoles other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (UserName != other.UserName) return false; + if(!permissions_.Equals(other.permissions_)) return false; + if(!roles_.Equals(other.roles_)) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (UserName.Length != 0) hash ^= UserName.GetHashCode(); + hash ^= permissions_.GetHashCode(); + hash ^= roles_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (UserName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(UserName); + } + permissions_.WriteTo(output, _repeated_permissions_codec); + roles_.WriteTo(output, _repeated_roles_codec); + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (UserName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserName); + } + size += permissions_.CalculateSize(_repeated_permissions_codec); + size += roles_.CalculateSize(_repeated_roles_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UnAssignRoles other) { + if (other == null) { + return; + } + if (other.UserName.Length != 0) { + UserName = other.UserName; + } + permissions_.Add(other.permissions_); + roles_.Add(other.roles_); + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + UserName = input.ReadString(); + break; + } + case 18: { + permissions_.AddEntriesFrom(input, _repeated_permissions_codec); + break; + } + case 26: { + roles_.AddEntriesFrom(input, _repeated_roles_codec); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class UnAssignRolesResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UnAssignRolesResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[201]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnAssignRolesResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnAssignRolesResponse(UnAssignRolesResponse other) : this() { + allRoles_ = other.allRoles_.Clone(); + allPermissions_ = other.allPermissions_.Clone(); + meta_ = other.meta_.Clone(); + responseStatus_ = other.responseStatus_ != null ? other.responseStatus_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnAssignRolesResponse Clone() { + return new UnAssignRolesResponse(this); + } + + /// Field number for the "AllRoles" field. + public const int AllRolesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_allRoles_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField allRoles_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AllRoles { + get { return allRoles_; } + } + + /// Field number for the "AllPermissions" field. + public const int AllPermissionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_allPermissions_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField allPermissions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AllPermissions { + get { return allPermissions_; } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 3; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 26); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + /// Field number for the "ResponseStatus" field. + public const int ResponseStatusFieldNumber = 4; + private global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus responseStatus_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UnAssignRolesResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UnAssignRolesResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!allRoles_.Equals(other.allRoles_)) return false; + if(!allPermissions_.Equals(other.allPermissions_)) return false; + if (!Meta.Equals(other.Meta)) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= allRoles_.GetHashCode(); + hash ^= allPermissions_.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + allRoles_.WriteTo(output, _repeated_allRoles_codec); + allPermissions_.WriteTo(output, _repeated_allPermissions_codec); + meta_.WriteTo(output, _map_meta_codec); + if (responseStatus_ != null) { + output.WriteRawTag(34); + output.WriteMessage(ResponseStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += allRoles_.CalculateSize(_repeated_allRoles_codec); + size += allPermissions_.CalculateSize(_repeated_allPermissions_codec); + size += meta_.CalculateSize(_map_meta_codec); + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UnAssignRolesResponse other) { + if (other == null) { + return; + } + allRoles_.Add(other.allRoles_); + allPermissions_.Add(other.allPermissions_); + meta_.Add(other.meta_); + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + allRoles_.AddEntriesFrom(input, _repeated_allRoles_codec); + break; + } + case 18: { + allPermissions_.AddEntriesFrom(input, _repeated_allPermissions_codec); + break; + } + case 26: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + case 34: { + if (responseStatus_ == null) { + ResponseStatus = new global::ServiceStack.Extensions.Tests.Protoc.ResponseStatus(); + } + input.ReadMessage(ResponseStatus); + break; + } + } + } + } + + } + + public sealed partial class UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[202]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[203]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse Clone() { + return new UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + public sealed partial class UpdateConnectionInfoRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateConnectionInfoRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[204]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateConnectionInfoRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateConnectionInfoRockstar(UpdateConnectionInfoRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateConnectionInfoRockstar Clone() { + return new UpdateConnectionInfoRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateConnectionInfoRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateConnectionInfoRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateConnectionInfoRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class UpdateNamedRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateNamedRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[205]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateNamedRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateNamedRockstar(UpdateNamedRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateNamedRockstar Clone() { + return new UpdateNamedRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateNamedRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateNamedRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateNamedRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[206]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstar(UpdateRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstar Clone() { + return new UpdateRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstarAdhocNonDefaults : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstarAdhocNonDefaults()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[207]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAdhocNonDefaults() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAdhocNonDefaults(UpdateRockstarAdhocNonDefaults other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAdhocNonDefaults Clone() { + return new UpdateRockstarAdhocNonDefaults(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 3; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 4; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 6; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 7; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstarAdhocNonDefaults); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstarAdhocNonDefaults other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(32); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(50); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(56); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstarAdhocNonDefaults other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 26: { + LastName = input.ReadString(); + break; + } + case 32: { + Age = input.ReadInt32(); + break; + } + case 42: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 50: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 56: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstarAudit : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstarAudit()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[208]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAudit() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAudit(UpdateRockstarAudit other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAudit Clone() { + return new UpdateRockstarAudit(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstarAudit); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstarAudit other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstarAudit other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstarAuditTenant : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstarAuditTenant()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[209]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenant() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenant(UpdateRockstarAuditTenant other) : this() { + bearerToken_ = other.bearerToken_; + id_ = other.id_; + firstName_ = other.firstName_; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenant Clone() { + return new UpdateRockstarAuditTenant(this); + } + + /// Field number for the "BearerToken" field. + public const int BearerTokenFieldNumber = 201; + private string bearerToken_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BearerToken { + get { return bearerToken_; } + set { + bearerToken_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 202; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 203; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 204; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstarAuditTenant); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstarAuditTenant other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BearerToken != other.BearerToken) return false; + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BearerToken.Length != 0) hash ^= BearerToken.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (BearerToken.Length != 0) { + output.WriteRawTag(202, 12); + output.WriteString(BearerToken); + } + if (Id != 0) { + output.WriteRawTag(208, 12); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(218, 12); + output.WriteString(FirstName); + } + if (LivingStatus != 0) { + output.WriteRawTag(224, 12); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BearerToken.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(BearerToken); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LivingStatus != 0) { + size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstarAuditTenant other) { + if (other == null) { + return; + } + if (other.BearerToken.Length != 0) { + BearerToken = other.BearerToken; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 1610: { + BearerToken = input.ReadString(); + break; + } + case 1616: { + Id = input.ReadInt32(); + break; + } + case 1626: { + FirstName = input.ReadString(); + break; + } + case 1632: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstarAuditTenantGateway : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstarAuditTenantGateway()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[210]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenantGateway() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenantGateway(UpdateRockstarAuditTenantGateway other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenantGateway Clone() { + return new UpdateRockstarAuditTenantGateway(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstarAuditTenantGateway); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstarAuditTenantGateway other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LivingStatus != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstarAuditTenantGateway other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 24: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstarAuditTenantMq : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstarAuditTenantMq()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[211]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenantMq() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenantMq(UpdateRockstarAuditTenantMq other) : this() { + id_ = other.id_; + firstName_ = other.firstName_; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarAuditTenantMq Clone() { + return new UpdateRockstarAuditTenantMq(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 2; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 3; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstarAuditTenantMq); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstarAuditTenantMq other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (FirstName != other.FirstName) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0) hash ^= Id.GetHashCode(); + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0) { + output.WriteRawTag(8); + output.WriteInt32(Id); + } + if (FirstName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(FirstName); + } + if (LivingStatus != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstarAuditTenantMq other) { + if (other == null) { + return; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt32(); + break; + } + case 18: { + FirstName = input.ReadString(); + break; + } + case 24: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class UpdateRockstarVersion : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateRockstarVersion()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[212]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarVersion() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarVersion(UpdateRockstarVersion other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + id_ = other.id_; + rowVersion_ = other.rowVersion_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateRockstarVersion Clone() { + return new UpdateRockstarVersion(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 101; + private int id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "RowVersion" field. + public const int RowVersionFieldNumber = 102; + private ulong rowVersion_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong RowVersion { + get { return rowVersion_; } + set { + rowVersion_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateRockstarVersion); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateRockstarVersion other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + if (Id != other.Id) return false; + if (RowVersion != other.RowVersion) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (Id != 0) hash ^= Id.GetHashCode(); + if (RowVersion != 0UL) hash ^= RowVersion.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (Id != 0) { + output.WriteRawTag(168, 6); + output.WriteInt32(Id); + } + if (RowVersion != 0UL) { + output.WriteRawTag(176, 6); + output.WriteUInt64(RowVersion); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (Id != 0) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(Id); + } + if (RowVersion != 0UL) { + size += 2 + pb::CodedOutputStream.ComputeUInt64Size(RowVersion); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateRockstarVersion other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + if (other.Id != 0) { + Id = other.Id; + } + if (other.RowVersion != 0UL) { + RowVersion = other.RowVersion; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + case 808: { + Id = input.ReadInt32(); + break; + } + case 816: { + RowVersion = input.ReadUInt64(); + break; + } + } + } + } + + } + + public sealed partial class UpdateTodo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpdateTodo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[213]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateTodo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateTodo(UpdateTodo other) : this() { + id_ = other.id_; + title_ = other.title_; + order_ = other.order_; + completed_ = other.completed_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpdateTodo Clone() { + return new UpdateTodo(this); + } + + /// Field number for the "Id" field. + public const int IdFieldNumber = 1; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "Title" field. + public const int TitleFieldNumber = 2; + private string title_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Title { + get { return title_; } + set { + title_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Order" field. + public const int OrderFieldNumber = 3; + private int order_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Order { + get { return order_; } + set { + order_ = value; + } + } + + /// Field number for the "Completed" field. + public const int CompletedFieldNumber = 4; + private bool completed_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Completed { + get { return completed_; } + set { + completed_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpdateTodo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpdateTodo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Title != other.Title) return false; + if (Order != other.Order) return false; + if (Completed != other.Completed) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (Title.Length != 0) hash ^= Title.GetHashCode(); + if (Order != 0) hash ^= Order.GetHashCode(); + if (Completed != false) hash ^= Completed.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (Title.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Title); + } + if (Order != 0) { + output.WriteRawTag(24); + output.WriteInt32(Order); + } + if (Completed != false) { + output.WriteRawTag(32); + output.WriteBool(Completed); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (Title.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Title); + } + if (Order != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Order); + } + if (Completed != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpdateTodo other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + if (other.Title.Length != 0) { + Title = other.Title; + } + if (other.Order != 0) { + Order = other.Order; + } + if (other.Completed != false) { + Completed = other.Completed; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + case 18: { + Title = input.ReadString(); + break; + } + case 24: { + Order = input.ReadInt32(); + break; + } + case 32: { + Completed = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class UserApiKey : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UserApiKey()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[214]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UserApiKey() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UserApiKey(UserApiKey other) : this() { + key_ = other.key_; + keyType_ = other.keyType_; + expiryDate_ = other.expiryDate_ != null ? other.expiryDate_.Clone() : null; + meta_ = other.meta_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UserApiKey Clone() { + return new UserApiKey(this); + } + + /// Field number for the "Key" field. + public const int KeyFieldNumber = 1; + private string key_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Key { + get { return key_; } + set { + key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "KeyType" field. + public const int KeyTypeFieldNumber = 2; + private string keyType_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string KeyType { + get { return keyType_; } + set { + keyType_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "ExpiryDate" field. + public const int ExpiryDateFieldNumber = 3; + private global::Google.Protobuf.WellKnownTypes.Timestamp expiryDate_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp ExpiryDate { + get { return expiryDate_; } + set { + expiryDate_ = value; + } + } + + /// Field number for the "Meta" field. + public const int MetaFieldNumber = 4; + private static readonly pbc::MapField.Codec _map_meta_codec + = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 34); + private readonly pbc::MapField meta_ = new pbc::MapField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::MapField Meta { + get { return meta_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UserApiKey); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UserApiKey other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Key != other.Key) return false; + if (KeyType != other.KeyType) return false; + if (!object.Equals(ExpiryDate, other.ExpiryDate)) return false; + if (!Meta.Equals(other.Meta)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Key.Length != 0) hash ^= Key.GetHashCode(); + if (KeyType.Length != 0) hash ^= KeyType.GetHashCode(); + if (expiryDate_ != null) hash ^= ExpiryDate.GetHashCode(); + hash ^= Meta.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Key.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Key); + } + if (KeyType.Length != 0) { + output.WriteRawTag(18); + output.WriteString(KeyType); + } + if (expiryDate_ != null) { + output.WriteRawTag(26); + output.WriteMessage(ExpiryDate); + } + meta_.WriteTo(output, _map_meta_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Key.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); + } + if (KeyType.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(KeyType); + } + if (expiryDate_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExpiryDate); + } + size += meta_.CalculateSize(_map_meta_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UserApiKey other) { + if (other == null) { + return; + } + if (other.Key.Length != 0) { + Key = other.Key; + } + if (other.KeyType.Length != 0) { + KeyType = other.KeyType; + } + if (other.expiryDate_ != null) { + if (expiryDate_ == null) { + ExpiryDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + ExpiryDate.MergeFrom(other.ExpiryDate); + } + meta_.Add(other.meta_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Key = input.ReadString(); + break; + } + case 18: { + KeyType = input.ReadString(); + break; + } + case 26: { + if (expiryDate_ == null) { + ExpiryDate = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(ExpiryDate); + break; + } + case 34: { + meta_.AddEntriesFrom(input, _map_meta_codec); + break; + } + } + } + } + + } + + public sealed partial class ValidateCreateRockstar : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ValidateCreateRockstar()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.MessageTypes[215]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ValidateCreateRockstar() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ValidateCreateRockstar(ValidateCreateRockstar other) : this() { + firstName_ = other.firstName_; + lastName_ = other.lastName_; + age_ = other.age_; + dateOfBirth_ = other.dateOfBirth_ != null ? other.dateOfBirth_.Clone() : null; + dateDied_ = other.dateDied_ != null ? other.dateDied_.Clone() : null; + livingStatus_ = other.livingStatus_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ValidateCreateRockstar Clone() { + return new ValidateCreateRockstar(this); + } + + /// Field number for the "FirstName" field. + public const int FirstNameFieldNumber = 1; + private string firstName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FirstName { + get { return firstName_; } + set { + firstName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "LastName" field. + public const int LastNameFieldNumber = 2; + private string lastName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LastName { + get { return lastName_; } + set { + lastName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Age" field. + public const int AgeFieldNumber = 3; + private int age_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Age { + get { return age_; } + set { + age_ = value; + } + } + + /// Field number for the "DateOfBirth" field. + public const int DateOfBirthFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateOfBirth_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateOfBirth { + get { return dateOfBirth_; } + set { + dateOfBirth_ = value; + } + } + + /// Field number for the "DateDied" field. + public const int DateDiedFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.Timestamp dateDied_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Google.Protobuf.WellKnownTypes.Timestamp DateDied { + get { return dateDied_; } + set { + dateDied_ = value; + } + } + + /// Field number for the "LivingStatus" field. + public const int LivingStatusFieldNumber = 6; + private global::ServiceStack.Extensions.Tests.Protoc.LivingStatus livingStatus_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::ServiceStack.Extensions.Tests.Protoc.LivingStatus LivingStatus { + get { return livingStatus_; } + set { + livingStatus_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ValidateCreateRockstar); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ValidateCreateRockstar other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FirstName != other.FirstName) return false; + if (LastName != other.LastName) return false; + if (Age != other.Age) return false; + if (!object.Equals(DateOfBirth, other.DateOfBirth)) return false; + if (!object.Equals(DateDied, other.DateDied)) return false; + if (LivingStatus != other.LivingStatus) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FirstName.Length != 0) hash ^= FirstName.GetHashCode(); + if (LastName.Length != 0) hash ^= LastName.GetHashCode(); + if (Age != 0) hash ^= Age.GetHashCode(); + if (dateOfBirth_ != null) hash ^= DateOfBirth.GetHashCode(); + if (dateDied_ != null) hash ^= DateDied.GetHashCode(); + if (LivingStatus != 0) hash ^= LivingStatus.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (FirstName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FirstName); + } + if (LastName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(LastName); + } + if (Age != 0) { + output.WriteRawTag(24); + output.WriteInt32(Age); + } + if (dateOfBirth_ != null) { + output.WriteRawTag(34); + output.WriteMessage(DateOfBirth); + } + if (dateDied_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DateDied); + } + if (LivingStatus != 0) { + output.WriteRawTag(48); + output.WriteEnum((int) LivingStatus); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FirstName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FirstName); + } + if (LastName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LastName); + } + if (Age != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age); + } + if (dateOfBirth_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateOfBirth); + } + if (dateDied_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DateDied); + } + if (LivingStatus != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) LivingStatus); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ValidateCreateRockstar other) { + if (other == null) { + return; + } + if (other.FirstName.Length != 0) { + FirstName = other.FirstName; + } + if (other.LastName.Length != 0) { + LastName = other.LastName; + } + if (other.Age != 0) { + Age = other.Age; + } + if (other.dateOfBirth_ != null) { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateOfBirth.MergeFrom(other.DateOfBirth); + } + if (other.dateDied_ != null) { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + DateDied.MergeFrom(other.DateDied); + } + if (other.LivingStatus != 0) { + LivingStatus = other.LivingStatus; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + FirstName = input.ReadString(); + break; + } + case 18: { + LastName = input.ReadString(); + break; + } + case 24: { + Age = input.ReadInt32(); + break; + } + case 34: { + if (dateOfBirth_ == null) { + DateOfBirth = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateOfBirth); + break; + } + case 42: { + if (dateDied_ == null) { + DateDied = new global::Google.Protobuf.WellKnownTypes.Timestamp(); + } + input.ReadMessage(DateDied); + break; + } + case 48: { + LivingStatus = (global::ServiceStack.Extensions.Tests.Protoc.LivingStatus) input.ReadEnum(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/ServicesGrpc.cs b/tests/ServiceStack.Extensions.Tests/Protoc/ServicesGrpc.cs new file mode 100644 index 00000000000..f4c44fe0f62 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/ServicesGrpc.cs @@ -0,0 +1,6094 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: services.proto +// +// Original file comments: +// Options: +// Date: 2020-06-03 21:41:31 +// Version: 5.81 +// Tip: To override a DTO option, remove "//" prefix before updating +// BaseUrl: http://localhost:20000 +// +// //GlobalNamespace: +// //AddDescriptionAsComments: True +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace ServiceStack.Extensions.Tests.Protoc { + public static partial class GrpcServices + { + static readonly string __ServiceName = "GrpcServices"; + + static readonly grpc::Marshaller __Marshaller_AddHeader = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.AddHeader.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_EmptyResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_AnyHello = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.AnyHello.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_HelloResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.HelloResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_AssignRoles = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.AssignRoles.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_AssignRolesResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.AssignRolesResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Authenticate = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.Authenticate.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_AuthenticateResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ChangeConnectionInfo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ChangeDbResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ChangeDb = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ChangeDb.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ConvertSessionToToken = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ConvertSessionToTokenResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToTokenResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateBookmark = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateBookmarkResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateBookmarkResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateConnectionInfoRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RockstarWithIdAndResultResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateNamedRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAdhocNonDefaults = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAudit = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RockstarWithIdResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAuditMqToken = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAuditTenant = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAuditTenantGateway = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAuditTenantMq = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarAutoMap = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarVersion = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RockstarWithIdAndRowVersionResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarWithAutoGuid = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarWithReturnGuidResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturnGuidResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarWithReturn = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateRockstarWithVoidReturn = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateTodo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateTodo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CreateTodoResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CreateTodoResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_CustomValidationErrors = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DeleteRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DeleteRockstarAudit = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RockstarWithIdAndCountResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DeleteRockstarFilters = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DeleteRockstarCountResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarCountResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DeleteTodo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DeleteTodos = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DynamicRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_Rockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_CustomRockstarSchema = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_Movie = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_RockstarReference = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_AllFields = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_TypeWithEnum = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_Adhoc = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_CustomSelectRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_CustomSelectRockstarResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_Foo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_CustomRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_RockstarAuto = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_Bookmark = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_NamedRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_RockstarAlbum = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_PagingTest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryResponse_RockstarAlias = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_DynamicValidationRules = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_EmptyValidators = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_EndsWithSuffixRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_EndsWithSuffixResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetAccessToken = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetAccessTokenResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetAccessTokenResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetApiKeys = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetApiKeysResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetApiKeysResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetFile = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetFile.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_FileContent = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.FileContent.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetHello = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetHello.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetTodo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetTodo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetTodoResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetTodoResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetTodos = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetTodos.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_GetTodosResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.GetTodosResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_HelloJwt = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.HelloJwt.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_HelloJwtResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Incr = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.Incr.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Multiply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.Multiply.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_MultiplyResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.MultiplyResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_NoAbstractValidator = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_OnlyValidatesRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_PatchRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_PatchRockstarAuditTenant = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_PatchRockstarAuditTenantGateway = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_PatchRockstarAuditTenantMq = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_PostChatToChannel = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ChatMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ChatMessage.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryAdhoc = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryAdhocRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryAllFields = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryBookmarks = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryCaseInsensitiveOrderBy = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryChangeConnectionInfo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryChangeDb = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryCustomRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryCustomRockstarsFilter = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryCustomRockstarsReferences = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryCustomRockstarsSchema = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryFieldRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryFieldRockstarsDynamic = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryFieldsImplicitConventions = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryFoos = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryFoos.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryGetRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryGetRockstarsDynamic = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryJoinedRockstarAlbums = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryJoinedRockstarAlbumsCustomSelect = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryJoinedRockstarAlbumsCustomSelectResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryMovies = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryMovies.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryMultiJoinRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryNamedRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryOrRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryOrRockstarsFields = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryOverridedCustomRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryOverridedRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryPagingTest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAlbums = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAlbumsCustomLeftJoin = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAlbumsImplicit = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAlbumsLeftJoin = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAlias = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAudit = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarAuditSubOr = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarFilters = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarsConventions = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarsFilter = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarsIFilter = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarsImplicit = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryRockstarsWithReferences = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryTypeWithEnums = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_QueryUnknownRockstars = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RealDeleteAuditTenant = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RealDeleteAuditTenantGateway = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RealDeleteAuditTenantMq = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RegenerateApiKeys = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RegenerateApiKeysResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeysResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Register = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.Register.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RegisterResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_RequiresAuth = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ResetTodos = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ResetTodos.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_SearchMovies = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.SearchMovies.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Secured = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.Secured.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_SecuredResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.SecuredResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_SoftDeleteAuditTenant = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_StreamFiles = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.StreamFiles.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_StreamMovies = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.StreamMovies.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_StreamServerEvents = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.StreamServerEvents.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_StreamServerEventsResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.StreamServerEventsResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TestAuthValidators = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TestDbCondition = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TestDbValidator = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TestIsAdmin = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TestMultiAuthValidators = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Throw = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.Throw.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ThrowCustom = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ThrowCustomResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ThrowCustomResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ThrowVoid = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TriggerAllValidators = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_TriggerValidators = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UnAssignRoles = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UnAssignRolesResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UnAssignRolesResponse.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateConnectionInfoRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateNamedRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstarAdhocNonDefaults = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstarAudit = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstarAuditTenant = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstarAuditTenantGateway = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstarAuditTenantMq = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateRockstarVersion = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_UpdateTodo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ValidateCreateRockstar = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar.Parser.ParseFrom); + + static readonly grpc::Method __Method_GetAddHeader = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetAddHeader", + __Marshaller_AddHeader, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_GetAnyHello = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetAnyHello", + __Marshaller_AnyHello, + __Marshaller_HelloResponse); + + static readonly grpc::Method __Method_PostAnyHello = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostAnyHello", + __Marshaller_AnyHello, + __Marshaller_HelloResponse); + + static readonly grpc::Method __Method_PutAnyHello = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutAnyHello", + __Marshaller_AnyHello, + __Marshaller_HelloResponse); + + static readonly grpc::Method __Method_DeleteAnyHello = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteAnyHello", + __Marshaller_AnyHello, + __Marshaller_HelloResponse); + + static readonly grpc::Method __Method_PostAssignRoles = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostAssignRoles", + __Marshaller_AssignRoles, + __Marshaller_AssignRolesResponse); + + static readonly grpc::Method __Method_OptionsAuthenticate = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "OptionsAuthenticate", + __Marshaller_Authenticate, + __Marshaller_AuthenticateResponse); + + static readonly grpc::Method __Method_GetAuthenticate = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetAuthenticate", + __Marshaller_Authenticate, + __Marshaller_AuthenticateResponse); + + static readonly grpc::Method __Method_PostAuthenticate = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostAuthenticate", + __Marshaller_Authenticate, + __Marshaller_AuthenticateResponse); + + static readonly grpc::Method __Method_DeleteAuthenticate = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteAuthenticate", + __Marshaller_Authenticate, + __Marshaller_AuthenticateResponse); + + static readonly grpc::Method __Method_GetChangeConnectionInfo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetChangeConnectionInfo", + __Marshaller_ChangeConnectionInfo, + __Marshaller_ChangeDbResponse); + + static readonly grpc::Method __Method_GetChangeDb = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetChangeDb", + __Marshaller_ChangeDb, + __Marshaller_ChangeDbResponse); + + static readonly grpc::Method __Method_PostConvertSessionToToken = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostConvertSessionToToken", + __Marshaller_ConvertSessionToToken, + __Marshaller_ConvertSessionToTokenResponse); + + static readonly grpc::Method __Method_PostCreateBookmark = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateBookmark", + __Marshaller_CreateBookmark, + __Marshaller_CreateBookmarkResponse); + + static readonly grpc::Method __Method_PostCreateConnectionInfoRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateConnectionInfoRockstar", + __Marshaller_CreateConnectionInfoRockstar, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PostCreateNamedRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateNamedRockstar", + __Marshaller_CreateNamedRockstar, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PostCreateRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstar", + __Marshaller_CreateRockstar, + __Marshaller_CreateRockstarResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAdhocNonDefaults = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAdhocNonDefaults", + __Marshaller_CreateRockstarAdhocNonDefaults, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAudit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAudit", + __Marshaller_CreateRockstarAudit, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAuditMqToken = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAuditMqToken", + __Marshaller_CreateRockstarAuditMqToken, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAuditTenant = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAuditTenant", + __Marshaller_CreateRockstarAuditTenant, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAuditTenantGateway = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAuditTenantGateway", + __Marshaller_CreateRockstarAuditTenantGateway, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_GetCreateRockstarAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetCreateRockstarAuditTenantMq", + __Marshaller_CreateRockstarAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAuditTenantMq", + __Marshaller_CreateRockstarAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PutCreateRockstarAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutCreateRockstarAuditTenantMq", + __Marshaller_CreateRockstarAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_DeleteCreateRockstarAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteCreateRockstarAuditTenantMq", + __Marshaller_CreateRockstarAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostCreateRockstarAutoMap = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarAutoMap", + __Marshaller_CreateRockstarAutoMap, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PostCreateRockstarVersion = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarVersion", + __Marshaller_CreateRockstarVersion, + __Marshaller_RockstarWithIdAndRowVersionResponse); + + static readonly grpc::Method __Method_PostCreateRockstarWithAutoGuid = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarWithAutoGuid", + __Marshaller_CreateRockstarWithAutoGuid, + __Marshaller_CreateRockstarWithReturnGuidResponse); + + static readonly grpc::Method __Method_PostCreateRockstarWithReturn = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarWithReturn", + __Marshaller_CreateRockstarWithReturn, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PostCreateRockstarWithVoidReturn = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateRockstarWithVoidReturn", + __Marshaller_CreateRockstarWithVoidReturn, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostCreateTodo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCreateTodo", + __Marshaller_CreateTodo, + __Marshaller_CreateTodoResponse); + + static readonly grpc::Method __Method_PostCustomValidationErrors = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostCustomValidationErrors", + __Marshaller_CustomValidationErrors, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_CallDeleteRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallDeleteRockstar", + __Marshaller_DeleteRockstar, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_CallDeleteRockstarAudit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallDeleteRockstarAudit", + __Marshaller_DeleteRockstarAudit, + __Marshaller_RockstarWithIdAndCountResponse); + + static readonly grpc::Method __Method_CallDeleteRockstarFilters = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallDeleteRockstarFilters", + __Marshaller_DeleteRockstarFilters, + __Marshaller_DeleteRockstarCountResponse); + + static readonly grpc::Method __Method_CallDeleteTodo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallDeleteTodo", + __Marshaller_DeleteTodo, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_CallDeleteTodos = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallDeleteTodos", + __Marshaller_DeleteTodos, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_GetDynamicQueryGetRockstarsDynamic = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryGetRockstarsDynamic", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryCustomRockstarsSchema = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryCustomRockstarsSchema", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstarSchema); + + static readonly grpc::Method __Method_GetDynamicSearchMovies = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicSearchMovies", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Movie); + + static readonly grpc::Method __Method_GetDynamicQueryMovies = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryMovies", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Movie); + + static readonly grpc::Method __Method_GetDynamicQueryUnknownRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryUnknownRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarsWithReferences = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarsWithReferences", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_RockstarReference); + + static readonly grpc::Method __Method_GetDynamicQueryAllFields = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryAllFields", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_AllFields); + + static readonly grpc::Method __Method_GetDynamicQueryTypeWithEnums = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryTypeWithEnums", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_TypeWithEnum); + + static readonly grpc::Method __Method_GetDynamicQueryAdhocRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryAdhocRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryAdhoc = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryAdhoc", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Adhoc); + + static readonly grpc::Method __Method_GetDynamicQueryChangeDb = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryChangeDb", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelect = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryJoinedRockstarAlbumsCustomSelect", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomSelectRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomSelectRockstarResponse); + + static readonly grpc::Method __Method_GetDynamicQueryFoos = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryFoos", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Foo); + + static readonly grpc::Method __Method_GetDynamicQueryOverridedRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryOverridedRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryOverridedCustomRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryOverridedCustomRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryCaseInsensitiveOrderBy = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryCaseInsensitiveOrderBy", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicStreamMovies = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicStreamMovies", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Movie); + + static readonly grpc::Method __Method_GetDynamicQueryCustomRockstarsReferences = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryCustomRockstarsReferences", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_RockstarReference); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAlbumsCustomLeftJoin = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAlbumsCustomLeftJoin", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryChangeConnectionInfo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryChangeConnectionInfo", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAudit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAudit", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_RockstarAuto); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAuditSubOr = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAuditSubOr", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_RockstarAuto); + + static readonly grpc::Method __Method_GetDynamicQueryBookmarks = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryBookmarks", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Bookmark); + + static readonly grpc::Method __Method_GetDynamicQueryNamedRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryNamedRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_NamedRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAlbums = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAlbums", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_RockstarAlbum); + + static readonly grpc::Method __Method_GetDynamicQueryPagingTest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryPagingTest", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_PagingTest); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarsConventions = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarsConventions", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryCustomRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryCustomRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryJoinedRockstarAlbums = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryJoinedRockstarAlbums", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAlbumsImplicit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAlbumsImplicit", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAlbumsLeftJoin = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAlbumsLeftJoin", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryMultiJoinRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryMultiJoinRockstar", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryFieldRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryFieldRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarAlias = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarAlias", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_RockstarAlias); + + static readonly grpc::Method __Method_GetDynamicQueryFieldRockstarsDynamic = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryFieldRockstarsDynamic", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarsFilter = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarsFilter", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryCustomRockstarsFilter = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryCustomRockstarsFilter", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarsIFilter = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarsIFilter", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryOrRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryOrRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarsImplicit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarsImplicit", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryOrRockstarsFields = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryOrRockstarsFields", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryFieldsImplicitConventions = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryFieldsImplicitConventions", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryGetRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryGetRockstars", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetDynamicQueryRockstarFilters = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetDynamicQueryRockstarFilters", + __Marshaller_DynamicRequest, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_PostDynamicValidationRules = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostDynamicValidationRules", + __Marshaller_DynamicValidationRules, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostEmptyValidators = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostEmptyValidators", + __Marshaller_EmptyValidators, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_GetEndsWithSuffixRequest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetEndsWithSuffixRequest", + __Marshaller_EndsWithSuffixRequest, + __Marshaller_EndsWithSuffixResponse); + + static readonly grpc::Method __Method_PostEndsWithSuffixRequest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostEndsWithSuffixRequest", + __Marshaller_EndsWithSuffixRequest, + __Marshaller_EndsWithSuffixResponse); + + static readonly grpc::Method __Method_PutEndsWithSuffixRequest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutEndsWithSuffixRequest", + __Marshaller_EndsWithSuffixRequest, + __Marshaller_EndsWithSuffixResponse); + + static readonly grpc::Method __Method_DeleteEndsWithSuffixRequest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteEndsWithSuffixRequest", + __Marshaller_EndsWithSuffixRequest, + __Marshaller_EndsWithSuffixResponse); + + static readonly grpc::Method __Method_PostGetAccessToken = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostGetAccessToken", + __Marshaller_GetAccessToken, + __Marshaller_GetAccessTokenResponse); + + static readonly grpc::Method __Method_CallGetApiKeys = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallGetApiKeys", + __Marshaller_GetApiKeys, + __Marshaller_GetApiKeysResponse); + + static readonly grpc::Method __Method_CallGetFile = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallGetFile", + __Marshaller_GetFile, + __Marshaller_FileContent); + + static readonly grpc::Method __Method_CallGetHello = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallGetHello", + __Marshaller_GetHello, + __Marshaller_HelloResponse); + + static readonly grpc::Method __Method_CallGetTodo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallGetTodo", + __Marshaller_GetTodo, + __Marshaller_GetTodoResponse); + + static readonly grpc::Method __Method_CallGetTodos = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallGetTodos", + __Marshaller_GetTodos, + __Marshaller_GetTodosResponse); + + static readonly grpc::Method __Method_GetHelloJwt = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetHelloJwt", + __Marshaller_HelloJwt, + __Marshaller_HelloJwtResponse); + + static readonly grpc::Method __Method_PostHelloJwt = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostHelloJwt", + __Marshaller_HelloJwt, + __Marshaller_HelloJwtResponse); + + static readonly grpc::Method __Method_PutHelloJwt = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutHelloJwt", + __Marshaller_HelloJwt, + __Marshaller_HelloJwtResponse); + + static readonly grpc::Method __Method_DeleteHelloJwt = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteHelloJwt", + __Marshaller_HelloJwt, + __Marshaller_HelloJwtResponse); + + static readonly grpc::Method __Method_GetIncr = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetIncr", + __Marshaller_Incr, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostIncr = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostIncr", + __Marshaller_Incr, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PutIncr = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutIncr", + __Marshaller_Incr, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_DeleteIncr = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteIncr", + __Marshaller_Incr, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostMultiply = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostMultiply", + __Marshaller_Multiply, + __Marshaller_MultiplyResponse); + + static readonly grpc::Method __Method_PostNoAbstractValidator = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostNoAbstractValidator", + __Marshaller_NoAbstractValidator, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostOnlyValidatesRequest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostOnlyValidatesRequest", + __Marshaller_OnlyValidatesRequest, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_CallPatchRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallPatchRockstar", + __Marshaller_PatchRockstar, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_CallPatchRockstarAuditTenant = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallPatchRockstarAuditTenant", + __Marshaller_PatchRockstarAuditTenant, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_CallPatchRockstarAuditTenantGateway = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallPatchRockstarAuditTenantGateway", + __Marshaller_PatchRockstarAuditTenantGateway, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_CallPatchRockstarAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallPatchRockstarAuditTenantMq", + __Marshaller_PatchRockstarAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_CallPostChatToChannel = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CallPostChatToChannel", + __Marshaller_PostChatToChannel, + __Marshaller_ChatMessage); + + static readonly grpc::Method __Method_GetQueryAdhoc = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryAdhoc", + __Marshaller_QueryAdhoc, + __Marshaller_QueryResponse_Adhoc); + + static readonly grpc::Method __Method_GetQueryAdhocRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryAdhocRockstars", + __Marshaller_QueryAdhocRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryAllFields = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryAllFields", + __Marshaller_QueryAllFields, + __Marshaller_QueryResponse_AllFields); + + static readonly grpc::Method __Method_GetQueryBookmarks = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryBookmarks", + __Marshaller_QueryBookmarks, + __Marshaller_QueryResponse_Bookmark); + + static readonly grpc::Method __Method_GetQueryCaseInsensitiveOrderBy = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryCaseInsensitiveOrderBy", + __Marshaller_QueryCaseInsensitiveOrderBy, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryChangeConnectionInfo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryChangeConnectionInfo", + __Marshaller_QueryChangeConnectionInfo, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryChangeDb = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryChangeDb", + __Marshaller_QueryChangeDb, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryCustomRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryCustomRockstars", + __Marshaller_QueryCustomRockstars, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryCustomRockstarsFilter = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryCustomRockstarsFilter", + __Marshaller_QueryCustomRockstarsFilter, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryCustomRockstarsReferences = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryCustomRockstarsReferences", + __Marshaller_QueryCustomRockstarsReferences, + __Marshaller_QueryResponse_RockstarReference); + + static readonly grpc::Method __Method_GetQueryCustomRockstarsSchema = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryCustomRockstarsSchema", + __Marshaller_QueryCustomRockstarsSchema, + __Marshaller_QueryResponse_CustomRockstarSchema); + + static readonly grpc::Method __Method_GetQueryFieldRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryFieldRockstars", + __Marshaller_QueryFieldRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryFieldRockstarsDynamic = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryFieldRockstarsDynamic", + __Marshaller_QueryFieldRockstarsDynamic, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryFieldsImplicitConventions = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryFieldsImplicitConventions", + __Marshaller_QueryFieldsImplicitConventions, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryFoos = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryFoos", + __Marshaller_QueryFoos, + __Marshaller_QueryResponse_Foo); + + static readonly grpc::Method __Method_GetQueryGetRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryGetRockstars", + __Marshaller_QueryGetRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryGetRockstarsDynamic = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryGetRockstarsDynamic", + __Marshaller_QueryGetRockstarsDynamic, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryJoinedRockstarAlbums = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryJoinedRockstarAlbums", + __Marshaller_QueryJoinedRockstarAlbums, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryJoinedRockstarAlbumsCustomSelect = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryJoinedRockstarAlbumsCustomSelect", + __Marshaller_QueryJoinedRockstarAlbumsCustomSelect, + __Marshaller_QueryResponse_CustomSelectRockstar); + + static readonly grpc::Method __Method_GetQueryJoinedRockstarAlbumsCustomSelectResponse = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryJoinedRockstarAlbumsCustomSelectResponse", + __Marshaller_QueryJoinedRockstarAlbumsCustomSelectResponse, + __Marshaller_QueryResponse_CustomSelectRockstarResponse); + + static readonly grpc::Method __Method_GetQueryMovies = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryMovies", + __Marshaller_QueryMovies, + __Marshaller_QueryResponse_Movie); + + static readonly grpc::Method __Method_GetQueryMultiJoinRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryMultiJoinRockstar", + __Marshaller_QueryMultiJoinRockstar, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryNamedRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryNamedRockstars", + __Marshaller_QueryNamedRockstars, + __Marshaller_QueryResponse_NamedRockstar); + + static readonly grpc::Method __Method_GetQueryOrRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryOrRockstars", + __Marshaller_QueryOrRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryOrRockstarsFields = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryOrRockstarsFields", + __Marshaller_QueryOrRockstarsFields, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryOverridedCustomRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryOverridedCustomRockstars", + __Marshaller_QueryOverridedCustomRockstars, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryOverridedRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryOverridedRockstars", + __Marshaller_QueryOverridedRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryPagingTest = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryPagingTest", + __Marshaller_QueryPagingTest, + __Marshaller_QueryResponse_PagingTest); + + static readonly grpc::Method __Method_GetQueryRockstarAlbums = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAlbums", + __Marshaller_QueryRockstarAlbums, + __Marshaller_QueryResponse_RockstarAlbum); + + static readonly grpc::Method __Method_GetQueryRockstarAlbumsCustomLeftJoin = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAlbumsCustomLeftJoin", + __Marshaller_QueryRockstarAlbumsCustomLeftJoin, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryRockstarAlbumsImplicit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAlbumsImplicit", + __Marshaller_QueryRockstarAlbumsImplicit, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryRockstarAlbumsLeftJoin = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAlbumsLeftJoin", + __Marshaller_QueryRockstarAlbumsLeftJoin, + __Marshaller_QueryResponse_CustomRockstar); + + static readonly grpc::Method __Method_GetQueryRockstarAlias = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAlias", + __Marshaller_QueryRockstarAlias, + __Marshaller_QueryResponse_RockstarAlias); + + static readonly grpc::Method __Method_GetQueryRockstarAudit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAudit", + __Marshaller_QueryRockstarAudit, + __Marshaller_QueryResponse_RockstarAuto); + + static readonly grpc::Method __Method_GetQueryRockstarAuditSubOr = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarAuditSubOr", + __Marshaller_QueryRockstarAuditSubOr, + __Marshaller_QueryResponse_RockstarAuto); + + static readonly grpc::Method __Method_GetQueryRockstarFilters = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarFilters", + __Marshaller_QueryRockstarFilters, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstars", + __Marshaller_QueryRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryRockstarsConventions = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarsConventions", + __Marshaller_QueryRockstarsConventions, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryRockstarsFilter = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarsFilter", + __Marshaller_QueryRockstarsFilter, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryRockstarsIFilter = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarsIFilter", + __Marshaller_QueryRockstarsIFilter, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryRockstarsImplicit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarsImplicit", + __Marshaller_QueryRockstarsImplicit, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_GetQueryRockstarsWithReferences = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryRockstarsWithReferences", + __Marshaller_QueryRockstarsWithReferences, + __Marshaller_QueryResponse_RockstarReference); + + static readonly grpc::Method __Method_GetQueryTypeWithEnums = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryTypeWithEnums", + __Marshaller_QueryTypeWithEnums, + __Marshaller_QueryResponse_TypeWithEnum); + + static readonly grpc::Method __Method_GetQueryUnknownRockstars = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetQueryUnknownRockstars", + __Marshaller_QueryUnknownRockstars, + __Marshaller_QueryResponse_Rockstar); + + static readonly grpc::Method __Method_DeleteRealDeleteAuditTenant = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteRealDeleteAuditTenant", + __Marshaller_RealDeleteAuditTenant, + __Marshaller_RockstarWithIdAndCountResponse); + + static readonly grpc::Method __Method_DeleteRealDeleteAuditTenantGateway = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteRealDeleteAuditTenantGateway", + __Marshaller_RealDeleteAuditTenantGateway, + __Marshaller_RockstarWithIdAndCountResponse); + + static readonly grpc::Method __Method_DeleteRealDeleteAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteRealDeleteAuditTenantMq", + __Marshaller_RealDeleteAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostRegenerateApiKeys = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostRegenerateApiKeys", + __Marshaller_RegenerateApiKeys, + __Marshaller_RegenerateApiKeysResponse); + + static readonly grpc::Method __Method_PutRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutRegister", + __Marshaller_Register, + __Marshaller_RegisterResponse); + + static readonly grpc::Method __Method_PostRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostRegister", + __Marshaller_Register, + __Marshaller_RegisterResponse); + + static readonly grpc::Method __Method_GetRequiresAuth = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetRequiresAuth", + __Marshaller_RequiresAuth, + __Marshaller_RequiresAuth); + + static readonly grpc::Method __Method_PostRequiresAuth = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostRequiresAuth", + __Marshaller_RequiresAuth, + __Marshaller_RequiresAuth); + + static readonly grpc::Method __Method_PutRequiresAuth = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutRequiresAuth", + __Marshaller_RequiresAuth, + __Marshaller_RequiresAuth); + + static readonly grpc::Method __Method_DeleteRequiresAuth = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "DeleteRequiresAuth", + __Marshaller_RequiresAuth, + __Marshaller_RequiresAuth); + + static readonly grpc::Method __Method_PostResetTodos = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostResetTodos", + __Marshaller_ResetTodos, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_GetSearchMovies = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetSearchMovies", + __Marshaller_SearchMovies, + __Marshaller_QueryResponse_Movie); + + static readonly grpc::Method __Method_PostSecured = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostSecured", + __Marshaller_Secured, + __Marshaller_SecuredResponse); + + static readonly grpc::Method __Method_PutSoftDeleteAuditTenant = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutSoftDeleteAuditTenant", + __Marshaller_SoftDeleteAuditTenant, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_ServerStreamFiles = new grpc::Method( + grpc::MethodType.ServerStreaming, + __ServiceName, + "ServerStreamFiles", + __Marshaller_StreamFiles, + __Marshaller_FileContent); + + static readonly grpc::Method __Method_GetStreamMovies = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetStreamMovies", + __Marshaller_StreamMovies, + __Marshaller_QueryResponse_Movie); + + static readonly grpc::Method __Method_ServerStreamServerEvents = new grpc::Method( + grpc::MethodType.ServerStreaming, + __ServiceName, + "ServerStreamServerEvents", + __Marshaller_StreamServerEvents, + __Marshaller_StreamServerEventsResponse); + + static readonly grpc::Method __Method_PostTestAuthValidators = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTestAuthValidators", + __Marshaller_TestAuthValidators, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostTestDbCondition = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTestDbCondition", + __Marshaller_TestDbCondition, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostTestDbValidator = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTestDbValidator", + __Marshaller_TestDbValidator, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostTestIsAdmin = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTestIsAdmin", + __Marshaller_TestIsAdmin, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostTestMultiAuthValidators = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTestMultiAuthValidators", + __Marshaller_TestMultiAuthValidators, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_GetThrow = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetThrow", + __Marshaller_Throw, + __Marshaller_HelloResponse); + + static readonly grpc::Method __Method_GetThrowCustom = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetThrowCustom", + __Marshaller_ThrowCustom, + __Marshaller_ThrowCustomResponse); + + static readonly grpc::Method __Method_GetThrowVoid = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetThrowVoid", + __Marshaller_ThrowVoid, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostTriggerAllValidators = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTriggerAllValidators", + __Marshaller_TriggerAllValidators, + __Marshaller_RockstarWithIdResponse); + + static readonly grpc::Method __Method_PostTriggerValidators = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostTriggerValidators", + __Marshaller_TriggerValidators, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostUnAssignRoles = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostUnAssignRoles", + __Marshaller_UnAssignRoles, + __Marshaller_UnAssignRolesResponse); + + static readonly grpc::Method __Method_PutUpdateConnectionInfoRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateConnectionInfoRockstar", + __Marshaller_UpdateConnectionInfoRockstar, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PutUpdateNamedRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateNamedRockstar", + __Marshaller_UpdateNamedRockstar, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PutUpdateRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateRockstar", + __Marshaller_UpdateRockstar, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PutUpdateRockstarAdhocNonDefaults = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateRockstarAdhocNonDefaults", + __Marshaller_UpdateRockstarAdhocNonDefaults, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PatchUpdateRockstarAudit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PatchUpdateRockstarAudit", + __Marshaller_UpdateRockstarAudit, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PutUpdateRockstarAuditTenant = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateRockstarAuditTenant", + __Marshaller_UpdateRockstarAuditTenant, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PutUpdateRockstarAuditTenantGateway = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateRockstarAuditTenantGateway", + __Marshaller_UpdateRockstarAuditTenantGateway, + __Marshaller_RockstarWithIdAndResultResponse); + + static readonly grpc::Method __Method_PutUpdateRockstarAuditTenantMq = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateRockstarAuditTenantMq", + __Marshaller_UpdateRockstarAuditTenantMq, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PatchUpdateRockstarVersion = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PatchUpdateRockstarVersion", + __Marshaller_UpdateRockstarVersion, + __Marshaller_RockstarWithIdAndRowVersionResponse); + + static readonly grpc::Method __Method_PutUpdateTodo = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PutUpdateTodo", + __Marshaller_UpdateTodo, + __Marshaller_EmptyResponse); + + static readonly grpc::Method __Method_PostValidateCreateRockstar = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "PostValidateCreateRockstar", + __Marshaller_ValidateCreateRockstar, + __Marshaller_RockstarWithIdResponse); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::ServiceStack.Extensions.Tests.Protoc.ServicesReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of GrpcServices + [grpc::BindServiceMethod(typeof(GrpcServices), "BindService")] + public abstract partial class GrpcServicesBase + { + public virtual global::System.Threading.Tasks.Task GetAddHeader(global::ServiceStack.Extensions.Tests.Protoc.AddHeader request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostAssignRoles(global::ServiceStack.Extensions.Tests.Protoc.AssignRoles request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task OptionsAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetChangeDb(global::ServiceStack.Extensions.Tests.Protoc.ChangeDb request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostConvertSessionToToken(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateBookmark(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateConnectionInfoRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateNamedRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAdhocNonDefaults(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAuditMqToken(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarAutoMap(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarVersion(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarWithAutoGuid(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarWithReturn(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateRockstarWithVoidReturn(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCreateTodo(global::ServiceStack.Extensions.Tests.Protoc.CreateTodo request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostCustomValidationErrors(global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallDeleteRockstar(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallDeleteRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallDeleteRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallDeleteTodo(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallDeleteTodos(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryGetRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryCustomRockstarsSchema(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicSearchMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryUnknownRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarsWithReferences(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryAllFields(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryTypeWithEnums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryAdhocRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryAdhoc(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryChangeDb(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryJoinedRockstarAlbumsCustomSelect(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryFoos(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryOverridedRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryOverridedCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryCaseInsensitiveOrderBy(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicStreamMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryCustomRockstarsReferences(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAlbumsCustomLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAuditSubOr(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryBookmarks(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryNamedRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryPagingTest(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarsConventions(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryJoinedRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAlbumsImplicit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAlbumsLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryMultiJoinRockstar(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryFieldRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarAlias(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryFieldRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryCustomRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarsIFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryOrRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarsImplicit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryOrRockstarsFields(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryFieldsImplicitConventions(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryGetRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetDynamicQueryRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostDynamicValidationRules(global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostEmptyValidators(global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostGetAccessToken(global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallGetApiKeys(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallGetFile(global::ServiceStack.Extensions.Tests.Protoc.GetFile request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallGetHello(global::ServiceStack.Extensions.Tests.Protoc.GetHello request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallGetTodo(global::ServiceStack.Extensions.Tests.Protoc.GetTodo request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallGetTodos(global::ServiceStack.Extensions.Tests.Protoc.GetTodos request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostMultiply(global::ServiceStack.Extensions.Tests.Protoc.Multiply request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostNoAbstractValidator(global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostOnlyValidatesRequest(global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallPatchRockstar(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallPatchRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallPatchRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallPatchRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task CallPostChatToChannel(global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryAdhoc(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryAdhocRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryAllFields(global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryBookmarks(global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryCaseInsensitiveOrderBy(global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryChangeDb(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryCustomRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryCustomRockstarsReferences(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryCustomRockstarsSchema(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryFieldRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryFieldRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryFieldsImplicitConventions(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryFoos(global::ServiceStack.Extensions.Tests.Protoc.QueryFoos request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryGetRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryGetRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryJoinedRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryJoinedRockstarAlbumsCustomSelect(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryJoinedRockstarAlbumsCustomSelectResponse(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryMovies(global::ServiceStack.Extensions.Tests.Protoc.QueryMovies request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryMultiJoinRockstar(global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryNamedRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryOrRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryOrRockstarsFields(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryOverridedCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryOverridedRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryPagingTest(global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAlbumsCustomLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAlbumsImplicit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAlbumsLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAlias(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarAuditSubOr(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarsConventions(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarsIFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarsImplicit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryRockstarsWithReferences(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryTypeWithEnums(global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetQueryUnknownRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteRealDeleteAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteRealDeleteAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteRealDeleteAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostRegenerateApiKeys(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutRegister(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostRegister(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task DeleteRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostResetTodos(global::ServiceStack.Extensions.Tests.Protoc.ResetTodos request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetSearchMovies(global::ServiceStack.Extensions.Tests.Protoc.SearchMovies request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostSecured(global::ServiceStack.Extensions.Tests.Protoc.Secured request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutSoftDeleteAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task ServerStreamFiles(global::ServiceStack.Extensions.Tests.Protoc.StreamFiles request, grpc::IServerStreamWriter responseStream, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetStreamMovies(global::ServiceStack.Extensions.Tests.Protoc.StreamMovies request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task ServerStreamServerEvents(global::ServiceStack.Extensions.Tests.Protoc.StreamServerEvents request, grpc::IServerStreamWriter responseStream, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTestAuthValidators(global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTestDbCondition(global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTestDbValidator(global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTestIsAdmin(global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTestMultiAuthValidators(global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetThrow(global::ServiceStack.Extensions.Tests.Protoc.Throw request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetThrowCustom(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task GetThrowVoid(global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTriggerAllValidators(global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostTriggerValidators(global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostUnAssignRoles(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateConnectionInfoRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateNamedRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateRockstarAdhocNonDefaults(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PatchUpdateRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PatchUpdateRockstarVersion(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PutUpdateTodo(global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task PostValidateCreateRockstar(global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for GrpcServices + public partial class GrpcServicesClient : grpc::ClientBase + { + /// Creates a new client for GrpcServices + /// The channel to use to make remote calls. + public GrpcServicesClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for GrpcServices that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public GrpcServicesClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected GrpcServicesClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected GrpcServicesClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetAddHeader(global::ServiceStack.Extensions.Tests.Protoc.AddHeader request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetAddHeader(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetAddHeader(global::ServiceStack.Extensions.Tests.Protoc.AddHeader request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetAddHeader, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetAddHeaderAsync(global::ServiceStack.Extensions.Tests.Protoc.AddHeader request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetAddHeaderAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetAddHeaderAsync(global::ServiceStack.Extensions.Tests.Protoc.AddHeader request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetAddHeader, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse GetAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetAnyHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse GetAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetAnyHello, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetAnyHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetAnyHello, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse PostAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostAnyHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse PostAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostAnyHello, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostAnyHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostAnyHello, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse PutAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutAnyHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse PutAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutAnyHello, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutAnyHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutAnyHello, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse DeleteAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteAnyHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse DeleteAnyHello(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteAnyHello, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteAnyHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteAnyHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.AnyHello request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteAnyHello, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AssignRolesResponse PostAssignRoles(global::ServiceStack.Extensions.Tests.Protoc.AssignRoles request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostAssignRoles(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AssignRolesResponse PostAssignRoles(global::ServiceStack.Extensions.Tests.Protoc.AssignRoles request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostAssignRoles, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostAssignRolesAsync(global::ServiceStack.Extensions.Tests.Protoc.AssignRoles request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostAssignRolesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostAssignRolesAsync(global::ServiceStack.Extensions.Tests.Protoc.AssignRoles request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostAssignRoles, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse OptionsAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return OptionsAuthenticate(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse OptionsAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_OptionsAuthenticate, null, options, request); + } + public virtual grpc::AsyncUnaryCall OptionsAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return OptionsAuthenticateAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall OptionsAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_OptionsAuthenticate, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse GetAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetAuthenticate(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse GetAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetAuthenticate, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetAuthenticateAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetAuthenticate, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse PostAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostAuthenticate(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse PostAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostAuthenticate, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostAuthenticateAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostAuthenticate, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse DeleteAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteAuthenticate(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.AuthenticateResponse DeleteAuthenticate(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteAuthenticate, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteAuthenticateAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteAuthenticateAsync(global::ServiceStack.Extensions.Tests.Protoc.Authenticate request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteAuthenticate, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse GetChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetChangeConnectionInfo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse GetChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetChangeConnectionInfo, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetChangeConnectionInfoAsync(global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetChangeConnectionInfoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetChangeConnectionInfoAsync(global::ServiceStack.Extensions.Tests.Protoc.ChangeConnectionInfo request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetChangeConnectionInfo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse GetChangeDb(global::ServiceStack.Extensions.Tests.Protoc.ChangeDb request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetChangeDb(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ChangeDbResponse GetChangeDb(global::ServiceStack.Extensions.Tests.Protoc.ChangeDb request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetChangeDb, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetChangeDbAsync(global::ServiceStack.Extensions.Tests.Protoc.ChangeDb request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetChangeDbAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetChangeDbAsync(global::ServiceStack.Extensions.Tests.Protoc.ChangeDb request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetChangeDb, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToTokenResponse PostConvertSessionToToken(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostConvertSessionToToken(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToTokenResponse PostConvertSessionToToken(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostConvertSessionToToken, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostConvertSessionToTokenAsync(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostConvertSessionToTokenAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostConvertSessionToTokenAsync(global::ServiceStack.Extensions.Tests.Protoc.ConvertSessionToToken request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostConvertSessionToToken, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateBookmarkResponse PostCreateBookmark(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateBookmark(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateBookmarkResponse PostCreateBookmark(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateBookmark, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateBookmarkAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateBookmarkAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateBookmarkAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateBookmark request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateBookmark, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateConnectionInfoRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateConnectionInfoRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateConnectionInfoRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateConnectionInfoRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateConnectionInfoRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateConnectionInfoRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateConnectionInfoRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateConnectionInfoRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateConnectionInfoRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateNamedRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateNamedRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateNamedRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateNamedRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateNamedRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateNamedRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateNamedRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateNamedRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateNamedRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarResponse PostCreateRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarResponse PostCreateRockstar(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAdhocNonDefaults(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAdhocNonDefaults(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAdhocNonDefaults(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAdhocNonDefaults, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAdhocNonDefaultsAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAdhocNonDefaultsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAdhocNonDefaultsAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAdhocNonDefaults request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAdhocNonDefaults, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostCreateRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAudit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostCreateRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAudit, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAudit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostCreateRockstarAuditMqToken(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditMqToken(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostCreateRockstarAuditMqToken(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAuditMqToken, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditMqTokenAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditMqTokenAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditMqTokenAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditMqToken request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAuditMqToken, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditTenant(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAuditTenant, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditTenantAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAuditTenant, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditTenantGateway(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAuditTenantGateway, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditTenantGatewayAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAuditTenantGateway, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetCreateRockstarAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetCreateRockstarAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetCreateRockstarAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetCreateRockstarAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutCreateRockstarAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutCreateRockstarAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutCreateRockstarAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutCreateRockstarAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse DeleteCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteCreateRockstarAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse DeleteCreateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteCreateRockstarAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteCreateRockstarAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteCreateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteCreateRockstarAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAutoMap(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAutoMap(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarAutoMap(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarAutoMap, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAutoMapAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarAutoMapAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarAutoMapAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarAutoMap request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarAutoMap, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse PostCreateRockstarVersion(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarVersion(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse PostCreateRockstarVersion(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarVersion, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarVersionAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarVersionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarVersionAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarVersion request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarVersion, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturnGuidResponse PostCreateRockstarWithAutoGuid(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarWithAutoGuid(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturnGuidResponse PostCreateRockstarWithAutoGuid(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarWithAutoGuid, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarWithAutoGuidAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarWithAutoGuidAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarWithAutoGuidAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithAutoGuid request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarWithAutoGuid, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarWithReturn(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarWithReturn(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PostCreateRockstarWithReturn(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarWithReturn, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarWithReturnAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarWithReturnAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarWithReturnAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithReturn request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarWithReturn, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostCreateRockstarWithVoidReturn(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarWithVoidReturn(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostCreateRockstarWithVoidReturn(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateRockstarWithVoidReturn, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarWithVoidReturnAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateRockstarWithVoidReturnAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateRockstarWithVoidReturnAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateRockstarWithVoidReturn request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateRockstarWithVoidReturn, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateTodoResponse PostCreateTodo(global::ServiceStack.Extensions.Tests.Protoc.CreateTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateTodo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.CreateTodoResponse PostCreateTodo(global::ServiceStack.Extensions.Tests.Protoc.CreateTodo request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCreateTodo, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCreateTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCreateTodoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCreateTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.CreateTodo request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCreateTodo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostCustomValidationErrors(global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCustomValidationErrors(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostCustomValidationErrors(global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostCustomValidationErrors, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostCustomValidationErrorsAsync(global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostCustomValidationErrorsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostCustomValidationErrorsAsync(global::ServiceStack.Extensions.Tests.Protoc.CustomValidationErrors request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostCustomValidationErrors, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallDeleteRockstar(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallDeleteRockstar(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallDeleteRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallDeleteRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallDeleteRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallDeleteRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse CallDeleteRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteRockstarAudit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse CallDeleteRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallDeleteRockstarAudit, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallDeleteRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteRockstarAuditAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallDeleteRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallDeleteRockstarAudit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarCountResponse CallDeleteRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteRockstarFilters(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarCountResponse CallDeleteRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallDeleteRockstarFilters, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallDeleteRockstarFiltersAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteRockstarFiltersAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallDeleteRockstarFiltersAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteRockstarFilters request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallDeleteRockstarFilters, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallDeleteTodo(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteTodo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallDeleteTodo(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallDeleteTodo, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallDeleteTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteTodoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallDeleteTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodo request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallDeleteTodo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallDeleteTodos(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteTodos(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallDeleteTodos(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallDeleteTodos, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallDeleteTodosAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallDeleteTodosAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallDeleteTodosAsync(global::ServiceStack.Extensions.Tests.Protoc.DeleteTodos request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallDeleteTodos, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryGetRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryGetRockstarsDynamic(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryGetRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryGetRockstarsDynamic, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryGetRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryGetRockstarsDynamicAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryGetRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryGetRockstarsDynamic, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema GetDynamicQueryCustomRockstarsSchema(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsSchema(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema GetDynamicQueryCustomRockstarsSchema(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryCustomRockstarsSchema, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsSchemaAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsSchemaAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsSchemaAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryCustomRockstarsSchema, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetDynamicSearchMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicSearchMovies(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetDynamicSearchMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicSearchMovies, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicSearchMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicSearchMoviesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicSearchMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicSearchMovies, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetDynamicQueryMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryMovies(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetDynamicQueryMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryMovies, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryMoviesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryMovies, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryUnknownRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryUnknownRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryUnknownRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryUnknownRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryUnknownRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryUnknownRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryUnknownRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryUnknownRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetDynamicQueryRockstarsWithReferences(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsWithReferences(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetDynamicQueryRockstarsWithReferences(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarsWithReferences, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsWithReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsWithReferencesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsWithReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarsWithReferences, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields GetDynamicQueryAllFields(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryAllFields(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields GetDynamicQueryAllFields(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryAllFields, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryAllFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryAllFieldsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryAllFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryAllFields, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum GetDynamicQueryTypeWithEnums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryTypeWithEnums(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum GetDynamicQueryTypeWithEnums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryTypeWithEnums, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryTypeWithEnumsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryTypeWithEnumsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryTypeWithEnumsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryTypeWithEnums, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryAdhocRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryAdhocRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryAdhocRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryAdhocRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryAdhocRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryAdhocRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryAdhocRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryAdhocRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc GetDynamicQueryAdhoc(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryAdhoc(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc GetDynamicQueryAdhoc(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryAdhoc, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryAdhocAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryAdhocAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryAdhocAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryAdhoc, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryChangeDb(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryChangeDb(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryChangeDb(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryChangeDb, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryChangeDbAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryChangeDbAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryChangeDbAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryChangeDb, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar GetDynamicQueryJoinedRockstarAlbumsCustomSelect(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryJoinedRockstarAlbumsCustomSelect(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar GetDynamicQueryJoinedRockstarAlbumsCustomSelect(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelect, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryJoinedRockstarAlbumsCustomSelectAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryJoinedRockstarAlbumsCustomSelectAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryJoinedRockstarAlbumsCustomSelectAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelect, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponseAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponseAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponseAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo GetDynamicQueryFoos(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFoos(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo GetDynamicQueryFoos(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryFoos, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFoosAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFoosAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFoosAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryFoos, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryOverridedRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOverridedRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryOverridedRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryOverridedRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOverridedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOverridedRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOverridedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryOverridedRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryOverridedCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOverridedCustomRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryOverridedCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryOverridedCustomRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOverridedCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOverridedCustomRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOverridedCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryOverridedCustomRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryCaseInsensitiveOrderBy(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCaseInsensitiveOrderBy(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryCaseInsensitiveOrderBy(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryCaseInsensitiveOrderBy, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCaseInsensitiveOrderByAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCaseInsensitiveOrderByAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCaseInsensitiveOrderByAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryCaseInsensitiveOrderBy, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetDynamicStreamMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicStreamMovies(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetDynamicStreamMovies(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicStreamMovies, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicStreamMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicStreamMoviesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicStreamMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicStreamMovies, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetDynamicQueryCustomRockstarsReferences(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsReferences(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetDynamicQueryCustomRockstarsReferences(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryCustomRockstarsReferences, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsReferencesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryCustomRockstarsReferences, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryRockstarAlbumsCustomLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsCustomLeftJoin(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryRockstarAlbumsCustomLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAlbumsCustomLeftJoin, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsCustomLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsCustomLeftJoinAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsCustomLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAlbumsCustomLeftJoin, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryChangeConnectionInfo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryChangeConnectionInfo, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryChangeConnectionInfoAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryChangeConnectionInfoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryChangeConnectionInfoAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryChangeConnectionInfo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetDynamicQueryRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAudit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetDynamicQueryRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAudit, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAuditAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAudit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetDynamicQueryRockstarAuditSubOr(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAuditSubOr(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetDynamicQueryRockstarAuditSubOr(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAuditSubOr, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAuditSubOrAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAuditSubOrAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAuditSubOrAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAuditSubOr, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark GetDynamicQueryBookmarks(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryBookmarks(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark GetDynamicQueryBookmarks(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryBookmarks, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryBookmarksAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryBookmarksAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryBookmarksAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryBookmarks, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar GetDynamicQueryNamedRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryNamedRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar GetDynamicQueryNamedRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryNamedRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryNamedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryNamedRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryNamedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryNamedRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum GetDynamicQueryRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbums(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum GetDynamicQueryRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAlbums, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAlbums, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest GetDynamicQueryPagingTest(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryPagingTest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest GetDynamicQueryPagingTest(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryPagingTest, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryPagingTestAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryPagingTestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryPagingTestAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryPagingTest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsConventions(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsConventions(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsConventions(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarsConventions, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsConventionsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarsConventions, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryCustomRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryCustomRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryJoinedRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryJoinedRockstarAlbums(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryJoinedRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryJoinedRockstarAlbums, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryJoinedRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryJoinedRockstarAlbumsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryJoinedRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryJoinedRockstarAlbums, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryRockstarAlbumsImplicit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsImplicit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryRockstarAlbumsImplicit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAlbumsImplicit, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsImplicitAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAlbumsImplicit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryRockstarAlbumsLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsLeftJoin(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryRockstarAlbumsLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAlbumsLeftJoin, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlbumsLeftJoinAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAlbumsLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAlbumsLeftJoin, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryMultiJoinRockstar(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryMultiJoinRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryMultiJoinRockstar(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryMultiJoinRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryMultiJoinRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryMultiJoinRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryMultiJoinRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryMultiJoinRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryFieldRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFieldRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryFieldRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryFieldRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFieldRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFieldRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFieldRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryFieldRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias GetDynamicQueryRockstarAlias(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAlias(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias GetDynamicQueryRockstarAlias(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarAlias, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAliasAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarAliasAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarAliasAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarAlias, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryFieldRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFieldRockstarsDynamic(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryFieldRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryFieldRockstarsDynamic, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFieldRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFieldRockstarsDynamicAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFieldRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryFieldRockstarsDynamic, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsFilter(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarsFilter, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsFilterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarsFilter, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryCustomRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsFilter(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetDynamicQueryCustomRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryCustomRockstarsFilter, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryCustomRockstarsFilterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryCustomRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryCustomRockstarsFilter, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsIFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsIFilter(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsIFilter(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarsIFilter, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsIFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsIFilterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsIFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarsIFilter, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryOrRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOrRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryOrRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryOrRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOrRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOrRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOrRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryOrRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsImplicit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsImplicit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarsImplicit(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarsImplicit, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarsImplicitAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarsImplicit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryOrRockstarsFields(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOrRockstarsFields(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryOrRockstarsFields(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryOrRockstarsFields, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOrRockstarsFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryOrRockstarsFieldsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryOrRockstarsFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryOrRockstarsFields, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryFieldsImplicitConventions(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFieldsImplicitConventions(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryFieldsImplicitConventions(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryFieldsImplicitConventions, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFieldsImplicitConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryFieldsImplicitConventionsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryFieldsImplicitConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryFieldsImplicitConventions, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryGetRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryGetRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryGetRockstars(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryGetRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryGetRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryGetRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryGetRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryGetRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarFilters(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetDynamicQueryRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetDynamicQueryRockstarFilters, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarFiltersAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetDynamicQueryRockstarFiltersAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetDynamicQueryRockstarFiltersAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetDynamicQueryRockstarFilters, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostDynamicValidationRules(global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostDynamicValidationRules(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostDynamicValidationRules(global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostDynamicValidationRules, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostDynamicValidationRulesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostDynamicValidationRulesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostDynamicValidationRulesAsync(global::ServiceStack.Extensions.Tests.Protoc.DynamicValidationRules request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostDynamicValidationRules, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostEmptyValidators(global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostEmptyValidators(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostEmptyValidators(global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostEmptyValidators, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostEmptyValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostEmptyValidatorsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostEmptyValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.EmptyValidators request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostEmptyValidators, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse GetEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetEndsWithSuffixRequest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse GetEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetEndsWithSuffixRequest, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetEndsWithSuffixRequestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetEndsWithSuffixRequest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse PostEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostEndsWithSuffixRequest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse PostEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostEndsWithSuffixRequest, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostEndsWithSuffixRequestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostEndsWithSuffixRequest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse PutEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutEndsWithSuffixRequest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse PutEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutEndsWithSuffixRequest, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutEndsWithSuffixRequestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutEndsWithSuffixRequest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse DeleteEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteEndsWithSuffixRequest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixResponse DeleteEndsWithSuffixRequest(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteEndsWithSuffixRequest, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteEndsWithSuffixRequestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteEndsWithSuffixRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.EndsWithSuffixRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteEndsWithSuffixRequest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetAccessTokenResponse PostGetAccessToken(global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostGetAccessToken(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetAccessTokenResponse PostGetAccessToken(global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostGetAccessToken, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostGetAccessTokenAsync(global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostGetAccessTokenAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostGetAccessTokenAsync(global::ServiceStack.Extensions.Tests.Protoc.GetAccessToken request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostGetAccessToken, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetApiKeysResponse CallGetApiKeys(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetApiKeys(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetApiKeysResponse CallGetApiKeys(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallGetApiKeys, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallGetApiKeysAsync(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetApiKeysAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallGetApiKeysAsync(global::ServiceStack.Extensions.Tests.Protoc.GetApiKeys request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallGetApiKeys, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.FileContent CallGetFile(global::ServiceStack.Extensions.Tests.Protoc.GetFile request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetFile(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.FileContent CallGetFile(global::ServiceStack.Extensions.Tests.Protoc.GetFile request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallGetFile, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallGetFileAsync(global::ServiceStack.Extensions.Tests.Protoc.GetFile request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetFileAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallGetFileAsync(global::ServiceStack.Extensions.Tests.Protoc.GetFile request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallGetFile, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse CallGetHello(global::ServiceStack.Extensions.Tests.Protoc.GetHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse CallGetHello(global::ServiceStack.Extensions.Tests.Protoc.GetHello request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallGetHello, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallGetHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.GetHello request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallGetHelloAsync(global::ServiceStack.Extensions.Tests.Protoc.GetHello request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallGetHello, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetTodoResponse CallGetTodo(global::ServiceStack.Extensions.Tests.Protoc.GetTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetTodo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetTodoResponse CallGetTodo(global::ServiceStack.Extensions.Tests.Protoc.GetTodo request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallGetTodo, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallGetTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.GetTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetTodoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallGetTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.GetTodo request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallGetTodo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetTodosResponse CallGetTodos(global::ServiceStack.Extensions.Tests.Protoc.GetTodos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetTodos(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.GetTodosResponse CallGetTodos(global::ServiceStack.Extensions.Tests.Protoc.GetTodos request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallGetTodos, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallGetTodosAsync(global::ServiceStack.Extensions.Tests.Protoc.GetTodos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallGetTodosAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallGetTodosAsync(global::ServiceStack.Extensions.Tests.Protoc.GetTodos request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallGetTodos, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse GetHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetHelloJwt(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse GetHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetHelloJwt, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetHelloJwtAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetHelloJwt, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse PostHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostHelloJwt(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse PostHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostHelloJwt, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostHelloJwtAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostHelloJwt, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse PutHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutHelloJwt(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse PutHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutHelloJwt, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutHelloJwtAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutHelloJwt, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse DeleteHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteHelloJwt(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloJwtResponse DeleteHelloJwt(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteHelloJwt, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteHelloJwtAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteHelloJwtAsync(global::ServiceStack.Extensions.Tests.Protoc.HelloJwt request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteHelloJwt, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetIncr(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetIncr, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetIncrAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetIncr, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostIncr(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostIncr, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostIncrAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostIncr, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutIncr(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutIncr, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutIncrAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutIncr, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse DeleteIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteIncr(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse DeleteIncr(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteIncr, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteIncrAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteIncrAsync(global::ServiceStack.Extensions.Tests.Protoc.Incr request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteIncr, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.MultiplyResponse PostMultiply(global::ServiceStack.Extensions.Tests.Protoc.Multiply request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostMultiply(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.MultiplyResponse PostMultiply(global::ServiceStack.Extensions.Tests.Protoc.Multiply request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostMultiply, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostMultiplyAsync(global::ServiceStack.Extensions.Tests.Protoc.Multiply request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostMultiplyAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostMultiplyAsync(global::ServiceStack.Extensions.Tests.Protoc.Multiply request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostMultiply, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostNoAbstractValidator(global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostNoAbstractValidator(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostNoAbstractValidator(global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostNoAbstractValidator, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostNoAbstractValidatorAsync(global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostNoAbstractValidatorAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostNoAbstractValidatorAsync(global::ServiceStack.Extensions.Tests.Protoc.NoAbstractValidator request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostNoAbstractValidator, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostOnlyValidatesRequest(global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostOnlyValidatesRequest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostOnlyValidatesRequest(global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostOnlyValidatesRequest, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostOnlyValidatesRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostOnlyValidatesRequestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostOnlyValidatesRequestAsync(global::ServiceStack.Extensions.Tests.Protoc.OnlyValidatesRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostOnlyValidatesRequest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallPatchRockstar(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallPatchRockstar(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallPatchRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallPatchRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse CallPatchRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAuditTenant(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse CallPatchRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallPatchRockstarAuditTenant, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAuditTenantAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallPatchRockstarAuditTenant, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse CallPatchRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAuditTenantGateway(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse CallPatchRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallPatchRockstarAuditTenantGateway, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAuditTenantGatewayAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallPatchRockstarAuditTenantGateway, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallPatchRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse CallPatchRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallPatchRockstarAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPatchRockstarAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallPatchRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.PatchRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallPatchRockstarAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ChatMessage CallPostChatToChannel(global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPostChatToChannel(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ChatMessage CallPostChatToChannel(global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CallPostChatToChannel, null, options, request); + } + public virtual grpc::AsyncUnaryCall CallPostChatToChannelAsync(global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CallPostChatToChannelAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall CallPostChatToChannelAsync(global::ServiceStack.Extensions.Tests.Protoc.PostChatToChannel request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CallPostChatToChannel, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc GetQueryAdhoc(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryAdhoc(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Adhoc GetQueryAdhoc(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryAdhoc, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryAdhocAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryAdhocAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryAdhocAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhoc request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryAdhoc, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryAdhocRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryAdhocRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryAdhocRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryAdhocRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryAdhocRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryAdhocRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryAdhocRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryAdhocRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryAdhocRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields GetQueryAllFields(global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryAllFields(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_AllFields GetQueryAllFields(global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryAllFields, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryAllFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryAllFieldsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryAllFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryAllFields request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryAllFields, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark GetQueryBookmarks(global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryBookmarks(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Bookmark GetQueryBookmarks(global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryBookmarks, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryBookmarksAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryBookmarksAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryBookmarksAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryBookmarks request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryBookmarks, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryCaseInsensitiveOrderBy(global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCaseInsensitiveOrderBy(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryCaseInsensitiveOrderBy(global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryCaseInsensitiveOrderBy, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryCaseInsensitiveOrderByAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCaseInsensitiveOrderByAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryCaseInsensitiveOrderByAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCaseInsensitiveOrderBy request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryCaseInsensitiveOrderBy, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryChangeConnectionInfo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryChangeConnectionInfo(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryChangeConnectionInfo, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryChangeConnectionInfoAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryChangeConnectionInfoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryChangeConnectionInfoAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeConnectionInfo request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryChangeConnectionInfo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryChangeDb(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryChangeDb(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryChangeDb(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryChangeDb, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryChangeDbAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryChangeDbAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryChangeDbAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryChangeDb request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryChangeDb, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryCustomRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryCustomRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryCustomRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsFilter(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryCustomRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryCustomRockstarsFilter, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsFilterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsFilter request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryCustomRockstarsFilter, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetQueryCustomRockstarsReferences(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsReferences(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetQueryCustomRockstarsReferences(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryCustomRockstarsReferences, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsReferencesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsReferences request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryCustomRockstarsReferences, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema GetQueryCustomRockstarsSchema(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsSchema(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstarSchema GetQueryCustomRockstarsSchema(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryCustomRockstarsSchema, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsSchemaAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryCustomRockstarsSchemaAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryCustomRockstarsSchemaAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryCustomRockstarsSchema request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryCustomRockstarsSchema, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryFieldRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFieldRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryFieldRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryFieldRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryFieldRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFieldRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryFieldRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryFieldRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryFieldRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFieldRockstarsDynamic(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryFieldRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryFieldRockstarsDynamic, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryFieldRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFieldRockstarsDynamicAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryFieldRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldRockstarsDynamic request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryFieldRockstarsDynamic, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryFieldsImplicitConventions(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFieldsImplicitConventions(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryFieldsImplicitConventions(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryFieldsImplicitConventions, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryFieldsImplicitConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFieldsImplicitConventionsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryFieldsImplicitConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFieldsImplicitConventions request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryFieldsImplicitConventions, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo GetQueryFoos(global::ServiceStack.Extensions.Tests.Protoc.QueryFoos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFoos(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Foo GetQueryFoos(global::ServiceStack.Extensions.Tests.Protoc.QueryFoos request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryFoos, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryFoosAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFoos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryFoosAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryFoosAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryFoos request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryFoos, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryGetRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryGetRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryGetRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryGetRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryGetRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryGetRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryGetRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryGetRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryGetRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryGetRockstarsDynamic(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryGetRockstarsDynamic(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryGetRockstarsDynamic, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryGetRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryGetRockstarsDynamicAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryGetRockstarsDynamicAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryGetRockstarsDynamic request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryGetRockstarsDynamic, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryJoinedRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryJoinedRockstarAlbums(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryJoinedRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryJoinedRockstarAlbums, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryJoinedRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryJoinedRockstarAlbumsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryJoinedRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbums request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryJoinedRockstarAlbums, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar GetQueryJoinedRockstarAlbumsCustomSelect(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryJoinedRockstarAlbumsCustomSelect(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstar GetQueryJoinedRockstarAlbumsCustomSelect(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryJoinedRockstarAlbumsCustomSelect, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryJoinedRockstarAlbumsCustomSelectAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryJoinedRockstarAlbumsCustomSelectAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryJoinedRockstarAlbumsCustomSelectAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelect request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryJoinedRockstarAlbumsCustomSelect, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse GetQueryJoinedRockstarAlbumsCustomSelectResponse(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryJoinedRockstarAlbumsCustomSelectResponse(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomSelectRockstarResponse GetQueryJoinedRockstarAlbumsCustomSelectResponse(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryJoinedRockstarAlbumsCustomSelectResponse, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryJoinedRockstarAlbumsCustomSelectResponseAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryJoinedRockstarAlbumsCustomSelectResponseAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryJoinedRockstarAlbumsCustomSelectResponseAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryJoinedRockstarAlbumsCustomSelectResponse request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryJoinedRockstarAlbumsCustomSelectResponse, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetQueryMovies(global::ServiceStack.Extensions.Tests.Protoc.QueryMovies request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryMovies(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetQueryMovies(global::ServiceStack.Extensions.Tests.Protoc.QueryMovies request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryMovies, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryMovies request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryMoviesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryMovies request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryMovies, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryMultiJoinRockstar(global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryMultiJoinRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryMultiJoinRockstar(global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryMultiJoinRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryMultiJoinRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryMultiJoinRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryMultiJoinRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryMultiJoinRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryMultiJoinRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar GetQueryNamedRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryNamedRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_NamedRockstar GetQueryNamedRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryNamedRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryNamedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryNamedRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryNamedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryNamedRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryNamedRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryOrRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOrRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryOrRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryOrRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryOrRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOrRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryOrRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryOrRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryOrRockstarsFields(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOrRockstarsFields(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryOrRockstarsFields(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryOrRockstarsFields, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryOrRockstarsFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOrRockstarsFieldsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryOrRockstarsFieldsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOrRockstarsFields request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryOrRockstarsFields, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryOverridedCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOverridedCustomRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryOverridedCustomRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryOverridedCustomRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryOverridedCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOverridedCustomRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryOverridedCustomRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedCustomRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryOverridedCustomRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryOverridedRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOverridedRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryOverridedRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryOverridedRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryOverridedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryOverridedRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryOverridedRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryOverridedRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryOverridedRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest GetQueryPagingTest(global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryPagingTest(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_PagingTest GetQueryPagingTest(global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryPagingTest, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryPagingTestAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryPagingTestAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryPagingTestAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryPagingTest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryPagingTest, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum GetQueryRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbums(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlbum GetQueryRockstarAlbums(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAlbums, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbums request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAlbums, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryRockstarAlbumsCustomLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsCustomLeftJoin(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryRockstarAlbumsCustomLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAlbumsCustomLeftJoin, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsCustomLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsCustomLeftJoinAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsCustomLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsCustomLeftJoin request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAlbumsCustomLeftJoin, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryRockstarAlbumsImplicit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsImplicit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryRockstarAlbumsImplicit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAlbumsImplicit, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsImplicitAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsImplicit request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAlbumsImplicit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryRockstarAlbumsLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsLeftJoin(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_CustomRockstar GetQueryRockstarAlbumsLeftJoin(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAlbumsLeftJoin, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlbumsLeftJoinAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAlbumsLeftJoinAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlbumsLeftJoin request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAlbumsLeftJoin, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias GetQueryRockstarAlias(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAlias(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAlias GetQueryRockstarAlias(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAlias, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAliasAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAliasAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAliasAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAlias request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAlias, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetQueryRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAudit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetQueryRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAudit, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAuditAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAudit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetQueryRockstarAuditSubOr(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAuditSubOr(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarAuto GetQueryRockstarAuditSubOr(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarAuditSubOr, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAuditSubOrAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarAuditSubOrAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarAuditSubOrAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarAuditSubOr request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarAuditSubOr, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarFilters(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarFilters(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarFilters, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarFiltersAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarFiltersAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarFiltersAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarFilters request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarFilters, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsConventions(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsConventions(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsConventions(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarsConventions, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsConventionsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsConventionsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsConventions request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarsConventions, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsFilter(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarsFilter, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsFilterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsFilter request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarsFilter, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsIFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsIFilter(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsIFilter(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarsIFilter, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsIFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsIFilterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsIFilterAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsIFilter request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarsIFilter, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsImplicit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsImplicit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryRockstarsImplicit(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarsImplicit, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsImplicitAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsImplicitAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsImplicit request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarsImplicit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetQueryRockstarsWithReferences(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsWithReferences(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_RockstarReference GetQueryRockstarsWithReferences(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryRockstarsWithReferences, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsWithReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryRockstarsWithReferencesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryRockstarsWithReferencesAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryRockstarsWithReferences request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryRockstarsWithReferences, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum GetQueryTypeWithEnums(global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryTypeWithEnums(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_TypeWithEnum GetQueryTypeWithEnums(global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryTypeWithEnums, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryTypeWithEnumsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryTypeWithEnumsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryTypeWithEnumsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryTypeWithEnums request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryTypeWithEnums, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryUnknownRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryUnknownRockstars(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Rockstar GetQueryUnknownRockstars(global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetQueryUnknownRockstars, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetQueryUnknownRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetQueryUnknownRockstarsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetQueryUnknownRockstarsAsync(global::ServiceStack.Extensions.Tests.Protoc.QueryUnknownRockstars request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetQueryUnknownRockstars, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse DeleteRealDeleteAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRealDeleteAuditTenant(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse DeleteRealDeleteAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteRealDeleteAuditTenant, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteRealDeleteAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRealDeleteAuditTenantAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteRealDeleteAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteRealDeleteAuditTenant, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse DeleteRealDeleteAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRealDeleteAuditTenantGateway(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndCountResponse DeleteRealDeleteAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteRealDeleteAuditTenantGateway, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteRealDeleteAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRealDeleteAuditTenantGatewayAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteRealDeleteAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteRealDeleteAuditTenantGateway, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse DeleteRealDeleteAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRealDeleteAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse DeleteRealDeleteAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteRealDeleteAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteRealDeleteAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRealDeleteAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteRealDeleteAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.RealDeleteAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteRealDeleteAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeysResponse PostRegenerateApiKeys(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostRegenerateApiKeys(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeysResponse PostRegenerateApiKeys(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostRegenerateApiKeys, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostRegenerateApiKeysAsync(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostRegenerateApiKeysAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostRegenerateApiKeysAsync(global::ServiceStack.Extensions.Tests.Protoc.RegenerateApiKeys request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostRegenerateApiKeys, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse PutRegister(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse PutRegister(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutRegisterAsync(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutRegisterAsync(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutRegister, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse PostRegister(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RegisterResponse PostRegister(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostRegisterAsync(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostRegisterAsync(global::ServiceStack.Extensions.Tests.Protoc.Register request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostRegister, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth GetRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetRequiresAuth(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth GetRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetRequiresAuth, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetRequiresAuthAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetRequiresAuth, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth PostRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostRequiresAuth(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth PostRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostRequiresAuth, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostRequiresAuthAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostRequiresAuth, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth PutRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutRequiresAuth(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth PutRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutRequiresAuth, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutRequiresAuthAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutRequiresAuth, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth DeleteRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRequiresAuth(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth DeleteRequiresAuth(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_DeleteRequiresAuth, null, options, request); + } + public virtual grpc::AsyncUnaryCall DeleteRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return DeleteRequiresAuthAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall DeleteRequiresAuthAsync(global::ServiceStack.Extensions.Tests.Protoc.RequiresAuth request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_DeleteRequiresAuth, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostResetTodos(global::ServiceStack.Extensions.Tests.Protoc.ResetTodos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostResetTodos(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostResetTodos(global::ServiceStack.Extensions.Tests.Protoc.ResetTodos request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostResetTodos, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostResetTodosAsync(global::ServiceStack.Extensions.Tests.Protoc.ResetTodos request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostResetTodosAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostResetTodosAsync(global::ServiceStack.Extensions.Tests.Protoc.ResetTodos request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostResetTodos, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetSearchMovies(global::ServiceStack.Extensions.Tests.Protoc.SearchMovies request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetSearchMovies(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetSearchMovies(global::ServiceStack.Extensions.Tests.Protoc.SearchMovies request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetSearchMovies, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetSearchMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.SearchMovies request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetSearchMoviesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetSearchMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.SearchMovies request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetSearchMovies, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.SecuredResponse PostSecured(global::ServiceStack.Extensions.Tests.Protoc.Secured request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostSecured(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.SecuredResponse PostSecured(global::ServiceStack.Extensions.Tests.Protoc.Secured request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostSecured, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostSecuredAsync(global::ServiceStack.Extensions.Tests.Protoc.Secured request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostSecuredAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostSecuredAsync(global::ServiceStack.Extensions.Tests.Protoc.Secured request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostSecured, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutSoftDeleteAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutSoftDeleteAuditTenant(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutSoftDeleteAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutSoftDeleteAuditTenant, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutSoftDeleteAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutSoftDeleteAuditTenantAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutSoftDeleteAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.SoftDeleteAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutSoftDeleteAuditTenant, null, options, request); + } + public virtual grpc::AsyncServerStreamingCall ServerStreamFiles(global::ServiceStack.Extensions.Tests.Protoc.StreamFiles request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ServerStreamFiles(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncServerStreamingCall ServerStreamFiles(global::ServiceStack.Extensions.Tests.Protoc.StreamFiles request, grpc::CallOptions options) + { + return CallInvoker.AsyncServerStreamingCall(__Method_ServerStreamFiles, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetStreamMovies(global::ServiceStack.Extensions.Tests.Protoc.StreamMovies request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetStreamMovies(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.QueryResponse_Movie GetStreamMovies(global::ServiceStack.Extensions.Tests.Protoc.StreamMovies request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetStreamMovies, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetStreamMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.StreamMovies request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetStreamMoviesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetStreamMoviesAsync(global::ServiceStack.Extensions.Tests.Protoc.StreamMovies request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetStreamMovies, null, options, request); + } + public virtual grpc::AsyncServerStreamingCall ServerStreamServerEvents(global::ServiceStack.Extensions.Tests.Protoc.StreamServerEvents request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ServerStreamServerEvents(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncServerStreamingCall ServerStreamServerEvents(global::ServiceStack.Extensions.Tests.Protoc.StreamServerEvents request, grpc::CallOptions options) + { + return CallInvoker.AsyncServerStreamingCall(__Method_ServerStreamServerEvents, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestAuthValidators(global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestAuthValidators(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestAuthValidators(global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTestAuthValidators, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTestAuthValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestAuthValidatorsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTestAuthValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TestAuthValidators request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTestAuthValidators, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestDbCondition(global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestDbCondition(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestDbCondition(global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTestDbCondition, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTestDbConditionAsync(global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestDbConditionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTestDbConditionAsync(global::ServiceStack.Extensions.Tests.Protoc.TestDbCondition request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTestDbCondition, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestDbValidator(global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestDbValidator(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestDbValidator(global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTestDbValidator, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTestDbValidatorAsync(global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestDbValidatorAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTestDbValidatorAsync(global::ServiceStack.Extensions.Tests.Protoc.TestDbValidator request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTestDbValidator, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestIsAdmin(global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestIsAdmin(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestIsAdmin(global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTestIsAdmin, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTestIsAdminAsync(global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestIsAdminAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTestIsAdminAsync(global::ServiceStack.Extensions.Tests.Protoc.TestIsAdmin request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTestIsAdmin, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestMultiAuthValidators(global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestMultiAuthValidators(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTestMultiAuthValidators(global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTestMultiAuthValidators, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTestMultiAuthValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTestMultiAuthValidatorsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTestMultiAuthValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TestMultiAuthValidators request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTestMultiAuthValidators, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse GetThrow(global::ServiceStack.Extensions.Tests.Protoc.Throw request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetThrow(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.HelloResponse GetThrow(global::ServiceStack.Extensions.Tests.Protoc.Throw request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetThrow, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetThrowAsync(global::ServiceStack.Extensions.Tests.Protoc.Throw request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetThrowAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetThrowAsync(global::ServiceStack.Extensions.Tests.Protoc.Throw request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetThrow, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ThrowCustomResponse GetThrowCustom(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetThrowCustom(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.ThrowCustomResponse GetThrowCustom(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetThrowCustom, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetThrowCustomAsync(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetThrowCustomAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetThrowCustomAsync(global::ServiceStack.Extensions.Tests.Protoc.ThrowCustom request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetThrowCustom, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetThrowVoid(global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetThrowVoid(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse GetThrowVoid(global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_GetThrowVoid, null, options, request); + } + public virtual grpc::AsyncUnaryCall GetThrowVoidAsync(global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetThrowVoidAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall GetThrowVoidAsync(global::ServiceStack.Extensions.Tests.Protoc.ThrowVoid request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_GetThrowVoid, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTriggerAllValidators(global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTriggerAllValidators(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostTriggerAllValidators(global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTriggerAllValidators, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTriggerAllValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTriggerAllValidatorsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTriggerAllValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TriggerAllValidators request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTriggerAllValidators, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostTriggerValidators(global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTriggerValidators(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PostTriggerValidators(global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostTriggerValidators, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostTriggerValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostTriggerValidatorsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostTriggerValidatorsAsync(global::ServiceStack.Extensions.Tests.Protoc.TriggerValidators request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostTriggerValidators, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.UnAssignRolesResponse PostUnAssignRoles(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostUnAssignRoles(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.UnAssignRolesResponse PostUnAssignRoles(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostUnAssignRoles, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostUnAssignRolesAsync(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostUnAssignRolesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostUnAssignRolesAsync(global::ServiceStack.Extensions.Tests.Protoc.UnAssignRoles request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostUnAssignRoles, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateConnectionInfoRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateConnectionInfoRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateConnectionInfoRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateConnectionInfoRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateConnectionInfoRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateConnectionInfoRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateConnectionInfoRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateConnectionInfoRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateConnectionInfoRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateNamedRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateNamedRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateNamedRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateNamedRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateNamedRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateNamedRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateNamedRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateNamedRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateNamedRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateRockstar(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateRockstar, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateRockstarAdhocNonDefaults(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAdhocNonDefaults(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateRockstarAdhocNonDefaults(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateRockstarAdhocNonDefaults, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAdhocNonDefaultsAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAdhocNonDefaultsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAdhocNonDefaultsAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAdhocNonDefaults request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateRockstarAdhocNonDefaults, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PatchUpdateRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PatchUpdateRockstarAudit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PatchUpdateRockstarAudit(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PatchUpdateRockstarAudit, null, options, request); + } + public virtual grpc::AsyncUnaryCall PatchUpdateRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PatchUpdateRockstarAuditAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PatchUpdateRockstarAuditAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAudit request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PatchUpdateRockstarAudit, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAuditTenant(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateRockstarAuditTenant(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateRockstarAuditTenant, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAuditTenantAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAuditTenantAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenant request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateRockstarAuditTenant, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAuditTenantGateway(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndResultResponse PutUpdateRockstarAuditTenantGateway(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateRockstarAuditTenantGateway, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAuditTenantGatewayAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAuditTenantGatewayAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantGateway request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateRockstarAuditTenantGateway, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAuditTenantMq(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateRockstarAuditTenantMq(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateRockstarAuditTenantMq, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateRockstarAuditTenantMqAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateRockstarAuditTenantMqAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarAuditTenantMq request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateRockstarAuditTenantMq, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse PatchUpdateRockstarVersion(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PatchUpdateRockstarVersion(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdAndRowVersionResponse PatchUpdateRockstarVersion(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PatchUpdateRockstarVersion, null, options, request); + } + public virtual grpc::AsyncUnaryCall PatchUpdateRockstarVersionAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PatchUpdateRockstarVersionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PatchUpdateRockstarVersionAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateRockstarVersion request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PatchUpdateRockstarVersion, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateTodo(global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateTodo(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.EmptyResponse PutUpdateTodo(global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PutUpdateTodo, null, options, request); + } + public virtual grpc::AsyncUnaryCall PutUpdateTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PutUpdateTodoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PutUpdateTodoAsync(global::ServiceStack.Extensions.Tests.Protoc.UpdateTodo request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PutUpdateTodo, null, options, request); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostValidateCreateRockstar(global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostValidateCreateRockstar(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::ServiceStack.Extensions.Tests.Protoc.RockstarWithIdResponse PostValidateCreateRockstar(global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_PostValidateCreateRockstar, null, options, request); + } + public virtual grpc::AsyncUnaryCall PostValidateCreateRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return PostValidateCreateRockstarAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall PostValidateCreateRockstarAsync(global::ServiceStack.Extensions.Tests.Protoc.ValidateCreateRockstar request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_PostValidateCreateRockstar, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override GrpcServicesClient NewInstance(ClientBaseConfiguration configuration) + { + return new GrpcServicesClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(GrpcServicesBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_GetAddHeader, serviceImpl.GetAddHeader) + .AddMethod(__Method_GetAnyHello, serviceImpl.GetAnyHello) + .AddMethod(__Method_PostAnyHello, serviceImpl.PostAnyHello) + .AddMethod(__Method_PutAnyHello, serviceImpl.PutAnyHello) + .AddMethod(__Method_DeleteAnyHello, serviceImpl.DeleteAnyHello) + .AddMethod(__Method_PostAssignRoles, serviceImpl.PostAssignRoles) + .AddMethod(__Method_OptionsAuthenticate, serviceImpl.OptionsAuthenticate) + .AddMethod(__Method_GetAuthenticate, serviceImpl.GetAuthenticate) + .AddMethod(__Method_PostAuthenticate, serviceImpl.PostAuthenticate) + .AddMethod(__Method_DeleteAuthenticate, serviceImpl.DeleteAuthenticate) + .AddMethod(__Method_GetChangeConnectionInfo, serviceImpl.GetChangeConnectionInfo) + .AddMethod(__Method_GetChangeDb, serviceImpl.GetChangeDb) + .AddMethod(__Method_PostConvertSessionToToken, serviceImpl.PostConvertSessionToToken) + .AddMethod(__Method_PostCreateBookmark, serviceImpl.PostCreateBookmark) + .AddMethod(__Method_PostCreateConnectionInfoRockstar, serviceImpl.PostCreateConnectionInfoRockstar) + .AddMethod(__Method_PostCreateNamedRockstar, serviceImpl.PostCreateNamedRockstar) + .AddMethod(__Method_PostCreateRockstar, serviceImpl.PostCreateRockstar) + .AddMethod(__Method_PostCreateRockstarAdhocNonDefaults, serviceImpl.PostCreateRockstarAdhocNonDefaults) + .AddMethod(__Method_PostCreateRockstarAudit, serviceImpl.PostCreateRockstarAudit) + .AddMethod(__Method_PostCreateRockstarAuditMqToken, serviceImpl.PostCreateRockstarAuditMqToken) + .AddMethod(__Method_PostCreateRockstarAuditTenant, serviceImpl.PostCreateRockstarAuditTenant) + .AddMethod(__Method_PostCreateRockstarAuditTenantGateway, serviceImpl.PostCreateRockstarAuditTenantGateway) + .AddMethod(__Method_GetCreateRockstarAuditTenantMq, serviceImpl.GetCreateRockstarAuditTenantMq) + .AddMethod(__Method_PostCreateRockstarAuditTenantMq, serviceImpl.PostCreateRockstarAuditTenantMq) + .AddMethod(__Method_PutCreateRockstarAuditTenantMq, serviceImpl.PutCreateRockstarAuditTenantMq) + .AddMethod(__Method_DeleteCreateRockstarAuditTenantMq, serviceImpl.DeleteCreateRockstarAuditTenantMq) + .AddMethod(__Method_PostCreateRockstarAutoMap, serviceImpl.PostCreateRockstarAutoMap) + .AddMethod(__Method_PostCreateRockstarVersion, serviceImpl.PostCreateRockstarVersion) + .AddMethod(__Method_PostCreateRockstarWithAutoGuid, serviceImpl.PostCreateRockstarWithAutoGuid) + .AddMethod(__Method_PostCreateRockstarWithReturn, serviceImpl.PostCreateRockstarWithReturn) + .AddMethod(__Method_PostCreateRockstarWithVoidReturn, serviceImpl.PostCreateRockstarWithVoidReturn) + .AddMethod(__Method_PostCreateTodo, serviceImpl.PostCreateTodo) + .AddMethod(__Method_PostCustomValidationErrors, serviceImpl.PostCustomValidationErrors) + .AddMethod(__Method_CallDeleteRockstar, serviceImpl.CallDeleteRockstar) + .AddMethod(__Method_CallDeleteRockstarAudit, serviceImpl.CallDeleteRockstarAudit) + .AddMethod(__Method_CallDeleteRockstarFilters, serviceImpl.CallDeleteRockstarFilters) + .AddMethod(__Method_CallDeleteTodo, serviceImpl.CallDeleteTodo) + .AddMethod(__Method_CallDeleteTodos, serviceImpl.CallDeleteTodos) + .AddMethod(__Method_GetDynamicQueryGetRockstarsDynamic, serviceImpl.GetDynamicQueryGetRockstarsDynamic) + .AddMethod(__Method_GetDynamicQueryCustomRockstarsSchema, serviceImpl.GetDynamicQueryCustomRockstarsSchema) + .AddMethod(__Method_GetDynamicSearchMovies, serviceImpl.GetDynamicSearchMovies) + .AddMethod(__Method_GetDynamicQueryMovies, serviceImpl.GetDynamicQueryMovies) + .AddMethod(__Method_GetDynamicQueryUnknownRockstars, serviceImpl.GetDynamicQueryUnknownRockstars) + .AddMethod(__Method_GetDynamicQueryRockstarsWithReferences, serviceImpl.GetDynamicQueryRockstarsWithReferences) + .AddMethod(__Method_GetDynamicQueryAllFields, serviceImpl.GetDynamicQueryAllFields) + .AddMethod(__Method_GetDynamicQueryTypeWithEnums, serviceImpl.GetDynamicQueryTypeWithEnums) + .AddMethod(__Method_GetDynamicQueryAdhocRockstars, serviceImpl.GetDynamicQueryAdhocRockstars) + .AddMethod(__Method_GetDynamicQueryAdhoc, serviceImpl.GetDynamicQueryAdhoc) + .AddMethod(__Method_GetDynamicQueryChangeDb, serviceImpl.GetDynamicQueryChangeDb) + .AddMethod(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelect, serviceImpl.GetDynamicQueryJoinedRockstarAlbumsCustomSelect) + .AddMethod(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse, serviceImpl.GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse) + .AddMethod(__Method_GetDynamicQueryFoos, serviceImpl.GetDynamicQueryFoos) + .AddMethod(__Method_GetDynamicQueryOverridedRockstars, serviceImpl.GetDynamicQueryOverridedRockstars) + .AddMethod(__Method_GetDynamicQueryOverridedCustomRockstars, serviceImpl.GetDynamicQueryOverridedCustomRockstars) + .AddMethod(__Method_GetDynamicQueryCaseInsensitiveOrderBy, serviceImpl.GetDynamicQueryCaseInsensitiveOrderBy) + .AddMethod(__Method_GetDynamicStreamMovies, serviceImpl.GetDynamicStreamMovies) + .AddMethod(__Method_GetDynamicQueryCustomRockstarsReferences, serviceImpl.GetDynamicQueryCustomRockstarsReferences) + .AddMethod(__Method_GetDynamicQueryRockstarAlbumsCustomLeftJoin, serviceImpl.GetDynamicQueryRockstarAlbumsCustomLeftJoin) + .AddMethod(__Method_GetDynamicQueryChangeConnectionInfo, serviceImpl.GetDynamicQueryChangeConnectionInfo) + .AddMethod(__Method_GetDynamicQueryRockstarAudit, serviceImpl.GetDynamicQueryRockstarAudit) + .AddMethod(__Method_GetDynamicQueryRockstarAuditSubOr, serviceImpl.GetDynamicQueryRockstarAuditSubOr) + .AddMethod(__Method_GetDynamicQueryBookmarks, serviceImpl.GetDynamicQueryBookmarks) + .AddMethod(__Method_GetDynamicQueryNamedRockstars, serviceImpl.GetDynamicQueryNamedRockstars) + .AddMethod(__Method_GetDynamicQueryRockstars, serviceImpl.GetDynamicQueryRockstars) + .AddMethod(__Method_GetDynamicQueryRockstarAlbums, serviceImpl.GetDynamicQueryRockstarAlbums) + .AddMethod(__Method_GetDynamicQueryPagingTest, serviceImpl.GetDynamicQueryPagingTest) + .AddMethod(__Method_GetDynamicQueryRockstarsConventions, serviceImpl.GetDynamicQueryRockstarsConventions) + .AddMethod(__Method_GetDynamicQueryCustomRockstars, serviceImpl.GetDynamicQueryCustomRockstars) + .AddMethod(__Method_GetDynamicQueryJoinedRockstarAlbums, serviceImpl.GetDynamicQueryJoinedRockstarAlbums) + .AddMethod(__Method_GetDynamicQueryRockstarAlbumsImplicit, serviceImpl.GetDynamicQueryRockstarAlbumsImplicit) + .AddMethod(__Method_GetDynamicQueryRockstarAlbumsLeftJoin, serviceImpl.GetDynamicQueryRockstarAlbumsLeftJoin) + .AddMethod(__Method_GetDynamicQueryMultiJoinRockstar, serviceImpl.GetDynamicQueryMultiJoinRockstar) + .AddMethod(__Method_GetDynamicQueryFieldRockstars, serviceImpl.GetDynamicQueryFieldRockstars) + .AddMethod(__Method_GetDynamicQueryRockstarAlias, serviceImpl.GetDynamicQueryRockstarAlias) + .AddMethod(__Method_GetDynamicQueryFieldRockstarsDynamic, serviceImpl.GetDynamicQueryFieldRockstarsDynamic) + .AddMethod(__Method_GetDynamicQueryRockstarsFilter, serviceImpl.GetDynamicQueryRockstarsFilter) + .AddMethod(__Method_GetDynamicQueryCustomRockstarsFilter, serviceImpl.GetDynamicQueryCustomRockstarsFilter) + .AddMethod(__Method_GetDynamicQueryRockstarsIFilter, serviceImpl.GetDynamicQueryRockstarsIFilter) + .AddMethod(__Method_GetDynamicQueryOrRockstars, serviceImpl.GetDynamicQueryOrRockstars) + .AddMethod(__Method_GetDynamicQueryRockstarsImplicit, serviceImpl.GetDynamicQueryRockstarsImplicit) + .AddMethod(__Method_GetDynamicQueryOrRockstarsFields, serviceImpl.GetDynamicQueryOrRockstarsFields) + .AddMethod(__Method_GetDynamicQueryFieldsImplicitConventions, serviceImpl.GetDynamicQueryFieldsImplicitConventions) + .AddMethod(__Method_GetDynamicQueryGetRockstars, serviceImpl.GetDynamicQueryGetRockstars) + .AddMethod(__Method_GetDynamicQueryRockstarFilters, serviceImpl.GetDynamicQueryRockstarFilters) + .AddMethod(__Method_PostDynamicValidationRules, serviceImpl.PostDynamicValidationRules) + .AddMethod(__Method_PostEmptyValidators, serviceImpl.PostEmptyValidators) + .AddMethod(__Method_GetEndsWithSuffixRequest, serviceImpl.GetEndsWithSuffixRequest) + .AddMethod(__Method_PostEndsWithSuffixRequest, serviceImpl.PostEndsWithSuffixRequest) + .AddMethod(__Method_PutEndsWithSuffixRequest, serviceImpl.PutEndsWithSuffixRequest) + .AddMethod(__Method_DeleteEndsWithSuffixRequest, serviceImpl.DeleteEndsWithSuffixRequest) + .AddMethod(__Method_PostGetAccessToken, serviceImpl.PostGetAccessToken) + .AddMethod(__Method_CallGetApiKeys, serviceImpl.CallGetApiKeys) + .AddMethod(__Method_CallGetFile, serviceImpl.CallGetFile) + .AddMethod(__Method_CallGetHello, serviceImpl.CallGetHello) + .AddMethod(__Method_CallGetTodo, serviceImpl.CallGetTodo) + .AddMethod(__Method_CallGetTodos, serviceImpl.CallGetTodos) + .AddMethod(__Method_GetHelloJwt, serviceImpl.GetHelloJwt) + .AddMethod(__Method_PostHelloJwt, serviceImpl.PostHelloJwt) + .AddMethod(__Method_PutHelloJwt, serviceImpl.PutHelloJwt) + .AddMethod(__Method_DeleteHelloJwt, serviceImpl.DeleteHelloJwt) + .AddMethod(__Method_GetIncr, serviceImpl.GetIncr) + .AddMethod(__Method_PostIncr, serviceImpl.PostIncr) + .AddMethod(__Method_PutIncr, serviceImpl.PutIncr) + .AddMethod(__Method_DeleteIncr, serviceImpl.DeleteIncr) + .AddMethod(__Method_PostMultiply, serviceImpl.PostMultiply) + .AddMethod(__Method_PostNoAbstractValidator, serviceImpl.PostNoAbstractValidator) + .AddMethod(__Method_PostOnlyValidatesRequest, serviceImpl.PostOnlyValidatesRequest) + .AddMethod(__Method_CallPatchRockstar, serviceImpl.CallPatchRockstar) + .AddMethod(__Method_CallPatchRockstarAuditTenant, serviceImpl.CallPatchRockstarAuditTenant) + .AddMethod(__Method_CallPatchRockstarAuditTenantGateway, serviceImpl.CallPatchRockstarAuditTenantGateway) + .AddMethod(__Method_CallPatchRockstarAuditTenantMq, serviceImpl.CallPatchRockstarAuditTenantMq) + .AddMethod(__Method_CallPostChatToChannel, serviceImpl.CallPostChatToChannel) + .AddMethod(__Method_GetQueryAdhoc, serviceImpl.GetQueryAdhoc) + .AddMethod(__Method_GetQueryAdhocRockstars, serviceImpl.GetQueryAdhocRockstars) + .AddMethod(__Method_GetQueryAllFields, serviceImpl.GetQueryAllFields) + .AddMethod(__Method_GetQueryBookmarks, serviceImpl.GetQueryBookmarks) + .AddMethod(__Method_GetQueryCaseInsensitiveOrderBy, serviceImpl.GetQueryCaseInsensitiveOrderBy) + .AddMethod(__Method_GetQueryChangeConnectionInfo, serviceImpl.GetQueryChangeConnectionInfo) + .AddMethod(__Method_GetQueryChangeDb, serviceImpl.GetQueryChangeDb) + .AddMethod(__Method_GetQueryCustomRockstars, serviceImpl.GetQueryCustomRockstars) + .AddMethod(__Method_GetQueryCustomRockstarsFilter, serviceImpl.GetQueryCustomRockstarsFilter) + .AddMethod(__Method_GetQueryCustomRockstarsReferences, serviceImpl.GetQueryCustomRockstarsReferences) + .AddMethod(__Method_GetQueryCustomRockstarsSchema, serviceImpl.GetQueryCustomRockstarsSchema) + .AddMethod(__Method_GetQueryFieldRockstars, serviceImpl.GetQueryFieldRockstars) + .AddMethod(__Method_GetQueryFieldRockstarsDynamic, serviceImpl.GetQueryFieldRockstarsDynamic) + .AddMethod(__Method_GetQueryFieldsImplicitConventions, serviceImpl.GetQueryFieldsImplicitConventions) + .AddMethod(__Method_GetQueryFoos, serviceImpl.GetQueryFoos) + .AddMethod(__Method_GetQueryGetRockstars, serviceImpl.GetQueryGetRockstars) + .AddMethod(__Method_GetQueryGetRockstarsDynamic, serviceImpl.GetQueryGetRockstarsDynamic) + .AddMethod(__Method_GetQueryJoinedRockstarAlbums, serviceImpl.GetQueryJoinedRockstarAlbums) + .AddMethod(__Method_GetQueryJoinedRockstarAlbumsCustomSelect, serviceImpl.GetQueryJoinedRockstarAlbumsCustomSelect) + .AddMethod(__Method_GetQueryJoinedRockstarAlbumsCustomSelectResponse, serviceImpl.GetQueryJoinedRockstarAlbumsCustomSelectResponse) + .AddMethod(__Method_GetQueryMovies, serviceImpl.GetQueryMovies) + .AddMethod(__Method_GetQueryMultiJoinRockstar, serviceImpl.GetQueryMultiJoinRockstar) + .AddMethod(__Method_GetQueryNamedRockstars, serviceImpl.GetQueryNamedRockstars) + .AddMethod(__Method_GetQueryOrRockstars, serviceImpl.GetQueryOrRockstars) + .AddMethod(__Method_GetQueryOrRockstarsFields, serviceImpl.GetQueryOrRockstarsFields) + .AddMethod(__Method_GetQueryOverridedCustomRockstars, serviceImpl.GetQueryOverridedCustomRockstars) + .AddMethod(__Method_GetQueryOverridedRockstars, serviceImpl.GetQueryOverridedRockstars) + .AddMethod(__Method_GetQueryPagingTest, serviceImpl.GetQueryPagingTest) + .AddMethod(__Method_GetQueryRockstarAlbums, serviceImpl.GetQueryRockstarAlbums) + .AddMethod(__Method_GetQueryRockstarAlbumsCustomLeftJoin, serviceImpl.GetQueryRockstarAlbumsCustomLeftJoin) + .AddMethod(__Method_GetQueryRockstarAlbumsImplicit, serviceImpl.GetQueryRockstarAlbumsImplicit) + .AddMethod(__Method_GetQueryRockstarAlbumsLeftJoin, serviceImpl.GetQueryRockstarAlbumsLeftJoin) + .AddMethod(__Method_GetQueryRockstarAlias, serviceImpl.GetQueryRockstarAlias) + .AddMethod(__Method_GetQueryRockstarAudit, serviceImpl.GetQueryRockstarAudit) + .AddMethod(__Method_GetQueryRockstarAuditSubOr, serviceImpl.GetQueryRockstarAuditSubOr) + .AddMethod(__Method_GetQueryRockstarFilters, serviceImpl.GetQueryRockstarFilters) + .AddMethod(__Method_GetQueryRockstars, serviceImpl.GetQueryRockstars) + .AddMethod(__Method_GetQueryRockstarsConventions, serviceImpl.GetQueryRockstarsConventions) + .AddMethod(__Method_GetQueryRockstarsFilter, serviceImpl.GetQueryRockstarsFilter) + .AddMethod(__Method_GetQueryRockstarsIFilter, serviceImpl.GetQueryRockstarsIFilter) + .AddMethod(__Method_GetQueryRockstarsImplicit, serviceImpl.GetQueryRockstarsImplicit) + .AddMethod(__Method_GetQueryRockstarsWithReferences, serviceImpl.GetQueryRockstarsWithReferences) + .AddMethod(__Method_GetQueryTypeWithEnums, serviceImpl.GetQueryTypeWithEnums) + .AddMethod(__Method_GetQueryUnknownRockstars, serviceImpl.GetQueryUnknownRockstars) + .AddMethod(__Method_DeleteRealDeleteAuditTenant, serviceImpl.DeleteRealDeleteAuditTenant) + .AddMethod(__Method_DeleteRealDeleteAuditTenantGateway, serviceImpl.DeleteRealDeleteAuditTenantGateway) + .AddMethod(__Method_DeleteRealDeleteAuditTenantMq, serviceImpl.DeleteRealDeleteAuditTenantMq) + .AddMethod(__Method_PostRegenerateApiKeys, serviceImpl.PostRegenerateApiKeys) + .AddMethod(__Method_PutRegister, serviceImpl.PutRegister) + .AddMethod(__Method_PostRegister, serviceImpl.PostRegister) + .AddMethod(__Method_GetRequiresAuth, serviceImpl.GetRequiresAuth) + .AddMethod(__Method_PostRequiresAuth, serviceImpl.PostRequiresAuth) + .AddMethod(__Method_PutRequiresAuth, serviceImpl.PutRequiresAuth) + .AddMethod(__Method_DeleteRequiresAuth, serviceImpl.DeleteRequiresAuth) + .AddMethod(__Method_PostResetTodos, serviceImpl.PostResetTodos) + .AddMethod(__Method_GetSearchMovies, serviceImpl.GetSearchMovies) + .AddMethod(__Method_PostSecured, serviceImpl.PostSecured) + .AddMethod(__Method_PutSoftDeleteAuditTenant, serviceImpl.PutSoftDeleteAuditTenant) + .AddMethod(__Method_ServerStreamFiles, serviceImpl.ServerStreamFiles) + .AddMethod(__Method_GetStreamMovies, serviceImpl.GetStreamMovies) + .AddMethod(__Method_ServerStreamServerEvents, serviceImpl.ServerStreamServerEvents) + .AddMethod(__Method_PostTestAuthValidators, serviceImpl.PostTestAuthValidators) + .AddMethod(__Method_PostTestDbCondition, serviceImpl.PostTestDbCondition) + .AddMethod(__Method_PostTestDbValidator, serviceImpl.PostTestDbValidator) + .AddMethod(__Method_PostTestIsAdmin, serviceImpl.PostTestIsAdmin) + .AddMethod(__Method_PostTestMultiAuthValidators, serviceImpl.PostTestMultiAuthValidators) + .AddMethod(__Method_GetThrow, serviceImpl.GetThrow) + .AddMethod(__Method_GetThrowCustom, serviceImpl.GetThrowCustom) + .AddMethod(__Method_GetThrowVoid, serviceImpl.GetThrowVoid) + .AddMethod(__Method_PostTriggerAllValidators, serviceImpl.PostTriggerAllValidators) + .AddMethod(__Method_PostTriggerValidators, serviceImpl.PostTriggerValidators) + .AddMethod(__Method_PostUnAssignRoles, serviceImpl.PostUnAssignRoles) + .AddMethod(__Method_PutUpdateConnectionInfoRockstar, serviceImpl.PutUpdateConnectionInfoRockstar) + .AddMethod(__Method_PutUpdateNamedRockstar, serviceImpl.PutUpdateNamedRockstar) + .AddMethod(__Method_PutUpdateRockstar, serviceImpl.PutUpdateRockstar) + .AddMethod(__Method_PutUpdateRockstarAdhocNonDefaults, serviceImpl.PutUpdateRockstarAdhocNonDefaults) + .AddMethod(__Method_PatchUpdateRockstarAudit, serviceImpl.PatchUpdateRockstarAudit) + .AddMethod(__Method_PutUpdateRockstarAuditTenant, serviceImpl.PutUpdateRockstarAuditTenant) + .AddMethod(__Method_PutUpdateRockstarAuditTenantGateway, serviceImpl.PutUpdateRockstarAuditTenantGateway) + .AddMethod(__Method_PutUpdateRockstarAuditTenantMq, serviceImpl.PutUpdateRockstarAuditTenantMq) + .AddMethod(__Method_PatchUpdateRockstarVersion, serviceImpl.PatchUpdateRockstarVersion) + .AddMethod(__Method_PutUpdateTodo, serviceImpl.PutUpdateTodo) + .AddMethod(__Method_PostValidateCreateRockstar, serviceImpl.PostValidateCreateRockstar).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, GrpcServicesBase serviceImpl) + { + serviceBinder.AddMethod(__Method_GetAddHeader, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetAddHeader)); + serviceBinder.AddMethod(__Method_GetAnyHello, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetAnyHello)); + serviceBinder.AddMethod(__Method_PostAnyHello, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostAnyHello)); + serviceBinder.AddMethod(__Method_PutAnyHello, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutAnyHello)); + serviceBinder.AddMethod(__Method_DeleteAnyHello, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteAnyHello)); + serviceBinder.AddMethod(__Method_PostAssignRoles, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostAssignRoles)); + serviceBinder.AddMethod(__Method_OptionsAuthenticate, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.OptionsAuthenticate)); + serviceBinder.AddMethod(__Method_GetAuthenticate, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetAuthenticate)); + serviceBinder.AddMethod(__Method_PostAuthenticate, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostAuthenticate)); + serviceBinder.AddMethod(__Method_DeleteAuthenticate, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteAuthenticate)); + serviceBinder.AddMethod(__Method_GetChangeConnectionInfo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetChangeConnectionInfo)); + serviceBinder.AddMethod(__Method_GetChangeDb, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetChangeDb)); + serviceBinder.AddMethod(__Method_PostConvertSessionToToken, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostConvertSessionToToken)); + serviceBinder.AddMethod(__Method_PostCreateBookmark, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateBookmark)); + serviceBinder.AddMethod(__Method_PostCreateConnectionInfoRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateConnectionInfoRockstar)); + serviceBinder.AddMethod(__Method_PostCreateNamedRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateNamedRockstar)); + serviceBinder.AddMethod(__Method_PostCreateRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstar)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAdhocNonDefaults, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAdhocNonDefaults)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAudit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAudit)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAuditMqToken, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAuditMqToken)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAuditTenant, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAuditTenant)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAuditTenantGateway, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAuditTenantGateway)); + serviceBinder.AddMethod(__Method_GetCreateRockstarAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetCreateRockstarAuditTenantMq)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAuditTenantMq)); + serviceBinder.AddMethod(__Method_PutCreateRockstarAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutCreateRockstarAuditTenantMq)); + serviceBinder.AddMethod(__Method_DeleteCreateRockstarAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteCreateRockstarAuditTenantMq)); + serviceBinder.AddMethod(__Method_PostCreateRockstarAutoMap, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarAutoMap)); + serviceBinder.AddMethod(__Method_PostCreateRockstarVersion, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarVersion)); + serviceBinder.AddMethod(__Method_PostCreateRockstarWithAutoGuid, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarWithAutoGuid)); + serviceBinder.AddMethod(__Method_PostCreateRockstarWithReturn, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarWithReturn)); + serviceBinder.AddMethod(__Method_PostCreateRockstarWithVoidReturn, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateRockstarWithVoidReturn)); + serviceBinder.AddMethod(__Method_PostCreateTodo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCreateTodo)); + serviceBinder.AddMethod(__Method_PostCustomValidationErrors, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostCustomValidationErrors)); + serviceBinder.AddMethod(__Method_CallDeleteRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallDeleteRockstar)); + serviceBinder.AddMethod(__Method_CallDeleteRockstarAudit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallDeleteRockstarAudit)); + serviceBinder.AddMethod(__Method_CallDeleteRockstarFilters, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallDeleteRockstarFilters)); + serviceBinder.AddMethod(__Method_CallDeleteTodo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallDeleteTodo)); + serviceBinder.AddMethod(__Method_CallDeleteTodos, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallDeleteTodos)); + serviceBinder.AddMethod(__Method_GetDynamicQueryGetRockstarsDynamic, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryGetRockstarsDynamic)); + serviceBinder.AddMethod(__Method_GetDynamicQueryCustomRockstarsSchema, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryCustomRockstarsSchema)); + serviceBinder.AddMethod(__Method_GetDynamicSearchMovies, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicSearchMovies)); + serviceBinder.AddMethod(__Method_GetDynamicQueryMovies, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryMovies)); + serviceBinder.AddMethod(__Method_GetDynamicQueryUnknownRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryUnknownRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarsWithReferences, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarsWithReferences)); + serviceBinder.AddMethod(__Method_GetDynamicQueryAllFields, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryAllFields)); + serviceBinder.AddMethod(__Method_GetDynamicQueryTypeWithEnums, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryTypeWithEnums)); + serviceBinder.AddMethod(__Method_GetDynamicQueryAdhocRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryAdhocRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryAdhoc, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryAdhoc)); + serviceBinder.AddMethod(__Method_GetDynamicQueryChangeDb, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryChangeDb)); + serviceBinder.AddMethod(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelect, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryJoinedRockstarAlbumsCustomSelect)); + serviceBinder.AddMethod(__Method_GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse)); + serviceBinder.AddMethod(__Method_GetDynamicQueryFoos, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryFoos)); + serviceBinder.AddMethod(__Method_GetDynamicQueryOverridedRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryOverridedRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryOverridedCustomRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryOverridedCustomRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryCaseInsensitiveOrderBy, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryCaseInsensitiveOrderBy)); + serviceBinder.AddMethod(__Method_GetDynamicStreamMovies, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicStreamMovies)); + serviceBinder.AddMethod(__Method_GetDynamicQueryCustomRockstarsReferences, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryCustomRockstarsReferences)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAlbumsCustomLeftJoin, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAlbumsCustomLeftJoin)); + serviceBinder.AddMethod(__Method_GetDynamicQueryChangeConnectionInfo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryChangeConnectionInfo)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAudit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAudit)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAuditSubOr, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAuditSubOr)); + serviceBinder.AddMethod(__Method_GetDynamicQueryBookmarks, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryBookmarks)); + serviceBinder.AddMethod(__Method_GetDynamicQueryNamedRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryNamedRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAlbums, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAlbums)); + serviceBinder.AddMethod(__Method_GetDynamicQueryPagingTest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryPagingTest)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarsConventions, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarsConventions)); + serviceBinder.AddMethod(__Method_GetDynamicQueryCustomRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryCustomRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryJoinedRockstarAlbums, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryJoinedRockstarAlbums)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAlbumsImplicit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAlbumsImplicit)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAlbumsLeftJoin, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAlbumsLeftJoin)); + serviceBinder.AddMethod(__Method_GetDynamicQueryMultiJoinRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryMultiJoinRockstar)); + serviceBinder.AddMethod(__Method_GetDynamicQueryFieldRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryFieldRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarAlias, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarAlias)); + serviceBinder.AddMethod(__Method_GetDynamicQueryFieldRockstarsDynamic, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryFieldRockstarsDynamic)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarsFilter, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarsFilter)); + serviceBinder.AddMethod(__Method_GetDynamicQueryCustomRockstarsFilter, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryCustomRockstarsFilter)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarsIFilter, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarsIFilter)); + serviceBinder.AddMethod(__Method_GetDynamicQueryOrRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryOrRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarsImplicit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarsImplicit)); + serviceBinder.AddMethod(__Method_GetDynamicQueryOrRockstarsFields, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryOrRockstarsFields)); + serviceBinder.AddMethod(__Method_GetDynamicQueryFieldsImplicitConventions, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryFieldsImplicitConventions)); + serviceBinder.AddMethod(__Method_GetDynamicQueryGetRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryGetRockstars)); + serviceBinder.AddMethod(__Method_GetDynamicQueryRockstarFilters, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetDynamicQueryRockstarFilters)); + serviceBinder.AddMethod(__Method_PostDynamicValidationRules, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostDynamicValidationRules)); + serviceBinder.AddMethod(__Method_PostEmptyValidators, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostEmptyValidators)); + serviceBinder.AddMethod(__Method_GetEndsWithSuffixRequest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetEndsWithSuffixRequest)); + serviceBinder.AddMethod(__Method_PostEndsWithSuffixRequest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostEndsWithSuffixRequest)); + serviceBinder.AddMethod(__Method_PutEndsWithSuffixRequest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutEndsWithSuffixRequest)); + serviceBinder.AddMethod(__Method_DeleteEndsWithSuffixRequest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteEndsWithSuffixRequest)); + serviceBinder.AddMethod(__Method_PostGetAccessToken, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostGetAccessToken)); + serviceBinder.AddMethod(__Method_CallGetApiKeys, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallGetApiKeys)); + serviceBinder.AddMethod(__Method_CallGetFile, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallGetFile)); + serviceBinder.AddMethod(__Method_CallGetHello, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallGetHello)); + serviceBinder.AddMethod(__Method_CallGetTodo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallGetTodo)); + serviceBinder.AddMethod(__Method_CallGetTodos, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallGetTodos)); + serviceBinder.AddMethod(__Method_GetHelloJwt, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetHelloJwt)); + serviceBinder.AddMethod(__Method_PostHelloJwt, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostHelloJwt)); + serviceBinder.AddMethod(__Method_PutHelloJwt, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutHelloJwt)); + serviceBinder.AddMethod(__Method_DeleteHelloJwt, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteHelloJwt)); + serviceBinder.AddMethod(__Method_GetIncr, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetIncr)); + serviceBinder.AddMethod(__Method_PostIncr, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostIncr)); + serviceBinder.AddMethod(__Method_PutIncr, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutIncr)); + serviceBinder.AddMethod(__Method_DeleteIncr, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteIncr)); + serviceBinder.AddMethod(__Method_PostMultiply, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostMultiply)); + serviceBinder.AddMethod(__Method_PostNoAbstractValidator, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostNoAbstractValidator)); + serviceBinder.AddMethod(__Method_PostOnlyValidatesRequest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostOnlyValidatesRequest)); + serviceBinder.AddMethod(__Method_CallPatchRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallPatchRockstar)); + serviceBinder.AddMethod(__Method_CallPatchRockstarAuditTenant, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallPatchRockstarAuditTenant)); + serviceBinder.AddMethod(__Method_CallPatchRockstarAuditTenantGateway, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallPatchRockstarAuditTenantGateway)); + serviceBinder.AddMethod(__Method_CallPatchRockstarAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallPatchRockstarAuditTenantMq)); + serviceBinder.AddMethod(__Method_CallPostChatToChannel, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.CallPostChatToChannel)); + serviceBinder.AddMethod(__Method_GetQueryAdhoc, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryAdhoc)); + serviceBinder.AddMethod(__Method_GetQueryAdhocRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryAdhocRockstars)); + serviceBinder.AddMethod(__Method_GetQueryAllFields, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryAllFields)); + serviceBinder.AddMethod(__Method_GetQueryBookmarks, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryBookmarks)); + serviceBinder.AddMethod(__Method_GetQueryCaseInsensitiveOrderBy, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryCaseInsensitiveOrderBy)); + serviceBinder.AddMethod(__Method_GetQueryChangeConnectionInfo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryChangeConnectionInfo)); + serviceBinder.AddMethod(__Method_GetQueryChangeDb, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryChangeDb)); + serviceBinder.AddMethod(__Method_GetQueryCustomRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryCustomRockstars)); + serviceBinder.AddMethod(__Method_GetQueryCustomRockstarsFilter, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryCustomRockstarsFilter)); + serviceBinder.AddMethod(__Method_GetQueryCustomRockstarsReferences, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryCustomRockstarsReferences)); + serviceBinder.AddMethod(__Method_GetQueryCustomRockstarsSchema, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryCustomRockstarsSchema)); + serviceBinder.AddMethod(__Method_GetQueryFieldRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryFieldRockstars)); + serviceBinder.AddMethod(__Method_GetQueryFieldRockstarsDynamic, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryFieldRockstarsDynamic)); + serviceBinder.AddMethod(__Method_GetQueryFieldsImplicitConventions, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryFieldsImplicitConventions)); + serviceBinder.AddMethod(__Method_GetQueryFoos, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryFoos)); + serviceBinder.AddMethod(__Method_GetQueryGetRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryGetRockstars)); + serviceBinder.AddMethod(__Method_GetQueryGetRockstarsDynamic, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryGetRockstarsDynamic)); + serviceBinder.AddMethod(__Method_GetQueryJoinedRockstarAlbums, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryJoinedRockstarAlbums)); + serviceBinder.AddMethod(__Method_GetQueryJoinedRockstarAlbumsCustomSelect, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryJoinedRockstarAlbumsCustomSelect)); + serviceBinder.AddMethod(__Method_GetQueryJoinedRockstarAlbumsCustomSelectResponse, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryJoinedRockstarAlbumsCustomSelectResponse)); + serviceBinder.AddMethod(__Method_GetQueryMovies, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryMovies)); + serviceBinder.AddMethod(__Method_GetQueryMultiJoinRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryMultiJoinRockstar)); + serviceBinder.AddMethod(__Method_GetQueryNamedRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryNamedRockstars)); + serviceBinder.AddMethod(__Method_GetQueryOrRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryOrRockstars)); + serviceBinder.AddMethod(__Method_GetQueryOrRockstarsFields, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryOrRockstarsFields)); + serviceBinder.AddMethod(__Method_GetQueryOverridedCustomRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryOverridedCustomRockstars)); + serviceBinder.AddMethod(__Method_GetQueryOverridedRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryOverridedRockstars)); + serviceBinder.AddMethod(__Method_GetQueryPagingTest, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryPagingTest)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAlbums, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAlbums)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAlbumsCustomLeftJoin, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAlbumsCustomLeftJoin)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAlbumsImplicit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAlbumsImplicit)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAlbumsLeftJoin, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAlbumsLeftJoin)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAlias, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAlias)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAudit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAudit)); + serviceBinder.AddMethod(__Method_GetQueryRockstarAuditSubOr, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarAuditSubOr)); + serviceBinder.AddMethod(__Method_GetQueryRockstarFilters, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarFilters)); + serviceBinder.AddMethod(__Method_GetQueryRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstars)); + serviceBinder.AddMethod(__Method_GetQueryRockstarsConventions, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarsConventions)); + serviceBinder.AddMethod(__Method_GetQueryRockstarsFilter, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarsFilter)); + serviceBinder.AddMethod(__Method_GetQueryRockstarsIFilter, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarsIFilter)); + serviceBinder.AddMethod(__Method_GetQueryRockstarsImplicit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarsImplicit)); + serviceBinder.AddMethod(__Method_GetQueryRockstarsWithReferences, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryRockstarsWithReferences)); + serviceBinder.AddMethod(__Method_GetQueryTypeWithEnums, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryTypeWithEnums)); + serviceBinder.AddMethod(__Method_GetQueryUnknownRockstars, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetQueryUnknownRockstars)); + serviceBinder.AddMethod(__Method_DeleteRealDeleteAuditTenant, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteRealDeleteAuditTenant)); + serviceBinder.AddMethod(__Method_DeleteRealDeleteAuditTenantGateway, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteRealDeleteAuditTenantGateway)); + serviceBinder.AddMethod(__Method_DeleteRealDeleteAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteRealDeleteAuditTenantMq)); + serviceBinder.AddMethod(__Method_PostRegenerateApiKeys, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostRegenerateApiKeys)); + serviceBinder.AddMethod(__Method_PutRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutRegister)); + serviceBinder.AddMethod(__Method_PostRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostRegister)); + serviceBinder.AddMethod(__Method_GetRequiresAuth, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetRequiresAuth)); + serviceBinder.AddMethod(__Method_PostRequiresAuth, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostRequiresAuth)); + serviceBinder.AddMethod(__Method_PutRequiresAuth, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutRequiresAuth)); + serviceBinder.AddMethod(__Method_DeleteRequiresAuth, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.DeleteRequiresAuth)); + serviceBinder.AddMethod(__Method_PostResetTodos, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostResetTodos)); + serviceBinder.AddMethod(__Method_GetSearchMovies, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetSearchMovies)); + serviceBinder.AddMethod(__Method_PostSecured, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostSecured)); + serviceBinder.AddMethod(__Method_PutSoftDeleteAuditTenant, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutSoftDeleteAuditTenant)); + serviceBinder.AddMethod(__Method_ServerStreamFiles, serviceImpl == null ? null : new grpc::ServerStreamingServerMethod(serviceImpl.ServerStreamFiles)); + serviceBinder.AddMethod(__Method_GetStreamMovies, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetStreamMovies)); + serviceBinder.AddMethod(__Method_ServerStreamServerEvents, serviceImpl == null ? null : new grpc::ServerStreamingServerMethod(serviceImpl.ServerStreamServerEvents)); + serviceBinder.AddMethod(__Method_PostTestAuthValidators, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTestAuthValidators)); + serviceBinder.AddMethod(__Method_PostTestDbCondition, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTestDbCondition)); + serviceBinder.AddMethod(__Method_PostTestDbValidator, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTestDbValidator)); + serviceBinder.AddMethod(__Method_PostTestIsAdmin, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTestIsAdmin)); + serviceBinder.AddMethod(__Method_PostTestMultiAuthValidators, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTestMultiAuthValidators)); + serviceBinder.AddMethod(__Method_GetThrow, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetThrow)); + serviceBinder.AddMethod(__Method_GetThrowCustom, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetThrowCustom)); + serviceBinder.AddMethod(__Method_GetThrowVoid, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.GetThrowVoid)); + serviceBinder.AddMethod(__Method_PostTriggerAllValidators, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTriggerAllValidators)); + serviceBinder.AddMethod(__Method_PostTriggerValidators, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostTriggerValidators)); + serviceBinder.AddMethod(__Method_PostUnAssignRoles, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostUnAssignRoles)); + serviceBinder.AddMethod(__Method_PutUpdateConnectionInfoRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateConnectionInfoRockstar)); + serviceBinder.AddMethod(__Method_PutUpdateNamedRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateNamedRockstar)); + serviceBinder.AddMethod(__Method_PutUpdateRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateRockstar)); + serviceBinder.AddMethod(__Method_PutUpdateRockstarAdhocNonDefaults, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateRockstarAdhocNonDefaults)); + serviceBinder.AddMethod(__Method_PatchUpdateRockstarAudit, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PatchUpdateRockstarAudit)); + serviceBinder.AddMethod(__Method_PutUpdateRockstarAuditTenant, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateRockstarAuditTenant)); + serviceBinder.AddMethod(__Method_PutUpdateRockstarAuditTenantGateway, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateRockstarAuditTenantGateway)); + serviceBinder.AddMethod(__Method_PutUpdateRockstarAuditTenantMq, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateRockstarAuditTenantMq)); + serviceBinder.AddMethod(__Method_PatchUpdateRockstarVersion, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PatchUpdateRockstarVersion)); + serviceBinder.AddMethod(__Method_PutUpdateTodo, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PutUpdateTodo)); + serviceBinder.AddMethod(__Method_PostValidateCreateRockstar, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.PostValidateCreateRockstar)); + } + + } +} +#endregion diff --git a/tests/ServiceStack.Extensions.Tests/Protoc/services.proto b/tests/ServiceStack.Extensions.Tests/Protoc/services.proto new file mode 100644 index 00000000000..e4c0a990053 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/Protoc/services.proto @@ -0,0 +1,2026 @@ +/* Options: +Date: 2020-06-03 21:41:31 +Version: 5.81 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://localhost:20000 + +//GlobalNamespace: +//AddDescriptionAsComments: True +*/ + +syntax = "proto3"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +option csharp_namespace = "ServiceStack.Extensions.Tests.Protoc"; +option php_namespace = "ServiceStack.Extensions.Tests.Protoc"; + +service GrpcServices { + + rpc GetAddHeader(AddHeader) returns (EmptyResponse) {} + + rpc GetAnyHello(AnyHello) returns (HelloResponse) {} + + rpc PostAnyHello(AnyHello) returns (HelloResponse) {} + + rpc PutAnyHello(AnyHello) returns (HelloResponse) {} + + rpc DeleteAnyHello(AnyHello) returns (HelloResponse) {} + + rpc PostAssignRoles(AssignRoles) returns (AssignRolesResponse) {} + + rpc OptionsAuthenticate(Authenticate) returns (AuthenticateResponse) {} + + rpc GetAuthenticate(Authenticate) returns (AuthenticateResponse) {} + + rpc PostAuthenticate(Authenticate) returns (AuthenticateResponse) {} + + rpc DeleteAuthenticate(Authenticate) returns (AuthenticateResponse) {} + + rpc GetChangeConnectionInfo(ChangeConnectionInfo) returns (ChangeDbResponse) {} + + rpc GetChangeDb(ChangeDb) returns (ChangeDbResponse) {} + + rpc PostConvertSessionToToken(ConvertSessionToToken) returns (ConvertSessionToTokenResponse) {} + + rpc PostCreateBookmark(CreateBookmark) returns (CreateBookmarkResponse) {} + + rpc PostCreateConnectionInfoRockstar(CreateConnectionInfoRockstar) returns (RockstarWithIdAndResultResponse) {} + + rpc PostCreateNamedRockstar(CreateNamedRockstar) returns (RockstarWithIdAndResultResponse) {} + + rpc PostCreateRockstar(CreateRockstar) returns (CreateRockstarResponse) {} + + rpc PostCreateRockstarAdhocNonDefaults(CreateRockstarAdhocNonDefaults) returns (RockstarWithIdAndResultResponse) {} + + rpc PostCreateRockstarAudit(CreateRockstarAudit) returns (RockstarWithIdResponse) {} + + rpc PostCreateRockstarAuditMqToken(CreateRockstarAuditMqToken) returns (RockstarWithIdResponse) {} + + rpc PostCreateRockstarAuditTenant(CreateRockstarAuditTenant) returns (RockstarWithIdAndResultResponse) {} + + rpc PostCreateRockstarAuditTenantGateway(CreateRockstarAuditTenantGateway) returns (RockstarWithIdAndResultResponse) {} + + rpc GetCreateRockstarAuditTenantMq(CreateRockstarAuditTenantMq) returns (EmptyResponse) {} + + rpc PostCreateRockstarAuditTenantMq(CreateRockstarAuditTenantMq) returns (EmptyResponse) {} + + rpc PutCreateRockstarAuditTenantMq(CreateRockstarAuditTenantMq) returns (EmptyResponse) {} + + rpc DeleteCreateRockstarAuditTenantMq(CreateRockstarAuditTenantMq) returns (EmptyResponse) {} + + rpc PostCreateRockstarAutoMap(CreateRockstarAutoMap) returns (RockstarWithIdAndResultResponse) {} + + rpc PostCreateRockstarVersion(CreateRockstarVersion) returns (RockstarWithIdAndRowVersionResponse) {} + + rpc PostCreateRockstarWithAutoGuid(CreateRockstarWithAutoGuid) returns (CreateRockstarWithReturnGuidResponse) {} + + rpc PostCreateRockstarWithReturn(CreateRockstarWithReturn) returns (RockstarWithIdAndResultResponse) {} + + rpc PostCreateRockstarWithVoidReturn(CreateRockstarWithVoidReturn) returns (EmptyResponse) {} + + rpc PostCreateTodo(CreateTodo) returns (CreateTodoResponse) {} + + rpc PostCustomValidationErrors(CustomValidationErrors) returns (RockstarWithIdResponse) {} + + rpc CallDeleteRockstar(DeleteRockstar) returns (EmptyResponse) {} + + rpc CallDeleteRockstarAudit(DeleteRockstarAudit) returns (RockstarWithIdAndCountResponse) {} + + rpc CallDeleteRockstarFilters(DeleteRockstarFilters) returns (DeleteRockstarCountResponse) {} + + rpc CallDeleteTodo(DeleteTodo) returns (EmptyResponse) {} + + rpc CallDeleteTodos(DeleteTodos) returns (EmptyResponse) {} + + rpc GetDynamicQueryGetRockstarsDynamic(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryCustomRockstarsSchema(DynamicRequest) returns (QueryResponse_CustomRockstarSchema) {} + + rpc GetDynamicSearchMovies(DynamicRequest) returns (QueryResponse_Movie) {} + + rpc GetDynamicQueryMovies(DynamicRequest) returns (QueryResponse_Movie) {} + + rpc GetDynamicQueryUnknownRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarsWithReferences(DynamicRequest) returns (QueryResponse_RockstarReference) {} + + rpc GetDynamicQueryAllFields(DynamicRequest) returns (QueryResponse_AllFields) {} + + rpc GetDynamicQueryTypeWithEnums(DynamicRequest) returns (QueryResponse_TypeWithEnum) {} + + rpc GetDynamicQueryAdhocRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryAdhoc(DynamicRequest) returns (QueryResponse_Adhoc) {} + + rpc GetDynamicQueryChangeDb(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryJoinedRockstarAlbumsCustomSelect(DynamicRequest) returns (QueryResponse_CustomSelectRockstar) {} + + rpc GetDynamicQueryJoinedRockstarAlbumsCustomSelectResponse(DynamicRequest) returns (QueryResponse_CustomSelectRockstarResponse) {} + + rpc GetDynamicQueryFoos(DynamicRequest) returns (QueryResponse_Foo) {} + + rpc GetDynamicQueryOverridedRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryOverridedCustomRockstars(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryCaseInsensitiveOrderBy(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicStreamMovies(DynamicRequest) returns (QueryResponse_Movie) {} + + rpc GetDynamicQueryCustomRockstarsReferences(DynamicRequest) returns (QueryResponse_RockstarReference) {} + + rpc GetDynamicQueryRockstarAlbumsCustomLeftJoin(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryChangeConnectionInfo(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarAudit(DynamicRequest) returns (QueryResponse_RockstarAuto) {} + + rpc GetDynamicQueryRockstarAuditSubOr(DynamicRequest) returns (QueryResponse_RockstarAuto) {} + + rpc GetDynamicQueryBookmarks(DynamicRequest) returns (QueryResponse_Bookmark) {} + + rpc GetDynamicQueryNamedRockstars(DynamicRequest) returns (QueryResponse_NamedRockstar) {} + + rpc GetDynamicQueryRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarAlbums(DynamicRequest) returns (QueryResponse_RockstarAlbum) {} + + rpc GetDynamicQueryPagingTest(DynamicRequest) returns (QueryResponse_PagingTest) {} + + rpc GetDynamicQueryRockstarsConventions(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryCustomRockstars(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryJoinedRockstarAlbums(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryRockstarAlbumsImplicit(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryRockstarAlbumsLeftJoin(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryMultiJoinRockstar(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryFieldRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarAlias(DynamicRequest) returns (QueryResponse_RockstarAlias) {} + + rpc GetDynamicQueryFieldRockstarsDynamic(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarsFilter(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryCustomRockstarsFilter(DynamicRequest) returns (QueryResponse_CustomRockstar) {} + + rpc GetDynamicQueryRockstarsIFilter(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryOrRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarsImplicit(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryOrRockstarsFields(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryFieldsImplicitConventions(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryGetRockstars(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc GetDynamicQueryRockstarFilters(DynamicRequest) returns (QueryResponse_Rockstar) {} + + rpc PostDynamicValidationRules(DynamicValidationRules) returns (RockstarWithIdResponse) {} + + rpc PostEmptyValidators(EmptyValidators) returns (RockstarWithIdResponse) {} + + rpc GetEndsWithSuffixRequest(EndsWithSuffixRequest) returns (EndsWithSuffixResponse) {} + + rpc PostEndsWithSuffixRequest(EndsWithSuffixRequest) returns (EndsWithSuffixResponse) {} + + rpc PutEndsWithSuffixRequest(EndsWithSuffixRequest) returns (EndsWithSuffixResponse) {} + + rpc DeleteEndsWithSuffixRequest(EndsWithSuffixRequest) returns (EndsWithSuffixResponse) {} + + rpc PostGetAccessToken(GetAccessToken) returns (GetAccessTokenResponse) {} + + rpc CallGetApiKeys(GetApiKeys) returns (GetApiKeysResponse) {} + + rpc CallGetFile(GetFile) returns (FileContent) {} + + rpc CallGetHello(GetHello) returns (HelloResponse) {} + + rpc CallGetTodo(GetTodo) returns (GetTodoResponse) {} + + rpc CallGetTodos(GetTodos) returns (GetTodosResponse) {} + + rpc GetHelloJwt(HelloJwt) returns (HelloJwtResponse) {} + + rpc PostHelloJwt(HelloJwt) returns (HelloJwtResponse) {} + + rpc PutHelloJwt(HelloJwt) returns (HelloJwtResponse) {} + + rpc DeleteHelloJwt(HelloJwt) returns (HelloJwtResponse) {} + + rpc GetIncr(Incr) returns (EmptyResponse) {} + + rpc PostIncr(Incr) returns (EmptyResponse) {} + + rpc PutIncr(Incr) returns (EmptyResponse) {} + + rpc DeleteIncr(Incr) returns (EmptyResponse) {} + + rpc PostMultiply(Multiply) returns (MultiplyResponse) {} + + rpc PostNoAbstractValidator(NoAbstractValidator) returns (RockstarWithIdResponse) {} + + rpc PostOnlyValidatesRequest(OnlyValidatesRequest) returns (RockstarWithIdResponse) {} + + rpc CallPatchRockstar(PatchRockstar) returns (EmptyResponse) {} + + rpc CallPatchRockstarAuditTenant(PatchRockstarAuditTenant) returns (RockstarWithIdAndResultResponse) {} + + rpc CallPatchRockstarAuditTenantGateway(PatchRockstarAuditTenantGateway) returns (RockstarWithIdAndResultResponse) {} + + rpc CallPatchRockstarAuditTenantMq(PatchRockstarAuditTenantMq) returns (EmptyResponse) {} + + rpc CallPostChatToChannel(PostChatToChannel) returns (ChatMessage) {} + + rpc GetQueryAdhoc(QueryAdhoc) returns (QueryResponse_Adhoc) {} + + rpc GetQueryAdhocRockstars(QueryAdhocRockstars) returns (QueryResponse_Rockstar) {} + + rpc GetQueryAllFields(QueryAllFields) returns (QueryResponse_AllFields) {} + + rpc GetQueryBookmarks(QueryBookmarks) returns (QueryResponse_Bookmark) {} + + rpc GetQueryCaseInsensitiveOrderBy(QueryCaseInsensitiveOrderBy) returns (QueryResponse_Rockstar) {} + + rpc GetQueryChangeConnectionInfo(QueryChangeConnectionInfo) returns (QueryResponse_Rockstar) {} + + rpc GetQueryChangeDb(QueryChangeDb) returns (QueryResponse_Rockstar) {} + + rpc GetQueryCustomRockstars(QueryCustomRockstars) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryCustomRockstarsFilter(QueryCustomRockstarsFilter) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryCustomRockstarsReferences(QueryCustomRockstarsReferences) returns (QueryResponse_RockstarReference) {} + + rpc GetQueryCustomRockstarsSchema(QueryCustomRockstarsSchema) returns (QueryResponse_CustomRockstarSchema) {} + + rpc GetQueryFieldRockstars(QueryFieldRockstars) returns (QueryResponse_Rockstar) {} + + rpc GetQueryFieldRockstarsDynamic(QueryFieldRockstarsDynamic) returns (QueryResponse_Rockstar) {} + + rpc GetQueryFieldsImplicitConventions(QueryFieldsImplicitConventions) returns (QueryResponse_Rockstar) {} + + rpc GetQueryFoos(QueryFoos) returns (QueryResponse_Foo) {} + + rpc GetQueryGetRockstars(QueryGetRockstars) returns (QueryResponse_Rockstar) {} + + rpc GetQueryGetRockstarsDynamic(QueryGetRockstarsDynamic) returns (QueryResponse_Rockstar) {} + + rpc GetQueryJoinedRockstarAlbums(QueryJoinedRockstarAlbums) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryJoinedRockstarAlbumsCustomSelect(QueryJoinedRockstarAlbumsCustomSelect) returns (QueryResponse_CustomSelectRockstar) {} + + rpc GetQueryJoinedRockstarAlbumsCustomSelectResponse(QueryJoinedRockstarAlbumsCustomSelectResponse) returns (QueryResponse_CustomSelectRockstarResponse) {} + + rpc GetQueryMovies(QueryMovies) returns (QueryResponse_Movie) {} + + rpc GetQueryMultiJoinRockstar(QueryMultiJoinRockstar) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryNamedRockstars(QueryNamedRockstars) returns (QueryResponse_NamedRockstar) {} + + rpc GetQueryOrRockstars(QueryOrRockstars) returns (QueryResponse_Rockstar) {} + + rpc GetQueryOrRockstarsFields(QueryOrRockstarsFields) returns (QueryResponse_Rockstar) {} + + rpc GetQueryOverridedCustomRockstars(QueryOverridedCustomRockstars) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryOverridedRockstars(QueryOverridedRockstars) returns (QueryResponse_Rockstar) {} + + rpc GetQueryPagingTest(QueryPagingTest) returns (QueryResponse_PagingTest) {} + + rpc GetQueryRockstarAlbums(QueryRockstarAlbums) returns (QueryResponse_RockstarAlbum) {} + + rpc GetQueryRockstarAlbumsCustomLeftJoin(QueryRockstarAlbumsCustomLeftJoin) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryRockstarAlbumsImplicit(QueryRockstarAlbumsImplicit) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryRockstarAlbumsLeftJoin(QueryRockstarAlbumsLeftJoin) returns (QueryResponse_CustomRockstar) {} + + rpc GetQueryRockstarAlias(QueryRockstarAlias) returns (QueryResponse_RockstarAlias) {} + + rpc GetQueryRockstarAudit(QueryRockstarAudit) returns (QueryResponse_RockstarAuto) {} + + rpc GetQueryRockstarAuditSubOr(QueryRockstarAuditSubOr) returns (QueryResponse_RockstarAuto) {} + + rpc GetQueryRockstarFilters(QueryRockstarFilters) returns (QueryResponse_Rockstar) {} + + rpc GetQueryRockstars(QueryRockstars) returns (QueryResponse_Rockstar) {} + + rpc GetQueryRockstarsConventions(QueryRockstarsConventions) returns (QueryResponse_Rockstar) {} + + rpc GetQueryRockstarsFilter(QueryRockstarsFilter) returns (QueryResponse_Rockstar) {} + + rpc GetQueryRockstarsIFilter(QueryRockstarsIFilter) returns (QueryResponse_Rockstar) {} + + rpc GetQueryRockstarsImplicit(QueryRockstarsImplicit) returns (QueryResponse_Rockstar) {} + + rpc GetQueryRockstarsWithReferences(QueryRockstarsWithReferences) returns (QueryResponse_RockstarReference) {} + + rpc GetQueryTypeWithEnums(QueryTypeWithEnums) returns (QueryResponse_TypeWithEnum) {} + + rpc GetQueryUnknownRockstars(QueryUnknownRockstars) returns (QueryResponse_Rockstar) {} + + rpc DeleteRealDeleteAuditTenant(RealDeleteAuditTenant) returns (RockstarWithIdAndCountResponse) {} + + rpc DeleteRealDeleteAuditTenantGateway(RealDeleteAuditTenantGateway) returns (RockstarWithIdAndCountResponse) {} + + rpc DeleteRealDeleteAuditTenantMq(RealDeleteAuditTenantMq) returns (EmptyResponse) {} + + rpc PostRegenerateApiKeys(RegenerateApiKeys) returns (RegenerateApiKeysResponse) {} + + rpc PutRegister(Register) returns (RegisterResponse) {} + + rpc PostRegister(Register) returns (RegisterResponse) {} + + rpc GetRequiresAuth(RequiresAuth) returns (RequiresAuth) {} + + rpc PostRequiresAuth(RequiresAuth) returns (RequiresAuth) {} + + rpc PutRequiresAuth(RequiresAuth) returns (RequiresAuth) {} + + rpc DeleteRequiresAuth(RequiresAuth) returns (RequiresAuth) {} + + rpc PostResetTodos(ResetTodos) returns (EmptyResponse) {} + + rpc GetSearchMovies(SearchMovies) returns (QueryResponse_Movie) {} + + rpc PostSecured(Secured) returns (SecuredResponse) {} + + rpc PutSoftDeleteAuditTenant(SoftDeleteAuditTenant) returns (RockstarWithIdAndResultResponse) {} + + rpc ServerStreamFiles(StreamFiles) returns (stream FileContent) {} + + rpc GetStreamMovies(StreamMovies) returns (QueryResponse_Movie) {} + + rpc ServerStreamServerEvents(StreamServerEvents) returns (stream StreamServerEventsResponse) {} + + rpc PostTestAuthValidators(TestAuthValidators) returns (RockstarWithIdResponse) {} + + rpc PostTestDbCondition(TestDbCondition) returns (RockstarWithIdResponse) {} + + rpc PostTestDbValidator(TestDbValidator) returns (RockstarWithIdResponse) {} + + rpc PostTestIsAdmin(TestIsAdmin) returns (RockstarWithIdResponse) {} + + rpc PostTestMultiAuthValidators(TestMultiAuthValidators) returns (RockstarWithIdResponse) {} + + rpc GetThrow(Throw) returns (HelloResponse) {} + + rpc GetThrowCustom(ThrowCustom) returns (ThrowCustomResponse) {} + + rpc GetThrowVoid(ThrowVoid) returns (EmptyResponse) {} + + rpc PostTriggerAllValidators(TriggerAllValidators) returns (RockstarWithIdResponse) {} + + rpc PostTriggerValidators(TriggerValidators) returns (EmptyResponse) {} + + rpc PostUnAssignRoles(UnAssignRoles) returns (UnAssignRolesResponse) {} + + rpc PutUpdateConnectionInfoRockstar(UpdateConnectionInfoRockstar) returns (RockstarWithIdAndResultResponse) {} + + rpc PutUpdateNamedRockstar(UpdateNamedRockstar) returns (RockstarWithIdAndResultResponse) {} + + rpc PutUpdateRockstar(UpdateRockstar) returns (EmptyResponse) {} + + rpc PutUpdateRockstarAdhocNonDefaults(UpdateRockstarAdhocNonDefaults) returns (EmptyResponse) {} + + rpc PatchUpdateRockstarAudit(UpdateRockstarAudit) returns (EmptyResponse) {} + + rpc PutUpdateRockstarAuditTenant(UpdateRockstarAuditTenant) returns (RockstarWithIdAndResultResponse) {} + + rpc PutUpdateRockstarAuditTenantGateway(UpdateRockstarAuditTenantGateway) returns (RockstarWithIdAndResultResponse) {} + + rpc PutUpdateRockstarAuditTenantMq(UpdateRockstarAuditTenantMq) returns (EmptyResponse) {} + + rpc PatchUpdateRockstarVersion(UpdateRockstarVersion) returns (RockstarWithIdAndRowVersionResponse) {} + + rpc PutUpdateTodo(UpdateTodo) returns (EmptyResponse) {} + + rpc PostValidateCreateRockstar(ValidateCreateRockstar) returns (RockstarWithIdResponse) {} +} + +message AddHeader { + string Name = 1; + string Value = 2; +} +message Adhoc { + int32 Id = 1; + string first_name = 2; + string LastName = 3; +} +message AllFields { + int32 Id = 1; + int32 NullableId = 2; + uint32 Byte = 3; + int32 Short = 4; + int32 Int = 5; + int64 Long = 6; + uint32 UShort = 7; + uint32 UInt = 8; + uint64 ULong = 9; + float Float = 10; + double Double = 11; + string Decimal = 12; + string String = 13; + .google.protobuf.Timestamp DateTime = 14; + .google.protobuf.Duration TimeSpan = 15; + string Guid = 16; // default value could not be applied: 00000000-0000-0000-0000-000000000000 + .google.protobuf.Timestamp NullableDateTime = 17; + .google.protobuf.Duration NullableTimeSpan = 18; + string NullableGuid = 19; + HttpStatusCode Enum = 20; + HttpStatusCode NullableEnum = 21; +} +message AnyHello { + string Name = 1; +} +message AssignRoles { + string UserName = 1; + repeated string Permissions = 2; + repeated string Roles = 3; + map Meta = 4; +} +message AssignRolesResponse { + repeated string AllRoles = 1; + repeated string AllPermissions = 2; + map Meta = 3; + ResponseStatus ResponseStatus = 4; +} +message AuditBase { + .google.protobuf.Timestamp CreatedDate = 1; + string CreatedBy = 2; + string CreatedInfo = 3; + .google.protobuf.Timestamp ModifiedDate = 4; + string ModifiedBy = 5; + string ModifiedInfo = 6; + .google.protobuf.Timestamp SoftDeletedDate = 7; + string SoftDeletedBy = 8; + string SoftDeletedInfo = 9; + oneof subtype { + RockstarAuditTenant RockstarAuditTenant = 252248706; + } +} +message Authenticate { + string provider = 1; + string State = 2; + string oauth_token = 3; + string oauth_verifier = 4; + string UserName = 5; + string Password = 6; + bool RememberMe = 7; + string ErrorView = 9; + string nonce = 10; + string uri = 11; + string response = 12; + string qop = 13; + string nc = 14; + string cnonce = 15; + bool UseTokenCookie = 16; + string AccessToken = 17; + string AccessTokenSecret = 18; + string scope = 19; + map Meta = 20; +} +message AuthenticateResponse { + string UserId = 1; + string SessionId = 2; + string UserName = 3; + string DisplayName = 4; + string ReferrerUrl = 5; + string BearerToken = 6; + string RefreshToken = 7; + string ProfileUrl = 8; + repeated string Roles = 9; + repeated string Permissions = 10; + ResponseStatus ResponseStatus = 11; + map Meta = 12; +} +message Bar { + string Y = 2; +} +message Bookmark { + string Slug = 1; + string Title = 2; + string Description = 3; + string Url = 4; +} +message ChangeConnectionInfo { +} +message ChangeDb { + string NamedConnection = 1; + string ConnectionString = 2; + string ProviderName = 3; +} +message ChangeDbResponse { + repeated Rockstar Results = 1; +} +message ChatMessage { + int64 Id = 1; + string Channel = 2; + string FromUserId = 3; + string FromName = 4; + string DisplayName = 5; + string Message = 6; + string UserAuthId = 7; + bool Private = 8; +} +message ConvertSessionToToken { + bool PreserveSession = 1; + map Meta = 2; +} +message ConvertSessionToTokenResponse { + map Meta = 1; + string AccessToken = 2; + string RefreshToken = 3; + ResponseStatus ResponseStatus = 4; +} +message CreateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message CreateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message CreateBookmark { + string Slug = 1; + string Title = 2; + string Description = 3; + string Url = 4; +} +message CreateBookmarkResponse { + string Id = 1; // default value could not be applied: 00000000-0000-0000-0000-000000000000 + DaoBase Result = 2; + ResponseStatus ResponseStatus = 3; +} +message CreateConnectionInfoRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message CreateNamedRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message CreateRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarAdhocNonDefaults { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarAudit { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarAuditMqToken { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + string BearerToken = 101; +} +message CreateRockstarAuditTenant { + string BearerToken = 201; + string FirstName = 202; + string LastName = 203; + int32 Age = 204; + .google.protobuf.Timestamp DateOfBirth = 205; + .google.protobuf.Timestamp DateDied = 206; + LivingStatus LivingStatus = 207; +} +message CreateRockstarAuditTenantGateway { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarAuditTenantMq { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarAutoMap { + string MapFirstName = 1; + string MapLastName = 2; + int32 MapAge = 3; + .google.protobuf.Timestamp MapDateOfBirth = 4; + .google.protobuf.Timestamp MapDateDied = 5; + LivingStatus MapLivingStatus = 6; +} +message CreateRockstarResponse { + ResponseStatus ResponseStatus = 1; +} +message CreateRockstarVersion { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarWithAutoGuid { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarWithReturn { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateRockstarWithReturnGuidResponse { + string Id = 1; // default value could not be applied: 00000000-0000-0000-0000-000000000000 + RockstarBase Result = 2; + ResponseStatus ResponseStatus = 3; +} +message CreateRockstarWithVoidReturn { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} +message CreateTodo { + string Title = 1; + int32 Order = 2; +} +message CreateTodoResponse { + Todo Result = 1; + ResponseStatus ResponseStatus = 2; +} +message CustomRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + string RockstarAlbumName = 4; + string RockstarGenreName = 5; +} +message CustomRockstarSchema { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + string RockstarAlbumName = 4; + string RockstarGenreName = 5; +} +message CustomSelectRockstar { + int32 Id = 1; + string FirstName = 2; + string LastName = 3; + int32 Age = 4; +} +message CustomSelectRockstarResponse { + int32 Id = 1; + string FirstName = 2; + int32 Age = 3; +} +message CustomValidationErrors { + string CustomErrorCode = 1; + int32 CustomErrorCodeAndMessage = 2; + string ErrorCodeRule = 3; + int32 IsOddCondition = 4; + int32 IsOddAndOverTwoDigitsCondition = 5; + int32 IsOddOrOverTwoDigitsCondition = 6; +} +message DaoBase { + string Id = 1; // default value could not be applied: 00000000-0000-0000-0000-000000000000 + .google.protobuf.Timestamp CreateDate = 2; + string CreatedBy = 3; + .google.protobuf.Timestamp ModifiedDate = 4; + string ModifiedBy = 5; + oneof subtype { + Bookmark Bookmark = 439450339; + } +} +message DeleteRockstar { + int32 Id = 1; +} +message DeleteRockstarAudit { + int32 Id = 1; +} +message DeleteRockstarCountResponse { + int32 Count = 1; + ResponseStatus ResponseStatus = 2; +} +message DeleteRockstarFilters { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; +} +message DeleteTodo { + int64 Id = 1; +} +message DeleteTodos { + repeated int64 Ids = 1 [packed = false]; +} +message DynamicRequest { + map Params = 1; +} +message DynamicValidationRules { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + LivingStatus LivingStatus = 5; +} +message EmptyResponse { + ResponseStatus ResponseStatus = 1; +} +message EmptyValidators { + int32 Int = 1; + int32 NInt = 2; + .google.protobuf.Duration TimeSpan = 3; + .google.protobuf.Duration NTimeSpan = 4; + string String = 5; + repeated int32 IntArray = 6 [packed = false]; + repeated string StringList = 7; +} +message EndsWithSuffixRequest { + string Suffix = 1; +} +message EndsWithSuffixResponse { + SearchResult Result = 1; + int32 Count = 2; + repeated string Words = 3; +} +message Entry { +} +message FileContent { + string Name = 1; + string Type = 2; + int32 Length = 3; + bytes Body = 4; + ResponseStatus ResponseStatus = 5; +} +message Foo { + string X = 1; + oneof subtype { + Bar Bar = 210304982; + } +} +message GetAccessToken { + string RefreshToken = 1; + bool UseTokenCookie = 2; + map Meta = 3; +} +message GetAccessTokenResponse { + string AccessToken = 1; + map Meta = 2; + ResponseStatus ResponseStatus = 3; +} +message GetApiKeys { + string Environment = 1; + map Meta = 2; +} +message GetApiKeysResponse { + repeated UserApiKey Results = 1; + map Meta = 2; + ResponseStatus ResponseStatus = 3; +} +message GetFile { + string Path = 1; +} +message GetHello { + string Name = 1; +} +message GetTodo { + int64 Id = 1; +} +message GetTodoResponse { + Todo Result = 1; + ResponseStatus ResponseStatus = 2; +} +message GetTodos { +} +message GetTodosResponse { + repeated Todo Results = 1; + ResponseStatus ResponseStatus = 2; +} +message HelloJwt { + string Name = 1; + string BearerToken = 2; +} +message HelloJwtResponse { + string Result = 1; + ResponseStatus ResponseStatus = 2; +} +message HelloResponse { + string Result = 1; + ResponseStatus ResponseStatus = 2; +} +enum HttpStatusCode { + option allow_alias = true; + ZERO = 0; // proto3 requires a zero value as the first item (it can be named anything) + Continue = 100; + SwitchingProtocols = 101; + Processing = 102; + EarlyHints = 103; + OK = 200; + Created = 201; + Accepted = 202; + NonAuthoritativeInformation = 203; + NoContent = 204; + ResetContent = 205; + PartialContent = 206; + MultiStatus = 207; + AlreadyReported = 208; + IMUsed = 226; + MultipleChoices = 300; + Ambiguous = 300; + MovedPermanently = 301; + Moved = 301; + Found = 302; + Redirect = 302; + SeeOther = 303; + RedirectMethod = 303; + NotModified = 304; + UseProxy = 305; + Unused = 306; + TemporaryRedirect = 307; + RedirectKeepVerb = 307; + PermanentRedirect = 308; + BadRequest = 400; + Unauthorized = 401; + PaymentRequired = 402; + Forbidden = 403; + NotFound = 404; + MethodNotAllowed = 405; + NotAcceptable = 406; + ProxyAuthenticationRequired = 407; + RequestTimeout = 408; + Conflict = 409; + Gone = 410; + LengthRequired = 411; + PreconditionFailed = 412; + RequestEntityTooLarge = 413; + RequestUriTooLong = 414; + UnsupportedMediaType = 415; + RequestedRangeNotSatisfiable = 416; + ExpectationFailed = 417; + MisdirectedRequest = 421; + UnprocessableEntity = 422; + Locked = 423; + FailedDependency = 424; + UpgradeRequired = 426; + PreconditionRequired = 428; + TooManyRequests = 429; + RequestHeaderFieldsTooLarge = 431; + UnavailableForLegalReasons = 451; + InternalServerError = 500; + NotImplemented = 501; + BadGateway = 502; + ServiceUnavailable = 503; + GatewayTimeout = 504; + HttpVersionNotSupported = 505; + VariantAlsoNegotiates = 506; + InsufficientStorage = 507; + LoopDetected = 508; + NotExtended = 510; + NetworkAuthenticationRequired = 511; +} +message Incr { + int32 Amount = 1; +} +enum LivingStatus { + Alive = 0; + Dead = 1; +} +message Movie { + int32 Id = 1; + string ImdbId = 2; + string Title = 3; + string Rating = 4; + string Score = 5; + string Director = 6; + .google.protobuf.Timestamp ReleaseDate = 7; + string TagLine = 8; + repeated string Genres = 9; +} +message Multiply { + int32 X = 1; + int32 Y = 2; +} +message MultiplyResponse { + int32 Result = 1; +} +message NamedRockstar { +} +message NoAbstractValidator { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + LivingStatus LivingStatus = 5; +} +message OnlyValidatesRequest { + int32 Test = 1; + string NotNull = 2; +} +message PagingTest { + int32 Id = 1; + string Name = 2; + int32 Value = 3; +} +message PatchAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message PatchAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message PatchRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message PatchRockstarAuditTenant { + string BearerToken = 201; + int32 Id = 202; + string FirstName = 203; + LivingStatus LivingStatus = 204; +} +message PatchRockstarAuditTenantGateway { + int32 Id = 1; + string FirstName = 2; + LivingStatus LivingStatus = 3; +} +message PatchRockstarAuditTenantMq { + int32 Id = 1; + string FirstName = 2; + LivingStatus LivingStatus = 3; +} +message PostChatToChannel { + string From = 1; + string ToUserId = 2; + string Channel = 3; + string Message = 4; + string Selector = 5; +} +message QueryAdhoc { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryAdhocRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string first_name = 201; +} +message QueryAllFields { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string Guid = 201; +} +message QueryBookmarks { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryCaseInsensitiveOrderBy { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryChangeConnectionInfo { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryChangeDb { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string NamedConnection = 201; + string ConnectionString = 202; + string ProviderName = 203; +} +message QueryCustomRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryCustomRockstarsFilter { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryCustomRockstarsReferences { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryCustomRockstarsSchema { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryDbTenant_RockstarAuditTenant_RockstarAuto { +} +message QueryFieldRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string FirstName = 201; + repeated string FirstNames = 202; + int32 Age = 203; + string FirstNameCaseInsensitive = 204; + string FirstNameStartsWith = 205; + string LastNameEndsWith = 206; + repeated string FirstNameBetween = 207; + string OrLastName = 208; +} +message QueryFieldRockstarsDynamic { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryFieldsImplicitConventions { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string FirstNameContains = 201; + string LastNameEndsWith = 202; +} +message QueryFoos { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string X = 201; +} +message QueryGetRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + repeated int32 Ids = 201 [packed = false]; + repeated int32 Ages = 202 [packed = false]; + repeated string FirstNames = 203; + repeated int32 IdsBetween = 204 [packed = false]; +} +message QueryGetRockstarsDynamic { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryJoinedRockstarAlbums { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string RockstarAlbumName = 202; +} +message QueryJoinedRockstarAlbumsCustomSelect { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string RockstarAlbumName = 202; +} +message QueryJoinedRockstarAlbumsCustomSelectResponse { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string RockstarAlbumName = 202; +} +message QueryMovies { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + repeated int32 Ids = 201 [packed = false]; + repeated string ImdbIds = 202; + repeated string Ratings = 203; +} +message QueryMultiJoinRockstar { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string RockstarAlbumName = 202; + string RockstarGenreName = 203; +} +message QueryNamedRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryOrRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string FirstName = 202; +} +message QueryOrRockstarsFields { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string FirstName = 201; + string LastName = 202; +} +message QueryOverridedCustomRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryOverridedRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryPagingTest { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Id = 201; + string Name = 202; + int32 Value = 203; +} +message QueryResponse_Adhoc { + int32 Offset = 1; + int32 Total = 2; + repeated Adhoc Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_AllFields { + int32 Offset = 1; + int32 Total = 2; + repeated AllFields Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_Bookmark { + int32 Offset = 1; + int32 Total = 2; + repeated DaoBase Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_CustomRockstar { + int32 Offset = 1; + int32 Total = 2; + repeated CustomRockstar Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_CustomRockstarSchema { + int32 Offset = 1; + int32 Total = 2; + repeated CustomRockstarSchema Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_CustomSelectRockstar { + int32 Offset = 1; + int32 Total = 2; + repeated CustomSelectRockstar Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_CustomSelectRockstarResponse { + int32 Offset = 1; + int32 Total = 2; + repeated CustomSelectRockstarResponse Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_Foo { + int32 Offset = 1; + int32 Total = 2; + repeated Foo Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_Movie { + int32 Offset = 1; + int32 Total = 2; + repeated Movie Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_NamedRockstar { + int32 Offset = 1; + int32 Total = 2; + repeated Rockstar Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_PagingTest { + int32 Offset = 1; + int32 Total = 2; + repeated PagingTest Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_Rockstar { + int32 Offset = 1; + int32 Total = 2; + repeated Rockstar Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_RockstarAlbum { + int32 Offset = 1; + int32 Total = 2; + repeated RockstarAlbum Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_RockstarAlias { + int32 Offset = 1; + int32 Total = 2; + repeated RockstarAlias Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_RockstarAuto { + int32 Offset = 1; + int32 Total = 2; + repeated RockstarBase Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_RockstarReference { + int32 Offset = 1; + int32 Total = 2; + repeated RockstarReference Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryResponse_TypeWithEnum { + int32 Offset = 1; + int32 Total = 2; + repeated TypeWithEnum Results = 3; + map Meta = 4; + ResponseStatus ResponseStatus = 5; +} +message QueryRockstarAlbums { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Id = 201; + int32 RockstarId = 202; + string Name = 203; + string Genre = 204; + repeated int32 IdBetween = 205 [packed = false]; +} +message QueryRockstarAlbumsCustomLeftJoin { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string AlbumName = 202; + int32 IdNotEqualTo = 203; +} +message QueryRockstarAlbumsImplicit { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryRockstarAlbumsLeftJoin { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string AlbumName = 202; + int32 IdNotEqualTo = 203; +} +message QueryRockstarAlias { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; + string RockstarAlbumName = 202; +} +message QueryRockstarAudit { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Id = 301; +} +message QueryRockstarAuditSubOr { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + string FirstNameStartsWith = 201; + int32 AgeOlderThan = 202; +} +message QueryRockstarFilters { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + repeated int32 Ids = 201 [packed = false]; + repeated int32 Ages = 202 [packed = false]; + repeated string FirstNames = 203; + repeated int32 IdsBetween = 204 [packed = false]; +} +message QueryRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryRockstarsConventions { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + .google.protobuf.Timestamp DateOfBirthGreaterThan = 201; + .google.protobuf.Timestamp DateDiedLessThan = 202; + repeated int32 Ids = 203 [packed = false]; + int32 AgeOlderThan = 204; + int32 AgeGreaterThanOrEqualTo = 205; + int32 AgeGreaterThan = 206; + int32 GreaterThanAge = 207; + string FirstNameStartsWith = 208; + string LastNameEndsWith = 209; + string LastNameContains = 210; + string RockstarAlbumNameContains = 211; + int32 RockstarIdAfter = 212; + int32 RockstarIdOnOrAfter = 213; +} +message QueryRockstarsFilter { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryRockstarsIFilter { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryRockstarsImplicit { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryRockstarsWithReferences { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 Age = 201; +} +message QueryTypeWithEnums { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message QueryUnknownRockstars { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + int32 UnknownInt = 201; + string UnknownProperty = 202; +} +message RealDeleteAuditTenant { + string BearerToken = 1; + int32 Id = 2; + int32 Age = 3; +} +message RealDeleteAuditTenantGateway { + int32 Id = 1; +} +message RealDeleteAuditTenantMq { + int32 Id = 1; +} +message RegenerateApiKeys { + string Environment = 1; + map Meta = 2; +} +message RegenerateApiKeysResponse { + repeated UserApiKey Results = 1; + map Meta = 2; + ResponseStatus ResponseStatus = 3; +} +message Register { + string UserName = 1; + string FirstName = 2; + string LastName = 3; + string DisplayName = 4; + string Email = 5; + string Password = 6; + string ConfirmPassword = 7; + bool AutoLogin = 8; + string ErrorView = 10; + map Meta = 11; +} +message RegisterResponse { + string UserId = 1; + string SessionId = 2; + string UserName = 3; + string ReferrerUrl = 4; + string BearerToken = 5; + string RefreshToken = 6; + ResponseStatus ResponseStatus = 7; + map Meta = 8; +} +message RequiresAuth { + string Name = 1; + string BearerToken = 2; +} +message ResetTodos { +} +message ResponseError { + string ErrorCode = 1; + string FieldName = 2; + string Message = 3; + map Meta = 4; +} +message ResponseStatus { + string ErrorCode = 1; + string Message = 2; + string StackTrace = 3; + repeated ResponseError Errors = 4; + map Meta = 5; +} +message Rockstar { + int32 Id = 1; + string FirstName = 2; + string LastName = 3; + int32 Age = 4; + .google.protobuf.Timestamp DateOfBirth = 5; + .google.protobuf.Timestamp DateDied = 6; + LivingStatus LivingStatus = 7; + oneof subtype { + NamedRockstar NamedRockstar = 345091624; + } +} +message RockstarAlbum { + int32 Id = 1; + int32 RockstarId = 2; + string Name = 3; + string Genre = 4; +} +message RockstarAlias { + int32 RockstarId = 1; + string FirstName = 2; + string Surname = 3; + string album = 4; +} +message RockstarAudit { + int32 Id = 1; + .google.protobuf.Timestamp CreatedDate = 2; + string CreatedBy = 3; + string CreatedInfo = 4; + .google.protobuf.Timestamp ModifiedDate = 5; + string ModifiedBy = 6; + string ModifiedInfo = 7; +} +message RockstarAuditTenant { + int32 TenantId = 1; + int32 Id = 2; + string FirstName = 3; + string LastName = 4; + int32 Age = 5; + .google.protobuf.Timestamp DateOfBirth = 6; + .google.protobuf.Timestamp DateDied = 7; + LivingStatus LivingStatus = 8; +} +message RockstarAuto { + int32 Id = 1; +} +message RockstarAutoGuid { + string Id = 1; // default value could not be applied: 00000000-0000-0000-0000-000000000000 +} +message RockstarBase { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + oneof subtype { + RockstarAutoGuid RockstarAutoGuid = 92000829; + RockstarAuto RockstarAuto = 92257311; + RockstarAudit RockstarAudit = 119875064; + RockstarVersion RockstarVersion = 320656675; + } +} +message RockstarGenre { + int32 Id = 1; + int32 RockstarId = 2; + string Name = 3; +} +message RockstarReference { + int32 Id = 1; + string FirstName = 2; + string LastName = 3; + int32 Age = 4; + repeated RockstarAlbum Albums = 5; +} +message RockstarVersion { + int32 Id = 1; + uint64 RowVersion = 2; +} +message RockstarWithIdAndCountResponse { + int32 Id = 1; + int32 Count = 2; + ResponseStatus ResponseStatus = 3; +} +message RockstarWithIdAndResultResponse { + int32 Id = 1; + RockstarBase Result = 2; + ResponseStatus ResponseStatus = 3; +} +message RockstarWithIdAndRowVersionResponse { + int32 Id = 1; + uint32 RowVersion = 2; + ResponseStatus ResponseStatus = 3; +} +message RockstarWithIdResponse { + int32 Id = 1; + ResponseStatus ResponseStatus = 2; +} +message SearchMovies { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; +} +message SearchResult { + int32 Id = 1; + string Suffix = 2; +} +message Secured { + string Name = 1; +} +message SecuredResponse { + string Result = 1; + ResponseStatus ResponseStatus = 2; +} +message SoftDeleteAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message SoftDeleteAuditTenant { + int32 Id = 201; +} +message SoftDeleteAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +enum SomeEnum { + SomeEnum_Value0 = 0; + SomeEnum_Value1 = 1; + SomeEnum_Value2 = 2; + SomeEnum_Value3 = 3; +} +enum SomeEnumAsInt { + Value0 = 0; + Value1 = 1; + Value2 = 2; + Value3 = 3; +} +message StreamFiles { + repeated string Paths = 1; +} +message StreamMovies { + int32 Skip = 1; + int32 Take = 2; + string OrderBy = 3; + string OrderByDesc = 4; + string Include = 5; + string Fields = 6; + map Meta = 7; + repeated string Ratings = 201; +} +message StreamServerEvents { + repeated string Channels = 1; +} +message StreamServerEventsResponse { + int64 EventId = 1; + string Channel = 2; + string Selector = 4; + string Json = 5; + string Op = 6; + string Target = 7; + string CssSelector = 8; + map Meta = 9; + string UserId = 10; + string DisplayName = 11; + string ProfileUrl = 12; + bool IsAuthenticated = 13; + repeated string Channels = 14; + int64 CreatedAt = 15; + string Id = 21; + string UnRegisterUrl = 22; + string UpdateSubscriberUrl = 23; + string HeartbeatUrl = 24; + int64 HeartbeatIntervalMs = 25; + int64 IdleTimeoutMs = 26; + ResponseStatus ResponseStatus = 30; +} +message TestAuthValidators { + string NotNull = 1; +} +message TestDbCondition { + int32 Id = 1; + string NotNull = 2; +} +message TestDbValidator { + int32 Id = 1; + string NotNull = 2; +} +message TestIsAdmin { + string NotNull = 1; +} +message TestMultiAuthValidators { + string NotNull = 1; +} +message Throw { + string Message = 1; +} +message ThrowCustom { +} +message ThrowCustomResponse { + ResponseStatus ResponseStatus = 1; +} +message ThrowVoid { + string Message = 1; +} +message Todo { + int64 Id = 1; + string Title = 2; + int32 Order = 3; + bool Completed = 4; +} +message TriggerAllValidators { + string CreditCard = 1; + string Email = 2; + string Empty = 3; + string Equal = 4; + int32 ExclusiveBetween = 5; + int32 GreaterThanOrEqual = 6; + int32 GreaterThan = 7; + int32 InclusiveBetween = 8; + string Length = 9; + int32 LessThanOrEqual = 10; + int32 LessThan = 11; + string NotEmpty = 12; + string NotEqual = 13; + string Null = 14; + string RegularExpression = 15; + string ScalePrecision = 16; +} +message TriggerValidators { + string CreditCard = 1; + string Email = 2; + string Empty = 3; + string Equal = 4; + int32 ExclusiveBetween = 5; + int32 GreaterThanOrEqual = 6; + int32 GreaterThan = 7; + int32 InclusiveBetween = 8; + string Length = 9; + int32 LessThanOrEqual = 10; + int32 LessThan = 11; + string NotEmpty = 12; + string NotEqual = 13; + string Null = 14; + string RegularExpression = 15; + string ScalePrecision = 16; +} +message TypeWithEnum { + int32 Id = 1; + string Name = 2; + SomeEnum SomeEnum = 3; + SomeEnumAsInt SomeEnumAsInt = 4; + SomeEnum NSomeEnum = 5; + SomeEnumAsInt NSomeEnumAsInt = 6; +} +message UnAssignRoles { + string UserName = 1; + repeated string Permissions = 2; + repeated string Roles = 3; + map Meta = 4; +} +message UnAssignRolesResponse { + repeated string AllRoles = 1; + repeated string AllPermissions = 2; + map Meta = 3; + ResponseStatus ResponseStatus = 4; +} +message UpdateAuditBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message UpdateAuditTenantBase_RockstarAuditTenant_RockstarWithIdAndResultResponse { +} +message UpdateConnectionInfoRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message UpdateNamedRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message UpdateRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message UpdateRockstarAdhocNonDefaults { + int32 Id = 1; + string FirstName = 2; + string LastName = 3; + int32 Age = 4; + .google.protobuf.Timestamp DateOfBirth = 5; + .google.protobuf.Timestamp DateDied = 6; + LivingStatus LivingStatus = 7; +} +message UpdateRockstarAudit { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; +} +message UpdateRockstarAuditTenant { + string BearerToken = 201; + int32 Id = 202; + string FirstName = 203; + LivingStatus LivingStatus = 204; +} +message UpdateRockstarAuditTenantGateway { + int32 Id = 1; + string FirstName = 2; + LivingStatus LivingStatus = 3; +} +message UpdateRockstarAuditTenantMq { + int32 Id = 1; + string FirstName = 2; + LivingStatus LivingStatus = 3; +} +message UpdateRockstarVersion { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; + int32 Id = 101; + uint64 RowVersion = 102; +} +message UpdateTodo { + int64 Id = 1; + string Title = 2; + int32 Order = 3; + bool Completed = 4; +} +message UserApiKey { + string Key = 1; + string KeyType = 2; + .google.protobuf.Timestamp ExpiryDate = 3; + map Meta = 4; +} +message ValidateCreateRockstar { + string FirstName = 1; + string LastName = 2; + int32 Age = 3; + .google.protobuf.Timestamp DateOfBirth = 4; + .google.protobuf.Timestamp DateDied = 5; + LivingStatus LivingStatus = 6; +} diff --git a/tests/ServiceStack.Extensions.Tests/ServiceStack.Extensions.Tests.csproj b/tests/ServiceStack.Extensions.Tests/ServiceStack.Extensions.Tests.csproj new file mode 100644 index 00000000000..7591de6a632 --- /dev/null +++ b/tests/ServiceStack.Extensions.Tests/ServiceStack.Extensions.Tests.csproj @@ -0,0 +1,38 @@ + + + + net6.0 + default + + + + + $(DefineConstants);AUTOQUERY_CRUD + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.IntegrationTests/RedisPerfTest/Program.cs b/tests/ServiceStack.IntegrationTests/RedisPerfTest/Program.cs deleted file mode 100644 index d4551f651ac..00000000000 --- a/tests/ServiceStack.IntegrationTests/RedisPerfTest/Program.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using ServiceStack.Redis; - -namespace RedisPerfTest -{ - class Program - { - const string KeyMaster = "key:"; - const string ValueMaster = "value:"; - private const int Iterations = 1000; - private const int LogEveryTimes = 100; - - static void Main(string[] args) - { - var host = args.Length > 0 ? args[0] : "localhost"; - var port = args.Length > 1 ? int.Parse(args[1]) : 6379; - - var redisClient = new RedisClient(host, port); - - var before = DateTime.Now; - for (var i = 0; i < Iterations; i++) - { - var key = KeyMaster + i; - redisClient.Set(key, ValueMaster); - - //if (i % LogEveryTimes == 0) - // Console.WriteLine("Time taken at {0}: {1}ms", i, (DateTime.Now - before).TotalMilliseconds); - } - - for (int i = 0; i < Iterations; i++) - { - var key = KeyMaster + i; - redisClient.Get(key); - - //if (i % LogEveryTimes == 0) - // Console.WriteLine("Time taken at {0}: {1}ms", i, (DateTime.Now - before).TotalMilliseconds); - } - - Console.WriteLine("Total Time Taken: {0}ms", (DateTime.Now - before).TotalMilliseconds); - } - } -} diff --git a/tests/ServiceStack.IntegrationTests/RedisPerfTest/Properties/AssemblyInfo.cs b/tests/ServiceStack.IntegrationTests/RedisPerfTest/Properties/AssemblyInfo.cs deleted file mode 100644 index f710af6e119..00000000000 --- a/tests/ServiceStack.IntegrationTests/RedisPerfTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("RedisPerfTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("RedisPerfTest")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4ce8d0fe-f79c-4d99-83fe-d58da09e153b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.IntegrationTests/RedisPerfTest/RedisPerfTest.csproj b/tests/ServiceStack.IntegrationTests/RedisPerfTest/RedisPerfTest.csproj deleted file mode 100644 index c39591c4665..00000000000 --- a/tests/ServiceStack.IntegrationTests/RedisPerfTest/RedisPerfTest.csproj +++ /dev/null @@ -1,63 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {BD927614-139E-48AE-8F0F-8124D6D0EECB} - Exe - Properties - RedisPerfTest - RedisPerfTest - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\Common\ServiceStack.Redis\Build\ServiceStack.Redis.dll - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/Program.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/Program.cs deleted file mode 100644 index ca4e008235c..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ServiceStack.IntegrationTests.ConsoleClient -{ - class Program - { - static void Main(string[] args) - { - } - } -} diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/Properties/AssemblyInfo.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/Properties/AssemblyInfo.cs deleted file mode 100644 index e5927109014..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.IntegrationTests.ConsoleClient")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.IntegrationTests.ConsoleClient")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4c171a0b-cda8-4900-8a7c-ac38dc167e27")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/ServiceStack.IntegrationTests.ConsoleClient.csproj b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/ServiceStack.IntegrationTests.ConsoleClient.csproj deleted file mode 100644 index 988c363a388..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ConsoleClient/ServiceStack.IntegrationTests.ConsoleClient.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF} - Exe - Properties - ServiceStack.IntegrationTests.ConsoleClient - ServiceStack.IntegrationTests.ConsoleClient - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/AppHost.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/AppHost.cs deleted file mode 100644 index 2093474add7..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/AppHost.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using Funq; -using ServiceStack.Configuration; -using ServiceStack.IntegrationTests.ServiceInterface; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.WebHost.Endpoints; - -namespace ServiceStack.IntegrationTests.Host.Web -{ - /// - /// An example of a AppHost to have your services running inside a webserver. - /// - public class AppHost - : AppHostBase - { - private static ILog log; - - public AppHost() - : base("ServiceStack IntegrationTests", typeof(PingService).Assembly) - { - LogManager.LogFactory = new DebugLogFactory(); - log = LogManager.GetLogger(typeof(AppHost)); - } - - public override void Configure(Container container) - { - container.Register(new ConfigurationResourceManager()); - - var config = container.Resolve(); - - log.InfoFormat("AppHost Configured: " + DateTime.Now); - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx deleted file mode 100644 index f30850ad17b..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx +++ /dev/null @@ -1,16 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ServiceStack.IntegrationTests.Host.Web._Default" %> - - - - - - - - -
-
- -
- - - diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx.cs deleted file mode 100644 index 3f386f4c842..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; - -namespace ServiceStack.IntegrationTests.Host.Web -{ - public partial class _Default : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - Response.Redirect("Public/Metadata"); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx.designer.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx.designer.cs deleted file mode 100644 index 85d93eacdce..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Default.aspx.designer.cs +++ /dev/null @@ -1,24 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4918 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ServiceStack.IntegrationTests.Host.Web -{ - public partial class _Default { - - /// - /// form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm form1; - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Global.asax b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Global.asax deleted file mode 100644 index 98135db256e..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="ServiceStack.IntegrationTests.Host.Web.Global" Language="C#" %> diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Global.asax.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Global.asax.cs deleted file mode 100644 index b6d30046808..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Global.asax.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace ServiceStack.IntegrationTests.Host.Web -{ - public class Global : System.Web.HttpApplication - { - - protected void Application_Start(object sender, EventArgs e) - { - var appHost = new AppHost(); - appHost.Init(); - } - - protected void Session_Start(object sender, EventArgs e) - { - - } - - protected void Application_BeginRequest(object sender, EventArgs e) - { - - } - - protected void Application_AuthenticateRequest(object sender, EventArgs e) - { - - } - - protected void Application_Error(object sender, EventArgs e) - { - - } - - protected void Session_End(object sender, EventArgs e) - { - - } - - protected void Application_End(object sender, EventArgs e) - { - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Properties/AssemblyInfo.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Properties/AssemblyInfo.cs deleted file mode 100644 index 6148c365a56..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.Examples.Host.Web")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.Examples.Host.Web")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap11/AsyncOneWay.svc b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap11/AsyncOneWay.svc deleted file mode 100644 index e0d3dbc8c4d..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap11/AsyncOneWay.svc +++ /dev/null @@ -1 +0,0 @@ -<%@ ServiceHost Language="C#" Service="ServiceStack.WebHost.Endpoints.Soap11AsyncOneWayHandler" %> \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap11/SyncReply.svc b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap11/SyncReply.svc deleted file mode 100644 index 0db3d12aae6..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap11/SyncReply.svc +++ /dev/null @@ -1 +0,0 @@ -<%@ ServiceHost Language="C#" Service="ServiceStack.WebHost.Endpoints.Soap11SyncReplyHandler" %> \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap12/AsyncOneWay.svc b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap12/AsyncOneWay.svc deleted file mode 100644 index be142ab5c34..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap12/AsyncOneWay.svc +++ /dev/null @@ -1 +0,0 @@ -<%@ ServiceHost Language="C#" Service="ServiceStack.WebHost.Endpoints.Soap12AsyncOneWayHandler" %> \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap12/SyncReply.svc b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap12/SyncReply.svc deleted file mode 100644 index 70dec3dadb8..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Public/Soap12/SyncReply.svc +++ /dev/null @@ -1 +0,0 @@ -<%@ ServiceHost Language="C#" Service="ServiceStack.WebHost.Endpoints.Soap12SyncReplyHandler" %> \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/ServiceStack.IntegrationTests.Host.Web.csproj b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/ServiceStack.IntegrationTests.Host.Web.csproj deleted file mode 100644 index 0646b6bb96a..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/ServiceStack.IntegrationTests.Host.Web.csproj +++ /dev/null @@ -1,126 +0,0 @@ - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - ServiceStack.IntegrationTests.Host.Web - ServiceStack.IntegrationTests.Host.Web - v3.5 - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - x86 - - - pdbonly - true - bin\ - TRACE - prompt - 4 - - - - False - ..\..\release\latest\ServiceStack.dll - - - False - ..\..\release\latest\ServiceStack.Interfaces.dll - - - - - 3.5 - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - - - - - - - - - ASPXCodeBehind - Default.aspx - - - Default.aspx - - - Global.asax - - - - - - - - - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191} - ServiceStack.IntegrationTests.ServiceInterface - - - - - - - - - - - - - True - True - 59436 - / - http://localhost/ServiceStack.IntegrationTests.Host.Web - False - False - - - False - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Web.config b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Web.config deleted file mode 100644 index 4e882054e1d..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Web.config +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - -
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Web.config.classic b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Web.config.classic deleted file mode 100644 index 22c3eb58fd8..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.Host.Web/Web.config.classic +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - -
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs deleted file mode 100644 index 0a1d4ff3975..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ServiceStack.IntegrationTests.ServiceModel; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class HttpPostXmlAndSecureLocalSubnetRestrictionService - : TestServiceBase - { - protected override object Run(HttpPostXmlAndSecureLocalSubnetRestriction request) - { - return new HttpPostXmlAndSecureLocalSubnetRestrictionResponse(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs deleted file mode 100644 index 789b1d805db..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using ServiceStack.IntegrationTests.ServiceModel; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class HttpPostXmlOrSecureLocalSubnetRestrictionService - : TestServiceBase - { - protected override object Run(HttpPostXmlOrSecureLocalSubnetRestriction request) - { - return new HttpPostXmlOrSecureLocalSubnetRestrictionResponse(); - } - } - -} diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/InternalRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/InternalRestrictionService.cs deleted file mode 100644 index e1c05dd961b..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/InternalRestrictionService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ServiceStack.IntegrationTests.ServiceModel; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class InternalRestrictionService - : TestServiceBase - { - protected override object Run(InternalRestriction request) - { - return new IntranetRestrictionResponse(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/LocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/LocalSubnetRestrictionService.cs deleted file mode 100644 index 7466c8c9cdd..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/LocalSubnetRestrictionService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ServiceStack.IntegrationTests.ServiceModel; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class LocalSubnetRestrictionService - : TestServiceBase - { - protected override object Run(LocalSubnetRestriction request) - { - return new LocalSubnetRestrictionResponse(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/LocalhostRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/LocalhostRestrictionService.cs deleted file mode 100644 index 0691f105013..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/LocalhostRestrictionService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ServiceStack.IntegrationTests.ServiceModel; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class LocalhostRestrictionService - : TestServiceBase - { - protected override object Run(LocalhostRestriction request) - { - return new LocalhostRestrictionResponse(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/PingService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/PingService.cs deleted file mode 100644 index d6237864d3c..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/PingService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using ServiceStack.IntegrationTests.ServiceModel; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class PingService - : IService - { - public object Execute(Ping request) - { - return new PingResponse { Text = "Pong " + request.Text }; - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/Properties/AssemblyInfo.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/Properties/AssemblyInfo.cs deleted file mode 100644 index dc0a9866a36..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.IntegrationTests.ServiceInterface")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.IntegrationTests.ServiceInterface")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("bed34094-2c18-4d5e-b789-451abbb38e30")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/RequestInfoService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/RequestInfoService.cs deleted file mode 100644 index 71d704df461..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/RequestInfoService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Text; -using System.Web; -using ServiceStack.IntegrationTests.ServiceModel; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class RequestInfoService - : IService, IRequiresRequestContext - { - public IRequestContext RequestContext { get; set; } - - public object Execute(RequestInfo request) - { - var ipAddr = HttpContext.Current.Request.UserHostAddress; - - var response = new RequestInfoResponse { - EnpointAttributes = RequestContext.EndpointAttributes.ToString().Split(',').ToList().ConvertAll(x => x.Trim()), - IpAddress = ipAddr, - IpAddressFamily = ipAddr, - NetworkLog = GetNetworkLog(), - Ipv4Addresses = GetIpv4Addresses(), - Ipv6Addresses = GetIpv6Addresses(), - }; - - var requestAttr = RequestContext.RequestAttributes; - if (requestAttr.AcceptsDeflate) - response.RequestAttributes.Add(requestAttr.AcceptsDeflate.ToString()); - - if (requestAttr.AcceptsGzip) - response.RequestAttributes.Add(requestAttr.AcceptsGzip.ToString()); - - return response; - } - - public Dictionary GetIpv4Addresses() - { - var map = new Dictionary(); - foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) - { - foreach (var uipi in ni.GetIPProperties().UnicastAddresses) - { - if (uipi.Address.AddressFamily != AddressFamily.InterNetwork) continue; - if (uipi.IPv4Mask == null) continue; - - map[uipi.Address.ToString()] = uipi.IPv4Mask.ToString(); - } - } - return map; - } - - public List GetIpv6Addresses() - { - var list = new List(); - foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) - { - foreach (var uipi in ni.GetIPProperties().UnicastAddresses) - { - if (uipi.Address.AddressFamily == AddressFamily.InterNetworkV6) - { - list.Add(uipi.Address.ToString()); - } - } - } - return list; - } - - public string GetNetworkLog() - { - var sb = new StringBuilder(); - foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) - { - sb.AppendLine(ni.Name); - sb.AppendFormat("Operational? {0}\n", ni.OperationalStatus == OperationalStatus.Up); - sb.AppendFormat("MAC: {0}\n", ni.GetPhysicalAddress()); - sb.AppendLine("Gateways:"); - foreach (var gipi in ni.GetIPProperties().GatewayAddresses) - { - sb.AppendFormat("\t{0}\n", gipi.Address); - } - sb.AppendLine("IP Addresses:"); - foreach (var uipi in ni.GetIPProperties().UnicastAddresses) - { - sb.AppendFormat("\t{0} / {1} [{2}, {3}, {4}]\n", - uipi.Address, uipi.IPv4Mask, - uipi.Address.AddressFamily, - uipi.PrefixOrigin, uipi.SuffixOrigin); - } - - sb.AppendLine(); - } - - return sb.ToString(); - } - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/SecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/SecureLocalSubnetRestrictionService.cs deleted file mode 100644 index 260c8a90e45..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/SecureLocalSubnetRestrictionService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ServiceStack.IntegrationTests.ServiceModel; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public class SecureLocalSubnetRestrictionService - : TestServiceBase - { - protected override object Run(SecureLocalSubnetRestriction request) - { - return new SecureLocalSubnetRestrictionResponse(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/ServiceStack.IntegrationTests.ServiceInterface.csproj b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/ServiceStack.IntegrationTests.ServiceInterface.csproj deleted file mode 100644 index 6443dd4b7d5..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/ServiceStack.IntegrationTests.ServiceInterface.csproj +++ /dev/null @@ -1,78 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191} - Library - Properties - ServiceStack.IntegrationTests.ServiceInterface - ServiceStack.IntegrationTests.ServiceInterface - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\release\latest\ServiceStack.Interfaces.dll - - - - 3.5 - - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - - - - - - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16} - ServiceStack.IntegrationTests.ServiceModel - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/TestServiceBase.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/TestServiceBase.cs deleted file mode 100644 index 3718c92cff9..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceInterface/TestServiceBase.cs +++ /dev/null @@ -1,15 +0,0 @@ -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceInterface -{ - public abstract class TestServiceBase - : IService - { - protected abstract object Run(TRequest request); - - public object Execute(TRequest request) - { - return Run(request); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs deleted file mode 100644 index bce242b4a32..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [Service(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class HttpPostXmlAndSecureLocalSubnetRestriction { } - - [DataContract] - public class HttpPostXmlAndSecureLocalSubnetRestrictionResponse { } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs deleted file mode 100644 index 0199b8dcc1b..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [Service(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure, EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class HttpPostXmlOrSecureLocalSubnetRestriction { } - - [DataContract] - public class HttpPostXmlOrSecureLocalSubnetRestrictionResponse { } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/InternalRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/InternalRestrictionService.cs deleted file mode 100644 index 4bd8113be7f..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/InternalRestrictionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [Service(EndpointAttributes.InternalNetworkAccess)] - [DataContract] - public class InternalRestriction { } - - [DataContract] - public class IntranetRestrictionResponse { } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/LocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/LocalSubnetRestrictionService.cs deleted file mode 100644 index caf7d23ffb0..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/LocalSubnetRestrictionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [Service(EndpointAttributes.LocalSubnet)] - [DataContract] - public class LocalSubnetRestriction { } - - [DataContract] - public class LocalSubnetRestrictionResponse { } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/LocalhostRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/LocalhostRestrictionService.cs deleted file mode 100644 index 98ca9399b6d..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/LocalhostRestrictionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [Service(EndpointAttributes.Localhost)] - [DataContract] - public class LocalhostRestriction { } - - [DataContract] - public class LocalhostRestrictionResponse { } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/Ping.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/Ping.cs deleted file mode 100644 index f60604c2889..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/Ping.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.Serialization; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [DataContract] - public class Ping - { - [DataMember] - public string Text { get; set; } - } - - [DataContract] - public class PingResponse - { - [DataMember] - public string Text { get; set; } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/Properties/AssemblyInfo.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/Properties/AssemblyInfo.cs deleted file mode 100644 index 55b3549ee20..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.IntegrationTests.ServiceModel")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.IntegrationTests.ServiceModel")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2edda6bc-f0b5-46d2-9a58-300f011f5c20")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/RequestInfo.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/RequestInfo.cs deleted file mode 100644 index 13ae598118c..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/RequestInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [DataContract] - public class RequestInfo - { - } - - [DataContract] - public class RequestInfoResponse - { - public RequestInfoResponse() - { - this.EnpointAttributes = new List(); - this.RequestAttributes = new List(); - this.Ipv4Addresses = new Dictionary(); - this.Ipv6Addresses = new List(); - } - - [DataMember] - public List EnpointAttributes { get; set; } - - [DataMember] - public List RequestAttributes { get; set; } - - [DataMember] - public string IpAddress { get; set; } - public string IpAddressFamily { get; set; } - - [DataMember] - public Dictionary Ipv4Addresses { get; set; } - - [DataMember] - public List Ipv6Addresses { get; set; } - - [DataMember] - public string NetworkLog { get; set; } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/SecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/SecureLocalSubnetRestrictionService.cs deleted file mode 100644 index caa977f4ca8..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/SecureLocalSubnetRestrictionService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.IntegrationTests.ServiceModel -{ - [Service(EndpointAttributes.Secure | EndpointAttributes.LocalSubnet)] - [DataContract] - public class SecureLocalSubnetRestriction { } - - [DataContract] - public class SecureLocalSubnetRestrictionResponse { } -} \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/ServiceStack.IntegrationTests.ServiceModel.csproj b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/ServiceStack.IntegrationTests.ServiceModel.csproj deleted file mode 100644 index b337466e0d1..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.ServiceModel/ServiceStack.IntegrationTests.ServiceModel.csproj +++ /dev/null @@ -1,73 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16} - Library - Properties - ServiceStack.IntegrationTests.ServiceModel - ServiceStack.IntegrationTests.ServiceModel - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\release\latest\ServiceStack.Interfaces.dll - - - - 3.5 - - - 3.0 - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.sln b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.sln deleted file mode 100644 index c1d23f78582..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.sln +++ /dev/null @@ -1,66 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.IntegrationTests.Host.Web", "ServiceStack.IntegrationTests.Host.Web\ServiceStack.IntegrationTests.Host.Web.csproj", "{3A8D2349-6E97-47A2-AC49-EFE7D89C0344}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.IntegrationTests.ServiceInterface", "ServiceStack.IntegrationTests.ServiceInterface\ServiceStack.IntegrationTests.ServiceInterface.csproj", "{3114D29B-152C-4A9C-A6AB-BEE43F0F6191}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.IntegrationTests.ServiceModel", "ServiceStack.IntegrationTests.ServiceModel\ServiceStack.IntegrationTests.ServiceModel.csproj", "{D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceStack.IntegrationTests.ConsoleClient", "ServiceStack.IntegrationTests.ConsoleClient\ServiceStack.IntegrationTests.ConsoleClient.csproj", "{7705AA03-1BAF-4952-83C6-5B7F5C2549DF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedisPerfTest", "RedisPerfTest\RedisPerfTest.csproj", "{BD927614-139E-48AE-8F0F-8124D6D0EECB}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - MonoTouch|Any CPU = MonoTouch|Any CPU - Release|Any CPU = Release|Any CPU - STATIC_ONLY NO_EXPRESSIONS|Any CPU = STATIC_ONLY NO_EXPRESSIONS|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.MonoTouch|Any CPU.Build.0 = Release|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.Release|Any CPU.Build.0 = Release|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU - {3A8D2349-6E97-47A2-AC49-EFE7D89C0344}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.MonoTouch|Any CPU.Build.0 = Release|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.Release|Any CPU.Build.0 = Release|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU - {3114D29B-152C-4A9C-A6AB-BEE43F0F6191}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.MonoTouch|Any CPU.Build.0 = Release|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.Release|Any CPU.Build.0 = Release|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU - {D8C24E17-CDB2-4E13-B5D7-F26A6815CF16}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.MonoTouch|Any CPU.Build.0 = Release|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.Release|Any CPU.Build.0 = Release|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU - {7705AA03-1BAF-4952-83C6-5B7F5C2549DF}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.MonoTouch|Any CPU.ActiveCfg = Release|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.MonoTouch|Any CPU.Build.0 = Release|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.Release|Any CPU.Build.0 = Release|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.ActiveCfg = Release|Any CPU - {BD927614-139E-48AE-8F0F-8124D6D0EECB}.STATIC_ONLY NO_EXPRESSIONS|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/Class1.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/Class1.cs deleted file mode 100644 index b2ae2b7af16..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/Class1.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ServiceStack.IntegrationTests.test -{ - public class Class1 - { - } -} diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/Properties/AssemblyInfo.cs b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/Properties/AssemblyInfo.cs deleted file mode 100644 index 07d3827d064..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.IntegrationTests.test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.IntegrationTests.test")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("fbddde0e-1019-42c4-b9a1-b6d5d7697e64")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/ServiceStack.IntegrationTests.test.csproj b/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/ServiceStack.IntegrationTests.test.csproj deleted file mode 100644 index 1947b461d50..00000000000 --- a/tests/ServiceStack.IntegrationTests/ServiceStack.IntegrationTests.test/ServiceStack.IntegrationTests.test.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {FAECB415-5EBF-4CBE-94E4-EBCA1B9D33EE} - Library - Properties - ServiceStack.IntegrationTests.test - ServiceStack.IntegrationTests.test - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - 3.5 - - - 3.5 - - - 3.5 - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Logging.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..c764773280d --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ServiceStack.Logging.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ServiceStack")] +[assembly: AssemblyProduct("ServiceStack.Logging.Tests")] +[assembly: AssemblyCopyright("Copyright ServiceStack 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("391f0578-ea4b-43c1-9409-d8dce2d68a71")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.Logging.Tests/ServiceStack.Logging.Tests.csproj b/tests/ServiceStack.Logging.Tests/ServiceStack.Logging.Tests.csproj new file mode 100644 index 00000000000..ff7704b34f7 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/ServiceStack.Logging.Tests.csproj @@ -0,0 +1,52 @@ + + + net472 + portable + ServiceStack.Logging.Tests + ServiceStack.Logging.Tests + false + false + false + false + false + false + false + false + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + $(DefineConstants);NET45;NET472 + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/Support/TestBase.cs b/tests/ServiceStack.Logging.Tests/Support/TestBase.cs new file mode 100644 index 00000000000..ccaa7497f8f --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/Support/TestBase.cs @@ -0,0 +1,46 @@ +using System; +using System.Diagnostics; +using NUnit.Framework; +using Rhino.Mocks; + +namespace ServiceStack.Logging.Tests.Support +{ + public class TestBase + { + private MockRepository mocks; + + protected virtual MockRepository Mocks + { + get { return mocks; } + } + + [SetUp] + protected virtual void SetUp() + { + mocks = new MockRepository(); + } + + [TearDown] + protected virtual void TearDown() + { + mocks = null; + } + + protected virtual void ReplayAll() + { + Mocks.ReplayAll(); + } + + protected virtual void VerifyAll() + { + try + { + Mocks.VerifyAll(); + } + catch (InvalidOperationException ex) + { + Debug.Print("InvalidOperationException thrown: {0}", ex.Message); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/App.config b/tests/ServiceStack.Logging.Tests/UnitTests/App.config new file mode 100644 index 00000000000..89f77113d77 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/App.config @@ -0,0 +1,82 @@ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/DebugLoggerTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/DebugLoggerTests.cs new file mode 100644 index 00000000000..e07c6cd08f4 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/DebugLoggerTests.cs @@ -0,0 +1,52 @@ +#if FALSE +using System; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class DebugLoggerTests + { + [Test] + public void Log4NetLoggerTest() + { + ILog log = new DebugLogger(GetType()); + Assert.IsNotNull(log); + + log = new DebugLogger(GetType().Name); + Assert.IsNotNull(log); + } + + [Test] + public void DebugLogger_LoggingTest() + { + string message = "Error Message"; + Exception ex = new Exception(); + string messageFormat = "Message Format: message: {0}, exception: {1}"; + + ILog log = new DebugLogger(GetType()); + Assert.IsNotNull(log); + + log.Debug(message); + log.Debug(message, ex); + log.DebugFormat(messageFormat, messageFormat, ex.Message); + + log.Error(message); + log.Error(message, ex); + log.ErrorFormat(messageFormat, messageFormat, ex.Message); + + log.Fatal(message); + log.Fatal(message, ex); + log.FatalFormat(messageFormat, messageFormat, ex.Message); + + log.Info(message); + log.Info(message, ex); + log.InfoFormat(messageFormat, messageFormat, ex.Message); + + log.Warn(message); + log.Warn(message, ex); + log.WarnFormat(messageFormat, messageFormat, ex.Message); + } + } +} +#endif diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/ElmahInterceptingLoggerTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/ElmahInterceptingLoggerTests.cs new file mode 100644 index 00000000000..0a2772e4801 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/ElmahInterceptingLoggerTests.cs @@ -0,0 +1,65 @@ +using System; +using System.Web; +using NUnit.Framework; +using Rhino.Mocks; +using ServiceStack.Logging.Elmah; +using ServiceStack.Logging.Log4Net; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class ElmahInterceptingLoggerTests + { + [Test] + public void ElmahInterceptingLoggerTest() + { + var wrappedLogger = MockRepository.GenerateStub(); + ILog log = new ElmahInterceptingLogger(wrappedLogger, new HttpApplication()); + Assert.IsNotNull(log); + } + + [Test] + public void ElmahInterceptingLogger_LoggingTest() + { + string message = "Error Message"; + Exception ex = new Exception(); + string messageFormat = "Message Format: message: {0}, exception: {1}"; + + var wrappedLogger = MockRepository.GenerateStub(); + ILog log = new ElmahInterceptingLogger(wrappedLogger, new HttpApplication()); + Assert.IsNotNull(log); + + log.Debug(message); + log.Debug(message, ex); + log.DebugFormat(messageFormat, message, ex.Message); + + log.Error(message); + log.Error(message, ex); + log.ErrorFormat(messageFormat, message, ex.Message); + + log.Fatal(message); + log.Fatal(message, ex); + log.FatalFormat(messageFormat, message, ex.Message); + + log.Info(message); + log.Info(message, ex); + log.InfoFormat(messageFormat, message, ex.Message); + + log.Warn(message); + log.Warn(message, ex); + log.WarnFormat(messageFormat, message, ex.Message); + } + + [Test] + public void Does_log_Log4Net_errors_to_Elmah() + { + var log4NetFactory = new Log4NetFactory(true); + LogManager.LogFactory = new ElmahLogFactory(log4NetFactory, new HttpApplication()); + + var log = LogManager.GetLogger(typeof(ElmahLogFactoryTests)); + log.Error("Error log test"); + + LogManager.LogFactory = null; + } + } +} diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/ElmahLogFactoryTest.cs b/tests/ServiceStack.Logging.Tests/UnitTests/ElmahLogFactoryTest.cs new file mode 100644 index 00000000000..acb19f83a31 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/ElmahLogFactoryTest.cs @@ -0,0 +1,21 @@ +using System; +using System.Web; +using NUnit.Framework; +using ServiceStack.Logging.Elmah; +using ServiceStack.Logging.Log4Net; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class ElmahLogFactoryTests + { + [Test] + public void ElmahLogFactoryTest() + { + ElmahLogFactory factory = new ElmahLogFactory(new Log4NetFactory(), new HttpApplication()); + ILog log = factory.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(log as ElmahInterceptingLogger); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/EventLogFactoryTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/EventLogFactoryTests.cs new file mode 100644 index 00000000000..7ef19d08111 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/EventLogFactoryTests.cs @@ -0,0 +1,24 @@ +using ServiceStack.Logging.EventLog; +using ServiceStack.Logging.Log4Net; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class EventLogFactoryTests + { + [Test] + public void EventLogFactoryTest() + { + EventLogFactory factory = new EventLogFactory("ServiceStack.Logging.Tests", "Application"); + ILog log = factory.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(log as EventLogger); + + factory = new EventLogFactory("ServiceStack.Logging.Tests"); + log = factory.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(log as EventLogger); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/EventLoggerTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/EventLoggerTests.cs new file mode 100644 index 00000000000..f8d1938b1ad --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/EventLoggerTests.cs @@ -0,0 +1,65 @@ +using System; +using ServiceStack.Logging.EventLog; +using ServiceStack.Logging.Log4Net; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class EventLoggerTests + { + [Test] + public void EventLoggerTest() + { + ILog log = new EventLogger("ServiceStack.Logging.Tests", "Application"); + Assert.IsNotNull(log); + } + + [Test] + public void EventLogger_NullLogNameTest() + { + Assert.Throws(() => { + ILog log = new EventLogger(null, "Application"); + }); + } + + [Test] + public void EventLogger_NullSourceNameTest() + { + Assert.Throws(() => { + ILog log = new EventLogger("ServiceStack.Logging.Tests", null); + }); + } + + [Test] + public void EventLogger_LoggingTest() + { + string message = "Error Message"; + Exception ex = new Exception("Exception"); + string messageFormat = "Message Format: message: {0}, exception: {1}"; + + ILog log = new EventLogger("ServiceStack.Logging.Tests", "Application"); + Assert.IsNotNull(log); + + log.Debug(message); + log.Debug(message, ex); + log.DebugFormat(messageFormat, message, ex.Message); + + log.Error(message); + log.Error(message, ex); + log.ErrorFormat(messageFormat, message, ex.Message); + + log.Fatal(message); + log.Fatal(message, ex); + log.FatalFormat(messageFormat, message, ex.Message); + + log.Info(message); + log.Info(message, ex); + log.InfoFormat(messageFormat, message, ex.Message); + + log.Warn(message); + log.Warn(message, ex); + log.WarnFormat(messageFormat, message, ex.Message); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/Log4NetFactoryTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/Log4NetFactoryTests.cs new file mode 100644 index 00000000000..ada235ea8bc --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/Log4NetFactoryTests.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using NUnit.Framework; +using ServiceStack.Logging.Log4Net; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class Log4NetFactoryTests + { + [Test] + public void Log4NetFactoryTest() + { + Log4NetFactory factory = new Log4NetFactory(); + ILog log = factory.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(log as Log4NetLogger); + + factory = new Log4NetFactory(true); + log = factory.GetLogger(GetType().Name); + Assert.IsNotNull(log); + Assert.IsNotNull(log as Log4NetLogger); + } + + [Test] + public void Log4NetFactoryTestWithExistingConfigFile() + { + const string configFile = "log4net.Test.config"; + + // R# Tests stopped copying required files + if (!File.Exists(configFile)) + { + Console.WriteLine($"{configFile} was not copied to {Environment.CurrentDirectory}"); + return; + } + + Assert.IsTrue(File.Exists(configFile), "Test setup failure. Required log4net config file is missing."); + + Log4NetFactory factory = new Log4NetFactory(configFile); + + ILog log = factory.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(log as Log4NetLogger); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/Log4NetLoggerTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/Log4NetLoggerTests.cs new file mode 100644 index 00000000000..33cdee8d2e1 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/Log4NetLoggerTests.cs @@ -0,0 +1,51 @@ +using System; +using ServiceStack.Logging.Log4Net; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class Log4NetLoggerTests + { + [Test] + public void Log4NetLoggerTest() + { + ILog log = new Log4NetLogger(GetType()); + Assert.IsNotNull(log); + + log = new Log4NetLogger(GetType().Name); + Assert.IsNotNull(log); + } + + [Test] + public void Log4NetLogger_LoggingTest() + { + string message = "Error Message"; + Exception ex = new Exception(); + string messageFormat = "Message Format: message: {0}, exception: {1}"; + + ILog log = new Log4NetLogger(GetType()); + Assert.IsNotNull(log); + + log.Debug(message); + log.Debug(message, ex); + log.DebugFormat(messageFormat, message, ex.Message); + + log.Error(message); + log.Error(message, ex); + log.ErrorFormat(messageFormat, message, ex.Message); + + log.Fatal(message); + log.Fatal(message, ex); + log.FatalFormat(messageFormat, message, ex.Message); + + log.Info(message); + log.Info(message, ex); + log.InfoFormat(messageFormat, message, ex.Message); + + log.Warn(message); + log.Warn(message, ex); + log.WarnFormat(messageFormat, message, ex.Message); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/LogManagerTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/LogManagerTests.cs new file mode 100644 index 00000000000..736c5356c56 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/LogManagerTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Rhino.Mocks; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class LogManagerTests : UnitTestBase + { + [Test] + public void LogManager_DefaultTest() + { + ILog log = LogManager.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(LogManager.LogFactory as NullLogFactory); + Assert.IsNotNull(log as NullDebugLogger); + + log = LogManager.GetLogger(GetType().Name); + Assert.IsNotNull(log); + Assert.IsNotNull(LogManager.LogFactory as NullLogFactory); + Assert.IsNotNull(log as NullDebugLogger); + } + + [Test] + public void LogManager_InjectionTest() + { + ILogFactory factory = Mocks.CreateMock(); + Expect.Call(factory.GetLogger(GetType())).Return(Mocks.DynamicMock()); + ReplayAll(); + + LogManager.LogFactory = factory; + ILog log = LogManager.GetLogger(GetType()); + + Assert.IsNotNull(log); + VerifyAll(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/NLogTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/NLogTests.cs new file mode 100644 index 00000000000..b9fafb6f5a3 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/NLogTests.cs @@ -0,0 +1,102 @@ +using System; +using NLog; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class NLogTests + { + [Test] + public void Does_maintain_callsite() + { + try + { + NLog.LogManager.ThrowExceptions = true; // Only use this for unit-tests + var target = new NLog.Targets.MemoryTarget(); + NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target); + Logging.LogManager.LogFactory = new NLogger.NLogFactory(); + var log = ServiceStack.Logging.LogManager.LogFactory.GetLogger(GetType()); + log.InfoFormat("Message"); + log.InfoFormat("Message with Args {0}", "Foo"); + log.Info("Message with Exception", new Exception("Foo Exception")); + Assert.AreEqual(3, target.Logs.Count); + } + finally + { + NLog.Common.InternalLogger.Reset(); + NLog.LogManager.Configuration = null; + } + } + + [Test] + public void PushPropertyTest() + { + try + { + NLog.LogManager.ThrowExceptions = true; // Only use this for unit-tests + var target = new NLog.Targets.MemoryTarget(); + NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target); + Logging.LogManager.LogFactory = new NLogger.NLogFactory(); + var log = Logging.LogManager.LogFactory.GetLogger(GetType()); + using (log.PushProperty("Hello", "World")) + { + log.InfoFormat("Message"); + } + Assert.AreEqual(1, target.Logs.Count); + } + finally + { + NLog.Common.InternalLogger.Reset(); + NLog.LogManager.Configuration = null; + } + } + + [Test] + public void CaptureSingleParameterExceptionTest() + { + try + { + NLog.LogManager.ThrowExceptions = true; // Only use this for unit-tests + var target = new NLog.Targets.DebugTarget() { Layout = "${exception:format=message}" }; + NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Trace); + Logging.LogManager.LogFactory = new NLogger.NLogFactory(); + var log = Logging.LogManager.LogFactory.GetLogger(GetType()); + log.Debug(new ApplicationException("Debug")); + Assert.AreEqual("Debug", target.LastMessage); + log.Info(new ApplicationException("Info")); + Assert.AreEqual("Info", target.LastMessage); + log.Warn(new ApplicationException("Warn")); + Assert.AreEqual("Warn", target.LastMessage); + log.Error(new ApplicationException("Error")); + Assert.AreEqual("Error", target.LastMessage); + log.Fatal(new ApplicationException("Fatal")); + Assert.AreEqual("Fatal", target.LastMessage); + } + finally + { + NLog.Common.InternalLogger.Reset(); + NLog.LogManager.Configuration = null; + } + } + + [Test] + public void Can_call_method_using_NLog_concrete_providers() + { + Logging.LogManager.LogFactory = new NLogger.NLogFactory(); + + var instance = new NLogExample(); + instance.Method(); + } + } + + public class NLogExample + { + public static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + public void Method() + { + logger.Log(LogLevel.Debug, "Method called"); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/SerilogFactoryTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/SerilogFactoryTests.cs new file mode 100644 index 00000000000..345c74dbcdf --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/SerilogFactoryTests.cs @@ -0,0 +1,18 @@ +using NUnit.Framework; +using ServiceStack.Logging.Serilog; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + [TestFixture] + public class SerilogFactoryTests + { + [Test] + public void Instantiation() + { + var factory = new SerilogFactory(); + var log = factory.GetLogger(GetType()); + Assert.IsNotNull(log); + Assert.IsNotNull(log as SerilogLogger); + } + } +} diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/SerilogLoggerTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/SerilogLoggerTests.cs new file mode 100644 index 00000000000..9c14033e49c --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/SerilogLoggerTests.cs @@ -0,0 +1,115 @@ +using System; +using NUnit.Framework; +using ServiceStack.Logging.Serilog; +using global::Serilog; +using ServiceStack.Logging.Tests.UseCases; +using ServiceStack.Text; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + using System.Collections.Generic; + using System.Linq; + using global::Serilog.Core; + using global::Serilog.Events; + + [TestFixture] + public class SerilogLoggerTests + { + [Test] + public void Instantiation() + { + var log = new SerilogLogger(GetType()); + Assert.IsNotNull(log); + } + + [Test] + public void Logging() + { + const string message = "Error Message"; + const string messageFormat = "Message Format: message: {0}, exception: {1}"; + var ex = new Exception(); + + var log = new SerilogLogger(GetType()); + Assert.IsNotNull(log); + + log.Debug(message); + log.Debug(message, ex); + log.DebugFormat(messageFormat, message, ex.Message); + log.Debug(ex, messageFormat, messageFormat, ex); + + log.Error(message); + log.Error(message, ex); + log.ErrorFormat(messageFormat, message, ex.Message); + log.Error(ex, messageFormat, messageFormat, ex); + + log.Fatal(message); + log.Fatal(message, ex); + log.FatalFormat(messageFormat, message, ex.Message); + log.Fatal(ex, messageFormat, messageFormat, ex); + + log.Info(message); + log.Info(message, ex); + log.InfoFormat(messageFormat, message, ex.Message); + log.Info(ex, messageFormat, messageFormat, ex); + + log.Warn(message); + log.Warn(message, ex); + log.WarnFormat(messageFormat, message, ex.Message); + log.Warn(ex, messageFormat, messageFormat, ex); + } + + [Test] + public void ForContextAddingPropertiesTests() + { + var dummySink = new DummySink(); + var log = new SerilogLogger(new LoggerConfiguration().WriteTo.Sink(dummySink).CreateLogger()); + + var messageTemplate = "Testing adding {prop2} props"; + log.ForContext("prop", "value").InfoFormat(messageTemplate, "awesome"); + Log.CloseAndFlush(); + + var result = dummySink.Events.SingleOrDefault(); + + Assert.NotNull(result); + Assert.AreEqual(LogEventLevel.Information, result.Level); + Assert.AreEqual(messageTemplate, result.MessageTemplate.Text); + Assert.True(result.Properties.ContainsKey("prop")); + Assert.AreEqual("\"value\"", result.Properties["prop"].ToString()); + Assert.True(result.Properties.ContainsKey("prop2")); + Assert.AreEqual("\"awesome\"", result.Properties["prop2"].ToString()); + } + + [Test] + public void PushPropertyTests() + { + var dummySink = new DummySink(); + LogManager.LogFactory = new SerilogFactory(new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Sink(dummySink) + .CreateLogger()); + + var log = LogManager.GetLogger(typeof(SerilogLoggerTests)); + + using (log.PushProperty("A", "1")) + using (log.PushProperty("B", "2")) + { + log.Info("log entry"); + } + + var result = dummySink.Events[0]; + Assert.That(result.Properties.Any(x => x.Key == "A")); + Assert.That(result.Properties.Any(x => x.Key == "B")); + } + + } + + internal class DummySink : ILogEventSink + { + public void Emit(LogEvent logEvent) + { + Events.Add(logEvent); + } + + public List Events { get; } = new List(); + } +} diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/SlackLogFactoryTests.cs b/tests/ServiceStack.Logging.Tests/UnitTests/SlackLogFactoryTests.cs new file mode 100644 index 00000000000..05e8204c12c --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/SlackLogFactoryTests.cs @@ -0,0 +1,237 @@ +//Requires ServiceStack deps +#if FALSE +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Logging.Slack; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + public class TestAppHost : AppSelfHostBase + { + public static Action AssertCallback = (req) => { }; + + public TestAppHost() + : base("TestSlackHost", typeof(TestAppHost).Assembly) + { + + } + + public class SlackLoggingData + { + public string Channel { get; set; } + public string Text { get; set; } + public string Username { get; set; } + public string IconEmoji { get; set; } + } + + public override void Configure(Container container) + { + + } + + [Route("/testing")] + public class SlackMessage : SlackLoggingData { } + + public class SlackTestService : Service + { + public void Any(SlackMessage request) + { + TestAppHost.AssertCallback(request); + } + } + } + + [TestFixture] + public class SlackLogFactoryTests + { + readonly AppSelfHostBase testAppHost = new TestAppHost(); + + [OneTimeSetUp] + public void SetUp() + { + testAppHost.Init().Start("http://localhost:22334/"); + } + + [Test] + public void CanLogWithoutChannel() + { + LogManager.LogFactory = new SlackLogFactory("http://localhost:22334/testing"); + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo(null)); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Error("This is a test"); + // Log is async HTTP request + Thread.Sleep(10); + } + + [Test] + public void CanLogWithDefaultChannel() + { + LogManager.LogFactory = new SlackLogFactory("http://localhost:22334/testing") + { + DefaultChannel = "Testing" + }; + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo("Testing")); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Error("This is a test"); + // Log is async HTTP request + Thread.Sleep(10); + } + + [Test] + public void CanLogWithTypeSpecificChannels() + { + LogManager.LogFactory = new SlackLogFactory("http://localhost:22334/testing", true) + { + DefaultChannel = "Testing", + ErrorChannel = "ERROR", + InfoChannel = "INFO", + WarnChannel = "WARN", + DebugChannel = "DEBUG", + FatalChannel = "FATAL" + }; + //ERROR + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo("ERROR")); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Error("This is a test"); + + //FATAL + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo("FATAL")); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Fatal("This is a test"); + + //WARN + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo("WARN")); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Warn("This is a test"); + + //INFO + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo("INFO")); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Info("This is a test"); + + //DEBUG + TestAppHost.AssertCallback = message => + { + Assert.That(message.Channel, Is.EqualTo("DEBUG")); + Assert.That(message.Text, Is.EqualTo("This is a test")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Debug("This is a test"); + // Log is async HTTP request + Thread.Sleep(10); + } + + [Test] + public void DebugNotUsedByDefault() + { + LogManager.LogFactory = new SlackLogFactory("http://localhost:22334/testing"); + bool assertNeverFired = true; + TestAppHost.AssertCallback = message => assertNeverFired = false; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Debug("This is a test."); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).DebugFormat("This is a test. {0}", 1); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Debug("This is a test.", new ArgumentException()); + Thread.Sleep(200); + Assert.That(assertNeverFired, Is.EqualTo(true)); + Assert.That(LogManager.LogFactory.GetLogger(typeof(TestAppHost)).IsDebugEnabled, Is.EqualTo(false)); + } + + [Test] + public void ExceptionsAreLoggedWhenThrown() + { + LogManager.LogFactory = new SlackLogFactory("http://localhost:22334/testing", true) + { + DefaultChannel = "Testing", + ErrorChannel = "ERROR", + InfoChannel = "INFO", + WarnChannel = "WARN", + DebugChannel = "DEBUG" + }; + //ERROR + TestAppHost.AssertCallback = message => + { + Assert.That(message.Text, Is.EqualTo( + "This is a test\nMessage: Foo is null\r\nParameter name: Foo\nSource: \nTarget site: \nStack trace: \n")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Error("This is a test", new ArgumentNullException("Foo", "Foo is null")); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Warn("This is a test", new ArgumentNullException("Foo", "Foo is null")); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Info("This is a test", new ArgumentNullException("Foo", "Foo is null")); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Fatal("This is a test", new ArgumentNullException("Foo", "Foo is null")); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)).Debug("This is a test", new ArgumentNullException("Foo", "Foo is null")); + Thread.Sleep(10); + } + + [Test] + public void FormatLoggingCorrectlyLogs() + { + LogManager.LogFactory = new SlackLogFactory("http://localhost:22334/testing", true) + { + DefaultChannel = "Testing", + ErrorChannel = "ERROR", + InfoChannel = "INFO", + WarnChannel = "WARN", + DebugChannel = "DEBUG" + }; + //ERROR + TestAppHost.AssertCallback = message => + { + Assert.That(message.Text, Is.EqualTo( + "Hello one, two, three, four")); + }; + LogManager.LogFactory.GetLogger(typeof(TestAppHost)) + .ErrorFormat("Hello {0}, {1}, {2}, {3}", "one", "two", "three", "four"); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)) + .FatalFormat("Hello {0}, {1}, {2}, {3}", "one", "two", "three", "four"); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)) + .WarnFormat("Hello {0}, {1}, {2}, {3}", "one", "two", "three", "four"); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)) + .InfoFormat("Hello {0}, {1}, {2}, {3}", "one", "two", "three", "four"); + LogManager.LogFactory.GetLogger(typeof(TestAppHost)) + .DebugFormat("Hello {0}, {1}, {2}, {3}", "one", "two", "three", "four"); + Thread.Sleep(10); + } + + [Ignore("Call live slack team")] + [Test] + public void LogToSlackTest() + { + var url = new AppSettings().GetString("SlackUrl"); + LogManager.LogFactory = new SlackLogFactory(url, true); + var logger = LogManager.LogFactory.GetLogger(typeof(TestAppHost)); + logger.Debug("Hello slack\nThis is a message from NUint tests."); + + LogManager.LogFactory = new SlackLogFactory(url, true) + { + BotUsername = "Log'O'Bot", + IconEmoji = ":ghost:", + FatalChannel = "logs-other", + }; + + var logger2 = LogManager.LogFactory.GetLogger(typeof(TestAppHost)); + logger2.Fatal("Hello slack\nThis is a message from NUint tests. 111"); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UnitTests/UnitTestBase.cs b/tests/ServiceStack.Logging.Tests/UnitTests/UnitTestBase.cs new file mode 100644 index 00000000000..0f544313ea9 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UnitTests/UnitTestBase.cs @@ -0,0 +1,9 @@ +using ServiceStack.Logging.Tests.Support; + +namespace ServiceStack.Logging.Tests.UnitTests +{ + public class UnitTestBase : TestBase + { + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UseCases/UseCaseBase.cs b/tests/ServiceStack.Logging.Tests/UseCases/UseCaseBase.cs new file mode 100644 index 00000000000..7a0e77cb8ce --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UseCases/UseCaseBase.cs @@ -0,0 +1,10 @@ +using ServiceStack.Logging.Tests.Support; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UseCases +{ + public class UseCaseBase : TestBase + { + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UseCases/UseCaseSlack.cs b/tests/ServiceStack.Logging.Tests/UseCases/UseCaseSlack.cs new file mode 100644 index 00000000000..ca45c0026f4 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UseCases/UseCaseSlack.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Logging.Slack; + +namespace ServiceStack.Logging.Tests.UseCases +{ + [TestFixture] + public class UseCaseSlack : UseCaseBase + { + public void SlackLogUseCase() + { + LogManager.LogFactory = new SlackLogFactory("{GeneratedSlackUrlFromCreatingIncomingWebhook}", debugEnabled:true) + { + //Alternate default channel than one specified when creating Incoming Webhook. + DefaultChannel = "other-default-channel", + //Custom channel for Fatal logs. Warn, Info etc will fallback to DefaultChannel or + //channel specified when Incoming Webhook was created. + FatalChannel = "more-grog-logs", + //Custom bot username other than default + BotUsername = "Guybrush Threepwood", + //Custom channel prefix can be provided to help filter logs from different users or environments. + ChannelPrefix = System.Security.Principal.WindowsIdentity.GetCurrent().Name + }; + ILog log = LogManager.GetLogger(GetType()); + + log.Debug("Start Logging..."); + } + + public void SlackFromAppConfig() + { + IAppSettings appSettings = null; // Get from ServiceStack core library. + // AppSettings is loaded from App/Web.config files and can populate all of the settings for the SlackLogFactory + // Keys prefix from app.config and web.config appSettings is "ServiceStack.Logging.Slack.{0}". + LogManager.LogFactory = new SlackLogFactory(appSettings); + ILog log = LogManager.GetLogger(GetType()); + + log.Debug("Start Logging..."); + } + } +} diff --git a/tests/ServiceStack.Logging.Tests/UseCases/UsingEventLog.cs b/tests/ServiceStack.Logging.Tests/UseCases/UsingEventLog.cs new file mode 100644 index 00000000000..8fd40098e02 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UseCases/UsingEventLog.cs @@ -0,0 +1,19 @@ +using ServiceStack.Logging.EventLog; +using ServiceStack.Logging.Log4Net; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UseCases +{ + [TestFixture] + public class UsingEventLog + { + [Test] + public void EventLogUseCase() + { + LogManager.LogFactory = new EventLogFactory("ServiceStack.Logging.Tests", "Application"); + ILog log = LogManager.GetLogger(GetType()); + + log.Debug("Start Logging..."); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UseCases/UsingLog4Net.cs b/tests/ServiceStack.Logging.Tests/UseCases/UsingLog4Net.cs new file mode 100644 index 00000000000..ca220998dca --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UseCases/UsingLog4Net.cs @@ -0,0 +1,31 @@ +using ServiceStack.Logging.Log4Net; +using NUnit.Framework; + +namespace ServiceStack.Logging.Tests.UseCases +{ + [TestFixture] + public class UsingLog4Net + { + [Test] + public void Log4NetUseCase() + { + LogManager.LogFactory = new Log4NetFactory(); + ILog log = LogManager.GetLogger(GetType()); + + log.Debug("Debug Event Log Entry."); + log.Warn("Warning Event Log Entry."); + } + + [Test] + public void Log4NetUseCasePushProperty() + { + LogManager.LogFactory = new Log4NetFactory(); + ILog log = LogManager.GetLogger(GetType()); + + using (log.PushProperty("Hello", "World")) + { + log.Warn("Warning Event Log Entry."); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/UseCases/UsingSerilog.cs b/tests/ServiceStack.Logging.Tests/UseCases/UsingSerilog.cs new file mode 100644 index 00000000000..70adf885669 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/UseCases/UsingSerilog.cs @@ -0,0 +1,70 @@ +using System; +using NUnit.Framework; +using Serilog; +using Serilog.Configuration; +using Serilog.Core; +using Serilog.Events; +using ServiceStack.Logging.Serilog; + +namespace ServiceStack.Logging.Tests.UseCases +{ + [TestFixture] + public class UsingSerilog + { + private void TestLog() + { + var log = LogManager.GetLogger(GetType()); + + log.Debug("Debug Event Log Entry."); + log.Info("Info Event Log Entry."); + log.Warn("Warning Event Log Entry."); + log.Error("Error Event Log Entry."); + log.Fatal("Fatal Event Log Entry."); + } + + [Test] + public void Use_default_SerilogFactory() + { + LogManager.LogFactory = new SerilogFactory(); + TestLog(); + } + + + + [Test] + public void Use_Serilog_with_custom_configuration_and_sink() + { + LogManager.LogFactory = new SerilogFactory(new LoggerConfiguration() + .WriteTo.MySink() + .CreateLogger()); + + TestLog(); + } + } + + public class MySink : ILogEventSink + { + private readonly IFormatProvider formatProvider; + + public MySink(IFormatProvider formatProvider) + { + this.formatProvider = formatProvider; + } + + public void Emit(LogEvent logEvent) + { + var message = logEvent.RenderMessage(formatProvider); + Console.WriteLine(DateTimeOffset.Now + " " + message); + } + } + + public static class MySinkExtensions + { + public static LoggerConfiguration MySink( + this LoggerSinkConfiguration loggerConfiguration, + IFormatProvider formatProvider = null) + { + return loggerConfiguration.Sink(new MySink(formatProvider)); + } + } +} diff --git a/tests/ServiceStack.Logging.Tests/app.config b/tests/ServiceStack.Logging.Tests/app.config new file mode 100644 index 00000000000..4911ea931f1 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/app.config @@ -0,0 +1,65 @@ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.Logging.Tests/entlib5.test.config b/tests/ServiceStack.Logging.Tests/entlib5.test.config new file mode 100644 index 00000000000..305dcc5c489 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/entlib5.test.config @@ -0,0 +1,82 @@ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/log4net.Test.config b/tests/ServiceStack.Logging.Tests/log4net.Test.config new file mode 100644 index 00000000000..a6a98df09a1 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/log4net.Test.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Logging.Tests/packages.config b/tests/ServiceStack.Logging.Tests/packages.config new file mode 100644 index 00000000000..c17b4645f40 --- /dev/null +++ b/tests/ServiceStack.Logging.Tests/packages.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Messaging.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Messaging.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index defed30b715..00000000000 --- a/tests/ServiceStack.Messaging.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.Messaging.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("ServiceStack.Messaging.Tests")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("b45c3b05-2cdc-486e-ae6d-fd76f7f48129")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.Messaging.Tests/ServiceStack.Messaging.Tests.csproj b/tests/ServiceStack.Messaging.Tests/ServiceStack.Messaging.Tests.csproj deleted file mode 100644 index 90cffcb0276..00000000000 --- a/tests/ServiceStack.Messaging.Tests/ServiceStack.Messaging.Tests.csproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {CA20892F-3FD7-4ACD-8506-B50C30CA4DE1} - Library - Properties - ServiceStack.Messaging.Tests - ServiceStack.Messaging.Tests - v3.5 - 512 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - True - full - False - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - True - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - True - bin\STATIC_ONLY NO_EXPRESSIONS\ - DEBUG;TRACE - full - AnyCPU - prompt - 4 - False - AllRules.ruleset - - - True - bin\MonoTouch\ - DEBUG;TRACE - full - AnyCPU - prompt - 4 - False - AllRules.ruleset - - - - ..\..\lib\ServiceStack.Redis.dll - - - - 3.5 - - - 3.0 - - - 3.5 - - - 3.5 - - - - - ..\..\lib\ServiceStack.Text.dll - - - ..\..\lib\tests\nunit.framework.dll - - - - - - - - - - - - - - - {982416DB-C143-4028-A0C3-CF41892D18D3} - ServiceStack.Common - - - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} - ServiceStack.Interfaces - - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface - - - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} - ServiceStack - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Messaging.Tests/Services/AlwaysFailService.cs b/tests/ServiceStack.Messaging.Tests/Services/AlwaysFailService.cs deleted file mode 100644 index 20befb1064a..00000000000 --- a/tests/ServiceStack.Messaging.Tests/Services/AlwaysFailService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.Messaging.Tests.Services -{ - [DataContract] - public class AlwaysFail - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class AlwaysFailResponse - { - [DataMember] - public string Result { get; set; } - } - - public class AlwaysFailService - : AsyncServiceBase - { - public int TimesCalled { get; set; } - public string Result { get; set; } - - protected override object Run(AlwaysFail request) - { - this.TimesCalled++; - - throw new NotSupportedException("This service always fails"); - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.Messaging.Tests/Services/GreetService.cs b/tests/ServiceStack.Messaging.Tests/Services/GreetService.cs deleted file mode 100644 index 5bbb7b2d8d0..00000000000 --- a/tests/ServiceStack.Messaging.Tests/Services/GreetService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.Messaging.Tests.Services -{ - [DataContract] - public class Greet - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class GreetResponse - { - [DataMember] - public string Result { get; set; } - } - - public class GreetService - : AsyncServiceBase - { - public int TimesCalled { get; set; } - public string Result { get; set; } - - protected override object Run(Greet request) - { - this.TimesCalled++; - - Result = "Hello, " + request.Name; - return new GreetResponse { Result = Result }; - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.Messaging.Tests/Services/UnRetryableFail.cs b/tests/ServiceStack.Messaging.Tests/Services/UnRetryableFail.cs deleted file mode 100644 index 50ab53acf6b..00000000000 --- a/tests/ServiceStack.Messaging.Tests/Services/UnRetryableFail.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.Messaging.Tests.Services -{ - [DataContract] - public class UnRetryableFail - { - [DataMember] - public string Name { get; set; } - } - - [DataContract] - public class UnRetryableFailResponse - { - [DataMember] - public string Result { get; set; } - } - - public class UnRetryableFailService - : AsyncServiceBase - { - public int TimesCalled { get; set; } - public string Result { get; set; } - - protected override object Run(UnRetryableFail request) - { - this.TimesCalled++; - - throw new UnRetryableMessagingException( - "This request should not get retried", - new NotSupportedException("This service always fails")); - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.Messaging.Tests/TransientServiceMessagingTests.cs b/tests/ServiceStack.Messaging.Tests/TransientServiceMessagingTests.cs deleted file mode 100644 index ff543920326..00000000000 --- a/tests/ServiceStack.Messaging.Tests/TransientServiceMessagingTests.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Funq; -using NUnit.Framework; -using ServiceStack.Messaging.Tests.Services; - -namespace ServiceStack.Messaging.Tests -{ - public abstract class TransientServiceMessagingTests - : MessagingHostTestBase - { - public override void OnBeforeEachTest() - { - base.OnBeforeEachTest(); - - Container.Register(c => new GreetService { - MessageFactory = c.Resolve() - }); - Container.Register(c => new AlwaysFailService { - MessageFactory = c.Resolve() - }); - Container.Register(c => new UnRetryableFailService { - MessageFactory = c.Resolve() - }); - } - - [Test] - public void Normal_GreetService_client_and_server_example() - { - var service = Container.Resolve(); - using (var serviceHost = CreateMessagingService()) - { - serviceHost.RegisterHandler(service.ExecuteAsync); - - serviceHost.Start(); - - using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) - { - client.Publish(new Greet { Name = "World!" }); - } - - Assert.That(service.Result, Is.EqualTo("Hello, World!")); - Assert.That(service.TimesCalled, Is.EqualTo(1)); - } - } - - [Test] - public void Publish_before_starting_host_GreetService_client_and_server_example() - { - var service = Container.Resolve(); - using (var serviceHost = CreateMessagingService()) - { - using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) - { - client.Publish(new Greet { Name = "World!" }); - } - - serviceHost.RegisterHandler(service.ExecuteAsync); - serviceHost.Start(); - - Assert.That(service.Result, Is.EqualTo("Hello, World!")); - Assert.That(service.TimesCalled, Is.EqualTo(1)); - } - } - - [Test] - public void AlwaysFailsService_ends_up_in_dlq_after_3_attempts() - { - var service = Container.Resolve(); - var request = new AlwaysFail { Name = "World!" }; - using (var serviceHost = CreateMessagingService()) - { - using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) - { - client.Publish(request); - } - - serviceHost.RegisterHandler(service.ExecuteAsync); - serviceHost.Start(); - - Assert.That(service.Result, Is.Null); - Assert.That(service.TimesCalled, Is.EqualTo(3)); - - using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) - { - var dlqMessage = client.GetAsync(QueueNames.Dlq) - .ToMessage(); - - Assert.That(dlqMessage, Is.Not.Null); - Assert.That(dlqMessage.GetBody().Name, Is.EqualTo(request.Name)); - } - } - } - - [Test] - public void UnRetryableFailService_ends_up_in_dlq_after_1_attempt() - { - var service = Container.Resolve(); - var request = new UnRetryableFail { Name = "World!" }; - using (var serviceHost = CreateMessagingService()) - { - using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) - { - client.Publish(request); - } - - serviceHost.RegisterHandler(service.ExecuteAsync); - serviceHost.Start(); - - Assert.That(service.Result, Is.Null); - Assert.That(service.TimesCalled, Is.EqualTo(1)); - - using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) - { - var dlqMessage = client.GetAsync(QueueNames.Dlq) - .ToMessage(); - - Assert.That(dlqMessage, Is.Not.Null); - Assert.That(dlqMessage.GetBody().Name, Is.EqualTo(request.Name)); - } - } - } - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Mvc.Stubs.Tests/ExternalController.cs b/tests/ServiceStack.Mvc.Stubs.Tests/ExternalController.cs deleted file mode 100644 index 72cd3babdbb..00000000000 --- a/tests/ServiceStack.Mvc.Stubs.Tests/ExternalController.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Web.Mvc; - -namespace ServiceStack.Mvc.Stubs.Tests -{ - public class ExternalController : Controller - { - // consumed by ServiceStack.Mvc.Tests to test discovery of IController types in external assemblies - // see https://github.com/ServiceStack/ServiceStack/issues/599 - } -} diff --git a/tests/ServiceStack.Mvc.Stubs.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Mvc.Stubs.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 6d51bc62df8..00000000000 --- a/tests/ServiceStack.Mvc.Stubs.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.Mvc.Stubs.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceStack.Mvc.Stubs.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("1363aecf-4bd5-4935-8976-0094c27f1e09")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.Mvc.Stubs.Tests/ServiceStack.Mvc.Stubs.Tests.csproj b/tests/ServiceStack.Mvc.Stubs.Tests/ServiceStack.Mvc.Stubs.Tests.csproj deleted file mode 100644 index bb0584fd6d5..00000000000 --- a/tests/ServiceStack.Mvc.Stubs.Tests/ServiceStack.Mvc.Stubs.Tests.csproj +++ /dev/null @@ -1,63 +0,0 @@ - - - - - Debug - AnyCPU - {60E9BDF4-38C8-4EEC-AB69-7128C6A35601} - Library - Properties - ServiceStack.Mvc.Stubs.Tests - ServiceStack.Mvc.Stubs.Tests - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - False - ..\..\lib\System.Web.Mvc.dll - - - - - - - - - - - - - - {680a1709-25eb-4d52-a87f-ee03ffd94baa} - ServiceStack - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Mvc.Tests/FunqControllerFactoryTests.cs b/tests/ServiceStack.Mvc.Tests/FunqControllerFactoryTests.cs deleted file mode 100644 index 6cad214d5ea..00000000000 --- a/tests/ServiceStack.Mvc.Tests/FunqControllerFactoryTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using NUnit.Framework; -using Funq; -using ServiceStack.Mvc.Stubs.Tests; -using ServiceStack.Mvc.Tests.Stubs; - -namespace ServiceStack.Mvc.Tests -{ - [TestFixture] - public class FunqControllerFactoryTests - { - [Test] - public void ConstructFactoryPopulatesLocalControllerByDefault() - { - var container = new Container(); - var factory = new FunqControllerFactory(container); - var testController = container.Resolve(); - Assert.That(testController, Is.Not.Null); - } - - [Test] - public void ConstructFactoryPopulatesLocalControllerAndExternalControllerByDefault() - { - var container = new Container(); - var factory = new FunqControllerFactory(container, typeof(ExternalController).Assembly); - - // test we can still resolve the local one (by default) - var testController = container.Resolve(); - Assert.That(testController, Is.Not.Null); - - // test we can resolve the external controller (via params assembly) - var externalController = container.Resolve(); - Assert.That(externalController, Is.Not.Null); - } - } -} diff --git a/tests/ServiceStack.Mvc.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Mvc.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 42d8c996333..00000000000 --- a/tests/ServiceStack.Mvc.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.Mvc.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceStack.Mvc.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("3c84c5a1-e573-4c12-b8f6-a3512b25bab4")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.Mvc.Tests/ServiceStack.Mvc.Tests.csproj b/tests/ServiceStack.Mvc.Tests/ServiceStack.Mvc.Tests.csproj deleted file mode 100644 index b69705ee709..00000000000 --- a/tests/ServiceStack.Mvc.Tests/ServiceStack.Mvc.Tests.csproj +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Debug - AnyCPU - {F89B1845-5B1E-4EF2-873F-5FFDBF56E365} - Library - Properties - ServiceStack.Mvc.Tests - ServiceStack.Mvc.Tests - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\lib\tests\nunit.framework.dll - - - False - ..\..\lib\tests\ServiceStack.Mvc.Stubs.Tests.dll - - - - - - False - ..\..\lib\System.Web.Mvc.dll - - - - - - - - - - - - - - - {672f2dfe-4ee8-498b-b449-23e9e7f6961c} - ServiceStack.FluentValidation.Mvc3 - - - {680a1709-25eb-4d52-a87f-ee03ffd94baa} - ServiceStack - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Mvc.Tests/Stubs/LocalController.cs b/tests/ServiceStack.Mvc.Tests/Stubs/LocalController.cs deleted file mode 100644 index 3e842dfb775..00000000000 --- a/tests/ServiceStack.Mvc.Tests/Stubs/LocalController.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Web.Mvc; - -namespace ServiceStack.Mvc.Tests.Stubs -{ - public class LocalController : Controller - { - } -} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/AllTypesTests.cs b/tests/ServiceStack.OpenApi.Tests/AllTypesTests.cs new file mode 100644 index 00000000000..abe265ad26e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/AllTypesTests.cs @@ -0,0 +1,94 @@ +using AutorestClient; +using AutorestClient.Models; +using NUnit.Framework; +using ServiceStack.OpenApi.Tests.Host; +using System; +using System.Threading; + +namespace ServiceStack.OpenApi.Tests +{ + [TestFixture] + class AllTypesTests : GeneratedClientTestBase + { + [Ignore("Debug Test"), Test] + public void Sleep() + { + Thread.Sleep(1000000); + } + + + [Test] + public void Can_post_all_types() + { + var dto = new HelloAllTypes + { + Name = "Hello", + AllTypes = DtoHelper.GetAllTypes(), + AllCollectionTypes = DtoHelper.GetAllCollectionTypes() + }; + + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var result = client.HelloAllTypes.Post("123", null, null, dto); + } + } + + [Test] + public void Can_get_all_types() + { + var dto = new HelloAllTypes + { + Name = "Hello", + AllTypes = DtoHelper.GetAllTypes(), + AllCollectionTypes = DtoHelper.GetAllCollectionTypes() + }; + + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var result = client.HelloAllTypes.Get("123", dto.AllTypes.ToJsv(), null); + } + } + + [Test] + public void Can_get_all_types_with_result() + { + var dto = new HelloAllTypesWithResult + { + Name = "Hello", + AllTypes = DtoHelper.GetAllTypes(), + AllCollectionTypes = DtoHelper.GetAllCollectionTypes() + }; + + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var at = dto.AllTypes.ToJsv(); + + var result = client.HelloAllTypesWithResult.Get(dto.Name, dto.AllTypes.ToJsv(), dto.AllCollectionTypes.ToJsv()); + + Assert.That(result.Result, Is.EqualTo(dto.Name)); + DtoHelper.AssertAllTypes(result.AllTypes, dto.AllTypes); + DtoHelper.AssertAllCollectionTypes(result.AllCollectionTypes, dto.AllCollectionTypes); + } + } + + [Test] + public void Can_post_all_types_with_result() + { + var dto = new HelloAllTypesWithResult + { + Name = "Hello", + AllTypes = DtoHelper.GetAllTypes(), + AllCollectionTypes = DtoHelper.GetAllCollectionTypes() + }; + + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var result = client.HelloAllTypesWithResult.Post(body: dto); + + Assert.That(result.Result, Is.EqualTo(dto.Name)); + DtoHelper.AssertAllTypes(result.AllTypes, dto.AllTypes); + DtoHelper.AssertAllCollectionTypes(result.AllCollectionTypes, dto.AllCollectionTypes); + } + } + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/AnnotatedPropertiesTests.cs b/tests/ServiceStack.OpenApi.Tests/AnnotatedPropertiesTests.cs new file mode 100644 index 00000000000..2d0ffb7dabc --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/AnnotatedPropertiesTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Remoting; +using System.Text; +using System.Threading.Tasks; +using AutorestClient; +using NUnit.Framework; +using ServiceStack.OpenApi.Tests.Host; +using ServiceStack.OpenApi.Tests.Services; + +namespace ServiceStack.OpenApi.Tests +{ + [TestFixture] + class AnnotatedPropertiesTests : GeneratedClientTestBase + { + [Test] + public void Can_get_annotated_service_with_array_enum() + { + var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri)); + + var dto = new GetMovie(){Id = 1, Includes = new[] {"Genres", "Releases" } }; + + var result = client.GetMovieId.Post(dto.Id, dto.Includes); + + Assert.That(result.Includes, Is.EquivalentTo(dto.Includes)); + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/App.config b/tests/ServiceStack.OpenApi.Tests/App.config new file mode 100644 index 00000000000..8f5920aa3e9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/App.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.OpenApi.Tests/DtoHelper.cs b/tests/ServiceStack.OpenApi.Tests/DtoHelper.cs new file mode 100644 index 00000000000..04c41351949 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/DtoHelper.cs @@ -0,0 +1,159 @@ +using AutorestClient.Models; +using NUnit.Framework; +using System; +using System.Collections.Generic; + +namespace ServiceStack.OpenApi.Tests +{ + class DtoHelper + { + public static AllTypes GetAllTypes() + { + return new AllTypes + { + ByteProperty = byte.MaxValue, + CharProperty = "n", + DateTimeProperty = DateTime.UtcNow, + DecimalProperty = 100.123456789, + DateTimeOffsetProperty = new DateTimeOffset(DateTime.UtcNow.AddDays(1)).ToString(), + DoubleProperty = 123.45678901, + FloatProperty = 456.312f, + GuidProperty = Guid.NewGuid().ToString(), + Id = 1, + IntProperty = int.MaxValue, + IntStringMap = new Dictionary { { "1", "abc" }, { "2", "bcd" }, { "3", "cde" } }, + KeyValuePairProperty = new KeyValuePairStringString("key1", "value1"), + LongProperty = long.MaxValue, + NullableDateTime = DateTime.UtcNow, + NullableId = 2, + NullableTimeSpan = new TimeSpan(1, 0, 0).ToString(), + TimeSpanProperty = new TimeSpan(2, 1, 3).ToString(), + ShortProperty = short.MaxValue, + StringProperty = "test string", + StringArray = new string[] { "string1", "string2", "string3" }, + StringList = new List() { "string4", "string5", "string6" }, + StringMap = new Dictionary() { { "ab", "abc" }, { "bc", "bcd" }, { "cd", "cde" } }, + SubType = new SubType() { Id = 10, Name = "SubType name" }, + UIntProperty = 123456, + ULongProperty = 1234567, + UShortProperty = UInt16.MaxValue, + }; + } + + public static AllCollectionTypes GetAllCollectionTypes() + { + return new AllCollectionTypes + { + IntArray = new[] { 1, 2, 3, 4 }, + IntList = new List{ 1, 2, 3, 4 }, + PocoArray = new[] { new Poco{ Name = "poco1" }, new Poco{ Name = "poco2" } }, + PocoList = new List{ new Poco{ Name = "poco1" }, new Poco{ Name = "poco2" } }, + PocoLookup = new Dictionary> + { + { "p1", new List{ new Poco{ Name = "poco1" }, new Poco{ Name = "poco2" } }}, + { "p2", new List{ new Poco{ Name = "poco3" }, new Poco{ Name = "poco4" } }} + }, + PocoLookupMap = new Dictionary>>() + { + { "pp1", new List> + { + new Dictionary{ + { "p11", new Poco{ Name = "poco1" } }, + { "p12", new Poco{ Name = "poco2" } } + }, + new Dictionary{ + { "p13", new Poco{ Name = "poco3" } }, + { "p14", new Poco{ Name = "poco4" } } + } + } + }, + { "pp2", new List>() + { + new Dictionary{ + { "p21", new Poco{ Name = "poco1" } }, + { "p22", new Poco{ Name = "poco2" } } + }, + new Dictionary{ + { "p23", new Poco{ Name = "poco3" } }, + { "p24", new Poco{ Name = "poco4" } } + } + } + } + }, + StringArray = new string[] { "string1", "string2" }, + StringList = new List{ "string1", "string2" } + }; + } + + public static void AssertAllTypes(AllTypes actual, AllTypes expected) + { + Assert.That(actual.ByteProperty, Is.EqualTo(expected.ByteProperty)); + Assert.That(actual.CharProperty, Is.EqualTo(expected.CharProperty)); + Assert.That(actual.DateTimeProperty, Is.EqualTo(expected.DateTimeProperty).Within(TimeSpan.FromSeconds(1))); + //Assert.That(actual.DateTimeOffset, Is.EqualTo(expected.DateTimeOffset)); + Assert.That(actual.DecimalProperty, Is.EqualTo(expected.DecimalProperty)); + Assert.That(actual.DoubleProperty, Is.EqualTo(expected.DoubleProperty)); + Assert.That(actual.FloatProperty, Is.EqualTo(expected.FloatProperty).Within(0.0001)); + Assert.That(actual.GuidProperty, Is.EqualTo(expected.GuidProperty.Replace("-", String.Empty))); + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.IntProperty, Is.EqualTo(expected.IntProperty)); + Assert.That(actual.IntStringMap, Is.EquivalentTo(expected.IntStringMap)); + Assert.That(actual.KeyValuePairProperty.Key, Is.EquivalentTo(expected.KeyValuePairProperty.Key)); + Assert.That(actual.KeyValuePairProperty.Value, Is.EquivalentTo(expected.KeyValuePairProperty.Value)); + Assert.That(actual.LongProperty, Is.EqualTo(expected.LongProperty)); + Assert.That(actual.NullableDateTime, Is.EqualTo(expected.NullableDateTime).Within(TimeSpan.FromSeconds(1))); + Assert.That(actual.NullableId, Is.EqualTo(expected.NullableId)); + //Assert.That(actual.NullableTimeSpan, Is.EqualTo(expected.NullableTimeSpan)); + Assert.That(actual.ShortProperty, Is.EqualTo(expected.ShortProperty)); + Assert.That(actual.StringArray, Is.EquivalentTo(expected.StringArray)); + Assert.That(actual.StringList, Is.EquivalentTo(expected.StringList)); + Assert.That(actual.StringMap, Is.EquivalentTo(expected.StringMap)); + Assert.That(actual.StringProperty, Is.EqualTo(expected.StringProperty)); + Assert.That(actual.SubType.Id, Is.EqualTo(expected.SubType.Id)); + Assert.That(actual.SubType.Name, Is.EqualTo(expected.SubType.Name)); + //Assert.That(actual.TimeSpan, Is.EqualTo(expected.TimeSpan)); + Assert.That(actual.UIntProperty, Is.EqualTo(expected.UIntProperty)); + Assert.That(actual.ULongProperty, Is.EqualTo(expected.ULongProperty)); + Assert.That(actual.UShortProperty, Is.EqualTo(expected.UShortProperty)); + } + + public static void AssertAllCollectionTypes(AllCollectionTypes actual, AllCollectionTypes expected) + { + Assert.That(actual.IntArray, Is.EqualTo(expected.IntArray)); + Assert.That(actual.IntList, Is.EqualTo(expected.IntList)); + AssertListPoco(actual.PocoArray, expected.PocoArray); + AssertListPoco(actual.PocoList, expected.PocoList); + + Assert.That(actual.PocoLookup.Count, Is.EqualTo(expected.PocoLookup.Count)); + foreach (var key in actual.PocoLookup.Keys) + AssertListPoco(actual.PocoLookup[key], expected.PocoLookup[key]); + + Assert.That(actual.PocoLookupMap.Count, Is.EqualTo(expected.PocoLookupMap.Count)); + + foreach(var key in actual.PocoLookupMap.Keys) + { + var actualList = actual.PocoLookupMap[key]; + var expectedList = expected.PocoLookupMap[key]; + + Assert.That(actualList.Count, Is.EqualTo(expectedList.Count)); + for(int i = 0; i < actualList.Count; i++) + { + Assert.That(actualList[i].Count, Is.EqualTo(expectedList[i].Count)); + + foreach (var key2 in actualList[i].Keys) + { + Assert.That(actualList[i][key2].Name, Is.EqualTo(expectedList[i][key2].Name)); + } + } + } + } + + public static void AssertListPoco(IList actual, IList expected) + { + Assert.That(actual.Count, Is.EqualTo(expected.Count)); + + for (int i = 0; i < actual.Count; i++) + Assert.That(actual[i].Name, Is.EqualTo(expected[i].Name)); + } + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AllowedAttributesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AllowedAttributesOperations.cs new file mode 100644 index 00000000000..19d8f171af4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AllowedAttributesOperations.cs @@ -0,0 +1,173 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// AllowedAttributesOperations operations. + /// + public partial class AllowedAttributesOperations : IServiceOperations, IAllowedAttributesOperations + { + /// + /// Initializes a new instance of the AllowedAttributesOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public AllowedAttributesOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// AllowedAttributes Description + /// + /// + /// AllowedAttributes Description + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task GetWithHttpMessagesAsync(int aliased, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("aliased", aliased); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "allowed-attributes").ToString(); + List _queryParameters = new List(); + _queryParameters.Add(string.Format("Aliased={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(aliased, Client.SerializationSettings).Trim('"')))); + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if ((int)_statusCode != 400) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AllowedAttributesOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AllowedAttributesOperationsExtensions.cs new file mode 100644 index 00000000000..9fe1cc331e4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AllowedAttributesOperationsExtensions.cs @@ -0,0 +1,52 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for AllowedAttributesOperations. + /// + public static partial class AllowedAttributesOperationsExtensions + { + /// + /// AllowedAttributes Description + /// + /// + /// AllowedAttributes Description + /// + /// + /// The operations group for this extension method. + /// + /// + /// + public static void Get(this IAllowedAttributesOperations operations, int aliased) + { + operations.GetAsync(aliased).GetAwaiter().GetResult(); + } + + /// + /// AllowedAttributes Description + /// + /// + /// AllowedAttributes Description + /// + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IAllowedAttributesOperations operations, int aliased, CancellationToken cancellationToken = default(CancellationToken)) + { + (await operations.GetWithHttpMessagesAsync(aliased, null, cancellationToken).ConfigureAwait(false)).Dispose(); + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AssignRolesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AssignRolesOperations.cs new file mode 100644 index 00000000000..d43c5839ff4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AssignRolesOperations.cs @@ -0,0 +1,635 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// AssignRolesOperations operations. + /// + public partial class AssignRolesOperations : IServiceOperations, IAssignRolesOperations + { + /// + /// Initializes a new instance of the AssignRolesOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public AssignRolesOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "assignroles").ToString(); + List _queryParameters = new List(); + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (permissions != null) + { + _queryParameters.Add(string.Format("Permissions={0}", System.Uri.EscapeDataString(permissions))); + } + if (roles != null) + { + _queryParameters.Add(string.Format("Roles={0}", System.Uri.EscapeDataString(roles))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "assignroles").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "assignroles").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "assignroles").ToString(); + List _queryParameters = new List(); + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (permissions != null) + { + _queryParameters.Add(string.Format("Permissions={0}", System.Uri.EscapeDataString(permissions))); + } + if (roles != null) + { + _queryParameters.Add(string.Format("Roles={0}", System.Uri.EscapeDataString(roles))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AssignRolesOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AssignRolesOperationsExtensions.cs new file mode 100644 index 00000000000..adfece8ce1d --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AssignRolesOperationsExtensions.cs @@ -0,0 +1,161 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for AssignRolesOperations. + /// + public static partial class AssignRolesOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static AssignRolesResponse Get(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string)) + { + return operations.GetAsync(userName, permissions, roles).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(userName, permissions, roles, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AssignRolesResponse Create(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles)) + { + return operations.CreateAsync(userName, permissions, roles, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(userName, permissions, roles, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AssignRolesResponse Post(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles)) + { + return operations.PostAsync(userName, permissions, roles, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(userName, permissions, roles, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static AssignRolesResponse Delete(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string)) + { + return operations.DeleteAsync(userName, permissions, roles).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(userName, permissions, roles, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticate2.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticate2.cs new file mode 100644 index 00000000000..91a7f64b581 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticate2.cs @@ -0,0 +1,935 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Authenticate2 operations. + /// + public partial class Authenticate2 : IServiceOperations, IAuthenticate2 + { + /// + /// Initializes a new instance of the Authenticate2 class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public Authenticate2(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate").ToString(); + List _queryParameters = new List(); + if (provider != null) + { + _queryParameters.Add(string.Format("provider={0}", System.Uri.EscapeDataString(provider))); + } + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate").ToString(); + List _queryParameters = new List(); + if (provider != null) + { + _queryParameters.Add(string.Format("provider={0}", System.Uri.EscapeDataString(provider))); + } + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticate2Extensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticate2Extensions.cs new file mode 100644 index 00000000000..3fb06baa85e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticate2Extensions.cs @@ -0,0 +1,401 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for Authenticate2. + /// + public static partial class Authenticate2Extensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Get(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.GetAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Create(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.CreateAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Post(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.PostAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Delete(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.DeleteAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IAuthenticate2 operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateOperations.cs new file mode 100644 index 00000000000..2b1ec3d08c0 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateOperations.cs @@ -0,0 +1,935 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// AuthenticateOperations operations. + /// + public partial class AuthenticateOperations : IServiceOperations, IAuthenticateOperations + { + /// + /// Initializes a new instance of the AuthenticateOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public AuthenticateOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth").ToString(); + List _queryParameters = new List(); + if (provider != null) + { + _queryParameters.Add(string.Format("provider={0}", System.Uri.EscapeDataString(provider))); + } + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth").ToString(); + List _queryParameters = new List(); + if (provider != null) + { + _queryParameters.Add(string.Format("provider={0}", System.Uri.EscapeDataString(provider))); + } + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateOperationsExtensions.cs new file mode 100644 index 00000000000..2a9c648b044 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateOperationsExtensions.cs @@ -0,0 +1,401 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for AuthenticateOperations. + /// + public static partial class AuthenticateOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Get(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.GetAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Create(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.CreateAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Post(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.PostAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Delete(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.DeleteAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IAuthenticateOperations operations, string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider.cs new file mode 100644 index 00000000000..daa7526331f --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider.cs @@ -0,0 +1,971 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Authenticateprovider operations. + /// + public partial class Authenticateprovider : IServiceOperations, IAuthenticateprovider + { + /// + /// Initializes a new instance of the Authenticateprovider class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public Authenticateprovider(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + List _queryParameters = new List(); + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "auth/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + List _queryParameters = new List(); + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider2.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider2.cs new file mode 100644 index 00000000000..6a204960d46 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider2.cs @@ -0,0 +1,971 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Authenticateprovider2 operations. + /// + public partial class Authenticateprovider2 : IServiceOperations, IAuthenticateprovider2 + { + /// + /// Initializes a new instance of the Authenticateprovider2 class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public Authenticateprovider2(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + List _queryParameters = new List(); + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (provider == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "provider"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("provider", provider); + tracingParameters.Add("state", state); + tracingParameters.Add("oauthToken", oauthToken); + tracingParameters.Add("oauthVerifier", oauthVerifier); + tracingParameters.Add("userName", userName); + tracingParameters.Add("password", password); + tracingParameters.Add("rememberMe", rememberMe); + tracingParameters.Add("continueParameter", continueParameter); + tracingParameters.Add("nonce", nonce); + tracingParameters.Add("uri", uri); + tracingParameters.Add("response", response); + tracingParameters.Add("qop", qop); + tracingParameters.Add("nc", nc); + tracingParameters.Add("cnonce", cnonce); + tracingParameters.Add("useTokenCookie", useTokenCookie); + tracingParameters.Add("accessToken", accessToken); + tracingParameters.Add("accessTokenSecret", accessTokenSecret); + tracingParameters.Add("meta", meta); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "authenticate/{provider}").ToString(); + _url = _url.Replace("{provider}", System.Uri.EscapeDataString(provider)); + List _queryParameters = new List(); + if (state != null) + { + _queryParameters.Add(string.Format("State={0}", System.Uri.EscapeDataString(state))); + } + if (oauthToken != null) + { + _queryParameters.Add(string.Format("oauth_token={0}", System.Uri.EscapeDataString(oauthToken))); + } + if (oauthVerifier != null) + { + _queryParameters.Add(string.Format("oauth_verifier={0}", System.Uri.EscapeDataString(oauthVerifier))); + } + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (password != null) + { + _queryParameters.Add(string.Format("Password={0}", System.Uri.EscapeDataString(password))); + } + if (rememberMe != null) + { + _queryParameters.Add(string.Format("RememberMe={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(rememberMe, Client.SerializationSettings).Trim('"')))); + } + if (continueParameter != null) + { + _queryParameters.Add(string.Format("Continue={0}", System.Uri.EscapeDataString(continueParameter))); + } + if (nonce != null) + { + _queryParameters.Add(string.Format("nonce={0}", System.Uri.EscapeDataString(nonce))); + } + if (uri != null) + { + _queryParameters.Add(string.Format("uri={0}", System.Uri.EscapeDataString(uri))); + } + if (response != null) + { + _queryParameters.Add(string.Format("response={0}", System.Uri.EscapeDataString(response))); + } + if (qop != null) + { + _queryParameters.Add(string.Format("qop={0}", System.Uri.EscapeDataString(qop))); + } + if (nc != null) + { + _queryParameters.Add(string.Format("nc={0}", System.Uri.EscapeDataString(nc))); + } + if (cnonce != null) + { + _queryParameters.Add(string.Format("cnonce={0}", System.Uri.EscapeDataString(cnonce))); + } + if (useTokenCookie != null) + { + _queryParameters.Add(string.Format("UseTokenCookie={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(useTokenCookie, Client.SerializationSettings).Trim('"')))); + } + if (accessToken != null) + { + _queryParameters.Add(string.Format("AccessToken={0}", System.Uri.EscapeDataString(accessToken))); + } + if (accessTokenSecret != null) + { + _queryParameters.Add(string.Format("AccessTokenSecret={0}", System.Uri.EscapeDataString(accessTokenSecret))); + } + if (meta != null) + { + _queryParameters.Add(string.Format("Meta={0}", System.Uri.EscapeDataString(meta))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new AuthenticateResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + AuthenticateResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider2Extensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider2Extensions.cs new file mode 100644 index 00000000000..a1eea4f7f02 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Authenticateprovider2Extensions.cs @@ -0,0 +1,401 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for Authenticateprovider2. + /// + public static partial class Authenticateprovider2Extensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Get(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.GetAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Create(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.CreateAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Post(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.PostAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Delete(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.DeleteAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IAuthenticateprovider2 operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateproviderExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateproviderExtensions.cs new file mode 100644 index 00000000000..eb77929bc01 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/AuthenticateproviderExtensions.cs @@ -0,0 +1,401 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for Authenticateprovider. + /// + public static partial class AuthenticateproviderExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Get(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.GetAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Create(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.CreateAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Post(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate)) + { + return operations.PostAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static AuthenticateResponse Delete(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string)) + { + return operations.DeleteAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IAuthenticateprovider operations, string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(provider, state, oauthToken, oauthVerifier, userName, password, rememberMe, continueParameter, nonce, uri, response, qop, nc, cnonce, useTokenCookie, accessToken, accessTokenSecret, meta, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetMovieId.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetMovieId.cs new file mode 100644 index 00000000000..d95598207af --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetMovieId.cs @@ -0,0 +1,669 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// GetMovieId operations. + /// + public partial class GetMovieId : IServiceOperations, IGetMovieId + { + /// + /// Initializes a new instance of the GetMovieId class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public GetMovieId(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(long id, IList includes = default(IList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("id", id); + tracingParameters.Add("includes", includes); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "movie/{Id}").ToString(); + _url = _url.Replace("{Id}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(id, Client.SerializationSettings).Trim('"'))); + List _queryParameters = new List(); + if (includes != null) + { + if (includes.Count == 0) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(string.Empty))); + } + else + { + foreach (var _item in includes) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(_item ?? string.Empty))); + } + } + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new MovieResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + MovieResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(long id, IList includes = default(IList), GetMovie body = default(GetMovie), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("id", id); + tracingParameters.Add("includes", includes); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "movie/{Id}").ToString(); + _url = _url.Replace("{Id}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(id, Client.SerializationSettings).Trim('"'))); + List _queryParameters = new List(); + if (includes != null) + { + if (includes.Count == 0) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(string.Empty))); + } + else + { + foreach (var _item in includes) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(_item ?? string.Empty))); + } + } + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new MovieResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + MovieResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(long id, IList includes = default(IList), GetMovie body = default(GetMovie), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("id", id); + tracingParameters.Add("includes", includes); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "movie/{Id}").ToString(); + _url = _url.Replace("{Id}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(id, Client.SerializationSettings).Trim('"'))); + List _queryParameters = new List(); + if (includes != null) + { + if (includes.Count == 0) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(string.Empty))); + } + else + { + foreach (var _item in includes) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(_item ?? string.Empty))); + } + } + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new MovieResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + MovieResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(long id, IList includes = default(IList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("id", id); + tracingParameters.Add("includes", includes); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "movie/{Id}").ToString(); + _url = _url.Replace("{Id}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(id, Client.SerializationSettings).Trim('"'))); + List _queryParameters = new List(); + if (includes != null) + { + if (includes.Count == 0) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(string.Empty))); + } + else + { + foreach (var _item in includes) + { + _queryParameters.Add(string.Format("Includes={0}", System.Uri.EscapeDataString(_item ?? string.Empty))); + } + } + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new MovieResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + MovieResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetMovieIdExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetMovieIdExtensions.cs new file mode 100644 index 00000000000..c48bfe1e8f3 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetMovieIdExtensions.cs @@ -0,0 +1,147 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for GetMovieId. + /// + public static partial class GetMovieIdExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static MovieResponse Get(this IGetMovieId operations, long id, IList includes = default(IList)) + { + return operations.GetAsync(id, includes).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IGetMovieId operations, long id, IList includes = default(IList), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(id, includes, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static MovieResponse Create(this IGetMovieId operations, long id, IList includes = default(IList), GetMovie body = default(GetMovie)) + { + return operations.CreateAsync(id, includes, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IGetMovieId operations, long id, IList includes = default(IList), GetMovie body = default(GetMovie), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(id, includes, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static MovieResponse Post(this IGetMovieId operations, long id, IList includes = default(IList), GetMovie body = default(GetMovie)) + { + return operations.PostAsync(id, includes, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IGetMovieId operations, long id, IList includes = default(IList), GetMovie body = default(GetMovie), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(id, includes, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static MovieResponse Delete(this IGetMovieId operations, long id, IList includes = default(IList)) + { + return operations.DeleteAsync(id, includes).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IGetMovieId operations, long id, IList includes = default(IList), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(id, includes, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetSession.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetSession.cs new file mode 100644 index 00000000000..46af20fce51 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetSession.cs @@ -0,0 +1,565 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// GetSession operations. + /// + public partial class GetSession : IServiceOperations, IGetSession + { + /// + /// Initializes a new instance of the GetSession class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public GetSession(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetSessionExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetSessionExtensions.cs new file mode 100644 index 00000000000..976f58249ef --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/GetSessionExtensions.cs @@ -0,0 +1,113 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for GetSession. + /// + public static partial class GetSessionExtensions + { + /// + /// The operations group for this extension method. + /// + public static GetSessionResponse Get(this IGetSession operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IGetSession operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static GetSessionResponse Create(this IGetSession operations, object body = default(object)) + { + return operations.CreateAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IGetSession operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static GetSessionResponse Post(this IGetSession operations, object body = default(object)) + { + return operations.PostAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IGetSession operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + public static GetSessionResponse Delete(this IGetSession operations) + { + return operations.DeleteAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IGetSession operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesOperations.cs new file mode 100644 index 00000000000..447c9389b94 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesOperations.cs @@ -0,0 +1,635 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloAllTypesOperations operations. + /// + public partial class HelloAllTypesOperations : IServiceOperations, IHelloAllTypesOperations + { + /// + /// Initializes a new instance of the HelloAllTypesOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloAllTypesOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (allTypes != null) + { + _queryParameters.Add(string.Format("AllTypes={0}", System.Uri.EscapeDataString(allTypes))); + } + if (allCollectionTypes != null) + { + _queryParameters.Add(string.Format("AllCollectionTypes={0}", System.Uri.EscapeDataString(allCollectionTypes))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (allTypes != null) + { + _queryParameters.Add(string.Format("AllTypes={0}", System.Uri.EscapeDataString(allTypes))); + } + if (allCollectionTypes != null) + { + _queryParameters.Add(string.Format("AllCollectionTypes={0}", System.Uri.EscapeDataString(allCollectionTypes))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesOperationsExtensions.cs new file mode 100644 index 00000000000..a10e32824f4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesOperationsExtensions.cs @@ -0,0 +1,161 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloAllTypesOperations. + /// + public static partial class HelloAllTypesOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static object Get(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string)) + { + return operations.GetAsync(name, allTypes, allCollectionTypes).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, allTypes, allCollectionTypes, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static object Create(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes)) + { + return operations.CreateAsync(name, allTypes, allCollectionTypes, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, allTypes, allCollectionTypes, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static object Post(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes)) + { + return operations.PostAsync(name, allTypes, allCollectionTypes, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, allTypes, allCollectionTypes, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static object Delete(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string)) + { + return operations.DeleteAsync(name, allTypes, allCollectionTypes).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloAllTypesOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, allTypes, allCollectionTypes, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesWithResultOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesWithResultOperations.cs new file mode 100644 index 00000000000..f18ca28d3fa --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesWithResultOperations.cs @@ -0,0 +1,635 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloAllTypesWithResultOperations operations. + /// + public partial class HelloAllTypesWithResultOperations : IServiceOperations, IHelloAllTypesWithResultOperations + { + /// + /// Initializes a new instance of the HelloAllTypesWithResultOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloAllTypesWithResultOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types-result").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (allTypes != null) + { + _queryParameters.Add(string.Format("AllTypes={0}", System.Uri.EscapeDataString(allTypes))); + } + if (allCollectionTypes != null) + { + _queryParameters.Add(string.Format("AllCollectionTypes={0}", System.Uri.EscapeDataString(allCollectionTypes))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloAllTypesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloAllTypesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types-result").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloAllTypesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloAllTypesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types-result").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloAllTypesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloAllTypesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("allTypes", allTypes); + tracingParameters.Add("allCollectionTypes", allCollectionTypes); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "all-types-result").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (allTypes != null) + { + _queryParameters.Add(string.Format("AllTypes={0}", System.Uri.EscapeDataString(allTypes))); + } + if (allCollectionTypes != null) + { + _queryParameters.Add(string.Format("AllCollectionTypes={0}", System.Uri.EscapeDataString(allCollectionTypes))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloAllTypesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloAllTypesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesWithResultOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesWithResultOperationsExtensions.cs new file mode 100644 index 00000000000..9db16017647 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloAllTypesWithResultOperationsExtensions.cs @@ -0,0 +1,161 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloAllTypesWithResultOperations. + /// + public static partial class HelloAllTypesWithResultOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloAllTypesResponse Get(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string)) + { + return operations.GetAsync(name, allTypes, allCollectionTypes).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, allTypes, allCollectionTypes, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static HelloAllTypesResponse Create(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult)) + { + return operations.CreateAsync(name, allTypes, allCollectionTypes, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, allTypes, allCollectionTypes, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static HelloAllTypesResponse Post(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult)) + { + return operations.PostAsync(name, allTypes, allCollectionTypes, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, allTypes, allCollectionTypes, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloAllTypesResponse Delete(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string)) + { + return operations.DeleteAsync(name, allTypes, allCollectionTypes).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloAllTypesWithResultOperations operations, string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, allTypes, allCollectionTypes, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloArrayOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloArrayOperations.cs new file mode 100644 index 00000000000..501982cd502 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloArrayOperations.cs @@ -0,0 +1,595 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloArrayOperations operations. + /// + public partial class HelloArrayOperations : IServiceOperations, IHelloArrayOperations + { + /// + /// Initializes a new instance of the HelloArrayOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloArrayOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> GetWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-array").ToString(); + List _queryParameters = new List(); + if (names != null) + { + _queryParameters.Add(string.Format("Names={0}", System.Uri.EscapeDataString(names))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> CreateWithHttpMessagesAsync(string names = default(string), HelloArray body = default(HelloArray), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-array").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> PostWithHttpMessagesAsync(string names = default(string), HelloArray body = default(HelloArray), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-array").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> DeleteWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-array").ToString(); + List _queryParameters = new List(); + if (names != null) + { + _queryParameters.Add(string.Format("Names={0}", System.Uri.EscapeDataString(names))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloArrayOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloArrayOperationsExtensions.cs new file mode 100644 index 00000000000..6b190aaaaf4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloArrayOperationsExtensions.cs @@ -0,0 +1,131 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloArrayOperations. + /// + public static partial class HelloArrayOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static IList Get(this IHelloArrayOperations operations, string names = default(string)) + { + return operations.GetAsync(names).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> GetAsync(this IHelloArrayOperations operations, string names = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(names, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static IList Create(this IHelloArrayOperations operations, string names = default(string), HelloArray body = default(HelloArray)) + { + return operations.CreateAsync(names, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> CreateAsync(this IHelloArrayOperations operations, string names = default(string), HelloArray body = default(HelloArray), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(names, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static IList Post(this IHelloArrayOperations operations, string names = default(string), HelloArray body = default(HelloArray)) + { + return operations.PostAsync(names, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> PostAsync(this IHelloArrayOperations operations, string names = default(string), HelloArray body = default(HelloArray), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(names, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static IList Delete(this IHelloArrayOperations operations, string names = default(string)) + { + return operations.DeleteAsync(names).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> DeleteAsync(this IHelloArrayOperations operations, string names = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(names, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloDateTimeOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloDateTimeOperations.cs new file mode 100644 index 00000000000..bc7c58ac9c9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloDateTimeOperations.cs @@ -0,0 +1,589 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloDateTimeOperations operations. + /// + public partial class HelloDateTimeOperations : IServiceOperations, IHelloDateTimeOperations + { + /// + /// Initializes a new instance of the HelloDateTimeOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloDateTimeOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("dateTime", dateTime); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-datetime").ToString(); + List _queryParameters = new List(); + _queryParameters.Add(string.Format("DateTime={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(dateTime, Client.SerializationSettings).Trim('"')))); + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloDateTimeException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloDateTime _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("dateTime", dateTime); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-datetime").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloDateTimeException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloDateTime _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("dateTime", dateTime); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-datetime").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloDateTimeException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloDateTime _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("dateTime", dateTime); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-datetime").ToString(); + List _queryParameters = new List(); + _queryParameters.Add(string.Format("DateTime={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(dateTime, Client.SerializationSettings).Trim('"')))); + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloDateTimeException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloDateTime _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloDateTimeOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloDateTimeOperationsExtensions.cs new file mode 100644 index 00000000000..8607007a2d5 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloDateTimeOperationsExtensions.cs @@ -0,0 +1,129 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloDateTimeOperations. + /// + public static partial class HelloDateTimeOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static HelloDateTime Get(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime)) + { + return operations.GetAsync(dateTime).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(dateTime, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloDateTime Create(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime)) + { + return operations.CreateAsync(dateTime, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(dateTime, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloDateTime Post(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime)) + { + return operations.PostAsync(dateTime, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(dateTime, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static HelloDateTime Delete(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime)) + { + return operations.DeleteAsync(dateTime).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloDateTimeOperations operations, System.DateTime dateTime = default(System.DateTime), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(dateTime, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloListOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloListOperations.cs new file mode 100644 index 00000000000..40fc4fab85b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloListOperations.cs @@ -0,0 +1,595 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloListOperations operations. + /// + public partial class HelloListOperations : IServiceOperations, IHelloListOperations + { + /// + /// Initializes a new instance of the HelloListOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloListOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> GetWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-list").ToString(); + List _queryParameters = new List(); + if (names != null) + { + _queryParameters.Add(string.Format("Names={0}", System.Uri.EscapeDataString(names))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> CreateWithHttpMessagesAsync(string names = default(string), HelloList body = default(HelloList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-list").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> PostWithHttpMessagesAsync(string names = default(string), HelloList body = default(HelloList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-list").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> DeleteWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("names", names); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-list").ToString(); + List _queryParameters = new List(); + if (names != null) + { + _queryParameters.Add(string.Format("Names={0}", System.Uri.EscapeDataString(names))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloListOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloListOperationsExtensions.cs new file mode 100644 index 00000000000..977fcdf1bd8 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloListOperationsExtensions.cs @@ -0,0 +1,131 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloListOperations. + /// + public static partial class HelloListOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static IList Get(this IHelloListOperations operations, string names = default(string)) + { + return operations.GetAsync(names).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> GetAsync(this IHelloListOperations operations, string names = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(names, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static IList Create(this IHelloListOperations operations, string names = default(string), HelloList body = default(HelloList)) + { + return operations.CreateAsync(names, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> CreateAsync(this IHelloListOperations operations, string names = default(string), HelloList body = default(HelloList), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(names, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static IList Post(this IHelloListOperations operations, string names = default(string), HelloList body = default(HelloList)) + { + return operations.PostAsync(names, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> PostAsync(this IHelloListOperations operations, string names = default(string), HelloList body = default(HelloList), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(names, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static IList Delete(this IHelloListOperations operations, string names = default(string)) + { + return operations.DeleteAsync(names).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task> DeleteAsync(this IHelloListOperations operations, string names = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(names, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloName.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloName.cs new file mode 100644 index 00000000000..c31204b6935 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloName.cs @@ -0,0 +1,651 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloName operations. + /// + public partial class HelloName : IServiceOperations, IHelloName + { + /// + /// Initializes a new instance of the HelloName class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloName(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name, string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (name == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "name"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello/{Name}").ToString(); + _url = _url.Replace("{Name}", System.Uri.EscapeDataString(name)); + List _queryParameters = new List(); + if (title != null) + { + _queryParameters.Add(string.Format("Title={0}", System.Uri.EscapeDataString(title))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name, string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (name == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "name"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello/{Name}").ToString(); + _url = _url.Replace("{Name}", System.Uri.EscapeDataString(name)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name, string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (name == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "name"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello/{Name}").ToString(); + _url = _url.Replace("{Name}", System.Uri.EscapeDataString(name)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name, string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (name == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "name"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello/{Name}").ToString(); + _url = _url.Replace("{Name}", System.Uri.EscapeDataString(name)); + List _queryParameters = new List(); + if (title != null) + { + _queryParameters.Add(string.Format("Title={0}", System.Uri.EscapeDataString(title))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloNameExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloNameExtensions.cs new file mode 100644 index 00000000000..e6d4720044a --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloNameExtensions.cs @@ -0,0 +1,145 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloName. + /// + public static partial class HelloNameExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloResponse Get(this IHelloName operations, string name, string title = default(string)) + { + return operations.GetAsync(name, title).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloName operations, string name, string title = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, title, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloResponse Create(this IHelloName operations, string name, string title = default(string), Hello body = default(Hello)) + { + return operations.CreateAsync(name, title, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloName operations, string name, string title = default(string), Hello body = default(Hello), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, title, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloResponse Post(this IHelloName operations, string name, string title = default(string), Hello body = default(Hello)) + { + return operations.PostAsync(name, title, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloName operations, string name, string title = default(string), Hello body = default(Hello), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, title, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloResponse Delete(this IHelloName operations, string name, string title = default(string)) + { + return operations.DeleteAsync(name, title).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloName operations, string name, string title = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, title, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloOperations.cs new file mode 100644 index 00000000000..b613c4a0100 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloOperations.cs @@ -0,0 +1,615 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloOperations operations. + /// + public partial class HelloOperations : IServiceOperations, IHelloOperations + { + /// + /// Initializes a new instance of the HelloOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (title != null) + { + _queryParameters.Add(string.Format("Title={0}", System.Uri.EscapeDataString(title))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("title", title); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (title != null) + { + _queryParameters.Add(string.Format("Title={0}", System.Uri.EscapeDataString(title))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloOperationsExtensions.cs new file mode 100644 index 00000000000..3814380de54 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloOperationsExtensions.cs @@ -0,0 +1,145 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloOperations. + /// + public static partial class HelloOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloResponse Get(this IHelloOperations operations, string name = default(string), string title = default(string)) + { + return operations.GetAsync(name, title).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloOperations operations, string name = default(string), string title = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, title, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloResponse Create(this IHelloOperations operations, string name = default(string), string title = default(string), Hello body = default(Hello)) + { + return operations.CreateAsync(name, title, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloOperations operations, string name = default(string), string title = default(string), Hello body = default(Hello), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, title, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloResponse Post(this IHelloOperations operations, string name = default(string), string title = default(string), Hello body = default(Hello)) + { + return operations.PostAsync(name, title, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloOperations operations, string name = default(string), string title = default(string), Hello body = default(Hello), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, title, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloResponse Delete(this IHelloOperations operations, string name = default(string), string title = default(string)) + { + return operations.DeleteAsync(name, title).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloOperations operations, string name = default(string), string title = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, title, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloStringOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloStringOperations.cs new file mode 100644 index 00000000000..8df2fcb8a4b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloStringOperations.cs @@ -0,0 +1,595 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloStringOperations operations. + /// + public partial class HelloStringOperations : IServiceOperations, IHelloStringOperations + { + /// + /// Initializes a new instance of the HelloStringOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloStringOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-string").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), HelloString body = default(HelloString), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-string").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), HelloString body = default(HelloString), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-string").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-string").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloStringOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloStringOperationsExtensions.cs new file mode 100644 index 00000000000..8b19d525905 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloStringOperationsExtensions.cs @@ -0,0 +1,129 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloStringOperations. + /// + public static partial class HelloStringOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Get(this IHelloStringOperations operations, string name = default(string)) + { + return operations.GetAsync(name).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloStringOperations operations, string name = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static string Create(this IHelloStringOperations operations, string name = default(string), HelloString body = default(HelloString)) + { + return operations.CreateAsync(name, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloStringOperations operations, string name = default(string), HelloString body = default(HelloString), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static string Post(this IHelloStringOperations operations, string name = default(string), HelloString body = default(HelloString)) + { + return operations.PostAsync(name, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloStringOperations operations, string name = default(string), HelloString body = default(HelloString), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Delete(this IHelloStringOperations operations, string name = default(string)) + { + return operations.DeleteAsync(name).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloStringOperations operations, string name = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloTypesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloTypesOperations.cs new file mode 100644 index 00000000000..470ae4ae9b2 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloTypesOperations.cs @@ -0,0 +1,623 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloTypesOperations operations. + /// + public partial class HelloTypesOperations : IServiceOperations, IHelloTypesOperations + { + /// + /// Initializes a new instance of the HelloTypesOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloTypesOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("stringParameter", stringParameter); + tracingParameters.Add("boolParameter", boolParameter); + tracingParameters.Add("intParameter", intParameter); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellotypes").ToString(); + List _queryParameters = new List(); + if (stringParameter != null) + { + _queryParameters.Add(string.Format("String={0}", System.Uri.EscapeDataString(stringParameter))); + } + _queryParameters.Add(string.Format("Bool={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(boolParameter, Client.SerializationSettings).Trim('"')))); + _queryParameters.Add(string.Format("Int={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(intParameter, Client.SerializationSettings).Trim('"')))); + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloTypesException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloTypes _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("stringParameter", stringParameter); + tracingParameters.Add("boolParameter", boolParameter); + tracingParameters.Add("intParameter", intParameter); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellotypes").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloTypesException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloTypes _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("stringParameter", stringParameter); + tracingParameters.Add("boolParameter", boolParameter); + tracingParameters.Add("intParameter", intParameter); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellotypes").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloTypesException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloTypes _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("stringParameter", stringParameter); + tracingParameters.Add("boolParameter", boolParameter); + tracingParameters.Add("intParameter", intParameter); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellotypes").ToString(); + List _queryParameters = new List(); + if (stringParameter != null) + { + _queryParameters.Add(string.Format("String={0}", System.Uri.EscapeDataString(stringParameter))); + } + _queryParameters.Add(string.Format("Bool={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(boolParameter, Client.SerializationSettings).Trim('"')))); + _queryParameters.Add(string.Format("Int={0}", System.Uri.EscapeDataString(Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(intParameter, Client.SerializationSettings).Trim('"')))); + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloTypesException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloTypes _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloTypesOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloTypesOperationsExtensions.cs new file mode 100644 index 00000000000..b7aa7542388 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloTypesOperationsExtensions.cs @@ -0,0 +1,161 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloTypesOperations. + /// + public static partial class HelloTypesOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloTypes Get(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int)) + { + return operations.GetAsync(stringParameter, boolParameter, intParameter).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(stringParameter, boolParameter, intParameter, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static HelloTypes Create(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes)) + { + return operations.CreateAsync(stringParameter, boolParameter, intParameter, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(stringParameter, boolParameter, intParameter, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static HelloTypes Post(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes)) + { + return operations.PostAsync(stringParameter, boolParameter, intParameter, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(stringParameter, boolParameter, intParameter, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloTypes Delete(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int)) + { + return operations.DeleteAsync(stringParameter, boolParameter, intParameter).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloTypesOperations operations, string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(stringParameter, boolParameter, intParameter, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloVoidOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloVoidOperations.cs new file mode 100644 index 00000000000..077206fd2fe --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloVoidOperations.cs @@ -0,0 +1,595 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloVoidOperations operations. + /// + public partial class HelloVoidOperations : IServiceOperations, IHelloVoidOperations + { + /// + /// Initializes a new instance of the HelloVoidOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloVoidOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-void").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), HelloVoid body = default(HelloVoid), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-void").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), HelloVoid body = default(HelloVoid), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-void").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hello-void").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloVoidOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloVoidOperationsExtensions.cs new file mode 100644 index 00000000000..5376595a9a8 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloVoidOperationsExtensions.cs @@ -0,0 +1,129 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloVoidOperations. + /// + public static partial class HelloVoidOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static object Get(this IHelloVoidOperations operations, string name = default(string)) + { + return operations.GetAsync(name).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloVoidOperations operations, string name = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static object Create(this IHelloVoidOperations operations, string name = default(string), HelloVoid body = default(HelloVoid)) + { + return operations.CreateAsync(name, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloVoidOperations operations, string name = default(string), HelloVoid body = default(HelloVoid), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static object Post(this IHelloVoidOperations operations, string name = default(string), HelloVoid body = default(HelloVoid)) + { + return operations.PostAsync(name, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloVoidOperations operations, string name = default(string), HelloVoid body = default(HelloVoid), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static object Delete(this IHelloVoidOperations operations, string name = default(string)) + { + return operations.DeleteAsync(name).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloVoidOperations operations, string name = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloWithRouteOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloWithRouteOperations.cs new file mode 100644 index 00000000000..8bb7552f7b0 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloWithRouteOperations.cs @@ -0,0 +1,595 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloWithRouteOperations operations. + /// + public partial class HelloWithRouteOperations : IServiceOperations, IHelloWithRouteOperations + { + /// + /// Initializes a new instance of the HelloWithRouteOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloWithRouteOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "helloroute").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), HelloWithRoute body = default(HelloWithRoute), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "helloroute").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), HelloWithRoute body = default(HelloWithRoute), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "helloroute").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "helloroute").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + object _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloWithRouteOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloWithRouteOperationsExtensions.cs new file mode 100644 index 00000000000..39241a30a05 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloWithRouteOperationsExtensions.cs @@ -0,0 +1,129 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloWithRouteOperations. + /// + public static partial class HelloWithRouteOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static object Get(this IHelloWithRouteOperations operations, string name = default(string)) + { + return operations.GetAsync(name).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloWithRouteOperations operations, string name = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static object Create(this IHelloWithRouteOperations operations, string name = default(string), HelloWithRoute body = default(HelloWithRoute)) + { + return operations.CreateAsync(name, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloWithRouteOperations operations, string name = default(string), HelloWithRoute body = default(HelloWithRoute), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static object Post(this IHelloWithRouteOperations operations, string name = default(string), HelloWithRoute body = default(HelloWithRoute)) + { + return operations.PostAsync(name, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloWithRouteOperations operations, string name = default(string), HelloWithRoute body = default(HelloWithRoute), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static object Delete(this IHelloWithRouteOperations operations, string name = default(string)) + { + return operations.DeleteAsync(name).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloWithRouteOperations operations, string name = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloZipOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloZipOperations.cs new file mode 100644 index 00000000000..7be55eaf910 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloZipOperations.cs @@ -0,0 +1,615 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloZipOperations operations. + /// + public partial class HelloZipOperations : IServiceOperations, IHelloZipOperations + { + /// + /// Initializes a new instance of the HelloZipOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public HelloZipOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string name = default(string), string test = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("test", test); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellozip").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (test != null) + { + _queryParameters.Add(string.Format("Test={0}", System.Uri.EscapeDataString(test))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloZipResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloZipResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string name = default(string), string test = default(string), HelloZip body = default(HelloZip), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("test", test); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellozip").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloZipResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloZipResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string name = default(string), string test = default(string), HelloZip body = default(HelloZip), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("test", test); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellozip").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloZipResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloZipResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string name = default(string), string test = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("name", name); + tracingParameters.Add("test", test); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "hellozip").ToString(); + List _queryParameters = new List(); + if (name != null) + { + _queryParameters.Add(string.Format("Name={0}", System.Uri.EscapeDataString(name))); + } + if (test != null) + { + _queryParameters.Add(string.Format("Test={0}", System.Uri.EscapeDataString(test))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HelloZipResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + HelloZipResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloZipOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloZipOperationsExtensions.cs new file mode 100644 index 00000000000..120b96ca84f --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/HelloZipOperationsExtensions.cs @@ -0,0 +1,145 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for HelloZipOperations. + /// + public static partial class HelloZipOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloZipResponse Get(this IHelloZipOperations operations, string name = default(string), string test = default(string)) + { + return operations.GetAsync(name, test).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IHelloZipOperations operations, string name = default(string), string test = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(name, test, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloZipResponse Create(this IHelloZipOperations operations, string name = default(string), string test = default(string), HelloZip body = default(HelloZip)) + { + return operations.CreateAsync(name, test, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IHelloZipOperations operations, string name = default(string), string test = default(string), HelloZip body = default(HelloZip), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(name, test, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static HelloZipResponse Post(this IHelloZipOperations operations, string name = default(string), string test = default(string), HelloZip body = default(HelloZip)) + { + return operations.PostAsync(name, test, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IHelloZipOperations operations, string name = default(string), string test = default(string), HelloZip body = default(HelloZip), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(name, test, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static HelloZipResponse Delete(this IHelloZipOperations operations, string name = default(string), string test = default(string)) + { + return operations.DeleteAsync(name, test).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IHelloZipOperations operations, string name = default(string), string test = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(name, test, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAllowedAttributesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAllowedAttributesOperations.cs new file mode 100644 index 00000000000..b76fc6ab5d9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAllowedAttributesOperations.cs @@ -0,0 +1,41 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// AllowedAttributesOperations operations. + /// + public partial interface IAllowedAttributesOperations + { + /// + /// AllowedAttributes Description + /// + /// + /// AllowedAttributes Description + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task GetWithHttpMessagesAsync(int aliased, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAssignRolesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAssignRolesOperations.cs new file mode 100644 index 00000000000..23f3cf262a0 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAssignRolesOperations.cs @@ -0,0 +1,100 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// AssignRolesOperations operations. + /// + public partial interface IAssignRolesOperations + { + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), AssignRoles body = default(AssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticate2.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticate2.cs new file mode 100644 index 00000000000..ca55d63e371 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticate2.cs @@ -0,0 +1,220 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Authenticate2 operations. + /// + public partial interface IAuthenticate2 + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateOperations.cs new file mode 100644 index 00000000000..29b3058b35f --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateOperations.cs @@ -0,0 +1,220 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// AuthenticateOperations operations. + /// + public partial interface IAuthenticateOperations + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateprovider.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateprovider.cs new file mode 100644 index 00000000000..f9a19e275c6 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateprovider.cs @@ -0,0 +1,220 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Authenticateprovider operations. + /// + public partial interface IAuthenticateprovider + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateprovider2.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateprovider2.cs new file mode 100644 index 00000000000..a1f163f9361 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IAuthenticateprovider2.cs @@ -0,0 +1,220 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Authenticateprovider2 operations. + /// + public partial interface IAuthenticateprovider2 + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Authenticate body = default(Authenticate), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string provider, string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueParameter = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), string meta = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IGetMovieId.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IGetMovieId.cs new file mode 100644 index 00000000000..2c1fa7a19b4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IGetMovieId.cs @@ -0,0 +1,92 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// GetMovieId operations. + /// + public partial interface IGetMovieId + { + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(long id, IList includes = default(IList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(long id, IList includes = default(IList), GetMovie body = default(GetMovie), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(long id, IList includes = default(IList), GetMovie body = default(GetMovie), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(long id, IList includes = default(IList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IGetSession.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IGetSession.cs new file mode 100644 index 00000000000..f4285ba65f2 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IGetSession.cs @@ -0,0 +1,76 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// GetSession operations. + /// + public partial interface IGetSession + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloAllTypesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloAllTypesOperations.cs new file mode 100644 index 00000000000..3b7f7c1f5c7 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloAllTypesOperations.cs @@ -0,0 +1,100 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloAllTypesOperations operations. + /// + public partial interface IHelloAllTypesOperations + { + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypes body = default(HelloAllTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloAllTypesWithResultOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloAllTypesWithResultOperations.cs new file mode 100644 index 00000000000..dddb99161f9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloAllTypesWithResultOperations.cs @@ -0,0 +1,100 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloAllTypesWithResultOperations operations. + /// + public partial interface IHelloAllTypesWithResultOperations + { + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), HelloAllTypesWithResult body = default(HelloAllTypesWithResult), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), string allTypes = default(string), string allCollectionTypes = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloArrayOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloArrayOperations.cs new file mode 100644 index 00000000000..8bfd2543915 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloArrayOperations.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloArrayOperations operations. + /// + public partial interface IHelloArrayOperations + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> GetWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> CreateWithHttpMessagesAsync(string names = default(string), HelloArray body = default(HelloArray), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> PostWithHttpMessagesAsync(string names = default(string), HelloArray body = default(HelloArray), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> DeleteWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloDateTimeOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloDateTimeOperations.cs new file mode 100644 index 00000000000..16b0141d78c --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloDateTimeOperations.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloDateTimeOperations operations. + /// + public partial interface IHelloDateTimeOperations + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), HelloDateTime body = default(HelloDateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(System.DateTime dateTime = default(System.DateTime), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloListOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloListOperations.cs new file mode 100644 index 00000000000..15a1e1d845a --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloListOperations.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloListOperations operations. + /// + public partial interface IHelloListOperations + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> GetWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> CreateWithHttpMessagesAsync(string names = default(string), HelloList body = default(HelloList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> PostWithHttpMessagesAsync(string names = default(string), HelloList body = default(HelloList), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> DeleteWithHttpMessagesAsync(string names = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloName.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloName.cs new file mode 100644 index 00000000000..3a0f040389b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloName.cs @@ -0,0 +1,92 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloName operations. + /// + public partial interface IHelloName + { + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name, string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name, string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name, string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name, string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloOperations.cs new file mode 100644 index 00000000000..bd1fd1298cc --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloOperations.cs @@ -0,0 +1,92 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloOperations operations. + /// + public partial interface IHelloOperations + { + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), string title = default(string), Hello body = default(Hello), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), string title = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloStringOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloStringOperations.cs new file mode 100644 index 00000000000..874cb405b0b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloStringOperations.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloStringOperations operations. + /// + public partial interface IHelloStringOperations + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), HelloString body = default(HelloString), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), HelloString body = default(HelloString), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloTypesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloTypesOperations.cs new file mode 100644 index 00000000000..4bee0f1e95c --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloTypesOperations.cs @@ -0,0 +1,100 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloTypesOperations operations. + /// + public partial interface IHelloTypesOperations + { + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), HelloTypes body = default(HelloTypes), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string stringParameter = default(string), bool boolParameter = default(bool), int intParameter = default(int), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloVoidOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloVoidOperations.cs new file mode 100644 index 00000000000..1bac7ad4512 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloVoidOperations.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloVoidOperations operations. + /// + public partial interface IHelloVoidOperations + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), HelloVoid body = default(HelloVoid), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), HelloVoid body = default(HelloVoid), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloWithRouteOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloWithRouteOperations.cs new file mode 100644 index 00000000000..94a60eeb95e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloWithRouteOperations.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloWithRouteOperations operations. + /// + public partial interface IHelloWithRouteOperations + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), HelloWithRoute body = default(HelloWithRoute), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), HelloWithRoute body = default(HelloWithRoute), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloZipOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloZipOperations.cs new file mode 100644 index 00000000000..76dd4fbb690 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IHelloZipOperations.cs @@ -0,0 +1,92 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// HelloZipOperations operations. + /// + public partial interface IHelloZipOperations + { + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string name = default(string), string test = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string name = default(string), string test = default(string), HelloZip body = default(HelloZip), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string name = default(string), string test = default(string), HelloZip body = default(HelloZip), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string name = default(string), string test = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnArrayRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnArrayRequest.cs new file mode 100644 index 00000000000..745512b6601 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnArrayRequest.cs @@ -0,0 +1,33 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnArrayRequest operations. + /// + public partial interface IReturnArrayRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnDictionaryDtoRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnDictionaryDtoRequest.cs new file mode 100644 index 00000000000..b7a6a2809ef --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnDictionaryDtoRequest.cs @@ -0,0 +1,33 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnDictionaryDtoRequest operations. + /// + public partial interface IReturnDictionaryDtoRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnDictionaryStringRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnDictionaryStringRequest.cs new file mode 100644 index 00000000000..8ad72523900 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnDictionaryStringRequest.cs @@ -0,0 +1,33 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnDictionaryStringRequest operations. + /// + public partial interface IReturnDictionaryStringRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnKeyValuePairRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnKeyValuePairRequest.cs new file mode 100644 index 00000000000..ba5986227e9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnKeyValuePairRequest.cs @@ -0,0 +1,33 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnKeyValuePairRequest operations. + /// + public partial interface IReturnKeyValuePairRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnListRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnListRequest.cs new file mode 100644 index 00000000000..50de3c3c6fb --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IReturnListRequest.cs @@ -0,0 +1,33 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnListRequest operations. + /// + public partial interface IReturnListRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredDtoRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredDtoRequest.cs new file mode 100644 index 00000000000..d1f4ffc543f --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredDtoRequest.cs @@ -0,0 +1,76 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// SecuredDtoRequest operations. + /// + public partial interface ISecuredDtoRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredOpsRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredOpsRequest.cs new file mode 100644 index 00000000000..29b6a78c37d --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredOpsRequest.cs @@ -0,0 +1,76 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// SecuredOpsRequest operations. + /// + public partial interface ISecuredOpsRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredRequest.cs new file mode 100644 index 00000000000..d2e169728ad --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ISecuredRequest.cs @@ -0,0 +1,76 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// SecuredRequest operations. + /// + public partial interface ISecuredRequest + { + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IServiceStackAutorestClient.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IServiceStackAutorestClient.cs new file mode 100644 index 00000000000..995b3007d6c --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IServiceStackAutorestClient.cs @@ -0,0 +1,186 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using Newtonsoft.Json; + + /// + /// + public partial interface IServiceStackAutorestClient : System.IDisposable + { + /// + /// The base URI of the service. + /// + System.Uri BaseUri { get; set; } + + /// + /// Gets or sets json serialization settings. + /// + JsonSerializerSettings SerializationSettings { get; } + + /// + /// Gets or sets json deserialization settings. + /// + JsonSerializerSettings DeserializationSettings { get; } + + /// + /// Accept Header + /// + string Accept { get; } + + + /// + /// Gets the IReturnListRequest. + /// + IReturnListRequest ReturnListRequest { get; } + + /// + /// Gets the IReturnArrayRequest. + /// + IReturnArrayRequest ReturnArrayRequest { get; } + + /// + /// Gets the IReturnKeyValuePairRequest. + /// + IReturnKeyValuePairRequest ReturnKeyValuePairRequest { get; } + + /// + /// Gets the IReturnDictionaryStringRequest. + /// + IReturnDictionaryStringRequest ReturnDictionaryStringRequest { get; } + + /// + /// Gets the IReturnDictionaryDtoRequest. + /// + IReturnDictionaryDtoRequest ReturnDictionaryDtoRequest { get; } + + /// + /// Gets the IGetMovieId. + /// + IGetMovieId GetMovieId { get; } + + /// + /// Gets the IHelloOperations. + /// + IHelloOperations Hello { get; } + + /// + /// Gets the IHelloName. + /// + IHelloName HelloName { get; } + + /// + /// Gets the IHelloListOperations. + /// + IHelloListOperations HelloList { get; } + + /// + /// Gets the IHelloArrayOperations. + /// + IHelloArrayOperations HelloArray { get; } + + /// + /// Gets the IAllowedAttributesOperations. + /// + IAllowedAttributesOperations AllowedAttributes { get; } + + /// + /// Gets the IHelloAllTypesOperations. + /// + IHelloAllTypesOperations HelloAllTypes { get; } + + /// + /// Gets the IHelloAllTypesWithResultOperations. + /// + IHelloAllTypesWithResultOperations HelloAllTypesWithResult { get; } + + /// + /// Gets the IHelloStringOperations. + /// + IHelloStringOperations HelloString { get; } + + /// + /// Gets the IHelloDateTimeOperations. + /// + IHelloDateTimeOperations HelloDateTime { get; } + + /// + /// Gets the IHelloVoidOperations. + /// + IHelloVoidOperations HelloVoid { get; } + + /// + /// Gets the IHelloWithRouteOperations. + /// + IHelloWithRouteOperations HelloWithRoute { get; } + + /// + /// Gets the IHelloTypesOperations. + /// + IHelloTypesOperations HelloTypes { get; } + + /// + /// Gets the IHelloZipOperations. + /// + IHelloZipOperations HelloZip { get; } + + /// + /// Gets the ISecuredRequest. + /// + ISecuredRequest SecuredRequest { get; } + + /// + /// Gets the ISecuredDtoRequest. + /// + ISecuredDtoRequest SecuredDtoRequest { get; } + + /// + /// Gets the ISecuredOpsRequest. + /// + ISecuredOpsRequest SecuredOpsRequest { get; } + + /// + /// Gets the IGetSession. + /// + IGetSession GetSession { get; } + + /// + /// Gets the IUpdateSessioneditCustomName. + /// + IUpdateSessioneditCustomName UpdateSessioneditCustomName { get; } + + /// + /// Gets the IAuthenticateOperations. + /// + IAuthenticateOperations Authenticate { get; } + + /// + /// Gets the IAuthenticateprovider. + /// + IAuthenticateprovider Authenticateprovider { get; } + + /// + /// Gets the IAuthenticate2. + /// + IAuthenticate2 Authenticate2 { get; } + + /// + /// Gets the IAuthenticateprovider2. + /// + IAuthenticateprovider2 Authenticateprovider2 { get; } + + /// + /// Gets the IAssignRolesOperations. + /// + IAssignRolesOperations AssignRoles { get; } + + /// + /// Gets the IUnAssignRolesOperations. + /// + IUnAssignRolesOperations UnAssignRoles { get; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IUnAssignRolesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IUnAssignRolesOperations.cs new file mode 100644 index 00000000000..a7e119dc823 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IUnAssignRolesOperations.cs @@ -0,0 +1,100 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// UnAssignRolesOperations operations. + /// + public partial interface IUnAssignRolesOperations + { + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IUpdateSessioneditCustomName.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IUpdateSessioneditCustomName.cs new file mode 100644 index 00000000000..7ca95b0c630 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/IUpdateSessioneditCustomName.cs @@ -0,0 +1,84 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// UpdateSessioneditCustomName operations. + /// + public partial interface IUpdateSessioneditCustomName + { + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> GetWithHttpMessagesAsync(string customName, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> CreateWithHttpMessagesAsync(string customName, UpdateSession body = default(UpdateSession), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> PostWithHttpMessagesAsync(string customName, UpdateSession body = default(UpdateSession), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// + /// + /// The headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + Task> DeleteWithHttpMessagesAsync(string customName, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllCollectionTypes.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllCollectionTypes.cs new file mode 100644 index 00000000000..70ef29abd0a --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllCollectionTypes.cs @@ -0,0 +1,90 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// AllCollectionTypes + /// + /// + /// AllCollectionTypes + /// + public partial class AllCollectionTypes + { + /// + /// Initializes a new instance of the AllCollectionTypes class. + /// + public AllCollectionTypes() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the AllCollectionTypes class. + /// + public AllCollectionTypes(IList intArray = default(IList), IList intList = default(IList), IList stringArray = default(IList), IList stringList = default(IList), IList pocoArray = default(IList), IList pocoList = default(IList), IDictionary> pocoLookup = default(IDictionary>), IDictionary>> pocoLookupMap = default(IDictionary>>)) + { + IntArray = intArray; + IntList = intList; + StringArray = stringArray; + StringList = stringList; + PocoArray = pocoArray; + PocoList = pocoList; + PocoLookup = pocoLookup; + PocoLookupMap = pocoLookupMap; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "IntArray")] + public IList IntArray { get; set; } + + /// + /// + [JsonProperty(PropertyName = "IntList")] + public IList IntList { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StringArray")] + public IList StringArray { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StringList")] + public IList StringList { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PocoArray")] + public IList PocoArray { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PocoList")] + public IList PocoList { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PocoLookup")] + public IDictionary> PocoLookup { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PocoLookupMap")] + public IDictionary>> PocoLookupMap { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllTypes.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllTypes.cs new file mode 100644 index 00000000000..79467771172 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllTypes.cs @@ -0,0 +1,198 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// AllTypes + /// + /// + /// AllTypes + /// + public partial class AllTypes + { + /// + /// Initializes a new instance of the AllTypes class. + /// + public AllTypes() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the AllTypes class. + /// + public AllTypes(int id = default(int), int? nullableId = default(int?), int byteProperty = default(int), int shortProperty = default(int), int intProperty = default(int), long longProperty = default(long), int uShortProperty = default(int), int uIntProperty = default(int), long uLongProperty = default(long), double floatProperty = default(double), double doubleProperty = default(double), double decimalProperty = default(double), string stringProperty = default(string), System.DateTime dateTimeProperty = default(System.DateTime), string timeSpanProperty = default(string), string dateTimeOffsetProperty = default(string), string guidProperty = default(string), string charProperty = default(string), KeyValuePairStringString keyValuePairProperty = default(KeyValuePairStringString), System.DateTime? nullableDateTime = default(System.DateTime?), string nullableTimeSpan = default(string), IList stringList = default(IList), IList stringArray = default(IList), IDictionary stringMap = default(IDictionary), IDictionary intStringMap = default(IDictionary), SubType subType = default(SubType)) + { + Id = id; + NullableId = nullableId; + ByteProperty = byteProperty; + ShortProperty = shortProperty; + IntProperty = intProperty; + LongProperty = longProperty; + UShortProperty = uShortProperty; + UIntProperty = uIntProperty; + ULongProperty = uLongProperty; + FloatProperty = floatProperty; + DoubleProperty = doubleProperty; + DecimalProperty = decimalProperty; + StringProperty = stringProperty; + DateTimeProperty = dateTimeProperty; + TimeSpanProperty = timeSpanProperty; + DateTimeOffsetProperty = dateTimeOffsetProperty; + GuidProperty = guidProperty; + CharProperty = charProperty; + KeyValuePairProperty = keyValuePairProperty; + NullableDateTime = nullableDateTime; + NullableTimeSpan = nullableTimeSpan; + StringList = stringList; + StringArray = stringArray; + StringMap = stringMap; + IntStringMap = intStringMap; + SubType = subType; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Id")] + public int Id { get; set; } + + /// + /// + [JsonProperty(PropertyName = "NullableId")] + public int? NullableId { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ByteProperty")] + public int ByteProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ShortProperty")] + public int ShortProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "IntProperty")] + public int IntProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "LongProperty")] + public long LongProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UShortProperty")] + public int UShortProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UIntProperty")] + public int UIntProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ULongProperty")] + public long ULongProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FloatProperty")] + public double FloatProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "DoubleProperty")] + public double DoubleProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "DecimalProperty")] + public double DecimalProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StringProperty")] + public string StringProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "DateTimeProperty")] + public System.DateTime DateTimeProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "TimeSpanProperty")] + public string TimeSpanProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "DateTimeOffsetProperty")] + public string DateTimeOffsetProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "GuidProperty")] + public string GuidProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "CharProperty")] + public string CharProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "KeyValuePairProperty")] + public KeyValuePairStringString KeyValuePairProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "NullableDateTime")] + public System.DateTime? NullableDateTime { get; set; } + + /// + /// + [JsonProperty(PropertyName = "NullableTimeSpan")] + public string NullableTimeSpan { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StringList")] + public IList StringList { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StringArray")] + public IList StringArray { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StringMap")] + public IDictionary StringMap { get; set; } + + /// + /// + [JsonProperty(PropertyName = "IntStringMap")] + public IDictionary IntStringMap { get; set; } + + /// + /// + [JsonProperty(PropertyName = "SubType")] + public SubType SubType { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllowedAttributes.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllowedAttributes.cs new file mode 100644 index 00000000000..ac7f139e7bb --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AllowedAttributes.cs @@ -0,0 +1,48 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// AllowedAttributes + /// + /// + /// AllowedAttributes Description + /// + public partial class AllowedAttributes + { + /// + /// Initializes a new instance of the AllowedAttributes class. + /// + public AllowedAttributes() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the AllowedAttributes class. + /// + /// Range Description + public AllowedAttributes(int aliased = default(int)) + { + Aliased = aliased; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// Gets or sets range Description + /// + [JsonProperty(PropertyName = "Aliased")] + public int Aliased { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ArrayResult.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ArrayResult.cs new file mode 100644 index 00000000000..3c446253d97 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ArrayResult.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// ArrayResult + /// + /// + /// ArrayResult + /// + public partial class ArrayResult + { + /// + /// Initializes a new instance of the ArrayResult class. + /// + public ArrayResult() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the ArrayResult class. + /// + public ArrayResult(string result = default(string)) + { + Result = result; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Result")] + public string Result { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRoles.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRoles.cs new file mode 100644 index 00000000000..079d4380fbe --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRoles.cs @@ -0,0 +1,60 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// AssignRoles + /// + /// + /// AssignRoles + /// + public partial class AssignRoles + { + /// + /// Initializes a new instance of the AssignRoles class. + /// + public AssignRoles() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the AssignRoles class. + /// + public AssignRoles(string userName = default(string), IList permissions = default(IList), IList roles = default(IList)) + { + UserName = userName; + Permissions = permissions; + Roles = roles; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "UserName")] + public string UserName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Permissions")] + public IList Permissions { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Roles")] + public IList Roles { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRolesResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRolesResponse.cs new file mode 100644 index 00000000000..5da06f2f775 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRolesResponse.cs @@ -0,0 +1,60 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// AssignRolesResponse + /// + /// + /// AssignRolesResponse + /// + public partial class AssignRolesResponse + { + /// + /// Initializes a new instance of the AssignRolesResponse class. + /// + public AssignRolesResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the AssignRolesResponse class. + /// + public AssignRolesResponse(IList allRoles = default(IList), IList allPermissions = default(IList), ResponseStatus responseStatus = default(ResponseStatus)) + { + AllRoles = allRoles; + AllPermissions = allPermissions; + ResponseStatus = responseStatus; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "AllRoles")] + public IList AllRoles { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllPermissions")] + public IList AllPermissions { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ResponseStatus")] + public ResponseStatus ResponseStatus { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRolesResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRolesResponseException.cs new file mode 100644 index 00000000000..64153de2baf --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AssignRolesResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with AssignRolesResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class AssignRolesResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public AssignRolesResponse Body { get; set; } + + /// + /// Initializes a new instance of the AssignRolesResponseException class. + /// + public AssignRolesResponseException() + { + } + + /// + /// Initializes a new instance of the AssignRolesResponseException class. + /// + /// The exception message. + public AssignRolesResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the AssignRolesResponseException class. + /// + /// The exception message. + /// Inner exception. + public AssignRolesResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the AssignRolesResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected AssignRolesResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Authenticate.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Authenticate.cs new file mode 100644 index 00000000000..3ae1361a2a5 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Authenticate.cs @@ -0,0 +1,150 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// Authenticate + /// + /// + /// Authenticate + /// + public partial class Authenticate + { + /// + /// Initializes a new instance of the Authenticate class. + /// + public Authenticate() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the Authenticate class. + /// + public Authenticate(string provider = default(string), string state = default(string), string oauthToken = default(string), string oauthVerifier = default(string), string userName = default(string), string password = default(string), bool? rememberMe = default(bool?), string continueProperty = default(string), string nonce = default(string), string uri = default(string), string response = default(string), string qop = default(string), string nc = default(string), string cnonce = default(string), bool? useTokenCookie = default(bool?), string accessToken = default(string), string accessTokenSecret = default(string), IDictionary meta = default(IDictionary)) + { + Provider = provider; + State = state; + OauthToken = oauthToken; + OauthVerifier = oauthVerifier; + UserName = userName; + Password = password; + RememberMe = rememberMe; + ContinueProperty = continueProperty; + Nonce = nonce; + Uri = uri; + Response = response; + Qop = qop; + Nc = nc; + Cnonce = cnonce; + UseTokenCookie = useTokenCookie; + AccessToken = accessToken; + AccessTokenSecret = accessTokenSecret; + Meta = meta; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "provider")] + public string Provider { get; set; } + + /// + /// + [JsonProperty(PropertyName = "State")] + public string State { get; set; } + + /// + /// + [JsonProperty(PropertyName = "oauth_token")] + public string OauthToken { get; set; } + + /// + /// + [JsonProperty(PropertyName = "oauth_verifier")] + public string OauthVerifier { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UserName")] + public string UserName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Password")] + public string Password { get; set; } + + /// + /// + [JsonProperty(PropertyName = "RememberMe")] + public bool? RememberMe { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Continue")] + public string ContinueProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "nonce")] + public string Nonce { get; set; } + + /// + /// + [JsonProperty(PropertyName = "uri")] + public string Uri { get; set; } + + /// + /// + [JsonProperty(PropertyName = "response")] + public string Response { get; set; } + + /// + /// + [JsonProperty(PropertyName = "qop")] + public string Qop { get; set; } + + /// + /// + [JsonProperty(PropertyName = "nc")] + public string Nc { get; set; } + + /// + /// + [JsonProperty(PropertyName = "cnonce")] + public string Cnonce { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UseTokenCookie")] + public bool? UseTokenCookie { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AccessToken")] + public string AccessToken { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AccessTokenSecret")] + public string AccessTokenSecret { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Meta")] + public IDictionary Meta { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AuthenticateResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AuthenticateResponse.cs new file mode 100644 index 00000000000..903a1505fd3 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AuthenticateResponse.cs @@ -0,0 +1,96 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// AuthenticateResponse + /// + /// + /// AuthenticateResponse + /// + public partial class AuthenticateResponse + { + /// + /// Initializes a new instance of the AuthenticateResponse class. + /// + public AuthenticateResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the AuthenticateResponse class. + /// + public AuthenticateResponse(string userId = default(string), string sessionId = default(string), string userName = default(string), string displayName = default(string), string referrerUrl = default(string), string bearerToken = default(string), string refreshToken = default(string), ResponseStatus responseStatus = default(ResponseStatus), IDictionary meta = default(IDictionary)) + { + UserId = userId; + SessionId = sessionId; + UserName = userName; + DisplayName = displayName; + ReferrerUrl = referrerUrl; + BearerToken = bearerToken; + RefreshToken = refreshToken; + ResponseStatus = responseStatus; + Meta = meta; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "UserId")] + public string UserId { get; set; } + + /// + /// + [JsonProperty(PropertyName = "SessionId")] + public string SessionId { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UserName")] + public string UserName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "DisplayName")] + public string DisplayName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ReferrerUrl")] + public string ReferrerUrl { get; set; } + + /// + /// + [JsonProperty(PropertyName = "BearerToken")] + public string BearerToken { get; set; } + + /// + /// + [JsonProperty(PropertyName = "RefreshToken")] + public string RefreshToken { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ResponseStatus")] + public ResponseStatus ResponseStatus { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Meta")] + public IDictionary Meta { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AuthenticateResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AuthenticateResponseException.cs new file mode 100644 index 00000000000..a28aafb8ddb --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/AuthenticateResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with AuthenticateResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class AuthenticateResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public AuthenticateResponse Body { get; set; } + + /// + /// Initializes a new instance of the AuthenticateResponseException class. + /// + public AuthenticateResponseException() + { + } + + /// + /// Initializes a new instance of the AuthenticateResponseException class. + /// + /// The exception message. + public AuthenticateResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the AuthenticateResponseException class. + /// + /// The exception message. + /// Inner exception. + public AuthenticateResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the AuthenticateResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected AuthenticateResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/CustomUserSession.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/CustomUserSession.cs new file mode 100644 index 00000000000..7fad6995403 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/CustomUserSession.cs @@ -0,0 +1,312 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// CustomUserSession + /// + /// + /// CustomUserSession + /// + public partial class CustomUserSession + { + /// + /// Initializes a new instance of the CustomUserSession class. + /// + public CustomUserSession() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the CustomUserSession class. + /// + public CustomUserSession(string customName = default(string), string customInfo = default(string), string referrerUrl = default(string), string id = default(string), string userAuthId = default(string), string userAuthName = default(string), string userName = default(string), string twitterUserId = default(string), string twitterScreenName = default(string), string facebookUserId = default(string), string facebookUserName = default(string), string firstName = default(string), string lastName = default(string), string displayName = default(string), string company = default(string), string email = default(string), string primaryEmail = default(string), string phoneNumber = default(string), System.DateTime? birthDate = default(System.DateTime?), string birthDateRaw = default(string), string address = default(string), string address2 = default(string), string city = default(string), string state = default(string), string country = default(string), string culture = default(string), string fullName = default(string), string gender = default(string), string language = default(string), string mailAddress = default(string), string nickname = default(string), string postalCode = default(string), string timeZone = default(string), string requestTokenSecret = default(string), System.DateTime createdAt = default(System.DateTime), System.DateTime lastModified = default(System.DateTime), IList roles = default(IList), IList permissions = default(IList), bool isAuthenticated = default(bool), bool fromToken = default(bool), string profileUrl = default(string), string sequence = default(string), long tag = default(long), string authProvider = default(string), IList providerOAuthAccess = default(IList)) + { + CustomName = customName; + CustomInfo = customInfo; + ReferrerUrl = referrerUrl; + Id = id; + UserAuthId = userAuthId; + UserAuthName = userAuthName; + UserName = userName; + TwitterUserId = twitterUserId; + TwitterScreenName = twitterScreenName; + FacebookUserId = facebookUserId; + FacebookUserName = facebookUserName; + FirstName = firstName; + LastName = lastName; + DisplayName = displayName; + Company = company; + Email = email; + PrimaryEmail = primaryEmail; + PhoneNumber = phoneNumber; + BirthDate = birthDate; + BirthDateRaw = birthDateRaw; + Address = address; + Address2 = address2; + City = city; + State = state; + Country = country; + Culture = culture; + FullName = fullName; + Gender = gender; + Language = language; + MailAddress = mailAddress; + Nickname = nickname; + PostalCode = postalCode; + TimeZone = timeZone; + RequestTokenSecret = requestTokenSecret; + CreatedAt = createdAt; + LastModified = lastModified; + Roles = roles; + Permissions = permissions; + IsAuthenticated = isAuthenticated; + FromToken = fromToken; + ProfileUrl = profileUrl; + Sequence = sequence; + Tag = tag; + AuthProvider = authProvider; + ProviderOAuthAccess = providerOAuthAccess; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "CustomName")] + public string CustomName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "CustomInfo")] + public string CustomInfo { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ReferrerUrl")] + public string ReferrerUrl { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Id")] + public string Id { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UserAuthId")] + public string UserAuthId { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UserAuthName")] + public string UserAuthName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UserName")] + public string UserName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "TwitterUserId")] + public string TwitterUserId { get; set; } + + /// + /// + [JsonProperty(PropertyName = "TwitterScreenName")] + public string TwitterScreenName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FacebookUserId")] + public string FacebookUserId { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FacebookUserName")] + public string FacebookUserName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FirstName")] + public string FirstName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "LastName")] + public string LastName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "DisplayName")] + public string DisplayName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Company")] + public string Company { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Email")] + public string Email { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PrimaryEmail")] + public string PrimaryEmail { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PhoneNumber")] + public string PhoneNumber { get; set; } + + /// + /// + [JsonProperty(PropertyName = "BirthDate")] + public System.DateTime? BirthDate { get; set; } + + /// + /// + [JsonProperty(PropertyName = "BirthDateRaw")] + public string BirthDateRaw { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Address")] + public string Address { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Address2")] + public string Address2 { get; set; } + + /// + /// + [JsonProperty(PropertyName = "City")] + public string City { get; set; } + + /// + /// + [JsonProperty(PropertyName = "State")] + public string State { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Country")] + public string Country { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Culture")] + public string Culture { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FullName")] + public string FullName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Gender")] + public string Gender { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Language")] + public string Language { get; set; } + + /// + /// + [JsonProperty(PropertyName = "MailAddress")] + public string MailAddress { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Nickname")] + public string Nickname { get; set; } + + /// + /// + [JsonProperty(PropertyName = "PostalCode")] + public string PostalCode { get; set; } + + /// + /// + [JsonProperty(PropertyName = "TimeZone")] + public string TimeZone { get; set; } + + /// + /// + [JsonProperty(PropertyName = "RequestTokenSecret")] + public string RequestTokenSecret { get; set; } + + /// + /// + [JsonProperty(PropertyName = "CreatedAt")] + public System.DateTime CreatedAt { get; set; } + + /// + /// + [JsonProperty(PropertyName = "LastModified")] + public System.DateTime LastModified { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Roles")] + public IList Roles { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Permissions")] + public IList Permissions { get; set; } + + /// + /// + [JsonProperty(PropertyName = "IsAuthenticated")] + public bool IsAuthenticated { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FromToken")] + public bool FromToken { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ProfileUrl")] + public string ProfileUrl { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Sequence")] + public string Sequence { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Tag")] + public long Tag { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AuthProvider")] + public string AuthProvider { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ProviderOAuthAccess")] + public IList ProviderOAuthAccess { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetErrorModel.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetErrorModel.cs new file mode 100644 index 00000000000..cd01559c160 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetErrorModel.cs @@ -0,0 +1,52 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// KeyValuePair<String,String> + /// + /// + /// KeyValuePair<String,String> + /// + public partial class GetErrorModel + { + /// + /// Initializes a new instance of the GetErrorModel class. + /// + public GetErrorModel() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the GetErrorModel class. + /// + public GetErrorModel(string key = default(string), string value = default(string)) + { + Key = key; + Value = value; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Key")] + public string Key { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Value")] + public string Value { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetErrorModelException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetErrorModelException.cs new file mode 100644 index 00000000000..f22ae689078 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetErrorModelException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with GetErrorModel + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class GetErrorModelException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public GetErrorModel Body { get; set; } + + /// + /// Initializes a new instance of the GetErrorModelException class. + /// + public GetErrorModelException() + { + } + + /// + /// Initializes a new instance of the GetErrorModelException class. + /// + /// The exception message. + public GetErrorModelException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the GetErrorModelException class. + /// + /// The exception message. + /// Inner exception. + public GetErrorModelException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the GetErrorModelException class. + /// + /// Serialization info. + /// Streaming context. + protected GetErrorModelException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetMovie.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetMovie.cs new file mode 100644 index 00000000000..a36c1da439d --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetMovie.cs @@ -0,0 +1,60 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// GetMovie + /// + /// + /// GetMovie + /// + public partial class GetMovie + { + /// + /// Initializes a new instance of the GetMovie class. + /// + public GetMovie() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the GetMovie class. + /// + /// Required ID of Movie. + /// List of additional objects to include in the + /// movie response. + public GetMovie(long id = default(long), IList includes = default(IList)) + { + Id = id; + Includes = includes; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// Gets or sets required ID of Movie. + /// + [JsonProperty(PropertyName = "Id")] + public long Id { get; set; } + + /// + /// Gets or sets list of additional objects to include in the movie + /// response. + /// + [JsonProperty(PropertyName = "Includes")] + public IList Includes { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetSessionResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetSessionResponse.cs new file mode 100644 index 00000000000..a3faf8c0039 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetSessionResponse.cs @@ -0,0 +1,58 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// GetSessionResponse + /// + /// + /// GetSessionResponse + /// + public partial class GetSessionResponse + { + /// + /// Initializes a new instance of the GetSessionResponse class. + /// + public GetSessionResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the GetSessionResponse class. + /// + public GetSessionResponse(CustomUserSession result = default(CustomUserSession), UnAuthInfo unAuthInfo = default(UnAuthInfo), ResponseStatus responseStatus = default(ResponseStatus)) + { + Result = result; + UnAuthInfo = unAuthInfo; + ResponseStatus = responseStatus; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Result")] + public CustomUserSession Result { get; set; } + + /// + /// + [JsonProperty(PropertyName = "UnAuthInfo")] + public UnAuthInfo UnAuthInfo { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ResponseStatus")] + public ResponseStatus ResponseStatus { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetSessionResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetSessionResponseException.cs new file mode 100644 index 00000000000..8f7054af4c9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/GetSessionResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with GetSessionResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class GetSessionResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public GetSessionResponse Body { get; set; } + + /// + /// Initializes a new instance of the GetSessionResponseException class. + /// + public GetSessionResponseException() + { + } + + /// + /// Initializes a new instance of the GetSessionResponseException class. + /// + /// The exception message. + public GetSessionResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the GetSessionResponseException class. + /// + /// The exception message. + /// Inner exception. + public GetSessionResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the GetSessionResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected GetSessionResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Hello.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Hello.cs new file mode 100644 index 00000000000..9f7731ec5c7 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Hello.cs @@ -0,0 +1,52 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// Hello + /// + /// + /// Hello + /// + public partial class Hello + { + /// + /// Initializes a new instance of the Hello class. + /// + public Hello() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the Hello class. + /// + public Hello(string name = default(string), string title = default(string)) + { + Name = name; + Title = title; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Title")] + public string Title { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypes.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypes.cs new file mode 100644 index 00000000000..a08d0d3e5dc --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypes.cs @@ -0,0 +1,58 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloAllTypes + /// + /// + /// HelloAllTypes + /// + public partial class HelloAllTypes + { + /// + /// Initializes a new instance of the HelloAllTypes class. + /// + public HelloAllTypes() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloAllTypes class. + /// + public HelloAllTypes(string name = default(string), AllTypes allTypes = default(AllTypes), AllCollectionTypes allCollectionTypes = default(AllCollectionTypes)) + { + Name = name; + AllTypes = allTypes; + AllCollectionTypes = allCollectionTypes; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllTypes")] + public AllTypes AllTypes { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllCollectionTypes")] + public AllCollectionTypes AllCollectionTypes { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesResponse.cs new file mode 100644 index 00000000000..ad7bf3566c0 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesResponse.cs @@ -0,0 +1,58 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloAllTypesResponse + /// + /// + /// HelloAllTypesResponse + /// + public partial class HelloAllTypesResponse + { + /// + /// Initializes a new instance of the HelloAllTypesResponse class. + /// + public HelloAllTypesResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloAllTypesResponse class. + /// + public HelloAllTypesResponse(string result = default(string), AllTypes allTypes = default(AllTypes), AllCollectionTypes allCollectionTypes = default(AllCollectionTypes)) + { + Result = result; + AllTypes = allTypes; + AllCollectionTypes = allCollectionTypes; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Result")] + public string Result { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllTypes")] + public AllTypes AllTypes { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllCollectionTypes")] + public AllCollectionTypes AllCollectionTypes { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesResponseException.cs new file mode 100644 index 00000000000..28cc3a909ec --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with HelloAllTypesResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class HelloAllTypesResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public HelloAllTypesResponse Body { get; set; } + + /// + /// Initializes a new instance of the HelloAllTypesResponseException class. + /// + public HelloAllTypesResponseException() + { + } + + /// + /// Initializes a new instance of the HelloAllTypesResponseException class. + /// + /// The exception message. + public HelloAllTypesResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the HelloAllTypesResponseException class. + /// + /// The exception message. + /// Inner exception. + public HelloAllTypesResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the HelloAllTypesResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected HelloAllTypesResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesWithResult.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesWithResult.cs new file mode 100644 index 00000000000..bce0544abfe --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloAllTypesWithResult.cs @@ -0,0 +1,58 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloAllTypesWithResult + /// + /// + /// HelloAllTypesWithResult + /// + public partial class HelloAllTypesWithResult + { + /// + /// Initializes a new instance of the HelloAllTypesWithResult class. + /// + public HelloAllTypesWithResult() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloAllTypesWithResult class. + /// + public HelloAllTypesWithResult(string name = default(string), AllTypes allTypes = default(AllTypes), AllCollectionTypes allCollectionTypes = default(AllCollectionTypes)) + { + Name = name; + AllTypes = allTypes; + AllCollectionTypes = allCollectionTypes; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllTypes")] + public AllTypes AllTypes { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllCollectionTypes")] + public AllCollectionTypes AllCollectionTypes { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloArray.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloArray.cs new file mode 100644 index 00000000000..f4a2451bdcf --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloArray.cs @@ -0,0 +1,48 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// HelloArray + /// + /// + /// HelloArray + /// + public partial class HelloArray + { + /// + /// Initializes a new instance of the HelloArray class. + /// + public HelloArray() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloArray class. + /// + public HelloArray(IList names = default(IList)) + { + Names = names; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Names")] + public IList Names { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloDateTime.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloDateTime.cs new file mode 100644 index 00000000000..24a8d5058a0 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloDateTime.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloDateTime + /// + /// + /// HelloDateTime + /// + public partial class HelloDateTime + { + /// + /// Initializes a new instance of the HelloDateTime class. + /// + public HelloDateTime() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloDateTime class. + /// + public HelloDateTime(System.DateTime dateTime = default(System.DateTime)) + { + DateTime = dateTime; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "DateTime")] + public System.DateTime DateTime { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloDateTimeException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloDateTimeException.cs new file mode 100644 index 00000000000..894f7c39471 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloDateTimeException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with HelloDateTime + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class HelloDateTimeException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public HelloDateTime Body { get; set; } + + /// + /// Initializes a new instance of the HelloDateTimeException class. + /// + public HelloDateTimeException() + { + } + + /// + /// Initializes a new instance of the HelloDateTimeException class. + /// + /// The exception message. + public HelloDateTimeException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the HelloDateTimeException class. + /// + /// The exception message. + /// Inner exception. + public HelloDateTimeException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the HelloDateTimeException class. + /// + /// Serialization info. + /// Streaming context. + protected HelloDateTimeException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloList.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloList.cs new file mode 100644 index 00000000000..1b783161f8f --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloList.cs @@ -0,0 +1,48 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// HelloList + /// + /// + /// HelloList + /// + public partial class HelloList + { + /// + /// Initializes a new instance of the HelloList class. + /// + public HelloList() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloList class. + /// + public HelloList(IList names = default(IList)) + { + Names = names; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Names")] + public IList Names { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloResponse.cs new file mode 100644 index 00000000000..d56e8b3e92e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloResponse.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloResponse + /// + /// + /// HelloResponse + /// + public partial class HelloResponse + { + /// + /// Initializes a new instance of the HelloResponse class. + /// + public HelloResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloResponse class. + /// + public HelloResponse(string result = default(string)) + { + Result = result; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Result")] + public string Result { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloResponseException.cs new file mode 100644 index 00000000000..de8000c78e1 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with HelloResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class HelloResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public HelloResponse Body { get; set; } + + /// + /// Initializes a new instance of the HelloResponseException class. + /// + public HelloResponseException() + { + } + + /// + /// Initializes a new instance of the HelloResponseException class. + /// + /// The exception message. + public HelloResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the HelloResponseException class. + /// + /// The exception message. + /// Inner exception. + public HelloResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the HelloResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected HelloResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloString.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloString.cs new file mode 100644 index 00000000000..c8aa3038b5d --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloString.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloString + /// + /// + /// HelloString + /// + public partial class HelloString + { + /// + /// Initializes a new instance of the HelloString class. + /// + public HelloString() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloString class. + /// + public HelloString(string name = default(string)) + { + Name = name; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloTypes.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloTypes.cs new file mode 100644 index 00000000000..1cc6d54b055 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloTypes.cs @@ -0,0 +1,58 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloTypes + /// + /// + /// HelloTypes + /// + public partial class HelloTypes + { + /// + /// Initializes a new instance of the HelloTypes class. + /// + public HelloTypes() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloTypes class. + /// + public HelloTypes(string stringProperty = default(string), bool boolProperty = default(bool), int intProperty = default(int)) + { + StringProperty = stringProperty; + BoolProperty = boolProperty; + IntProperty = intProperty; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "String")] + public string StringProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Bool")] + public bool BoolProperty { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Int")] + public int IntProperty { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloTypesException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloTypesException.cs new file mode 100644 index 00000000000..403bc3f9ea1 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloTypesException.cs @@ -0,0 +1,92 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with HelloTypes information. + /// +#if LEGACY + [System.Serializable] +#endif + public class HelloTypesException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public HelloTypes Body { get; set; } + + /// + /// Initializes a new instance of the HelloTypesException class. + /// + public HelloTypesException() + { + } + + /// + /// Initializes a new instance of the HelloTypesException class. + /// + /// The exception message. + public HelloTypesException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the HelloTypesException class. + /// + /// The exception message. + /// Inner exception. + public HelloTypesException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the HelloTypesException class. + /// + /// Serialization info. + /// Streaming context. + protected HelloTypesException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloVoid.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloVoid.cs new file mode 100644 index 00000000000..46ae22a87bb --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloVoid.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloVoid + /// + /// + /// HelloVoid + /// + public partial class HelloVoid + { + /// + /// Initializes a new instance of the HelloVoid class. + /// + public HelloVoid() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloVoid class. + /// + public HelloVoid(string name = default(string)) + { + Name = name; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloWithRoute.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloWithRoute.cs new file mode 100644 index 00000000000..9ed066d65bd --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloWithRoute.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloWithRoute + /// + /// + /// HelloWithRoute + /// + public partial class HelloWithRoute + { + /// + /// Initializes a new instance of the HelloWithRoute class. + /// + public HelloWithRoute() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloWithRoute class. + /// + public HelloWithRoute(string name = default(string)) + { + Name = name; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZip.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZip.cs new file mode 100644 index 00000000000..6c55ff70a74 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZip.cs @@ -0,0 +1,54 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// HelloZip + /// + /// + /// HelloZip + /// + public partial class HelloZip + { + /// + /// Initializes a new instance of the HelloZip class. + /// + public HelloZip() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloZip class. + /// + public HelloZip(string name = default(string), IList test = default(IList)) + { + Name = name; + Test = test; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Test")] + public IList Test { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZipResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZipResponse.cs new file mode 100644 index 00000000000..5ca648a5634 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZipResponse.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// HelloZipResponse + /// + /// + /// HelloZipResponse + /// + public partial class HelloZipResponse + { + /// + /// Initializes a new instance of the HelloZipResponse class. + /// + public HelloZipResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the HelloZipResponse class. + /// + public HelloZipResponse(string result = default(string)) + { + Result = result; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Result")] + public string Result { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZipResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZipResponseException.cs new file mode 100644 index 00000000000..306d687a8e6 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/HelloZipResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with HelloZipResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class HelloZipResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public HelloZipResponse Body { get; set; } + + /// + /// Initializes a new instance of the HelloZipResponseException class. + /// + public HelloZipResponseException() + { + } + + /// + /// Initializes a new instance of the HelloZipResponseException class. + /// + /// The exception message. + public HelloZipResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the HelloZipResponseException class. + /// + /// The exception message. + /// Inner exception. + public HelloZipResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the HelloZipResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected HelloZipResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/KeyValuePairStringString.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/KeyValuePairStringString.cs new file mode 100644 index 00000000000..da928d7b377 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/KeyValuePairStringString.cs @@ -0,0 +1,52 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// KeyValuePair<String,String> + /// + /// + /// KeyValuePair<String,String> + /// + public partial class KeyValuePairStringString + { + /// + /// Initializes a new instance of the KeyValuePairStringString class. + /// + public KeyValuePairStringString() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the KeyValuePairStringString class. + /// + public KeyValuePairStringString(string key = default(string), string value = default(string)) + { + Key = key; + Value = value; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Key")] + public string Key { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Value")] + public string Value { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ListResult.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ListResult.cs new file mode 100644 index 00000000000..f422e2c439e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ListResult.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// ListResult + /// + /// + /// ListResult + /// + public partial class ListResult + { + /// + /// Initializes a new instance of the ListResult class. + /// + public ListResult() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the ListResult class. + /// + public ListResult(string result = default(string)) + { + Result = result; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Result")] + public string Result { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/MovieResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/MovieResponse.cs new file mode 100644 index 00000000000..9ed0cd9257e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/MovieResponse.cs @@ -0,0 +1,48 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// MovieResponse + /// + /// + /// MovieResponse + /// + public partial class MovieResponse + { + /// + /// Initializes a new instance of the MovieResponse class. + /// + public MovieResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the MovieResponse class. + /// + public MovieResponse(IList includes = default(IList)) + { + Includes = includes; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Includes")] + public IList Includes { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/MovieResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/MovieResponseException.cs new file mode 100644 index 00000000000..3941e42801f --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/MovieResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with MovieResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class MovieResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public MovieResponse Body { get; set; } + + /// + /// Initializes a new instance of the MovieResponseException class. + /// + public MovieResponseException() + { + } + + /// + /// Initializes a new instance of the MovieResponseException class. + /// + /// The exception message. + public MovieResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the MovieResponseException class. + /// + /// The exception message. + /// Inner exception. + public MovieResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the MovieResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected MovieResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Poco.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Poco.cs new file mode 100644 index 00000000000..d18b3b77940 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/Poco.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// Poco + /// + /// + /// Poco + /// + public partial class Poco + { + /// + /// Initializes a new instance of the Poco class. + /// + public Poco() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the Poco class. + /// + public Poco(string name = default(string)) + { + Name = name; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ResponseError.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ResponseError.cs new file mode 100644 index 00000000000..4966a5f11de --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ResponseError.cs @@ -0,0 +1,66 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// ResponseError + /// + /// + /// ResponseError + /// + public partial class ResponseError + { + /// + /// Initializes a new instance of the ResponseError class. + /// + public ResponseError() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the ResponseError class. + /// + public ResponseError(string errorCode = default(string), string fieldName = default(string), string message = default(string), IDictionary meta = default(IDictionary)) + { + ErrorCode = errorCode; + FieldName = fieldName; + Message = message; + Meta = meta; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "ErrorCode")] + public string ErrorCode { get; set; } + + /// + /// + [JsonProperty(PropertyName = "FieldName")] + public string FieldName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Message")] + public string Message { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Meta")] + public IDictionary Meta { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ResponseStatus.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ResponseStatus.cs new file mode 100644 index 00000000000..ff3a7528624 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ResponseStatus.cs @@ -0,0 +1,72 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// ResponseStatus + /// + /// + /// ResponseStatus + /// + public partial class ResponseStatus + { + /// + /// Initializes a new instance of the ResponseStatus class. + /// + public ResponseStatus() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the ResponseStatus class. + /// + public ResponseStatus(string errorCode = default(string), string message = default(string), string stackTrace = default(string), IList errors = default(IList), IDictionary meta = default(IDictionary)) + { + ErrorCode = errorCode; + Message = message; + StackTrace = stackTrace; + Errors = errors; + Meta = meta; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "ErrorCode")] + public string ErrorCode { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Message")] + public string Message { get; set; } + + /// + /// + [JsonProperty(PropertyName = "StackTrace")] + public string StackTrace { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Errors")] + public IList Errors { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Meta")] + public IDictionary Meta { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ReturnedDto.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ReturnedDto.cs new file mode 100644 index 00000000000..55f1e625200 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/ReturnedDto.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// ReturnedDto + /// + /// + /// ReturnedDto + /// + public partial class ReturnedDto + { + /// + /// Initializes a new instance of the ReturnedDto class. + /// + public ReturnedDto() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the ReturnedDto class. + /// + public ReturnedDto(int id = default(int)) + { + Id = id; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Id")] + public int Id { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/SubType.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/SubType.cs new file mode 100644 index 00000000000..b66e398d646 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/SubType.cs @@ -0,0 +1,52 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// SubType + /// + /// + /// SubType + /// + public partial class SubType + { + /// + /// Initializes a new instance of the SubType class. + /// + public SubType() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the SubType class. + /// + public SubType(int id = default(int), string name = default(string)) + { + Id = id; + Name = name; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "Id")] + public int Id { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Name")] + public string Name { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRoles.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRoles.cs new file mode 100644 index 00000000000..cf08a8c3ed6 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRoles.cs @@ -0,0 +1,60 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// UnAssignRoles + /// + /// + /// UnAssignRoles + /// + public partial class UnAssignRoles + { + /// + /// Initializes a new instance of the UnAssignRoles class. + /// + public UnAssignRoles() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the UnAssignRoles class. + /// + public UnAssignRoles(string userName = default(string), IList permissions = default(IList), IList roles = default(IList)) + { + UserName = userName; + Permissions = permissions; + Roles = roles; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "UserName")] + public string UserName { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Permissions")] + public IList Permissions { get; set; } + + /// + /// + [JsonProperty(PropertyName = "Roles")] + public IList Roles { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRolesResponse.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRolesResponse.cs new file mode 100644 index 00000000000..4c5cb485285 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRolesResponse.cs @@ -0,0 +1,60 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + /// + /// UnAssignRolesResponse + /// + /// + /// UnAssignRolesResponse + /// + public partial class UnAssignRolesResponse + { + /// + /// Initializes a new instance of the UnAssignRolesResponse class. + /// + public UnAssignRolesResponse() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the UnAssignRolesResponse class. + /// + public UnAssignRolesResponse(IList allRoles = default(IList), IList allPermissions = default(IList), ResponseStatus responseStatus = default(ResponseStatus)) + { + AllRoles = allRoles; + AllPermissions = allPermissions; + ResponseStatus = responseStatus; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "AllRoles")] + public IList AllRoles { get; set; } + + /// + /// + [JsonProperty(PropertyName = "AllPermissions")] + public IList AllPermissions { get; set; } + + /// + /// + [JsonProperty(PropertyName = "ResponseStatus")] + public ResponseStatus ResponseStatus { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRolesResponseException.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRolesResponseException.cs new file mode 100644 index 00000000000..80b1975fe78 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAssignRolesResponseException.cs @@ -0,0 +1,93 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Microsoft.Rest; + + /// + /// Exception thrown for an invalid response with UnAssignRolesResponse + /// information. + /// +#if LEGACY + [System.Serializable] +#endif + public class UnAssignRolesResponseException : RestException + { + /// + /// Gets information about the associated HTTP request. + /// + public HttpRequestMessageWrapper Request { get; set; } + + /// + /// Gets information about the associated HTTP response. + /// + public HttpResponseMessageWrapper Response { get; set; } + + /// + /// Gets or sets the body object. + /// + public UnAssignRolesResponse Body { get; set; } + + /// + /// Initializes a new instance of the UnAssignRolesResponseException class. + /// + public UnAssignRolesResponseException() + { + } + + /// + /// Initializes a new instance of the UnAssignRolesResponseException class. + /// + /// The exception message. + public UnAssignRolesResponseException(string message) + : this(message, null) + { + } + + /// + /// Initializes a new instance of the UnAssignRolesResponseException class. + /// + /// The exception message. + /// Inner exception. + public UnAssignRolesResponseException(string message, System.Exception innerException) + : base(message, innerException) + { + } + +#if LEGACY + /// + /// Initializes a new instance of the UnAssignRolesResponseException class. + /// + /// Serialization info. + /// Streaming context. + protected UnAssignRolesResponseException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } + + /// + /// Serializes content of the exception. + /// + /// Serialization info. + /// Streaming context. + /// + /// Thrown when a required parameter is null + /// + [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + { + base.GetObjectData(info, context); + if (info == null) + { + throw new System.ArgumentNullException("info"); + } + + info.AddValue("Request", Request); + info.AddValue("Response", Response); + info.AddValue("Body", Body); + } +#endif + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAuthInfo.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAuthInfo.cs new file mode 100644 index 00000000000..950274262fb --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UnAuthInfo.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// UnAuthInfo + /// + /// + /// UnAuthInfo + /// + public partial class UnAuthInfo + { + /// + /// Initializes a new instance of the UnAuthInfo class. + /// + public UnAuthInfo() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the UnAuthInfo class. + /// + public UnAuthInfo(string customInfo = default(string)) + { + CustomInfo = customInfo; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "CustomInfo")] + public string CustomInfo { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UpdateSession.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UpdateSession.cs new file mode 100644 index 00000000000..925a6b67df8 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/Models/UpdateSession.cs @@ -0,0 +1,46 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient.Models +{ + using Newtonsoft.Json; + using System.Linq; + + /// + /// UpdateSession + /// + /// + /// UpdateSession + /// + public partial class UpdateSession + { + /// + /// Initializes a new instance of the UpdateSession class. + /// + public UpdateSession() + { + CustomInit(); + } + + /// + /// Initializes a new instance of the UpdateSession class. + /// + public UpdateSession(string customName = default(string)) + { + CustomName = customName; + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults + /// + partial void CustomInit(); + + /// + /// + [JsonProperty(PropertyName = "CustomName")] + public string CustomName { get; set; } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnArrayRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnArrayRequest.cs new file mode 100644 index 00000000000..3a6bab856c3 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnArrayRequest.cs @@ -0,0 +1,172 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnArrayRequest operations. + /// + public partial class ReturnArrayRequest : IServiceOperations, IReturnArrayRequest + { + /// + /// Initializes a new instance of the ReturnArrayRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public ReturnArrayRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "return-array").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnArrayRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnArrayRequestExtensions.cs new file mode 100644 index 00000000000..f3fcc6aca8b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnArrayRequestExtensions.cs @@ -0,0 +1,41 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for ReturnArrayRequest. + /// + public static partial class ReturnArrayRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static IList Get(this IReturnArrayRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task> GetAsync(this IReturnArrayRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryDtoRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryDtoRequest.cs new file mode 100644 index 00000000000..5f30509950e --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryDtoRequest.cs @@ -0,0 +1,172 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnDictionaryDtoRequest operations. + /// + public partial class ReturnDictionaryDtoRequest : IServiceOperations, IReturnDictionaryDtoRequest + { + /// + /// Initializes a new instance of the ReturnDictionaryDtoRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public ReturnDictionaryDtoRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "return-dictionarydto").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IDictionary _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryDtoRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryDtoRequestExtensions.cs new file mode 100644 index 00000000000..d5414d84f3c --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryDtoRequestExtensions.cs @@ -0,0 +1,41 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for ReturnDictionaryDtoRequest. + /// + public static partial class ReturnDictionaryDtoRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static IDictionary Get(this IReturnDictionaryDtoRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task> GetAsync(this IReturnDictionaryDtoRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryStringRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryStringRequest.cs new file mode 100644 index 00000000000..2d0777d21df --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryStringRequest.cs @@ -0,0 +1,172 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnDictionaryStringRequest operations. + /// + public partial class ReturnDictionaryStringRequest : IServiceOperations, IReturnDictionaryStringRequest + { + /// + /// Initializes a new instance of the ReturnDictionaryStringRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public ReturnDictionaryStringRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "return-dictionarystring").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IDictionary _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryStringRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryStringRequestExtensions.cs new file mode 100644 index 00000000000..180bf0f40ab --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnDictionaryStringRequestExtensions.cs @@ -0,0 +1,41 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for ReturnDictionaryStringRequest. + /// + public static partial class ReturnDictionaryStringRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static IDictionary Get(this IReturnDictionaryStringRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task> GetAsync(this IReturnDictionaryStringRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnKeyValuePairRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnKeyValuePairRequest.cs new file mode 100644 index 00000000000..35c52bafdf1 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnKeyValuePairRequest.cs @@ -0,0 +1,172 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnKeyValuePairRequest operations. + /// + public partial class ReturnKeyValuePairRequest : IServiceOperations, IReturnKeyValuePairRequest + { + /// + /// Initializes a new instance of the ReturnKeyValuePairRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public ReturnKeyValuePairRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "return-keyvaluepair").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetErrorModelException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetErrorModel _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnKeyValuePairRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnKeyValuePairRequestExtensions.cs new file mode 100644 index 00000000000..dbdbf5cdae1 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnKeyValuePairRequestExtensions.cs @@ -0,0 +1,39 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for ReturnKeyValuePairRequest. + /// + public static partial class ReturnKeyValuePairRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static GetErrorModel Get(this IReturnKeyValuePairRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IReturnKeyValuePairRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnListRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnListRequest.cs new file mode 100644 index 00000000000..59cc44eeab7 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnListRequest.cs @@ -0,0 +1,172 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// ReturnListRequest operations. + /// + public partial class ReturnListRequest : IServiceOperations, IReturnListRequest + { + /// + /// Initializes a new instance of the ReturnListRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public ReturnListRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task>> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "return-list").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + IList _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse>(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject>(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnListRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnListRequestExtensions.cs new file mode 100644 index 00000000000..690033ea09b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ReturnListRequestExtensions.cs @@ -0,0 +1,41 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Collections; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for ReturnListRequest. + /// + public static partial class ReturnListRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static IList Get(this IReturnListRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task> GetAsync(this IReturnListRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredDtoRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredDtoRequest.cs new file mode 100644 index 00000000000..695b8e879ad --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredDtoRequest.cs @@ -0,0 +1,565 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// SecuredDtoRequest operations. + /// + public partial class SecuredDtoRequest : IServiceOperations, ISecuredDtoRequest + { + /// + /// Initializes a new instance of the SecuredDtoRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public SecuredDtoRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-dto-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-dto-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-dto-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-dto-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredDtoRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredDtoRequestExtensions.cs new file mode 100644 index 00000000000..b696cab49ff --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredDtoRequestExtensions.cs @@ -0,0 +1,113 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for SecuredDtoRequest. + /// + public static partial class SecuredDtoRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static string Get(this ISecuredDtoRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this ISecuredDtoRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Create(this ISecuredDtoRequest operations, object body = default(object)) + { + return operations.CreateAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this ISecuredDtoRequest operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Post(this ISecuredDtoRequest operations, object body = default(object)) + { + return operations.PostAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this ISecuredDtoRequest operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + public static string Delete(this ISecuredDtoRequest operations) + { + return operations.DeleteAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this ISecuredDtoRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredOpsRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredOpsRequest.cs new file mode 100644 index 00000000000..2c0f81c4a60 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredOpsRequest.cs @@ -0,0 +1,565 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// SecuredOpsRequest operations. + /// + public partial class SecuredOpsRequest : IServiceOperations, ISecuredOpsRequest + { + /// + /// Initializes a new instance of the SecuredOpsRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public SecuredOpsRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-ops-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-ops-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-ops-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-ops-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredOpsRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredOpsRequestExtensions.cs new file mode 100644 index 00000000000..194e6e7ce05 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredOpsRequestExtensions.cs @@ -0,0 +1,113 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for SecuredOpsRequest. + /// + public static partial class SecuredOpsRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static string Get(this ISecuredOpsRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this ISecuredOpsRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Create(this ISecuredOpsRequest operations, object body = default(object)) + { + return operations.CreateAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this ISecuredOpsRequest operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Post(this ISecuredOpsRequest operations, object body = default(object)) + { + return operations.PostAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this ISecuredOpsRequest operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + public static string Delete(this ISecuredOpsRequest operations) + { + return operations.DeleteAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this ISecuredOpsRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredRequest.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredRequest.cs new file mode 100644 index 00000000000..3b0e0742220 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredRequest.cs @@ -0,0 +1,565 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// SecuredRequest operations. + /// + public partial class SecuredRequest : IServiceOperations, ISecuredRequest + { + /// + /// Initializes a new instance of the SecuredRequest class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public SecuredRequest(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(object body = default(object), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "secured-service").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + string _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredRequestExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredRequestExtensions.cs new file mode 100644 index 00000000000..2038b5c5ffc --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/SecuredRequestExtensions.cs @@ -0,0 +1,113 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for SecuredRequest. + /// + public static partial class SecuredRequestExtensions + { + /// + /// The operations group for this extension method. + /// + public static string Get(this ISecuredRequest operations) + { + return operations.GetAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this ISecuredRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Create(this ISecuredRequest operations, object body = default(object)) + { + return operations.CreateAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this ISecuredRequest operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static string Post(this ISecuredRequest operations, object body = default(object)) + { + return operations.PostAsync(body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this ISecuredRequest operations, object body = default(object), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + public static string Delete(this ISecuredRequest operations) + { + return operations.DeleteAsync().GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this ISecuredRequest operations, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ServiceStackAutorestClient.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ServiceStackAutorestClient.cs new file mode 100644 index 00000000000..89a7d3978e7 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/ServiceStackAutorestClient.cs @@ -0,0 +1,327 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Microsoft.Rest.Serialization; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.Net; + using System.Net.Http; + + public partial class ServiceStackAutorestClient : ServiceClient, IServiceStackAutorestClient + { + /// + /// The base URI of the service. + /// + public System.Uri BaseUri { get; set; } + + /// + /// Gets or sets json serialization settings. + /// + public JsonSerializerSettings SerializationSettings { get; private set; } + + /// + /// Gets or sets json deserialization settings. + /// + public JsonSerializerSettings DeserializationSettings { get; private set; } + + /// + /// Accept Header + /// + public string Accept { get; private set; } + + /// + /// Gets the IReturnListRequest. + /// + public virtual IReturnListRequest ReturnListRequest { get; private set; } + + /// + /// Gets the IReturnArrayRequest. + /// + public virtual IReturnArrayRequest ReturnArrayRequest { get; private set; } + + /// + /// Gets the IReturnKeyValuePairRequest. + /// + public virtual IReturnKeyValuePairRequest ReturnKeyValuePairRequest { get; private set; } + + /// + /// Gets the IReturnDictionaryStringRequest. + /// + public virtual IReturnDictionaryStringRequest ReturnDictionaryStringRequest { get; private set; } + + /// + /// Gets the IReturnDictionaryDtoRequest. + /// + public virtual IReturnDictionaryDtoRequest ReturnDictionaryDtoRequest { get; private set; } + + /// + /// Gets the IGetMovieId. + /// + public virtual IGetMovieId GetMovieId { get; private set; } + + /// + /// Gets the IHelloOperations. + /// + public virtual IHelloOperations Hello { get; private set; } + + /// + /// Gets the IHelloName. + /// + public virtual IHelloName HelloName { get; private set; } + + /// + /// Gets the IHelloListOperations. + /// + public virtual IHelloListOperations HelloList { get; private set; } + + /// + /// Gets the IHelloArrayOperations. + /// + public virtual IHelloArrayOperations HelloArray { get; private set; } + + /// + /// Gets the IAllowedAttributesOperations. + /// + public virtual IAllowedAttributesOperations AllowedAttributes { get; private set; } + + /// + /// Gets the IHelloAllTypesOperations. + /// + public virtual IHelloAllTypesOperations HelloAllTypes { get; private set; } + + /// + /// Gets the IHelloAllTypesWithResultOperations. + /// + public virtual IHelloAllTypesWithResultOperations HelloAllTypesWithResult { get; private set; } + + /// + /// Gets the IHelloStringOperations. + /// + public virtual IHelloStringOperations HelloString { get; private set; } + + /// + /// Gets the IHelloDateTimeOperations. + /// + public virtual IHelloDateTimeOperations HelloDateTime { get; private set; } + + /// + /// Gets the IHelloVoidOperations. + /// + public virtual IHelloVoidOperations HelloVoid { get; private set; } + + /// + /// Gets the IHelloWithRouteOperations. + /// + public virtual IHelloWithRouteOperations HelloWithRoute { get; private set; } + + /// + /// Gets the IHelloTypesOperations. + /// + public virtual IHelloTypesOperations HelloTypes { get; private set; } + + /// + /// Gets the IHelloZipOperations. + /// + public virtual IHelloZipOperations HelloZip { get; private set; } + + /// + /// Gets the ISecuredRequest. + /// + public virtual ISecuredRequest SecuredRequest { get; private set; } + + /// + /// Gets the ISecuredDtoRequest. + /// + public virtual ISecuredDtoRequest SecuredDtoRequest { get; private set; } + + /// + /// Gets the ISecuredOpsRequest. + /// + public virtual ISecuredOpsRequest SecuredOpsRequest { get; private set; } + + /// + /// Gets the IGetSession. + /// + public virtual IGetSession GetSession { get; private set; } + + /// + /// Gets the IUpdateSessioneditCustomName. + /// + public virtual IUpdateSessioneditCustomName UpdateSessioneditCustomName { get; private set; } + + /// + /// Gets the IAuthenticateOperations. + /// + public virtual IAuthenticateOperations Authenticate { get; private set; } + + /// + /// Gets the IAuthenticateprovider. + /// + public virtual IAuthenticateprovider Authenticateprovider { get; private set; } + + /// + /// Gets the IAuthenticate2. + /// + public virtual IAuthenticate2 Authenticate2 { get; private set; } + + /// + /// Gets the IAuthenticateprovider2. + /// + public virtual IAuthenticateprovider2 Authenticateprovider2 { get; private set; } + + /// + /// Gets the IAssignRolesOperations. + /// + public virtual IAssignRolesOperations AssignRoles { get; private set; } + + /// + /// Gets the IUnAssignRolesOperations. + /// + public virtual IUnAssignRolesOperations UnAssignRoles { get; private set; } + + /// + /// Initializes a new instance of the ServiceStackAutorestClient class. + /// + /// + /// Optional. The delegating handlers to add to the http client pipeline. + /// + public ServiceStackAutorestClient(params DelegatingHandler[] handlers) : base(handlers) + { + Initialize(); + } + + /// + /// Initializes a new instance of the ServiceStackAutorestClient class. + /// + /// + /// Optional. The http client handler used to handle http transport. + /// + /// + /// Optional. The delegating handlers to add to the http client pipeline. + /// + public ServiceStackAutorestClient(HttpClientHandler rootHandler, params DelegatingHandler[] handlers) : base(rootHandler, handlers) + { + Initialize(); + } + + /// + /// Initializes a new instance of the ServiceStackAutorestClient class. + /// + /// + /// Optional. The base URI of the service. + /// + /// + /// Optional. The delegating handlers to add to the http client pipeline. + /// + /// + /// Thrown when a required parameter is null + /// + public ServiceStackAutorestClient(System.Uri baseUri, params DelegatingHandler[] handlers) : this(handlers) + { + if (baseUri == null) + { + throw new System.ArgumentNullException("baseUri"); + } + BaseUri = baseUri; + } + + /// + /// Initializes a new instance of the ServiceStackAutorestClient class. + /// + /// + /// Optional. The base URI of the service. + /// + /// + /// Optional. The http client handler used to handle http transport. + /// + /// + /// Optional. The delegating handlers to add to the http client pipeline. + /// + /// + /// Thrown when a required parameter is null + /// + public ServiceStackAutorestClient(System.Uri baseUri, HttpClientHandler rootHandler, params DelegatingHandler[] handlers) : this(rootHandler, handlers) + { + if (baseUri == null) + { + throw new System.ArgumentNullException("baseUri"); + } + BaseUri = baseUri; + } + + /// + /// An optional partial-method to perform custom initialization. + /// + partial void CustomInitialize(); + /// + /// Initializes client properties. + /// + private void Initialize() + { + ReturnListRequest = new ReturnListRequest(this); + ReturnArrayRequest = new ReturnArrayRequest(this); + ReturnKeyValuePairRequest = new ReturnKeyValuePairRequest(this); + ReturnDictionaryStringRequest = new ReturnDictionaryStringRequest(this); + ReturnDictionaryDtoRequest = new ReturnDictionaryDtoRequest(this); + GetMovieId = new GetMovieId(this); + Hello = new HelloOperations(this); + HelloName = new HelloName(this); + HelloList = new HelloListOperations(this); + HelloArray = new HelloArrayOperations(this); + AllowedAttributes = new AllowedAttributesOperations(this); + HelloAllTypes = new HelloAllTypesOperations(this); + HelloAllTypesWithResult = new HelloAllTypesWithResultOperations(this); + HelloString = new HelloStringOperations(this); + HelloDateTime = new HelloDateTimeOperations(this); + HelloVoid = new HelloVoidOperations(this); + HelloWithRoute = new HelloWithRouteOperations(this); + HelloTypes = new HelloTypesOperations(this); + HelloZip = new HelloZipOperations(this); + SecuredRequest = new SecuredRequest(this); + SecuredDtoRequest = new SecuredDtoRequest(this); + SecuredOpsRequest = new SecuredOpsRequest(this); + GetSession = new GetSession(this); + UpdateSessioneditCustomName = new UpdateSessioneditCustomName(this); + Authenticate = new AuthenticateOperations(this); + Authenticateprovider = new Authenticateprovider(this); + Authenticate2 = new Authenticate2(this); + Authenticateprovider2 = new Authenticateprovider2(this); + AssignRoles = new AssignRolesOperations(this); + UnAssignRoles = new UnAssignRolesOperations(this); + BaseUri = new System.Uri("http://localhost:20000/"); + Accept = "application/json"; + SerializationSettings = new JsonSerializerSettings + { + Formatting = Newtonsoft.Json.Formatting.Indented, + DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat, + DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc, + NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore, + ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize, + ContractResolver = new ReadOnlyJsonContractResolver(), + Converters = new List + { + new Iso8601TimeSpanConverter() + } + }; + DeserializationSettings = new JsonSerializerSettings + { + DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat, + DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc, + NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore, + ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize, + ContractResolver = new ReadOnlyJsonContractResolver(), + Converters = new List + { + new Iso8601TimeSpanConverter() + } + }; + CustomInitialize(); + } + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UnAssignRolesOperations.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UnAssignRolesOperations.cs new file mode 100644 index 00000000000..e950258959d --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UnAssignRolesOperations.cs @@ -0,0 +1,635 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// UnAssignRolesOperations operations. + /// + public partial class UnAssignRolesOperations : IServiceOperations, IUnAssignRolesOperations + { + /// + /// Initializes a new instance of the UnAssignRolesOperations class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public UnAssignRolesOperations(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "unassignroles").ToString(); + List _queryParameters = new List(); + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (permissions != null) + { + _queryParameters.Add(string.Format("Permissions={0}", System.Uri.EscapeDataString(permissions))); + } + if (roles != null) + { + _queryParameters.Add(string.Format("Roles={0}", System.Uri.EscapeDataString(roles))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new UnAssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + UnAssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "unassignroles").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new UnAssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + UnAssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "unassignroles").ToString(); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new UnAssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + UnAssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string userName = default(string), string permissions = default(string), string roles = default(string), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("userName", userName); + tracingParameters.Add("permissions", permissions); + tracingParameters.Add("roles", roles); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "unassignroles").ToString(); + List _queryParameters = new List(); + if (userName != null) + { + _queryParameters.Add(string.Format("UserName={0}", System.Uri.EscapeDataString(userName))); + } + if (permissions != null) + { + _queryParameters.Add(string.Format("Permissions={0}", System.Uri.EscapeDataString(permissions))); + } + if (roles != null) + { + _queryParameters.Add(string.Format("Roles={0}", System.Uri.EscapeDataString(roles))); + } + if (_queryParameters.Count > 0) + { + _url += "?" + string.Join("&", _queryParameters); + } + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new UnAssignRolesResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + UnAssignRolesResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UnAssignRolesOperationsExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UnAssignRolesOperationsExtensions.cs new file mode 100644 index 00000000000..f3ac294bdff --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UnAssignRolesOperationsExtensions.cs @@ -0,0 +1,161 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for UnAssignRolesOperations. + /// + public static partial class UnAssignRolesOperationsExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static UnAssignRolesResponse Get(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string)) + { + return operations.GetAsync(userName, permissions, roles).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(userName, permissions, roles, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static UnAssignRolesResponse Create(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles)) + { + return operations.CreateAsync(userName, permissions, roles, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(userName, permissions, roles, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static UnAssignRolesResponse Post(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles)) + { + return operations.PostAsync(userName, permissions, roles, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), UnAssignRoles body = default(UnAssignRoles), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(userName, permissions, roles, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + public static UnAssignRolesResponse Delete(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string)) + { + return operations.DeleteAsync(userName, permissions, roles).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IUnAssignRolesOperations operations, string userName = default(string), string permissions = default(string), string roles = default(string), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(userName, permissions, roles, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UpdateSessioneditCustomName.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UpdateSessioneditCustomName.cs new file mode 100644 index 00000000000..c0bf2379dab --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UpdateSessioneditCustomName.cs @@ -0,0 +1,621 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Microsoft.Rest; + using Models; + using Newtonsoft.Json; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Net; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + + /// + /// UpdateSessioneditCustomName operations. + /// + public partial class UpdateSessioneditCustomName : IServiceOperations, IUpdateSessioneditCustomName + { + /// + /// Initializes a new instance of the UpdateSessioneditCustomName class. + /// + /// + /// Reference to the service client. + /// + /// + /// Thrown when a required parameter is null + /// + public UpdateSessioneditCustomName(ServiceStackAutorestClient client) + { + if (client == null) + { + throw new System.ArgumentNullException("client"); + } + Client = client; + } + + /// + /// Gets a reference to the ServiceStackAutorestClient + /// + public ServiceStackAutorestClient Client { get; private set; } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> GetWithHttpMessagesAsync(string customName, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (customName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "customName"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("customName", customName); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Get", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session/edit/{CustomName}").ToString(); + _url = _url.Replace("{CustomName}", System.Uri.EscapeDataString(customName)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("GET"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> CreateWithHttpMessagesAsync(string customName, UpdateSession body = default(UpdateSession), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (customName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "customName"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("customName", customName); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Create", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session/edit/{CustomName}").ToString(); + _url = _url.Replace("{CustomName}", System.Uri.EscapeDataString(customName)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("PUT"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> PostWithHttpMessagesAsync(string customName, UpdateSession body = default(UpdateSession), Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (customName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "customName"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("customName", customName); + tracingParameters.Add("body", body); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Post", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session/edit/{CustomName}").ToString(); + _url = _url.Replace("{CustomName}", System.Uri.EscapeDataString(customName)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("POST"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + if(body != null) + { + _requestContent = Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(body, Client.SerializationSettings); + _httpRequest.Content = new StringContent(_requestContent, System.Text.Encoding.UTF8); + _httpRequest.Content.Headers.ContentType =System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8"); + } + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + /// + /// + /// + /// Headers that will be added to request. + /// + /// + /// The cancellation token. + /// + /// + /// Thrown when the operation returned an invalid status code + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// Thrown when a required parameter is null + /// + /// + /// A response object containing the response body and response headers. + /// + public async Task> DeleteWithHttpMessagesAsync(string customName, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + { + if (customName == null) + { + throw new ValidationException(ValidationRules.CannotBeNull, "customName"); + } + // Tracing + bool _shouldTrace = ServiceClientTracing.IsEnabled; + string _invocationId = null; + if (_shouldTrace) + { + _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + Dictionary tracingParameters = new Dictionary(); + tracingParameters.Add("customName", customName); + tracingParameters.Add("cancellationToken", cancellationToken); + ServiceClientTracing.Enter(_invocationId, this, "Delete", tracingParameters); + } + // Construct URL + var _baseUrl = Client.BaseUri.AbsoluteUri; + var _url = new System.Uri(new System.Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "session/edit/{CustomName}").ToString(); + _url = _url.Replace("{CustomName}", System.Uri.EscapeDataString(customName)); + // Create HTTP transport objects + var _httpRequest = new HttpRequestMessage(); + HttpResponseMessage _httpResponse = null; + _httpRequest.Method = new HttpMethod("DELETE"); + _httpRequest.RequestUri = new System.Uri(_url); + // Set Headers + if (Client.Accept != null) + { + if (_httpRequest.Headers.Contains("Accept")) + { + _httpRequest.Headers.Remove("Accept"); + } + _httpRequest.Headers.TryAddWithoutValidation("Accept", Client.Accept); + } + + + if (customHeaders != null) + { + foreach(var _header in customHeaders) + { + if (_httpRequest.Headers.Contains(_header.Key)) + { + _httpRequest.Headers.Remove(_header.Key); + } + _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); + } + } + + // Serialize Request + string _requestContent = null; + // Send Request + if (_shouldTrace) + { + ServiceClientTracing.SendRequest(_invocationId, _httpRequest); + } + cancellationToken.ThrowIfCancellationRequested(); + _httpResponse = await Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false); + if (_shouldTrace) + { + ServiceClientTracing.ReceiveResponse(_invocationId, _httpResponse); + } + HttpStatusCode _statusCode = _httpResponse.StatusCode; + cancellationToken.ThrowIfCancellationRequested(); + string _responseContent = null; + if (!_httpResponse.IsSuccessStatusCode) + { + var ex = new GetSessionResponseException(string.Format("Operation returned an invalid status code '{0}'", _statusCode)); + try + { + _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + GetSessionResponse _errorBody = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_responseContent, Client.DeserializationSettings); + if (_errorBody != null) + { + ex.Body = _errorBody; + } + } + catch (JsonException) + { + // Ignore the exception + } + ex.Request = new HttpRequestMessageWrapper(_httpRequest, _requestContent); + ex.Response = new HttpResponseMessageWrapper(_httpResponse, _responseContent); + if (_shouldTrace) + { + ServiceClientTracing.Error(_invocationId, ex); + } + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw ex; + } + // Create Result + var _result = new HttpOperationResponse(); + _result.Request = _httpRequest; + _result.Response = _httpResponse; + string _defaultResponseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject(_defaultResponseContent, Client.DeserializationSettings); + } + catch (JsonException ex) + { + _httpRequest.Dispose(); + if (_httpResponse != null) + { + _httpResponse.Dispose(); + } + throw new SerializationException("Unable to deserialize the response.", _defaultResponseContent, ex); + } + if (_shouldTrace) + { + ServiceClientTracing.Exit(_invocationId, _result); + } + return _result; + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UpdateSessioneditCustomNameExtensions.cs b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UpdateSessioneditCustomNameExtensions.cs new file mode 100644 index 00000000000..6542f751aa9 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/GeneratedClient/UpdateSessioneditCustomNameExtensions.cs @@ -0,0 +1,129 @@ +// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. + +namespace AutorestClient +{ + using Models; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Extension methods for UpdateSessioneditCustomName. + /// + public static partial class UpdateSessioneditCustomNameExtensions + { + /// + /// The operations group for this extension method. + /// + /// + /// + public static GetSessionResponse Get(this IUpdateSessioneditCustomName operations, string customName) + { + return operations.GetAsync(customName).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task GetAsync(this IUpdateSessioneditCustomName operations, string customName, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.GetWithHttpMessagesAsync(customName, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static GetSessionResponse Create(this IUpdateSessioneditCustomName operations, string customName, UpdateSession body = default(UpdateSession)) + { + return operations.CreateAsync(customName, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task CreateAsync(this IUpdateSessioneditCustomName operations, string customName, UpdateSession body = default(UpdateSession), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.CreateWithHttpMessagesAsync(customName, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + public static GetSessionResponse Post(this IUpdateSessioneditCustomName operations, string customName, UpdateSession body = default(UpdateSession)) + { + return operations.PostAsync(customName, body).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task PostAsync(this IUpdateSessioneditCustomName operations, string customName, UpdateSession body = default(UpdateSession), CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.PostWithHttpMessagesAsync(customName, body, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + /// + /// The operations group for this extension method. + /// + /// + /// + public static GetSessionResponse Delete(this IUpdateSessioneditCustomName operations, string customName) + { + return operations.DeleteAsync(customName).GetAwaiter().GetResult(); + } + + /// + /// The operations group for this extension method. + /// + /// + /// + /// + /// The cancellation token. + /// + public static async Task DeleteAsync(this IUpdateSessioneditCustomName operations, string customName, CancellationToken cancellationToken = default(CancellationToken)) + { + using (var _result = await operations.DeleteWithHttpMessagesAsync(customName, null, cancellationToken).ConfigureAwait(false)) + { + return _result.Body; + } + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/Host/Config.cs b/tests/ServiceStack.OpenApi.Tests/Host/Config.cs new file mode 100644 index 00000000000..55e5fd55b79 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Host/Config.cs @@ -0,0 +1,11 @@ +using System; + +namespace ServiceStack.OpenApi.Tests.Host +{ + public class Config + { + public static readonly string ServiceStackBaseUri = Environment.GetEnvironmentVariable("CI_BASEURI") ?? "http://localhost:20000"; + public static readonly string AbsoluteBaseUri = ServiceStackBaseUri + "/"; + public static readonly string ListeningOn = ServiceStackBaseUri + "/"; + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/Host/GeneratedClientTestBase.cs b/tests/ServiceStack.OpenApi.Tests/Host/GeneratedClientTestBase.cs new file mode 100644 index 00000000000..8bde42a67d8 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Host/GeneratedClientTestBase.cs @@ -0,0 +1,139 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Api.OpenApi; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.Logging; +using ServiceStack.OpenApi.Tests.Services; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Text; +using System.Collections.Generic; + +namespace ServiceStack.OpenApi.Tests.Host +{ + [TestFixture] + public class GeneratedClientTestBase + { + TestAppHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new TestAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + } + + public class TestAppHost + : AppSelfHostBase + { + //private static ILog log; + + public TestAppHost() + : base("ServiceStack Autorest Client", typeof(NativeTypesTestService).Assembly) + { + //LogManager.LogFactory = new DebugLogFactory(); + //log = LogManager.GetLogger(typeof(ExampleAppHostHttpListener)); + } + + public override void Configure(Container container) + { + JsConfig.Init(new Text.Config { TextCase = TextCase.CamelCase }); + + SetConfig(new HostConfig + { + DebugMode = true, + Return204NoContentForEmptyResponse = true, + }); + + container.Register(c => new OrmLiteConnectionFactory( + ":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve()) + { + UseDistinctRoleTables = AppSettings.Get("UseDistinctRoleTables", true), + }); + + var authRepo = (OrmLiteAuthRepository)container.Resolve(); + authRepo.DropAndReCreateTables(); + + CreateUser(authRepo, 1, "test", "test", new List { "TheRole" }, new List { "ThePermission" }); + CreateUser(authRepo, 2, "test2", "test2"); + + Plugins.Add(new CorsFeature( + allowOriginWhitelist: new[] { "http://localhost", "http://localhost:8080", "http://localhost:56500", "http://test.servicestack.net", "http://null.jsbin.com" }, + allowCredentials: true, + allowedHeaders: "Content-Type, Allow, Authorization")); + + Plugins.Add(new AuthFeature(() => new CustomUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(AppSettings), + new CredentialsAuthProvider(AppSettings), + })); + + Plugins.Add(new OpenApiFeature()); + + /*Plugins.Add(new AutoQueryFeature + { + MaxLimit = 100, + }); + + container.RegisterValidators(typeof(ThrowValidationValidator).Assembly); + + JavaGenerator.AddGsonImport = true; + var nativeTypes = this.GetPlugin(); + nativeTypes.MetadataTypesConfig.ExportTypes.Add(typeof(DayOfWeek)); + + + + this.RegisterRequestBinder( + httpReq => new CustomRequestBinder { IsFromBinder = true }); + + Routes + .Add("/custom-movies", "GET") + .Add("/custom-movies/genres/{Genre}") + .Add("/custom-movies", "POST,PUT") + .Add("/custom-movies/{Id}") + .Add("/fact/{ForNumber}") + .Add("/all-movies.zip") + .Add("/gethttpresult") + ; + */ + } + + private void CreateUser(OrmLiteAuthRepository authRepo, + int id, string username, string password, List roles = null, List permissions = null) + { + string hash; + string salt; + new SaltedHash().GetHashAndSaltString(password, out hash, out salt); + + authRepo.CreateUserAuth(new UserAuth + { + Id = id, + DisplayName = username + " DisplayName", + Email = username + "@gmail.com", + UserName = username, + FirstName = "First " + username, + LastName = "Last " + username, + PasswordHash = hash, + Salt = salt, + Roles = roles, + Permissions = permissions + }, password); + + authRepo.AssignRoles(id.ToString(), roles, permissions); + } + + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/NetCoreTestsRunner.cs b/tests/ServiceStack.OpenApi.Tests/NetCoreTestsRunner.cs new file mode 100644 index 00000000000..5221c4884ba --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/NetCoreTestsRunner.cs @@ -0,0 +1,34 @@ +using NUnitLite; +using NUnit.Common; +using System.Reflection; +using ServiceStack.Text; +using System; +using System.Globalization; + +namespace ServiceStack.OpenApi.Tests +{ + public class NetCoreTestsRunner + { + /// + /// The main program executes the tests. Output may be routed to + /// various locations, depending on the arguments passed. + /// + /// Run with --help for a full list of arguments supported + /// + public static int Main(string[] args) + { + var licenseKey = Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE"); + if (licenseKey.IsNullOrEmpty()) + throw new ArgumentNullException("SERVICESTACK_LICENSE", "Add Environment variable for SERVICESTACK_LICENSE"); + + Licensing.RegisterLicense(licenseKey); + //"ActivatedLicenseFeatures: ".Print(LicenseUtils.ActivatedLicenseFeatures()); + + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); + JsConfig.InitStatics(); + //JsonServiceClient client = new JsonServiceClient(); + var writer = new ExtendedTextWrapper(Console.Out); + return new AutoRun(((IReflectableType)typeof(NetCoreTestsRunner)).GetTypeInfo().Assembly).Execute(args, writer, Console.In); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.OpenApi.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..f7846bac392 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ServiceStack.OpenApi.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ServiceStack.OpenApi.Tests")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cfd618dd-5de8-42fe-8d83-cc5ab7a40fc1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.OpenApi.Tests/ReturnTypeTests.cs b/tests/ServiceStack.OpenApi.Tests/ReturnTypeTests.cs new file mode 100644 index 00000000000..62bb8390ecc --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/ReturnTypeTests.cs @@ -0,0 +1,87 @@ +using AutorestClient; +using NUnit.Framework; +using ServiceStack.OpenApi.Tests.Host; +using System; + +namespace ServiceStack.OpenApi.Tests +{ + [TestFixture] + public class ReturnTypeTests : GeneratedClientTestBase + { + [Test] + public void Can_get_generic_list() + { + var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri)); + + var result = client.ReturnListRequest.Get(); + + Assert.That(result.Count, Is.EqualTo(3)); + Assert.That(result[0].Id, Is.EqualTo(1)); + Assert.That(result[1].Id, Is.EqualTo(2)); + Assert.That(result[2].Id, Is.EqualTo(3)); + } + + [Test] + public void Can_get_array() + { + var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri)); + + var result = client.ReturnArrayRequest.Get(); + + Assert.That(result.Count, Is.EqualTo(3)); + Assert.That(result[0].Id, Is.EqualTo(1)); + Assert.That(result[1].Id, Is.EqualTo(2)); + Assert.That(result[2].Id, Is.EqualTo(3)); + } + + [Test] + public void Can_get_keyvaluepair() + { + var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri)); + + var result = client.ReturnKeyValuePairRequest.Get(); + + Assert.That(result.Key, Is.EqualTo("key1")); + Assert.That(result.Value, Is.EqualTo("value1")); + } + + [Test] + public void Can_get_returned_dto_dictionary() + { + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var result = client.ReturnDictionaryDtoRequest.Get(); + + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result["key1"].Id, Is.EqualTo(1)); + Assert.That(result["key2"].Id, Is.EqualTo(2)); + } + } + + [Test] + public void Can_get_returned_string_dictionary() + { + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var result = client.ReturnDictionaryStringRequest.Get(); + + Assert.That(result.Count, Is.EqualTo(2)); + Assert.That(result["key1"], Is.EqualTo("value1")); + Assert.That(result["key2"], Is.EqualTo("value2")); + + } + } + + [Test] + public void Can_Get_Returned_KeyPair() + { + using (var client = new ServiceStackAutorestClient(new Uri(Config.AbsoluteBaseUri))) + { + var result = client.ReturnKeyValuePairRequest.Get(); + + Assert.That(result.Key, Is.EqualTo("key1")); + Assert.That(result.Value, Is.EqualTo("value1")); + } + } + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/ServiceStack.OpenApi.Tests.csproj b/tests/ServiceStack.OpenApi.Tests/ServiceStack.OpenApi.Tests.csproj new file mode 100644 index 00000000000..7c8cf0a391b --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/ServiceStack.OpenApi.Tests.csproj @@ -0,0 +1,279 @@ + + + + + Debug + AnyCPU + {CFD618DD-5DE8-42FE-8D83-CC5AB7A40FC1} + Library + Properties + ServiceStack.OpenApi.Tests + ServiceStack.OpenApi.Tests + v4.7.2 + 512 + true + true + + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {5E258282-86A6-4780-AB25-5E458F2E6F70} + ServiceStack.Api.OpenApi + + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + + + {982416db-c143-4028-a0c3-cf41892d18d3} + ServiceStack.Common + + + {55942102-033a-4da8-a6af-1db7b2f34a2d} + ServiceStack.Interfaces + + + {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} + ServiceStack.Server + + + {680a1709-25eb-4d52-a87f-ee03ffd94baa} + ServiceStack + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Services/AllTypes.cs b/tests/ServiceStack.OpenApi.Tests/Services/AllTypes.cs new file mode 100644 index 00000000000..fd324b600d4 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/AllTypes.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; + +namespace ServiceStack.OpenApi.Tests.Services +{ + public class AllTypes + { + public int Id { get; set; } + public int? NullableId { get; set; } + public byte ByteProperty { get; set; } + public short ShortProperty { get; set; } + public int IntProperty { get; set; } + public long LongProperty { get; set; } + public UInt16 UShortProperty { get; set; } + public uint UIntProperty { get; set; } + public ulong ULongProperty { get; set; } + public float FloatProperty { get; set; } + public double DoubleProperty { get; set; } + public decimal DecimalProperty { get; set; } + public string StringProperty { get; set; } + public DateTime DateTimeProperty { get; set; } + public TimeSpan TimeSpanProperty { get; set; } + public DateTimeOffset DateTimeOffsetProperty { get; set; } + public Guid GuidProperty { get; set; } + public Char CharProperty { get; set; } + public KeyValuePair KeyValuePairProperty { get; set; } + public DateTime? NullableDateTime { get; set; } + public TimeSpan? NullableTimeSpan { get; set; } + public List StringList { get; set; } + public string[] StringArray { get; set; } + public Dictionary StringMap { get; set; } + public Dictionary IntStringMap { get; set; } + public SubType SubType { get; set; } + } + + public class AllCollectionTypes + { + public int[] IntArray { get; set; } + public List IntList { get; set; } + + public string[] StringArray { get; set; } + public List StringList { get; set; } + + public Poco[] PocoArray { get; set; } + public List PocoList { get; set; } + + public Dictionary> PocoLookup { get; set; } + public Dictionary>> PocoLookupMap { get; set; } + } + + public class Poco + { + public string Name { get; set; } + } + + public abstract class HelloBase + { + public int Id { get; set; } + } + + public abstract class HelloResponseBase + { + public int RefId { get; set; } + } + + public class HelloType + { + public string Result { get; set; } + } + + public abstract class HelloWithReturnResponse + { + public string Result { get; set; } + } + + public class SubType + { + public int Id { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Services/AnnotatedService.cs b/tests/ServiceStack.OpenApi.Tests/Services/AnnotatedService.cs new file mode 100644 index 00000000000..44b64894728 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/AnnotatedService.cs @@ -0,0 +1,92 @@ +using System.Net; +using System.Runtime.Serialization; + +namespace ServiceStack.OpenApi.Tests.Services +{ + + public class HelloDto + { + [ApiMember(IsRequired = true)] + public string Name { get; set; } + } + + [Api(Description = "Create new hello", BodyParameter = GenerateBodyParameter.Always, IsRequired = true)] + [Route("/annotated-hello", "POST", Summary = "Creates a new hello.")] + public class CreateHelloReq : IReturn + { + [ApiMember(IsRequired = true, ParameterType = "model")] + public HelloDto Hello { get; set; } + } + + [Api("Description of the response")] + public class GatewayCredentialResponse + { + public string Result { get; set; } + } + + [Route("/gatewaycredential/{MID}", "POST, OPTIONS")] + [DataContract] + public class GatewayCredentialRequest : IReturn + { + [ApiMember(IsRequired = true, ExcludeInSchema = true, ParameterType = "path")] + [DataMember] + public string MID { get; set; } + + [ApiMember(IsRequired = true, ParameterType = "model")] + [DataMember] + public string UserName { get; set; } + + [ApiMember(IsRequired = true, ParameterType = "model")] + [ApiAllowableValues("Type", Values = new string[] { "Merchant", "API" })] + [DataMember] + public string Type { get; set; } + } + + + + [Api("Gets the movie")] + [Route("/movie/{Id}")] + public class GetMovie : IReturn + { + [ApiMember(IsRequired = true, Description = "Required ID of Movie.", DataType = "integer", ParameterType = "path")] + public long Id { get; set; } + + [ApiMember(IsRequired = false, AllowMultiple = true, Description = "List of additional objects to include in the movie response.")] + [ApiAllowableValues("Includes", Values = new string[] { "Genres", "Releases", "Contributors", "AlternateTitles", "Descriptions", "Companies", "Tags", "Images", "Videos" })] // This breaks the swagger UI + public string[] Includes { get; set; } + } + + [Api("Movie response with includes")] + public class MovieResponse + { + public string[] Includes { get; set; } + } + + [Api("CRUD for ServiceProviders")] + [Route("/ServiceProvider/{Id}", "Delete", Summary = "Delete a ServiceProvider by Id")] + [ApiResponse(HttpStatusCode.InternalServerError, "Something went wrong. Please contact the support team")] + public class DeleteServiceProviderRequestDto : IReturn + { + [ApiMember(ParameterType = "path", IsRequired = true)] + public int Id { get; set; } + [ApiMember(DataType = "boolean")] + public bool ForceDelete { get; set; } + } + + public class DeleteServiceProviderReponseDto : IHasResponseStatus + { + public ResponseStatus ResponseStatus { get; set; } + } + + + public class AnnotatedService : Service + { + public object Any(GetMovie request) => new MovieResponse {Includes = request.Includes}; + + public object Any(GatewayCredentialRequest request) => new GatewayCredentialResponse {Result = "hello"}; + + public object Any(CreateHelloReq request) => new Hello { Name = request.Hello.Name }; + + public object Any(DeleteServiceProviderRequestDto request) => new DeleteServiceProviderReponseDto { ResponseStatus = new ResponseStatus() {ErrorCode = "200"}}; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Services/AsyncService.cs b/tests/ServiceStack.OpenApi.Tests/Services/AsyncService.cs new file mode 100644 index 00000000000..9ec92a992cd --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/AsyncService.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ServiceStack.OpenApi.Tests.Services +{ + public class InfoUpdateResponseDto + { + public string Result { get; set; } + } + + [Route("/UpdateInfo/{Id}", "PUT", Summary = "Updates info.")] + public class UpdateInfoReq : IReturn + { + [ApiMember(IsRequired = true)] + public Guid Id { get; set; } + } + + + public class AsyncService : Service + { + public async Task Update(UpdateInfoReq query) + { + return new InfoUpdateResponseDto {Result = "Hello"}; + } + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/Services/CodeGenTestTypes.cs b/tests/ServiceStack.OpenApi.Tests/Services/CodeGenTestTypes.cs new file mode 100644 index 00000000000..ca7e673cd40 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/CodeGenTestTypes.cs @@ -0,0 +1,408 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.Serialization; +using ServiceStack.DataAnnotations; + +namespace ServiceStack.OpenApi.Tests.Services +{ + [Route("/hello")] + [Route("/hello/{Name}")] + public class Hello : IReturn + { + [Required] + public string Name { get; set; } + public string Title { get; set; } + } + + public class HelloResponse + { + public string Result { get; set; } + } + + public class HelloWithNestedClass : IReturn + { + public string Name { get; set; } + public NestedClass NestedClassProp { get; set; } + + // This will generate a class definition "public partial class Hello.NestedClass" + public class NestedClass + { + public string Value { get; set; } + } + } + + public class ListResult + { + public string Result { get; set; } + } + + public class ArrayResult + { + public string Result { get; set; } + } + + [Route("/hello-list")] + public class HelloList : IReturn> + { + public List Names { get; set; } + } + + [Route("/hello-array")] + public class HelloArray : IReturn + { + public List Names { get; set; } + } + + public class HelloWithEnum + { + public EnumType EnumProp { get; set; } + public EnumType? NullableEnumProp { get; set; } + + public EnumFlags EnumFlags { get; set; } + } + + public enum EnumType + { + Value1, + Value2 + } + + [Flags] + public enum EnumFlags + { + Value1 = 1, + Value2 = 2, + Value3 = 4, + } + + [Restrict(InternalOnly = true)] + [System.ComponentModel.Description("Description on HelloAll type")] + [DataContract] + public class HelloAnnotated + : IReturn + { + [DataMember] + public string Name { get; set; } + } + + [Restrict(ExternalOnly = true)] + public class HelloExternal + { + public string Name { get; set; } + } + + [Restrict(InternalOnly = true)] + [Alias("Alias")] + public class RestrictedAttributes + { + [PrimaryKey] + [AutoIncrement] + public int Id { get; set; } + + [Index] + [ApiAllowableValues("DateKind", typeof(DateTimeKind))] + public string Name { get; set; } + + public Hello Hello { get; set; } + } + + [DataContract] + [Route("/allowed-attributes", "GET")] + [Api("AllowedAttributes Description")] + [ApiResponse(HttpStatusCode.BadRequest, "Your request was not understood")] + [Description("Description on AllowedAttributes")] + public class AllowedAttributes + { + [Required] + [Range(1, 10)] + [Default(5)] + public int Id { get; set; } + + [Range(1.0, 10.0)] + [DataMember(Name = "Aliased")] + [ApiMember(Description = "Range Description", + ParameterType = "query", DataType = "integer", IsRequired = true)] + public double Range { get; set; } + + [StringLength(20)] + [References(typeof(Hello))] + [Meta("Foo", "Bar")] + public string Name { get; set; } + } + + [System.ComponentModel.Description("Description on HelloAllResponse type")] + [DataContract] + public class HelloAnnotatedResponse + { + [DataMember] + public string Result { get; set; } + } + + [Route("/all-types")] + public class HelloAllTypes + { + public string Name { get; set; } + public AllTypes AllTypes { get; set; } + public AllCollectionTypes AllCollectionTypes { get; set; } + } + + [Route("/all-types-result")] + public class HelloAllTypesWithResult : IReturn + { + public string Name { get; set; } + public AllTypes AllTypes { get; set; } + public AllCollectionTypes AllCollectionTypes { get; set; } + } + + + public class HelloAllTypesResponse + { + public string Result { get; set; } + public AllTypes AllTypes { get; set; } + public AllCollectionTypes AllCollectionTypes { get; set; } + } + + [Route("/hello-string")] + public class HelloString : IReturn + { + public string Name { get; set; } + } + + [Route("/hello-datetime")] + public class HelloDateTime : IReturn + { + public DateTime DateTime { get; set; } + } + + [Route("/hello-void")] + public class HelloVoid + { + public string Name { get; set; } + } + + [DataContract] + public class HelloWithDataContract + { + [DataMember(Name = "name", Order = 1, IsRequired = true, EmitDefaultValue = false)] + public string Name { get; set; } + + [DataMember(Name = "id", Order = 2, EmitDefaultValue = false)] + public int Id { get; set; } + } + + [DataContract] + public class HelloWithDataContractResponse + { + [DataMember(Name = "result", Order = 1, IsRequired = true, EmitDefaultValue = false)] + public string Result { get; set; } + } + + [System.ComponentModel.Description("Description on HelloWithDescription type")] + public class HelloWithDescription + { + public string Name { get; set; } + } + + [System.ComponentModel.Description("Description on HelloWithDescriptionResponse type")] + public class HelloWithDescriptionResponse + { + public string Result { get; set; } + } + + public class HelloWithInheritance + : HelloBase + { + public string Name { get; set; } + } + + public class HelloWithInheritanceResponse + : HelloResponseBase + { + public string Result { get; set; } + } + + public class HelloWithGenericInheritance : HelloBase + { + public string Result { get; set; } + } + + public class HelloWithGenericInheritance2 : HelloBase + { + public string Result { get; set; } + } + + public class HelloWithNestedInheritance : HelloBase + { + public class Item + { + public string Value { get; set; } + } + } + + public class HelloWithListInheritance : List { } + + public class InheritedItem + { + public string Name { get; set; } + } + + public abstract class HelloBase + { + public List Items { get; set; } + public virtual List Counts { get; set; } + } + + public class HelloWithReturn + : IReturn + { + public string Name { get; set; } + } + + public class HelloWithAlternateReturnResponse + : HelloWithReturnResponse + { + public string AltResult { get; set; } + } + + [Route("/helloroute")] + public class HelloWithRoute + { + public string Name { get; set; } + } + + public class HelloWithRouteResponse + { + public string Result { get; set; } + } + + public class HelloWithType + { + public string Name { get; set; } + } + + public class HelloWithTypeResponse + { + public HelloType Result { get; set; } + } + + public class HelloInterface + { + public IPoco Poco { get; set; } + public IEmptyInterface EmptyInterface { get; set; } + public EmptyClass EmptyClass { get; set; } + } + + public interface IPoco + { + string Name { get; set; } + } + + public interface IEmptyInterface { } + public class EmptyClass { } + + public class TypesGroup + { + public class InnerType + { + public long Id { get; set; } + public string Name { get; set; } + } + + public enum InnerEnum + { + Foo, + Bar, + Baz + } + } + + public class HelloInnerTypes : IReturn { } + + public class HelloInnerTypesResponse + { + public TypesGroup.InnerType InnerType { get; set; } + + public TypesGroup.InnerEnum InnerEnum { get; set; } + } + + public class HelloBuiltin + { + public DayOfWeek DayOfWeek { get; set; } + } + + public class HelloVerbResponse + { + public string Result { get; set; } + } + + public class HelloGet : IReturn, IGet + { + public int Id { get; set; } + } + public class HelloPost : HelloBase, IReturn, IPost + { + } + public class HelloPut : IReturn, IPut + { + public int Id { get; set; } + } + public class HelloDelete : IReturn, IDelete + { + public int Id { get; set; } + } + public class HelloPatch : IReturn, IPatch + { + public int Id { get; set; } + } + + public class HelloReturnVoid : IReturnVoid + { + public int Id { get; set; } + } + + public class EnumRequest : IReturn, IPut + { + public ScopeType Operator { get; set; } + } + + public class EnumResponse + { + public ScopeType Operator { get; set; } + } + + [DataContract] + public enum ScopeType + { + [EnumMember] + Global = 1, + [EnumMember] + Sale = 2, + } + + [Route("/hellotypes")] + public class HelloTypes : IReturn + { + public string String { get; set; } + public bool Bool { get; set; } + public int Int { get; set; } + } + + [DataContract] + [Route("/hellozip")] + public class HelloZip : IReturn + { + [DataMember] + public string Name { get; set; } + + [DataMember] + public List Test { get; set; } + } + + [DataContract] + public class HelloZipResponse + { + [DataMember] + public string Result { get; set; } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Services/InheritedDtoService.cs b/tests/ServiceStack.OpenApi.Tests/Services/InheritedDtoService.cs new file mode 100644 index 00000000000..8f464fa9706 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/InheritedDtoService.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ServiceStack.OpenApi.Tests.Services +{ + + public class Pet + { + virtual public int? PetId { get; set; } + virtual public string Name { get; set; } + } + + [Route("/Pets", "POST")] + public class PetsPOSTRequest : Pet, IReturn + { + [System.Runtime.Serialization.IgnoreDataMember] + public override int? PetId { get; set; } + } + + + public class InheritedDtoService : Service + { + public Pet POST(PetsPOSTRequest request) + { + return request; + } + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/Services/NativeTypesTestService.cs b/tests/ServiceStack.OpenApi.Tests/Services/NativeTypesTestService.cs new file mode 100644 index 00000000000..407862ed3bc --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/NativeTypesTestService.cs @@ -0,0 +1,215 @@ +namespace ServiceStack.OpenApi.Tests.Services +{ + public class NativeTypesTestService : Service + { + public object Any(Hello request) + { + return new HelloResponse + { + Result = "Hello, {0}{1}!".Fmt( + request.Title != null ? request.Title + ". " : "", + request.Name) + }; + } + + public object Any(HelloAnnotated request) + { + return new HelloAnnotatedResponse { Result = request.Name }; + } + + public object Any(HelloWithNestedClass request) + { + return new HelloResponse { Result = request.Name }; + } + + public object Any(HelloList request) + { + return request.Names.Map(name => new ListResult { Result = name }); + } + + public object Any(HelloArray request) + { + return request.Names.Map(name => new ArrayResult { Result = name }); + } + + public object Any(HelloWithEnum request) + { + return request; + } + + public object Any(HelloExternal request) + { + return request; + } + + public object Any(RestrictedAttributes request) + { + return request; + } + + public object Any(AllowedAttributes request) + { + return request; + } + + public object Any(HelloAllTypes request) + { + return new HelloAllTypesResponse + { + AllTypes = request.AllTypes, + AllCollectionTypes = request.AllCollectionTypes, + Result = request.Name + }; + } + + public object Any(HelloAllTypesWithResult request) + { + return new HelloAllTypesResponse + { + AllTypes = request.AllTypes, + AllCollectionTypes = request.AllCollectionTypes, + Result = request.Name + }; + } + + + public object Any(AllTypes request) + { + return request; + } + + public object Any(HelloString request) + { + return request.Name; + } + + public object Any(HelloDateTime request) + { + return request; + } + + public void Any(HelloVoid request) + { + } + + public object Any(HelloWithDataContract request) + { + return new HelloWithDataContractResponse { Result = request.Name }; + } + + public object Any(HelloWithDescription request) + { + return new HelloWithDescriptionResponse { Result = request.Name }; + } + + public object Any(HelloWithInheritance request) + { + return new HelloWithInheritanceResponse { Result = request.Name }; + } + + public object Any(HelloWithGenericInheritance request) + { + return request; + } + + public object Any(HelloWithGenericInheritance2 request) + { + return request; + } + + public object Any(HelloWithNestedInheritance request) + { + return request; + } + + //public object Any(HelloWithListInheritance request) + //{ + // return request; + //} + + public object Any(HelloWithReturn request) + { + return new HelloWithAlternateReturnResponse { Result = request.Name }; + } + + public object Any(HelloWithRoute request) + { + return new HelloWithRouteResponse { Result = request.Name }; + } + + public object Any(HelloWithType request) + { + return new HelloWithTypeResponse + { + Result = new HelloType { Result = request.Name } + }; + } + + public object Any(HelloInterface request) + { + return request; + } + + public object Any(HelloInnerTypes request) + { + return new HelloInnerTypesResponse(); + } + + //Uncomment to generate SS.Client built-in types + //public object Any(GenerateBuiltInTypes request) + //{ + // return request; + //} + + public object Any(HelloBuiltin request) + { + return request; + } + + public object Any(HelloGet request) + { + return new HelloVerbResponse { Result = HttpMethods.Get }; + } + + public object Any(HelloPost request) + { + return new HelloVerbResponse { Result = HttpMethods.Post }; + } + + public object Any(HelloPut request) + { + return new HelloVerbResponse { Result = HttpMethods.Put }; + } + + public object Any(HelloDelete request) + { + return new HelloVerbResponse { Result = HttpMethods.Delete }; + } + + public object Any(HelloPatch request) + { + return new HelloVerbResponse { Result = HttpMethods.Patch }; + } + + public void Any(HelloReturnVoid request) + { + } + + public object Any(EnumRequest request) + { + return new EnumResponse { Operator = request.Operator }; + } + + public object Any(HelloTypes request) + { + return request; + } + + public object Any(HelloZip request) + { + return request.Test == null + ? new HelloZipResponse { Result = $"Hello, {request.Name} {base.Request.ContentLength}" } + : new HelloZipResponse { Result = $"Hello, {request.Name} ({request.Test?.Count}) {base.Request.ContentLength}" }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Services/ReturnTypeServices.cs b/tests/ServiceStack.OpenApi.Tests/Services/ReturnTypeServices.cs new file mode 100644 index 00000000000..0668800b09c --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/ReturnTypeServices.cs @@ -0,0 +1,128 @@ +using System.Collections.Generic; +using ServiceStack; +using System.Linq; +using System.Net; + +namespace ServiceStack.OpenApi.Test.Services +{ + public class ReturnedDto + { + public virtual int Id { get; set; } + } + + [Route("/return-list", "GET")] + public class ReturnListRequest : IReturn>, IGet + { + } + + [Route("/return-array", "GET")] + public class ReturnArrayRequest : IReturn, IGet + { + } + + [Route("/return-keyvaluepair", "GET")] + public class ReturnKeyValuePairRequest : IReturn>, IGet + { + } + + [Route("/return-dictionarystring", "GET")] + public class ReturnDictionaryStringRequest : IReturn>, IGet + { + } + + [Route("/return-dictionarydto", "GET")] + public class ReturnDictionaryDtoRequest : IReturn>, IGet + { + } + + [Route("/return-ireturnvoid", "GET")] + public class ReturnIReturnVoidDtoRequest : IReturn, IGet + { + } + + + [Route("/return-void", "GET")] + public class ReturnVoidDtoRequest : IReturnVoid + { + } + + public class Return200Response + { + public string SuccessMessage { get; set; } + } + + public class Return403Response + { + public string ForbiddenMessage { get; set; } + } + + [Route("/return-annotated", "GET")] + [ApiResponse(StatusCode = (int) HttpStatusCode.OK, Description = "All OK")] + [ApiResponse(StatusCode = (int) HttpStatusCode.Forbidden, Description = "Forbidden Service", + ResponseType = typeof(Return403Response))] + [ApiResponse(Description = "Default Response", ResponseType = typeof(Return200Response), IsDefaultResponse = true)] + public class ReturnAnnotatedDtoRequest : IReturn, IGet + { + public int Code { get; set; } + } + + [Route("/dhcp/servers/{ServerName}/scopes/{ScopeId}", "DELETE", Summary = "Deletes a DHCP scope.")] + public class DeleteDhcpScope : IReturnVoid + { + [ApiMember(ParameterType = "path", IsRequired = true, Description = "The FQDN of the DHCP server")] + public string ServerName { get; set; } + + [ApiMember(ParameterType = "path", Description = "The Scope Id of the DHCP scope")] + public string ScopeId { get; set; } + } + + public class ReturnGenericListServices : Service + { + public static readonly ReturnedDto[] returnedDtos = new ReturnedDto[] + { + new ReturnedDto() {Id = 1}, + new ReturnedDto() {Id = 2}, + new ReturnedDto() {Id = 3}, + }; + + public object Any(ReturnListRequest request) => returnedDtos.ToList(); + public object Any(ReturnArrayRequest request) => returnedDtos; + + public object Any(ReturnKeyValuePairRequest request) => new KeyValuePair("key1", "value1"); + + public object Any(ReturnDictionaryStringRequest request) => new Dictionary + { + {"key1", "value1"}, + {"key2", "value2"} + }; + + public object Any(ReturnDictionaryDtoRequest request) => new Dictionary + { + {"key1", new ReturnedDto {Id = 1}}, + {"key2", new ReturnedDto {Id = 2}} + }; + + public void Any(ReturnVoidDtoRequest request) + { + } + + public void Any(ReturnIReturnVoidDtoRequest request) + { + } + + public void Any(DeleteDhcpScope request) + { + } + + public object Any(ReturnAnnotatedDtoRequest request) + { + switch (request.Code) + { + case 403: + return new Return403Response(); + default: + return new Return200Response(); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.OpenApi.Tests/Services/SecuredService.cs b/tests/ServiceStack.OpenApi.Tests/Services/SecuredService.cs new file mode 100644 index 00000000000..b8fcbec0209 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/SecuredService.cs @@ -0,0 +1,31 @@ +namespace ServiceStack.OpenApi.Tests.Services +{ + [Route("/secured-service")] + public class SecuredRequest : IReturn { } + + [Route("/secured-dto-service")] + [Authenticate] + public class SecuredDtoRequest : IReturn { } + + [Route("/secured-ops-service")] + public class SecuredOpsRequest : IReturn { } + + [Authenticate] + public class SecuredService : Service + { + public object Any(SecuredRequest request) => "Secured"; + } + + public class SecuredDtoService : Service + { + public string Any(SecuredDtoRequest request) => "Secured"; + } + + public class SecuredOpsService : Service + { + [Authenticate] + public string Get(SecuredOpsRequest request) => "Secured"; + + public string Post(SecuredOpsRequest request) => "Not Secured"; + } +} diff --git a/tests/ServiceStack.OpenApi.Tests/Services/SessionService.cs b/tests/ServiceStack.OpenApi.Tests/Services/SessionService.cs new file mode 100644 index 00000000000..4f826e49b99 --- /dev/null +++ b/tests/ServiceStack.OpenApi.Tests/Services/SessionService.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using ServiceStack; +using ServiceStack.Auth; + +namespace ServiceStack.OpenApi.Tests.Services +{ + public class CustomUserSession : AuthUserSession + { + [DataMember] + public string CustomName { get; set; } + + [DataMember] + public string CustomInfo { get; set; } + + public override void OnAuthenticated(IServiceBase authService, IAuthSession session, + IAuthTokens tokens, Dictionary authInfo) + { + var unAuthInfo = authService.GetSessionBag().Get(); + + if (unAuthInfo != null) + this.CustomInfo = unAuthInfo.CustomInfo; + } + } + + public class UnAuthInfo + { + public string CustomInfo { get; set; } + } + + [Route("/session")] + public class GetSession : IReturn + { + } + + [Route("/session/edit/{CustomName}")] + public class UpdateSession : IReturn + { + public string CustomName { get; set; } + } + + public class GetSessionResponse + { + public CustomUserSession Result { get; set; } + + public UnAuthInfo UnAuthInfo { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class SessionService : Service + { + public object Any(GetSession request) + { + return new GetSessionResponse + { + Result = SessionAs(), + UnAuthInfo = SessionBag.Get(typeof(UnAuthInfo).Name), + }; + } + + public object Any(UpdateSession request) + { + var session = SessionAs(); + session.CustomName = request.CustomName; + + var unAuthInfo = SessionBag.Get() ?? new UnAuthInfo(); + unAuthInfo.CustomInfo = request.CustomName + " - CustomInfo"; + SessionBag.Set(unAuthInfo); + + this.SaveSession(session); + + return new GetSessionResponse + { + Result = SessionAs(), + UnAuthInfo = unAuthInfo, + }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Razor.Tests/CheckBoxService.cs b/tests/ServiceStack.Razor.Tests/CheckBoxService.cs deleted file mode 100644 index 49ee4705890..00000000000 --- a/tests/ServiceStack.Razor.Tests/CheckBoxService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using ServiceStack.ServiceHost; - -namespace ServiceStack.Razor.Tests -{ - public class CheckBoxService : ServiceInterface.Service - { - public CheckBoxData Get(GetCheckBox request) - { - return new CheckBoxData - { - BooleanValue = true - }; - } - - public CheckBoxData Post(CheckBoxData request) - { - return Get(new GetCheckBox()); - } - } - - [Route("/checkbox", "GET")] - public class GetCheckBox - { - - } - - [Route("/checkbox", "POST")] - public class CheckBoxData - { - public bool BooleanValue { get; set; } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.Razor.Tests/Global.asax b/tests/ServiceStack.Razor.Tests/Global.asax deleted file mode 100644 index f70867abef4..00000000000 --- a/tests/ServiceStack.Razor.Tests/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="ServiceStack.Razor.Tests.Global" Language="C#" %> diff --git a/tests/ServiceStack.Razor.Tests/Global.asax.cs b/tests/ServiceStack.Razor.Tests/Global.asax.cs deleted file mode 100644 index 5e25340c7c1..00000000000 --- a/tests/ServiceStack.Razor.Tests/Global.asax.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using ServiceStack.Logging.NLogger; - -namespace ServiceStack.Razor.Tests -{ - public class Global : System.Web.HttpApplication - { - - protected void Application_Start( object sender, EventArgs e ) - { - Logging.LogManager.LogFactory = new NLogFactory(); - new HelloAppHost().Init(); - } - - protected void Session_Start( object sender, EventArgs e ) - { - - } - - protected void Application_BeginRequest( object sender, EventArgs e ) - { - - } - - protected void Application_AuthenticateRequest( object sender, EventArgs e ) - { - - } - - protected void Application_Error( object sender, EventArgs e ) - { - - } - - protected void Session_End( object sender, EventArgs e ) - { - - } - - protected void Application_End( object sender, EventArgs e ) - { - - } - } -} diff --git a/tests/ServiceStack.Razor.Tests/HelloAppHost.cs b/tests/ServiceStack.Razor.Tests/HelloAppHost.cs deleted file mode 100644 index 79c11e849b0..00000000000 --- a/tests/ServiceStack.Razor.Tests/HelloAppHost.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.IO; -using System.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Admin; -using ServiceStack.WebHost.Endpoints; - -namespace ServiceStack.Razor.Tests -{ - public class HelloAppHost : AppHostBase - { - public HelloAppHost() - : base("Hello Web Services", typeof(HelloService).Assembly) { } - - public override void Configure(Funq.Container container) - { - //http://stackoverflow.com/questions/13206038/servicestack-razor-default-page/13206221 - - var razor3 = new RazorFormat(); - - this.Plugins.Add(razor3); - this.Plugins.Add(new RequestLogsFeature() - { - EnableErrorTracking = true, - EnableResponseTracking = true, - EnableSessionTracking = true, - EnableRequestBodyTracking = true, - RequiredRoles = new string[0] - }); - - this.PreRequestFilters.Add(SimplePreRequestFilter); - - this.RequestFilters.Add(SimpleRequestFilter); - - //this.SetConfig( new EndpointHostConfig() - // { - // DebugMode = false, - - // } ); - - - this.Routes.Add("/hello"); - this.Routes.Add("/hello/{Name}"); - this.Routes.Add("/Foo/{WhatToSay}"); - this.Routes.Add("/DefaultViewFoo/{WhatToSay}"); - } - - private void SimpleRequestFilter(IHttpRequest req, IHttpResponse res, object obj) - { - if (Path.GetFileName(req.PathInfo).StartsWith("_")) - { - throw new HttpException("FIles with leading underscore ('_') cannot be served."); - } - } - - private void SimplePreRequestFilter(IHttpRequest req, IHttpResponse res) - { - if (Path.GetFileName(req.PathInfo).StartsWith("_")) - { - throw new HttpException("Files with leading underscores ('_') cannot be served."); - } - } - } -} diff --git a/tests/ServiceStack.Razor.Tests/HelloRequest.cs b/tests/ServiceStack.Razor.Tests/HelloRequest.cs deleted file mode 100644 index 01c40b1a527..00000000000 --- a/tests/ServiceStack.Razor.Tests/HelloRequest.cs +++ /dev/null @@ -1,76 +0,0 @@ -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; - -namespace ServiceStack.Razor.Tests -{ - public class HelloRequest - { - public string Name { get; set; } - } - public class HelloResponse - { - public string Result { get; set; } - } - - //https://github.com/ServiceStack/ServiceStack/wiki/New-Api - public class HelloService : ServiceInterface.Service, IAny - { - //public HelloResponse Any( Hello h ) - //{ - // //return new HelloResponse { Result = "Hello, " + h.Name }; - // return h; - //} - - - public object Any(HelloRequest request) - { - //return new HelloResponse { Result = "Hello, " + request.Name }; - return new { Foo = "foo", Password = "pwd", Pw2 = "222", FooMasta = new { Charisma = 10, Mula = 10000000000, Car = "911Turbo" } }; - } - } - - - public class FooRequest - { - public string WhatToSay { get; set; } - } - - public class FooResponse - { - public string FooSaid { get; set; } - } - - public class DefaultViewFooRequest - { - public string WhatToSay { get; set; } - } - - public class DefaultViewFooResponse - { - public string FooSaid { get; set; } - } - - public class FooController : ServiceInterface.Service, IGet, IPost - { - public object Get(FooRequest request) - { - return new FooResponse { FooSaid = string.Format("GET: {0}", request.WhatToSay) }; - } - - public object Post(FooRequest request) - { - return new FooResponse { FooSaid = string.Format("POST: {0}", request.WhatToSay) }; - } - - [DefaultView("DefaultViewFoo")] - public object Get(DefaultViewFooRequest request) - { - if (request.WhatToSay == "redirect") - { - return HttpResult.Redirect("/"); - } - return new DefaultViewFooResponse { FooSaid = string.Format("GET: {0}", request.WhatToSay) }; - } - } -} diff --git a/tests/ServiceStack.Razor.Tests/NoController.cshtml b/tests/ServiceStack.Razor.Tests/NoController.cshtml deleted file mode 100644 index 9c7c78ec6c7..00000000000 --- a/tests/ServiceStack.Razor.Tests/NoController.cshtml +++ /dev/null @@ -1,42 +0,0 @@ - -@inherits ServiceStack.Razor.ViewPage -@using System -@using ServiceStack.Razor.Tests -@using ServiceStack.Common -@using ServiceStack.Common.Web -@using ServiceStack.WebHost.Endpoints - - -@{ - - var myvariable = ""; - if ( this.Request.HttpMethod == HttpMethods.Post ) - { - //there is a postback... - myvariable = "FFFFFFFFFFFFFFF"; - } - -} - -
-

/default.cshtml

- The time is: @DateTime.Now - - @if ( this.Request.HttpMethod == HttpMethods.Post ) - { -

Your name is @Model.Name

-

This IS A POST BACK

-

@myvariable

- } - else - { -

This is a GET request

- } - - -
- What name do you want? @Html.TextBox( "Name" ) - - - -
diff --git a/tests/ServiceStack.Razor.Tests/Person.cs b/tests/ServiceStack.Razor.Tests/Person.cs deleted file mode 100644 index 97f5b2c254e..00000000000 --- a/tests/ServiceStack.Razor.Tests/Person.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ServiceStack.Razor.Tests -{ - public class Person - { - public string Name { get; set; } - } -} diff --git a/tests/ServiceStack.Razor.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Razor.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index af544d05af2..00000000000 --- a/tests/ServiceStack.Razor.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle( "ServiceStack.Razor.Tests" )] -[assembly: AssemblyDescription( "" )] -[assembly: AssemblyConfiguration( "" )] -[assembly: AssemblyCompany( "" )] -[assembly: AssemblyProduct( "ServiceStack.Razor.Tests" )] -[assembly: AssemblyCopyright( "Copyright © 2013" )] -[assembly: AssemblyTrademark( "" )] -[assembly: AssemblyCulture( "" )] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible( false )] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid( "3ba5a48b-b4c1-4095-a9a8-4a5baab038eb" )] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion( "1.0.0.0" )] -[assembly: AssemblyFileVersion( "1.0.0.0" )] diff --git a/tests/ServiceStack.Razor.Tests/ServiceStack.Razor.Tests.csproj b/tests/ServiceStack.Razor.Tests/ServiceStack.Razor.Tests.csproj deleted file mode 100644 index e452d6209b1..00000000000 --- a/tests/ServiceStack.Razor.Tests/ServiceStack.Razor.Tests.csproj +++ /dev/null @@ -1,165 +0,0 @@ - - - - - Debug - AnyCPU - - - 2.0 - {7F42298E-7DEA-458B-B7BC-057A7229A7CF} - {E3E379DF-F4C6-4180-9B81-6769533ABE47};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - ServiceStack.Razor.Tests - ServiceStack.Razor.Tests - v4.5 - false - true - - - - - - - - true - full - false - bin\ - TRACE;DEBUG - prompt - 4 - true - false - - - pdbonly - true - bin\ - TRACE - prompt - 4 - false - - - - - lib\NLog.dll - - - lib\ServiceStack.Logging.NLog.dll - - - - - - - - - False - ..\lib\System.Web.Razor.dll - - - - - - - - - - Designer - - - - - - Global.asax - - - - - - - - - - - - - - - - - - Web.config - - - Web.config - Designer - - - - - - - - - - - {982416db-c143-4028-a0c3-cf41892d18d3} - ServiceStack.Common - - - {42e1c8c0-a163-44cc-92b1-8f416f2c0b01} - ServiceStack.Interfaces - - - {d73274ae-006b-4cee-ba60-0ecf5873048d} - ServiceStack.Razor - - - {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} - ServiceStack.ServiceInterface - - - {680a1709-25eb-4d52-a87f-ee03ffd94baa} - ServiceStack - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - - False - False - 8181 - / - http://localhost:33011/ - False - False - - - False - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Razor.Tests/Views/CheckBoxData.cshtml b/tests/ServiceStack.Razor.Tests/Views/CheckBoxData.cshtml deleted file mode 100644 index 1500adaecc7..00000000000 --- a/tests/ServiceStack.Razor.Tests/Views/CheckBoxData.cshtml +++ /dev/null @@ -1,14 +0,0 @@ -@inherits ServiceStack.Razor.ViewPage -@using System - -
-

Html CheckBox Helper

-

/Views/CheckBox

- The time is: @DateTime.Now - -
- @Html.CheckBoxFor(x => x.BooleanValue) Boolean Value -
- - -
diff --git a/tests/ServiceStack.Razor.Tests/Views/Foobar/DefaultViewFoo.cshtml b/tests/ServiceStack.Razor.Tests/Views/Foobar/DefaultViewFoo.cshtml deleted file mode 100644 index b57137ff9d0..00000000000 --- a/tests/ServiceStack.Razor.Tests/Views/Foobar/DefaultViewFoo.cshtml +++ /dev/null @@ -1,23 +0,0 @@ -@inherits ServiceStack.Razor.ViewPage -@using System -@using ServiceStack.Razor.Tests -@using ServiceStack.Common -@using ServiceStack.WebHost.Endpoints - -
-

/Views/DefaultViewFoo

- The time is: @DateTime.Now -

Foo Was Here!

-

He said: @Model.FooSaid

- -
- @Html.TextBox( "foo" ) - - - - obob - - -

DefaultViewFoo is executed on redirect

-

@Model.FooSaid.ToUpper()

-
diff --git a/tests/ServiceStack.Razor.Tests/Views/Foobar/FooResponse.cshtml b/tests/ServiceStack.Razor.Tests/Views/Foobar/FooResponse.cshtml deleted file mode 100644 index c1ddcf2ae26..00000000000 --- a/tests/ServiceStack.Razor.Tests/Views/Foobar/FooResponse.cshtml +++ /dev/null @@ -1,20 +0,0 @@ -@inherits ServiceStack.Razor.ViewPage -@using System -@using ServiceStack.Razor.Tests -@using ServiceStack.Common -@using ServiceStack.WebHost.Endpoints - -
-

/Views/Foo

- The time is: @DateTime.Now -

Foo Was Here!

-

He said: @Model.FooSaid

- -
- @Html.TextBox( "foo" ) - - - - obob - -
diff --git a/tests/ServiceStack.Razor.Tests/Views/Shared/_Layout.cshtml b/tests/ServiceStack.Razor.Tests/Views/Shared/_Layout.cshtml deleted file mode 100644 index f5b67e35787..00000000000 --- a/tests/ServiceStack.Razor.Tests/Views/Shared/_Layout.cshtml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Some Title - - -

/Shared/_Layout.cshtml

-
- @RenderBody() -
- - diff --git a/tests/ServiceStack.Razor.Tests/Web.Release.config b/tests/ServiceStack.Razor.Tests/Web.Release.config deleted file mode 100644 index 760dff3eb87..00000000000 --- a/tests/ServiceStack.Razor.Tests/Web.Release.config +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Razor.Tests/Web.config b/tests/ServiceStack.Razor.Tests/Web.config deleted file mode 100644 index dfc6a663c14..00000000000 --- a/tests/ServiceStack.Razor.Tests/Web.config +++ /dev/null @@ -1,92 +0,0 @@ - - - - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Razor.Tests/_Layout.cshtml b/tests/ServiceStack.Razor.Tests/_Layout.cshtml deleted file mode 100644 index 7caa2263030..00000000000 --- a/tests/ServiceStack.Razor.Tests/_Layout.cshtml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Some Title - - -

/_Layout.cshtml

-
- @RenderBody() -
- - diff --git a/tests/ServiceStack.Razor.Tests/cool/Test.cshtml b/tests/ServiceStack.Razor.Tests/cool/Test.cshtml deleted file mode 100644 index 2a58142d759..00000000000 --- a/tests/ServiceStack.Razor.Tests/cool/Test.cshtml +++ /dev/null @@ -1,6 +0,0 @@ -@using System - -
-

/cool/Test.cshtml

- In cool dir: the time is @DateTime.Now -
diff --git a/tests/ServiceStack.Razor.Tests/cool/_Layout.cshtml b/tests/ServiceStack.Razor.Tests/cool/_Layout.cshtml deleted file mode 100644 index 4bd05685d47..00000000000 --- a/tests/ServiceStack.Razor.Tests/cool/_Layout.cshtml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Some Title - - -

/cool/_Layout.cshtml

-
- @RenderBody() -
- - diff --git a/tests/ServiceStack.Razor.Tests/default.cshtml b/tests/ServiceStack.Razor.Tests/default.cshtml deleted file mode 100644 index 347b979d212..00000000000 --- a/tests/ServiceStack.Razor.Tests/default.cshtml +++ /dev/null @@ -1,17 +0,0 @@ - -@using System -@using ServiceStack.Razor.Tests -@using ServiceStack.Common -@using ServiceStack.ServiceHost -@using ServiceStack.WebHost.Endpoints - -
-

/default.cshtml

- The time is: @DateTime.Now -

@this.GetType().BaseType

-

@this.Request.RemoteIp

-

@this.Request.IsLocal

-

@this.Request.IsSecureConnection

-

Is debug nnrr? @EndpointHost.DebugMode

-

hello :)

-
diff --git a/tests/ServiceStack.Razor.Tests/default4.cshtml b/tests/ServiceStack.Razor.Tests/default4.cshtml deleted file mode 100644 index 3f10905d587..00000000000 --- a/tests/ServiceStack.Razor.Tests/default4.cshtml +++ /dev/null @@ -1,18 +0,0 @@ - - -@using System -@using ServiceStack.Razor.Tests -@using ServiceStack.Common -@using ServiceStack.ServiceHost -@using ServiceStack.WebHost.Endpoints - -
-

/default.cshtml

- The time is: @DateTime.Now -

@this.GetType().BaseType

-

@this.Request.RemoteIp

-

@this.Request.IsLocal

-

@this.Request.IsSecureConnection

-

Is debug nnrr? @EndpointHost.DebugMode

-

hello :)

-
diff --git a/tests/ServiceStack.Razor.Tests/lib/NLog.dll b/tests/ServiceStack.Razor.Tests/lib/NLog.dll deleted file mode 100644 index 491a6641b26..00000000000 Binary files a/tests/ServiceStack.Razor.Tests/lib/NLog.dll and /dev/null differ diff --git a/tests/ServiceStack.Razor.Tests/lib/ServiceStack.Logging.NLog.dll b/tests/ServiceStack.Razor.Tests/lib/ServiceStack.Logging.NLog.dll deleted file mode 100644 index 75927d92fea..00000000000 Binary files a/tests/ServiceStack.Razor.Tests/lib/ServiceStack.Logging.NLog.dll and /dev/null differ diff --git a/tests/ServiceStack.RazorHostTests/AppHost.cs b/tests/ServiceStack.RazorHostTests/AppHost.cs index 93f19595928..20bfe1f450f 100644 --- a/tests/ServiceStack.RazorHostTests/AppHost.cs +++ b/tests/ServiceStack.RazorHostTests/AppHost.cs @@ -1,21 +1,19 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Funq; -using ServiceStack.Common; +using ServiceStack.Data; using ServiceStack.DataAnnotations; using ServiceStack.OrmLite; using ServiceStack.OrmLite.Sqlite; using ServiceStack.Razor; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Text; namespace ServiceStack.RazorHostTests { - [Route( "/rockstars" )] - [Route( "/rockstars/aged/{Age}" )] - [Route( "/rockstars/delete/{Delete}" )] - [Route( "/rockstars/{Id}" )] + [Route("/rockstars")] + [Route("/rockstars/aged/{Age}")] + [Route("/rockstars/delete/{Delete}")] + [Route("/rockstars/{Id}")] public class Rockstars { public int Id { get; set; } @@ -38,7 +36,7 @@ public class RockstarsResponse public List Results { get; set; } } - public class RockstarsService : ServiceInterface.Service + public class RockstarsService : Service { public IDbConnectionFactory DbFactory { get; set; } @@ -57,7 +55,7 @@ public object Get(Rockstars request) return new RockstarsResponse { Aged = request.Age, - Total = Db.GetScalar("select count(*) from Rockstar"), + Total = Db.Scalar("select count(*) from Rockstar"), Results = request.Id != default(int) ? Db.Select(q => q.Id == request.Id) : request.Age.HasValue ? @@ -68,15 +66,15 @@ public object Get(Rockstars request) public object Post(Rockstars request) { - using( var db = DbFactory.OpenDbConnection() ) + using (var db = DbFactory.OpenDbConnection()) { - db.Insert( request.TranslateTo() ); - return Get( new Rockstars() ); + db.Insert(request.ConvertTo()); + return Get(new Rockstars()); } } } - [Route( "/viewmodel/{Id}" )] + [Route("/viewmodel/{Id}")] public class ViewThatUsesLayoutAndModel { public string Id { get; set; } @@ -88,7 +86,7 @@ public class ViewThatUsesLayoutAndModelResponse public List Results { get; set; } } - public class ViewService : ServiceInterface.Service + public class ViewService : Service { public object Any(ViewThatUsesLayoutAndModel request) { @@ -123,7 +121,7 @@ public class Rockstar public int? Age { get; set; } public Rockstar() { } - public Rockstar( int id, string firstName, string lastName, int age ) + public Rockstar(int id, string firstName, string lastName, int age) { Id = id; FirstName = firstName; @@ -132,8 +130,6 @@ public Rockstar( int id, string firstName, string lastName, int age ) } } - - public class AppHost : AppHostBase { public AppHost() @@ -141,15 +137,14 @@ public AppHost() public override void Configure(Container container) { - Plugins.Add( new RazorFormat() - { - //TemplateProvider = {CompileInParallelWithNoOfThreads = 0} - } ); + Plugins.Add(new RazorFormat { + //TemplateProvider = {CompileInParallelWithNoOfThreads = 0} + }); container.Register(new DataSource()); container.Register( - new OrmLiteConnectionFactory(":memory:", false, SqliteOrmLiteDialectProvider.Instance)); + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); using (var db = container.Resolve().OpenDbConnection()) { diff --git a/tests/ServiceStack.RazorHostTests/CatchAll.cshtml b/tests/ServiceStack.RazorHostTests/CatchAll.cshtml index 783a531bc8b..521db0fabb4 100644 --- a/tests/ServiceStack.RazorHostTests/CatchAll.cshtml +++ b/tests/ServiceStack.RazorHostTests/CatchAll.cshtml @@ -20,3 +20,5 @@
  • @person.FirstName - @person.LastName (@person.Age)
  • } + +@Html.Partial("_CatchAllPartial") diff --git a/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs b/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs index 880e880218b..dfb479c5cf4 100644 --- a/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.RazorHostTests/Properties/AssemblyInfo.cs @@ -10,8 +10,8 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ServiceStack.RazorHostTests")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCopyright("Copyright (c) ServiceStack 2018")] +[assembly: AssemblyTrademark("Service Stack")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible @@ -32,4 +32,4 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("6.0.0.0")] diff --git a/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj b/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj index 1af17e193e3..eaf700a78ea 100644 --- a/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj +++ b/tests/ServiceStack.RazorHostTests/ServiceStack.RazorHostTests.csproj @@ -1,5 +1,5 @@  - + Debug @@ -14,7 +14,7 @@ ServiceStack.RazorHostTests ServiceStack.RazorHostTests false - v4.0 + v4.7.2 4.0 @@ -24,6 +24,12 @@ + ..\..\src\ + true + + + + True @@ -33,6 +39,7 @@ DEBUG;TRACE prompt 4 + false pdbonly @@ -41,35 +48,31 @@ TRACE prompt 4 + false - - ..\..\lib\tests\Mono.Data.Sqlite.dll - - - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - + + + + + + + + + - - + - - sqlite3.dll - PreserveNewest - Designer @@ -94,26 +97,22 @@ + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + {982416DB-C143-4028-A0C3-CF41892D18D3} ServiceStack.Common - - {672F2DFE-4EE8-498B-B449-23E9E7F6961C} - ServiceStack.FluentValidation.Mvc3 - - {42e1c8c0-a163-44cc-92b1-8f416f2c0b01} + {55942102-033a-4da8-a6af-1db7b2f34a2d} ServiceStack.Interfaces {d73274ae-006b-4cee-ba60-0ecf5873048d} ServiceStack.Razor - - {5a315f92-80d2-4c60-a5a4-22e027ac7e7e} - ServiceStack.ServiceInterface - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} ServiceStack @@ -175,22 +174,46 @@ + + + + + + + + + + + + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + bin\ + TRACE + true + pdbonly + AnyCPU + prompt + MinimumRecommendedRules.ruleset + false + - - False - True - 65318 + False + 58772 / @@ -208,6 +231,7 @@ + - + - + @@ -46,13 +55,21 @@ - + - + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.RazorHostTests/_CatchAllPartial.cshtml b/tests/ServiceStack.RazorHostTests/_CatchAllPartial.cshtml new file mode 100644 index 00000000000..3e53da7eff0 --- /dev/null +++ b/tests/ServiceStack.RazorHostTests/_CatchAllPartial.cshtml @@ -0,0 +1,7 @@ +

    Db.Select<Person>() Partial

    +
      + @foreach (var person in Db.Select(q => q.Age == 27)) + { +
    • @person.FirstName - @person.LastName (@person.Age)
    • + } +
    diff --git a/tests/ServiceStack.RazorNancyTests/Global.asax b/tests/ServiceStack.RazorNancyTests/Global.asax deleted file mode 100644 index 0789797c479..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="ServiceStack.RazorNancyTests.Global" Language="C#" %> diff --git a/tests/ServiceStack.RazorNancyTests/Global.asax.cs b/tests/ServiceStack.RazorNancyTests/Global.asax.cs deleted file mode 100644 index 86a4d207fa6..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Global.asax.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Security; -using System.Web.SessionState; -using Nancy; - -namespace ServiceStack.RazorNancyTests -{ - public class TestModel - { - public string Name { get; set; } - } - - public class Module : NancyModule - { - public Module() - { - Get["/greet/{name}"] = x => "Hello " + x.name; - - Get["/simple/view"] = param => View["SimpleView.cshtml"]; - - Get["/simple/model"] = param => { - var model = new TestModel { Name = "Demis" }; - return View["ViewThatUsesLayoutAndModel.cshtml", model]; - }; - - Get["/simple"] = param => View["ViewThatUsesLayout.cshtml"]; - } - } - - public class Global : System.Web.HttpApplication - { - - void Application_Start(object sender, EventArgs e) - { - // Code that runs on application startup - - } - - void Application_End(object sender, EventArgs e) - { - // Code that runs on application shutdown - - } - - void Application_Error(object sender, EventArgs e) - { - // Code that runs when an unhandled error occurs - - } - } -} diff --git a/tests/ServiceStack.RazorNancyTests/Properties/AssemblyInfo.cs b/tests/ServiceStack.RazorNancyTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 894274414a5..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.RazorNancyTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceStack.RazorNancyTests")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("251f44c5-f952-447d-9757-7ec61ee08365")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.RazorNancyTests/ServiceStack.RazorNancyTests.csproj b/tests/ServiceStack.RazorNancyTests/ServiceStack.RazorNancyTests.csproj deleted file mode 100644 index a899f23e2a2..00000000000 --- a/tests/ServiceStack.RazorNancyTests/ServiceStack.RazorNancyTests.csproj +++ /dev/null @@ -1,129 +0,0 @@ - - - - Debug - AnyCPU - - - 2.0 - {1B1151B2-19A6-4F08-9765-5EA6EF06F3FB} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - ServiceStack.RazorNancyTests - ServiceStack.RazorNancyTests - v4.0 - false - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\ - TRACE - prompt - 4 - - - - - ..\..\src\packages\Nancy.0.10.0\lib\net40\Nancy.dll - - - ..\..\src\packages\Nancy.Hosting.Aspnet.0.10.0\lib\net40\Nancy.Hosting.Aspnet.dll - - - ..\..\src\packages\Nancy.Viewengines.Razor.0.10.0\lib\net40\Nancy.ViewEngines.Razor.dll - - - - - - - - True - ..\..\src\packages\Nancy.Viewengines.Razor.0.10.0\lib\net40\System.Web.Razor.dll - - - - - - - - - - - - - - - - Designer - - - - - Global.asax - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - True - 30314 - / - - - False - False - - - False - - - - - - -xcopy /s /y "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.10.0\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin" -xcopy /s /y "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.10.0\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin" - - - \ No newline at end of file diff --git a/tests/ServiceStack.RazorNancyTests/Views/Shared/SimplyLayout.cshtml b/tests/ServiceStack.RazorNancyTests/Views/Shared/SimplyLayout.cshtml deleted file mode 100644 index 522dd8ed04e..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Views/Shared/SimplyLayout.cshtml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - -

    SimplyLayout

    -
    - @RenderBody() -
    - - \ No newline at end of file diff --git a/tests/ServiceStack.RazorNancyTests/Views/SimpleView.cshtml b/tests/ServiceStack.RazorNancyTests/Views/SimpleView.cshtml deleted file mode 100644 index 11c9ddde394..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Views/SimpleView.cshtml +++ /dev/null @@ -1 +0,0 @@ -
    Simple View
    \ No newline at end of file diff --git a/tests/ServiceStack.RazorNancyTests/Views/ViewThatUsesLayout.cshtml b/tests/ServiceStack.RazorNancyTests/Views/ViewThatUsesLayout.cshtml deleted file mode 100644 index e80ff1cb544..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Views/ViewThatUsesLayout.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@{ - Layout = "Shared/SimplyLayout"; -} - -
    ViewThatUsesLayout
    \ No newline at end of file diff --git a/tests/ServiceStack.RazorNancyTests/Views/ViewThatUsesLayoutAndModel.cshtml b/tests/ServiceStack.RazorNancyTests/Views/ViewThatUsesLayoutAndModel.cshtml deleted file mode 100644 index 3aabd3df04d..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Views/ViewThatUsesLayoutAndModel.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@{ - Layout = "Shared/SimplyLayout"; -} - -
    ViewThatUsesLayoutAndModel: @Model.Name
    \ No newline at end of file diff --git a/tests/ServiceStack.RazorNancyTests/Web.config b/tests/ServiceStack.RazorNancyTests/Web.config deleted file mode 100644 index 66f69959813..00000000000 --- a/tests/ServiceStack.RazorNancyTests/Web.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.RazorNancyTests/packages.config b/tests/ServiceStack.RazorNancyTests/packages.config deleted file mode 100644 index 7245e19ad34..00000000000 --- a/tests/ServiceStack.RazorNancyTests/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/App.config b/tests/ServiceStack.Server.Tests/App.config new file mode 100644 index 00000000000..4d4458b3952 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/App.config @@ -0,0 +1,34 @@ + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Async/ValueTaskTests.cs b/tests/ServiceStack.Server.Tests/Async/ValueTaskTests.cs new file mode 100644 index 00000000000..94a3dde657c --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Async/ValueTaskTests.cs @@ -0,0 +1,126 @@ +using System.Linq; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Server.Tests.Auth; +using ServiceStack.Server.Tests.Services; + +namespace ServiceStack.Server.Tests.Async +{ + [TestFixture] + public class ValueTaskTests + { + class AppHost : AppSelfHostBase + { + public static ApiKey LastApiKey; + + public AppHost() : base(nameof(ApiKeyAuthTests), typeof(AppHost).Assembly) { } + + public override void Configure(Container container) + { + container.Register(c => + new RedisManagerPool()); + + container.Register(c => + new RedisAuthRepository(c.Resolve())); + + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(), + new ApiKeyAuthProvider(AppSettings) { RequireSecureConnection = false }, + }) { + IncludeRegistrationService = true, + }); + } + } + + public const string ListeningOn = "http://localhost:20000/"; + public const string Username = "user"; + public const string Password = "p@55word"; + private ServiceStackHost appHost; + private string userId; + private ApiKey liveKey; + private ApiKey testKey; + + JsonServiceClient client = new JsonServiceClient(ListeningOn); + + public ValueTaskTests() + { + appHost = new AppHost() + .Init() + .Start(ListeningOn); + + // var response = client.Post(new Register { + // UserName = Username, + // Password = Password, + // Email = "as@if{0}.com", + // DisplayName = "DisplayName", + // FirstName = "FirstName", + // LastName = "LastName", + // }); + // + // userId = response.UserId; + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public async Task Can_call_AsyncRedis_ValueTask() + { + await using var redis = await appHost.GetRedisClientAsync(); + await redis.FlushAllAsync(); + + var response = await client.GetAsync(new AsyncRedis { + Incr = 1, + }); + + Assert.That(response.Id, Is.EqualTo("1")); + } + + [Test] + public async Task Can_call_SGAsyncRedis1_ValueTask() + { + await using var redis = await appHost.GetRedisClientAsync(); + await redis.FlushAllAsync(); + + var response = await client.GetAsync(new SGAsyncRedis1 { + Incr = 1, + }); + + Assert.That(response.Id, Is.EqualTo("1")); + } + + [Test] + public async Task Can_call_SGAsyncRedis2_ValueTask() + { + await using var redis = await appHost.GetRedisClientAsync(); + await redis.FlushAllAsync(); + + var response = await client.GetAsync(new SGAsyncRedis1 { + Incr = 1, + }); + + Assert.That(response.Id, Is.EqualTo("1")); + } + + [Test] + public async Task Can_call_SGAsyncRedisSync_ValueTask() + { + await using var redis = await appHost.GetRedisClientAsync(); + await redis.FlushAllAsync(); + + var response = await client.GetAsync(new SGAsyncRedisSync { + Incr = 1, + }); + + Assert.That(response.Id, Is.EqualTo("1")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Auth/ApiKeyAuthTests.cs b/tests/ServiceStack.Server.Tests/Auth/ApiKeyAuthTests.cs new file mode 100644 index 00000000000..6844a31ab92 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Auth/ApiKeyAuthTests.cs @@ -0,0 +1,200 @@ +using System.Linq; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Auth +{ + public class RequiresAuth : IReturn, IHasBearerToken + { + public string Name { get; set; } + public string BearerToken { get; set; } + } + + [Authenticate] + public class RequiresAuthService : Service + { + public static ApiKey LastApiKey; + + public object Any(RequiresAuth request) + { + LastApiKey = base.Request.GetApiKey(); + return request; + } + } + + [Route("/requires-auth")] + public class RequiresAuthAction : IReturn + { + public string Name { get; set; } + } + + public class RequiresAuthActionService : Service + { + public static ApiKey LastApiKey; + + [Authenticate] + public object Any(RequiresAuthAction request) + { + LastApiKey = base.Request.GetApiKey(); + return request; + } + } + + [TestFixture] + public class ApiKeyAuthTests + { + class AppHost : AppSelfHostBase + { + public static ApiKey LastApiKey; + + public AppHost() : base(nameof(ApiKeyAuthTests), typeof(AppHost).Assembly) { } + + public override void Configure(Container container) + { + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new ApiKeyAuthProvider(AppSettings) { RequireSecureConnection = false }, + }) + { + IncludeRegistrationService = true, + }); + + GlobalRequestFilters.Add((req, res, dto) => + { + LastApiKey = req.GetApiKey(); + }); + } + } + + public const string ListeningOn = "http://localhost:2337/"; + public const string Username = "user"; + public const string Password = "p@55word"; + private ServiceStackHost appHost; + protected IManageApiKeys apiRepo; + private string userId; + private ApiKey liveKey; + private ApiKey testKey; + + public ApiKeyAuthTests() + { + //System.Diagnostics.Debugger.Break(); + appHost = new AppHost() + .Init() + .Start("http://*:2337/"); + + var client = new JsonServiceClient(ListeningOn); + var response = client.Post(new Register + { + UserName = Username, + Password = Password, + Email = "as@if{0}.com", + DisplayName = "DisplayName", + FirstName = "FirstName", + LastName = "LastName", + }); + + userId = response.UserId; + apiRepo = (IManageApiKeys)appHost.Resolve(); + var apiKeys = apiRepo.GetUserApiKeys(userId); + liveKey = apiKeys.First(x => x.Environment == "live"); + testKey = apiKeys.First(x => x.Environment == "test"); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_return_APIKey_for_ApiKey_request_in_GlobalRequestFilters() + { + AppHost.LastApiKey = null; + RequiresAuthService.LastApiKey = null; + + var client = new JsonServiceClient(ListeningOn) + { + Credentials = new NetworkCredential(liveKey.Id, ""), + }; + + var request = new RequiresAuth { Name = "foo" }; + var response = client.Send(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + Assert.That(RequiresAuthService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + } + + [Test] + public void Does_return_APIKey_for_ApiKey_request_in_GlobalRequestFilters_Action() + { + RequiresAuthActionService.LastApiKey = null; + + var client = new JsonServiceClient(ListeningOn) + { + Credentials = new NetworkCredential(liveKey.Id, ""), + }; + + var request = new RequiresAuthAction { Name = "foo" }; + var response = client.Send(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(RequiresAuthActionService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + } + + [Test] + public void Does_allow_ApiKey_in_IHasBearerToken_RequestDto() + { + AppHost.LastApiKey = null; + RequiresAuthService.LastApiKey = null; + + var client = new JsonServiceClient(ListeningOn); + + var request = new RequiresAuth { BearerToken = liveKey.Id, Name = "foo" }; + var response = client.Send(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + Assert.That(AppHost.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + Assert.That(RequiresAuthService.LastApiKey.Id, Is.EqualTo(liveKey.Id)); + } + + [Test] + public void Does_not_allow_ApiKey_in_QueryString() + { + var url = ListeningOn.CombineWith("/requires-auth").AddQueryParam("apikey", liveKey.Id); + + try + { + var json = url.GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (WebException ex) + { + Assert.That(ex.GetStatus().Value, Is.EqualTo(HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Does_allow_ApiKey_in_QueryString_when_AllowInHttpParams() + { + var apiKeyAuth = (ApiKeyAuthProvider)AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name); + apiKeyAuth.AllowInHttpParams = true; + + var url = ListeningOn.CombineWith("/requires-auth").AddQueryParam("apikey", liveKey.Id); + var json = url.GetJsonFromUrl(); + + Assert.That(json, Is.Not.Null); + + apiKeyAuth.AllowInHttpParams = false; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Auth/AppHost.cs b/tests/ServiceStack.Server.Tests/Auth/AppHost.cs new file mode 100644 index 00000000000..d6ce63948cc --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Auth/AppHost.cs @@ -0,0 +1,357 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Net; +using System.Runtime.Serialization; +using System.Security.Cryptography; +using Funq; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.Web; + +#if NETCORE +using Microsoft.Extensions.DependencyInjection; +#endif + +//The entire C# code for the stand-alone RazorRockstars demo. +namespace ServiceStack.Server.Tests.Auth +{ + public class AppHost : AppSelfHostBase + { + public AppHost() : base("Test Auth", typeof(AppHost).Assembly) { } + + public RSAParameters? JwtRsaPrivateKey; + public RSAParameters? JwtRsaPublicKey; + public bool JwtEncryptPayload = false; + public List FallbackAuthKeys = new List(); + public List FallbackPublicKeys = new List(); + public Func GetAuthRepositoryFn; + + public Action Use; + +#if NETCORE + public override void Configure(Microsoft.Extensions.DependencyInjection.IServiceCollection services) + { + services.AddMvc(); + } +#endif + + public override void Configure(Container container) + { + Use?.Invoke(container); + + SetConfig(new HostConfig + { + AdminAuthSecret = "secret", + DebugMode = true, + WebHostPhysicalPath = Path.GetFullPath("../../../"), + }); + +#if NETCORE + Plugins.Add(new Mvc.RazorFormat()); +#else + Plugins.Add(new Razor.RazorFormat()); +#endif + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + + dbFactory.RegisterConnection("testdb", MapProjectPath("~/App_Data/test.sqlite"), SqliteDialect.Provider); + + using (var db = dbFactory.OpenDbConnection()) + { + db.DropAndCreateTable(); //Create table if not exists + db.Insert(Rockstar.SeedData); //Populate with seed data + } + + using (var db = dbFactory.OpenDbConnection("testdb")) + { + db.DropAndCreateTable(); //Create table if not exists + db.Insert(new Rockstar(1, "Test", "Database", 27)); + } + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new BasicAuthProvider(AppSettings), + new CredentialsAuthProvider(AppSettings), + new ApiKeyAuthProvider(AppSettings) { RequireSecureConnection = false }, + new JwtAuthProvider(AppSettings) + { + AuthKey = JwtRsaPrivateKey != null || JwtRsaPublicKey != null ? null : AesUtils.CreateKey(), + RequireSecureConnection = false, + HashAlgorithm = JwtRsaPrivateKey != null || JwtRsaPublicKey != null ? "RS256" : "HS256", + PublicKey = JwtRsaPublicKey, + PrivateKey = JwtRsaPrivateKey, + EncryptPayload = JwtEncryptPayload, + FallbackAuthKeys = FallbackAuthKeys, + FallbackPublicKeys = FallbackPublicKeys, + }, + }) + { + IncludeRegistrationService = true, + }); + + container.Resolve().InitSchema(); + } + + public override IDbConnection GetDbConnection(IRequest req = null) + { + var apiKey = req.GetApiKey(); + return apiKey != null && apiKey.Environment == "test" + ? TryResolve().OpenDbConnection("testdb") + : base.GetDbConnection(req); + } + + public override IAuthRepository GetAuthRepository(IRequest req = null) + { + return GetAuthRepositoryFn != null + ? GetAuthRepositoryFn(req) + : base.GetAuthRepository(req); + } + } + + public class Rockstar + { + public static Rockstar[] SeedData = new[] { + new Rockstar(1, "Jimi", "Hendrix", 27), + new Rockstar(2, "Janis", "Joplin", 27), + new Rockstar(3, "Jim", "Morrisson", 27), + new Rockstar(4, "Kurt", "Cobain", 27), + new Rockstar(5, "Elvis", "Presley", 42), + new Rockstar(6, "Michael", "Jackson", 50), + }; + + [AutoIncrement] + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public bool Alive { get; set; } + + public Rockstar() { } + public Rockstar(int id, string firstName, string lastName, int age) + { + Id = id; + FirstName = firstName; + LastName = lastName; + Age = age; + } + } + + [Route("/rockstars")] + [Route("/rockstars/aged/{Age}")] + [Route("/rockstars/delete/{Delete}")] + [Route("/rockstars/{Id}")] + public class Rockstars : IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public bool Alive { get; set; } + public string Delete { get; set; } + public string View { get; set; } + public string Template { get; set; } + } + + [DataContract] //Attrs for CSV Format to recognize it's a DTO and serialize the Enumerable property + public class RockstarsResponse + { + [DataMember] + public int Total { get; set; } + [DataMember] + public int? Aged { get; set; } + [DataMember] + public List Results { get; set; } + } + + [Route("/ilist1/{View}")] + public class IList1 + { + public string View { get; set; } + } + + [Route("/ilist2/{View}")] + public class IList2 + { + public string View { get; set; } + } + + [Route("/ilist3/{View}")] + public class IList3 + { + public string View { get; set; } + } + + [Route("/partialmodel")] + public class PartialModel + { + public IEnumerable Items { get; set; } + } + public class PartialChildModel + { + public string SomeProperty { get; set; } + } + + public class GetAllRockstars : IReturn { } + + [Authenticate] + public class SecureServices : Service + { + public object Any(GetAllRockstars request) + { + return new RockstarsResponse { Results = Db.Select() }; + } + } + + public class RockstarsService : Service + { + public object Get(Rockstars request) + { + if (request.Delete == "reset") + { + Db.DeleteAll(); + Db.Insert(Rockstar.SeedData); + } + else if (request.Delete.IsInt()) + { + Db.DeleteById(request.Delete.ToInt()); + } + + var response = new RockstarsResponse + { + Aged = request.Age, + Total = Db.Scalar("select count(*) from Rockstar"), + Results = request.Id != default(int) ? + Db.Select(q => q.Id == request.Id) + : request.Age.HasValue ? + Db.Select(q => q.Age == request.Age.Value) + : Db.Select() + }; + + if (request.View != null || request.Template != null) + return new HttpResult(response) + { + View = request.View, + Template = request.Template, + }; + + return response; + } + + public object Post(Rockstars request) + { + Db.Insert(request.ConvertTo()); + return Get(new Rockstars()); + } + + public IList Get(IList1 request) + { + base.Request.Items["View"] = request.View; + return Db.Select(); + } + + public List Get(IList2 request) + { + base.Request.Items["View"] = request.View; + return Db.Select(); + } + + public object Get(IList3 request) + { + base.Request.Items["View"] = request.View; + return Db.Select(); + } + + public PartialModel Any(PartialModel request) + { + return new PartialModel + { + Items = 5.Times(x => new PartialChildModel + { + SomeProperty = "value " + x + }) + }; + } + + public void Any(RedirectWithoutQueryString request) { } + } + + public class RedirectWithoutQueryStringFilterAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + if (req.QueryString.Count > 0) + { + res.RedirectToUrl(req.PathInfo); + } + } + } + + [RedirectWithoutQueryStringFilter] + public class RedirectWithoutQueryString + { + public int Id { get; set; } + } + + [Route("/Content/hello/{Name*}")] + public class TestWildcardRazorPage + { + public string Name { get; set; } + } + + public class IssueServices : Service + { + public object Get(TestWildcardRazorPage request) + { + return request; + } + } + + [Route("/test/session")] + public class TestSession : IReturn { } + + [Route("/test/session/view")] + public class TestSessionView : IReturn { } + + public class TestSessionResponse + { + public string UserAuthId { get; set; } + public bool IsAuthenticated { get; set; } + } + + public class TestSessionAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var session = req.GetSession(); + if (!session.IsAuthenticated) + { + res.StatusCode = (int)HttpStatusCode.Unauthorized; + res.EndRequestWithNoContent(); + } + } + } + + public class TestSessionService : Service + { + [TestSession] + public object Any(TestSession request) + { + var session = base.Request.GetSession(); + return new TestSessionResponse + { + UserAuthId = session.UserAuthId, + IsAuthenticated = session.IsAuthenticated, + }; + } + + public object Any(TestSessionView request) + { + return new TestSessionResponse(); + } + } +} diff --git a/tests/ServiceStack.Server.Tests/Auth/StatelessAuthRazorTests.cs b/tests/ServiceStack.Server.Tests/Auth/StatelessAuthRazorTests.cs new file mode 100644 index 00000000000..7aeb6ff50eb --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Auth/StatelessAuthRazorTests.cs @@ -0,0 +1,257 @@ +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; + +namespace ServiceStack.Server.Tests.Auth +{ +#if NETCORE + [Ignore("Not working on .NET Core")] +#endif + public class OrmLiteStatelessAuthRazorTests : StatelessAuthRazorTests + { + } + + public abstract class StatelessAuthRazorTests + { + public const string ListeningOn = "http://localhost:2337/"; + + protected readonly ServiceStackHost appHost; + protected string ApiKey; + public const string Username = "user"; + public const string Password = "p@55word"; + + protected StatelessAuthRazorTests() + { + appHost = CreateAppHost() + .Init() + .Start("http://*:2337/"); + + var client = GetClient(); + var response = client.Post(new Register + { + UserName = "user", + Password = "p@55word", + Email = "as@if{0}.com", + DisplayName = "DisplayName", + FirstName = "FirstName", + LastName = "LastName", + }); + + var userId = response.UserId; + var apiRepo = (IManageApiKeys)appHost.Resolve(); + var user1Client = GetClientWithUserPassword(alwaysSend: true); + ApiKey = user1Client.Get(new GetApiKeys { Environment = "live" }).Results[0].Key; + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected virtual ServiceStackHost CreateAppHost() => + new AppHost { + Use = container => container.Register(c => + new OrmLiteAuthRepository(c.Resolve())) + }; + + protected virtual IServiceClient GetClient() => new JsonServiceClient(ListeningOn); + + protected virtual IServiceClient GetClientWithUserPassword(bool alwaysSend = false, string userName = null) => + new JsonServiceClient(ListeningOn) { + UserName = userName ?? Username, + Password = Password, + AlwaysSendBasicAuthHeader = alwaysSend, + }; + + [Test] + public void Can_not_access_Secured_Pages_without_Authentication() + { + Assert.That(ListeningOn.CombineWith("/secured").GetStringFromUrl(), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/SecuredPage").GetStringFromUrl(), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrl(), + Does.Contain("IsAuthenticated:False")); + + Assert.That(ListeningOn.CombineWith("/test/session/view").GetStringFromUrl(), + Does.Contain("IsAuthenticated:False")); + } + + [Test] + public void Can_access_Secured_Pages_with_BasicAuth() + { + Assert.That(ListeningOn.CombineWith("/secured").GetStringFromUrl( + requestFilter: req => req.AddBasicAuth(Username, Password)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/SecuredPage").GetStringFromUrl( + requestFilter: req => req.AddBasicAuth(Username, Password)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/test/session").GetJsonFromUrl( + requestFilter: req => req.AddBasicAuth(Username, Password)), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrl( + requestFilter: req => req.AddBasicAuth(Username, Password)), + Does.Contain("IsAuthenticated:True")); + + Assert.That(ListeningOn.CombineWith("/test/session/view").GetStringFromUrl( + requestFilter: req => req.AddBasicAuth(Username, Password)), + Does.Contain("IsAuthenticated:True")); + } + + [Test] + public void Can_access_Secured_Pages_with_JWT() + { + var client = GetClientWithUserPassword(alwaysSend: true); + var authResponse = client.Send(new Authenticate()); + + Assert.That(ListeningOn.CombineWith("/secured").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(authResponse.BearerToken)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/SecuredPage").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(authResponse.BearerToken)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/test/session").GetJsonFromUrl( + requestFilter: req => req.AddBearerToken(authResponse.BearerToken)), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(authResponse.BearerToken)), + Does.Contain("IsAuthenticated:True")); + + Assert.That(ListeningOn.CombineWith("/test/session/view").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(authResponse.BearerToken)), + Does.Contain("IsAuthenticated:True")); + } + + [Test] + public void Can_access_Secured_Pages_with_ApiKeyAuth() + { + Assert.That(ListeningOn.CombineWith("/secured").GetStringFromUrl( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/SecuredPage").GetStringFromUrl( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/test/session").GetJsonFromUrl( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrl( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("IsAuthenticated:True")); + + Assert.That(ListeningOn.CombineWith("/test/session/view").GetStringFromUrl( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("IsAuthenticated:True")); + } + + [Test] + public async Task Can_access_Secured_Pages_with_ApiKeyAuth_async() + { + Assert.That(await ListeningOn.CombineWith("/secured").GetStringFromUrlAsync( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("")); + + Assert.That(await ListeningOn.CombineWith("/SecuredPage").GetStringFromUrlAsync( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("")); + + Assert.That(await ListeningOn.CombineWith("/test/session").GetJsonFromUrlAsync( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(await ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrlAsync( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("IsAuthenticated:True")); + + Assert.That(await ListeningOn.CombineWith("/test/session/view").GetStringFromUrlAsync( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("IsAuthenticated:True")); + } + + [Test] + public void Can_access_Secured_Pages_with_ApiKeyAuth_BearerToken() + { + Assert.That(ListeningOn.CombineWith("/secured").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/SecuredPage").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("")); + + Assert.That(ListeningOn.CombineWith("/test/session").GetJsonFromUrl( + requestFilter: req => req.AddApiKeyAuth(ApiKey)), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("IsAuthenticated:True")); + + Assert.That(ListeningOn.CombineWith("/test/session/view").GetStringFromUrl( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("IsAuthenticated:True")); + } + + [Test] + public async Task Can_access_Secured_Pages_with_ApiKeyAuth_BearerToken_Async() + { + Assert.That(await ListeningOn.CombineWith("/secured").GetStringFromUrlAsync( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("")); + + Assert.That(await ListeningOn.CombineWith("/SecuredPage").GetStringFromUrlAsync( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("")); + + Assert.That(await ListeningOn.CombineWith("/test/session").GetJsonFromUrlAsync( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(await ListeningOn.CombineWith("/TestSessionPage").GetStringFromUrlAsync( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("IsAuthenticated:True")); + + Assert.That(await ListeningOn.CombineWith("/test/session/view").GetStringFromUrlAsync( + requestFilter: req => req.AddBearerToken(ApiKey)), + Does.Contain("IsAuthenticated:True")); + } + + [Test] + public void Can_access_Secured_Pages_with_CredentialsAuth() + { + var client = GetClient(); + client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + + Assert.That(client.Get("/secured?format=html"), + Does.Contain("")); + + Assert.That(client.Get("/SecuredPage?format=html"), + Does.Contain("")); + + Assert.That(client.Get(new TestSession()).IsAuthenticated); + + Assert.That(client.Get("/test/session"), + Does.Contain("\"IsAuthenticated\":true")); + + Assert.That(client.Get("/TestSessionPage"), + Does.Contain("IsAuthenticated:True")); + } + } +} diff --git a/tests/ServiceStack.Server.Tests/Auth/StatelessAuthTests.cs b/tests/ServiceStack.Server.Tests/Auth/StatelessAuthTests.cs new file mode 100644 index 00000000000..519a1d4495d --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Auth/StatelessAuthTests.cs @@ -0,0 +1,1510 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +#if !NETCORE +using MongoDB.Driver; +using ServiceStack.Authentication.MongoDb; +#endif +using ServiceStack.Aws.DynamoDb; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Auth +{ + public class CustomUserSession : AuthUserSession + { + public int Counter { get; set; } + } + + [Route("/secured")] + public class Secured : IReturn + { + public string Name { get; set; } + } + + public class SecuredResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/secured-by-role")] + public class SecuredByRole : IReturn + { + public string Name { get; set; } + } + + [Route("/secured-by-permission")] + public class SecuredByPermission : IReturn + { + public string Name { get; set; } + } + + public class GetAuthUserSession : IReturn { } + + [Authenticate] + public class SecureService : Service + { + public object Any(Secured request) + { + return new SecuredResponse { Result = request.Name }; + } + + public object Any(GetAuthUserSession request) + { + return Request.GetSession() as AuthUserSession; + } + + [RequiredRole("TheRole")] + public object Any(SecuredByRole request) + { + return new SecuredResponse { Result = request.Name }; + } + + [RequiredPermission("ThePermission")] + public object Any(SecuredByPermission request) + { + return new SecuredResponse { Result = request.Name }; + } + } + + public class JsonHttpClientStatelessAuthTests : StatelessAuthTests + { + protected override IJsonServiceClient GetClientWithUserPassword(bool alwaysSend = false, string userName = null) + { + return new JsonHttpClient(ListeningOn) + { + UserName = userName ?? Username, + Password = Password, + AlwaysSendBasicAuthHeader = alwaysSend, + }; + } + + protected override IJsonServiceClient GetClientWithApiKey(string apiKey = null) + { + return new JsonHttpClient(ListeningOn) + { + Credentials = new NetworkCredential(apiKey ?? ApiKey, ""), + }; + } + + protected override IJsonServiceClient GetClientWithBearerTokenCookie(string bearerToken) + { + return new JsonHttpClient(ListeningOn).Apply(c => c.SetTokenCookie(bearerToken)); + } + + protected override IJsonServiceClient GetClient() + { + return new JsonHttpClient(ListeningOn); + } + } + +#if NET6_0_OR_GREATER + public class JsonApiClientStatelessAuthTests : StatelessAuthTests + { + protected override IJsonServiceClient GetClientWithUserPassword(bool alwaysSend = false, string userName = null) + { + return new JsonApiClient(ListeningOn) + { + UserName = userName ?? Username, + Password = Password, + AlwaysSendBasicAuthHeader = alwaysSend, + }; + } + + protected override IJsonServiceClient GetClientWithApiKey(string apiKey = null) + { + return new JsonApiClient(ListeningOn) + { + Credentials = new NetworkCredential(apiKey ?? ApiKey, ""), + }; + } + + protected override IJsonServiceClient GetClientWithBearerTokenCookie(string bearerToken) + { + return new JsonApiClient(ListeningOn).Apply(c => c.SetTokenCookie(bearerToken)); + } + + protected override IJsonServiceClient GetClient() + { + return new JsonApiClient(ListeningOn); + } + } + +#endif + + public class DynamoDbAuthRepoStatelessAuthTests : StatelessAuthTests + { + public static AmazonDynamoDBClient CreateDynamoDBClient() + { + var dynamoClient = new AmazonDynamoDBClient("keyId", "key", new AmazonDynamoDBConfig + { + ServiceURL = Environment.GetEnvironmentVariable("CI_DYNAMODB") ?? "http://localhost:8000", + }); + + return dynamoClient; + } + protected override ServiceStackHost CreateAppHost() + { + var pocoDynamo = new PocoDynamo(CreateDynamoDBClient()); + pocoDynamo.DeleteAllTables(TimeSpan.FromMinutes(1)); + + return new AppHost + { + Use = container => container.Register(c => new DynamoDbAuthRepository(pocoDynamo)) + }; + } + } + + public class MemoryAuthRepoStatelessAuthTests : StatelessAuthTests + { + protected override ServiceStackHost CreateAppHost() + { + return new AppHost + { + Use = container => container.Register(c => new InMemoryAuthRepository()) + }; + } + } + + public class RedisAuthRepoStatelessAuthTests : StatelessAuthTests + { + protected override ServiceStackHost CreateAppHost() + { + var redisManager = new RedisManagerPool(); + using (var redis = redisManager.GetClient()) + { + redis.FlushAll(); + } + + return new AppHost + { + Use = container => container.Register(c => new RedisAuthRepository(redisManager)) + }; + } + } + +#if !NETCORE + [Ignore("Requires MongoDB Dependency")] + public class MongoDbAuthRepoStatelessAuthTests : StatelessAuthTests + { + protected override ServiceStackHost CreateAppHost() + { + var mongoClient = new MongoClient(); + mongoClient.DropDatabase("testmongodbauth"); + IMongoDatabase mongoDatabase = mongoClient.GetDatabase("testmongodbauth"); + + return new AppHost + { + Use = container => container.Register(c => + new MongoDbAuthRepository(mongoDatabase, true)) + }; + } + } +#endif + + public class OrmLiteStatelessAuthTests : StatelessAuthTests + { + [Test] + public void Does_use_different_database_depending_on_ApiKey() + { + var apiKeys = apiRepo.GetUserApiKeys(userId); + var testKey = apiKeys.First(x => x.Environment == "test"); + var liveKey = apiKeys.First(x => x.Environment == "live"); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = testKey.Id, + }; + + var response = client.Get(new GetAllRockstars()); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Test")); + + client = new JsonServiceClient(ListeningOn) + { + BearerToken = liveKey.Id, + }; + + response = client.Get(new GetAllRockstars()); + Assert.That(response.Results.Count, Is.EqualTo(Rockstar.SeedData.Length)); + } + } + + [Ignore("Dirty")] + public class OrmLiteMultitenancyStatelessAuthTests : StatelessAuthTests + { + protected override ServiceStackHost CreateAppHost() + { + return new AppHost + { + Use = container => container.Register(c => + new OrmLiteAuthRepositoryMultitenancy(c.TryResolve(), + new[] { + ":memory:", + "~/App_Data/test.sqlite".MapAbsolutePath() + })), + + GetAuthRepositoryFn = req => + req != null + ? new OrmLiteAuthRepositoryMultitenancy(HostContext.AppHost.GetDbConnection(req)) + : HostContext.Resolve() + }; + } + + [Test] + public void Does_use_different_database_depending_on_ApiKey() + { + var testKey = GetClientWithUserPassword().Get(new GetApiKeys { Environment = "test" }).Results[0].Key; + var liveKey = GetClientWithUserPassword().Get(new GetApiKeys { Environment = "live" }).Results[0].Key; + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = testKey + }; + + var response = client.Get(new GetAllRockstars()); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Test")); + + client = new JsonServiceClient(ListeningOn) + { + BearerToken = liveKey, + }; + + response = client.Get(new GetAllRockstars()); + Assert.That(response.Results.Count, Is.EqualTo(Rockstar.SeedData.Length)); + } + } + + public class FallbackAuthKeyTests + { + public const string ListeningOn = "http://localhost:2337/"; + + protected readonly ServiceStackHost appHost; + + private readonly byte[] authKey; + private readonly byte[] fallbackAuthKey; + + class JwtAuthProviderReaderAppHost : AppSelfHostBase + { + public JwtAuthProviderReaderAppHost() : base(nameof(FallbackAuthKeyTests), typeof(AppHost).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new JwtAuthProviderReader(AppSettings), + })); + } + } + + public FallbackAuthKeyTests() + { + authKey = AesUtils.CreateKey(); + fallbackAuthKey = AesUtils.CreateKey(); + + appHost = new JwtAuthProviderReaderAppHost + { + AppSettings = new DictionarySettings(new Dictionary { + { "jwt.AuthKeyBase64", Convert.ToBase64String(authKey) }, + { "jwt.AuthKeyBase64.1", Convert.ToBase64String(fallbackAuthKey) }, + { "jwt.RequireSecureConnection", "False" }, + }) + } + .Init() + .Start("http://*:2337/"); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_authenticate_with_HM256_token_created_from_fallback_AuthKey() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }, "external-jwt", TimeSpan.FromDays(14)); + + var token = JwtAuthProvider.CreateJwt(header, payload, + data => JwtAuthProviderReader.HmacAlgorithms["HS256"](fallbackAuthKey, data)); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = token + }; + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + } + + public class RsaJwtStatelessAuthTests : StatelessAuthTests + { + protected override ServiceStackHost CreateAppHost() + { + return new AppHost + { + JwtRsaPrivateKey = RsaUtils.CreatePrivateKeyParams(), + Use = container => container.Register(c => + new OrmLiteAuthRepository(c.Resolve())) + }; + } + } + + public class RsaJwtWithEncryptedPayloadsStatelessAuthTests : StatelessAuthTests + { + private RSAParameters privateKey; + private RSAParameters publicKey; + + protected override ServiceStackHost CreateAppHost() + { + privateKey = RsaUtils.CreatePrivateKeyParams(); + publicKey = privateKey.ToPublicRsaParameters(); + + return new AppHost + { + JwtRsaPrivateKey = privateKey, + JwtEncryptPayload = true, + Use = container => container.Register(c => + new OrmLiteAuthRepository(c.Resolve())) + }; + } + + [Test] + public void Can_populate_entire_session_using_JWE_Token() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + Roles = new List { "TheRole", "Role 2" }, + Permissions = new List { "ThePermission", "Perm 2" }, + ProfileUrl = "http://example.org/profile.jpg" + }, "external-jwt", TimeSpan.FromDays(14)); + + JwtAuthProviderReaderTests.PopulateWithAdditionalMetadata(payload); + + var jweToken = JwtAuthProvider.CreateEncryptedJweToken(payload, privateKey); + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = jweToken + }; + + var session = client.Get(new GetAuthUserSession()); + + JwtAuthProviderReaderTests.AssertAdditionalMetadataWasPopulated(session); + } + } + + public class JwtAuthProviderReaderTests + { + public const string ListeningOn = "http://localhost:2337/"; + + protected readonly ServiceStackHost appHost; + + private readonly RSAParameters privateKey; + private readonly RSAParameters fallbackPrivakeKey; + + class JwtAuthProviderReaderAppHost : AppSelfHostBase + { + public JwtAuthProviderReaderAppHost() : base("Test Razor", typeof(AppHost).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new JwtAuthProviderReader(AppSettings), + })); + } + } + + public JwtAuthProviderReaderTests() + { + privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + fallbackPrivakeKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + + appHost = new JwtAuthProviderReaderAppHost + { + AppSettings = new DictionarySettings(new Dictionary { + { "jwt.HashAlgorithm", "RS256" }, + { "jwt.PublicKeyXml", privateKey.ToPublicKeyXml() }, + { "jwt.PublicKeyXml.1", fallbackPrivakeKey.ToPublicKeyXml() }, + { "jwt.RequireSecureConnection", "False" }, + }) + } + .Init() + .Start("http://*:2337/"); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_authenticate_with_RSA_token_created_from_external_source() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }, "external-jwt", TimeSpan.FromDays(14)); + + var token = JwtAuthProvider.CreateJwt(header, payload, + data => RsaUtils.Authenticate(data, privateKey, "SHA256", RsaKeyLengths.Bit2048)); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = token + }; + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_authenticate_with_RSA_token_created_from_fallback_PrivateKey() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }, "external-jwt", TimeSpan.FromDays(14)); + + var token = JwtAuthProvider.CreateJwt(header, payload, + data => RsaUtils.Authenticate(data, fallbackPrivakeKey, "SHA256", RsaKeyLengths.Bit2048)); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = token + }; + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Token_without_roles_or_permssions_cannot_access_SecuredBy_Role_or_Permission() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + }, "external-jwt", TimeSpan.FromDays(14)); + + var token = JwtAuthProvider.CreateJwt(header, payload, + data => RsaUtils.Authenticate(data, privateKey, "SHA256", RsaKeyLengths.Bit2048)); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = token + }; + + StatelessAuthTests.AssertNoAccessToSecuredByRoleAndPermission(client); + } + + [Test] + public void Token_with_roles_and_permssions_can_access_SecuredBy_Role_or_Permission() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + Roles = new List { "TheRole", "Role 2" }, + Permissions = new List { "ThePermission", "Perm 2" }, + }, "external-jwt", TimeSpan.FromDays(14)); + + var token = JwtAuthProvider.CreateJwt(header, payload, + data => RsaUtils.Authenticate(data, privateKey, "SHA256", RsaKeyLengths.Bit2048)); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = token + }; + + StatelessAuthTests.AssertAccessToSecuredByRoleAndPermission(client); + } + + [Test] + public void Can_populate_entire_session_using_JWT_Token() + { + var jwtProvider = (JwtAuthProviderReader)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + Roles = new List { "TheRole" }, + Permissions = new List { "ThePermission" }, + ProfileUrl = "http://example.org/profile.jpg" + }, "external-jwt", TimeSpan.FromDays(14)); + + PopulateWithAdditionalMetadata(payload); + + var token = JwtAuthProvider.CreateJwt(header, payload, + data => RsaUtils.Authenticate(data, privateKey, "SHA256", RsaKeyLengths.Bit2048)); + + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = token + }; + + var session = client.Get(new GetAuthUserSession()); + + AssertAdditionalMetadataWasPopulated(session); + } + + public static void AssertAdditionalMetadataWasPopulated(AuthUserSession session) + { + Assert.That(session.Id, Is.EqualTo("SESSIONID")); + Assert.That(session.ReferrerUrl, Is.EqualTo("http://example.org/ReferrerUrl")); + Assert.That(session.UserAuthName, Is.EqualTo("UserAuthName")); + Assert.That(session.TwitterUserId, Is.EqualTo("TwitterUserId")); + Assert.That(session.TwitterScreenName, Is.EqualTo("TwitterScreenName")); + Assert.That(session.FacebookUserId, Is.EqualTo("FacebookUserId")); + Assert.That(session.FirstName, Is.EqualTo("FirstName")); + Assert.That(session.LastName, Is.EqualTo("LastName")); + Assert.That(session.Company, Is.EqualTo("Company")); + Assert.That(session.PrimaryEmail, Is.EqualTo("PrimaryEmail")); + Assert.That(session.PhoneNumber, Is.EqualTo("PhoneNumber")); + Assert.That(session.BirthDate, Is.EqualTo(new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc))); + Assert.That(session.Address, Is.EqualTo("Address")); + Assert.That(session.Address2, Is.EqualTo("Address2")); + Assert.That(session.City, Is.EqualTo("City")); + Assert.That(session.State, Is.EqualTo("State")); + Assert.That(session.Country, Is.EqualTo("Country")); + Assert.That(session.Culture, Is.EqualTo("Culture")); + Assert.That(session.FullName, Is.EqualTo("FullName")); + Assert.That(session.Gender, Is.EqualTo("Gender")); + Assert.That(session.Language, Is.EqualTo("Language")); + Assert.That(session.MailAddress, Is.EqualTo("MailAddress")); + Assert.That(session.Nickname, Is.EqualTo("Nickname")); + Assert.That(session.PostalCode, Is.EqualTo("PostalCode")); + Assert.That(session.TimeZone, Is.EqualTo("TimeZone")); + Assert.That(session.RequestTokenSecret, Is.EqualTo("RequestTokenSecret")); + Assert.That(session.CreatedAt, Is.EqualTo(new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc))); + Assert.That(session.LastModified, Is.EqualTo(new DateTime(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc))); + Assert.That(session.Sequence, Is.EqualTo("Sequence")); + Assert.That(session.Tag, Is.EqualTo(1)); + } + + public static void PopulateWithAdditionalMetadata(Dictionary payload) + { + payload["Id"] = "SESSIONID"; + payload["ReferrerUrl"] = "http://example.org/ReferrerUrl"; + payload["UserAuthName"] = "UserAuthName"; + payload["TwitterUserId"] = "TwitterUserId"; + payload["TwitterScreenName"] = "TwitterScreenName"; + payload["FacebookUserId"] = "FacebookUserId"; + payload["FacebookUserName"] = "FacebookUserName"; + payload["FirstName"] = "FirstName"; + payload["LastName"] = "LastName"; + payload["Company"] = "Company"; + payload["PrimaryEmail"] = "PrimaryEmail"; + payload["PhoneNumber"] = "PhoneNumber"; + payload["BirthDate"] = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToUnixTime().ToString(); + payload["Address"] = "Address"; + payload["Address2"] = "Address2"; + payload["City"] = "City"; + payload["State"] = "State"; + payload["Country"] = "Country"; + payload["Culture"] = "Culture"; + payload["FullName"] = "FullName"; + payload["Gender"] = "Gender"; + payload["Language"] = "Language"; + payload["MailAddress"] = "MailAddress"; + payload["Nickname"] = "Nickname"; + payload["PostalCode"] = "PostalCode"; + payload["TimeZone"] = "TimeZone"; + payload["RequestTokenSecret"] = "RequestTokenSecret"; + payload["CreatedAt"] = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToUnixTime().ToString(); + payload["LastModified"] = new DateTime(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToUnixTime().ToString(); + payload["Sequence"] = "Sequence"; + payload["Tag"] = 1.ToString(); + } + } + + public abstract class StatelessAuthTests + { + public const string ListeningOn = "http://localhost:2337/"; + + protected readonly ServiceStackHost appHost; + protected string ApiKey; + protected string ApiKeyTest; + protected string ApiKeyWithRole; + protected IManageApiKeys apiRepo; + protected ApiKeyAuthProvider apiProvider; + protected string userId; + protected string userIdWithRoles; + + protected virtual ServiceStackHost CreateAppHost() + { + return new AppHost + { + Use = container => container.Register(c => + new OrmLiteAuthRepository(c.Resolve())) + }; + } + + public StatelessAuthTests() + { + //LogManager.LogFactory = new ConsoleLogFactory(); + appHost = CreateAppHost() + .Init() + .Start("http://*:2337/"); + + var client = GetClient(); + var response = client.Post(new Register + { + UserName = "user", + Password = "p@55word", + Email = "as@if{0}.com", + DisplayName = "DisplayName", + FirstName = "FirstName", + LastName = "LastName", + }); + + userId = response.UserId; + apiRepo = (IManageApiKeys)appHost.Resolve(); + var user1Client = GetClientWithUserPassword(alwaysSend:true); + ApiKey = user1Client.Get(new GetApiKeys { Environment = "live" }).Results[0].Key; + + apiProvider = (ApiKeyAuthProvider)AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name); + + response = client.Post(new Register + { + UserName = "user2", + Password = "p@55word", + Email = "as2@if{0}.com", + DisplayName = "DisplayName2", + FirstName = "FirstName2", + LastName = "LastName2", + }); + userIdWithRoles = response.UserId; + var user2Client = GetClientWithUserPassword(alwaysSend: true, userName: "user2"); + ApiKeyWithRole = user2Client.Get(new GetApiKeys { Environment = "live" }).Results[0].Key; + + ListeningOn.CombineWith("/assignroles").AddQueryParam("authsecret", "secret") + .PostJsonToUrl(new AssignRoles + { + UserName = "user2", + Roles = new List { "TheRole" }, + Permissions = new List { "ThePermission" } + }.ToJson()); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Ignore("Debug Run")] + [Test] + public void RunFor10Mins() + { + Process.Start(ListeningOn); + Thread.Sleep(TimeSpan.FromMinutes(10)); + } + + public const string Username = "user"; + public const string Password = "p@55word"; + + protected virtual IJsonServiceClient GetClientWithUserPassword(bool alwaysSend = false, string userName = null) + { + return new JsonServiceClient(ListeningOn) + { + UserName = userName ?? Username, + Password = Password, + AlwaysSendBasicAuthHeader = alwaysSend, + }; + } + + protected virtual IJsonServiceClient GetClientWithApiKey(string apiKey = null) => + new JsonServiceClient(ListeningOn) { + Credentials = new NetworkCredential(apiKey ?? ApiKey, ""), + }; + + protected virtual IJsonServiceClient GetClientWithBearerToken(string apiKey = null) => + new JsonServiceClient(ListeningOn) { BearerToken = apiKey }; + + protected virtual IJsonServiceClient GetClientWithBearerTokenCookie(string bearerToken) => + new JsonServiceClient(ListeningOn).Apply(c => { + c.SetTokenCookie(bearerToken); + }); + + protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(ListeningOn); + + [Test] + public void Does_create_multiple_ApiKeys() + { + if (GetType() == typeof(OrmLiteMultitenancyStatelessAuthTests)) + return; + + var apiKeys = apiRepo.GetUserApiKeys(userId); + Assert.That(apiKeys.Count, Is.EqualTo( + apiProvider.Environments.Length * apiProvider.KeyTypes.Length)); + + Assert.That(apiKeys.All(x => x.UserAuthId != null)); + Assert.That(apiKeys.All(x => x.Environment != null)); + Assert.That(apiKeys.All(x => x.KeyType != null)); + Assert.That(apiKeys.All(x => x.CreatedDate != default(DateTime))); + Assert.That(apiKeys.All(x => x.CancelledDate == null)); + Assert.That(apiKeys.All(x => x.ExpiryDate == null)); + + foreach (var apiKey in apiKeys) + { + var byId = apiRepo.GetApiKey(ApiKey); + Assert.That(byId.Id, Is.EqualTo(ApiKey)); + } + } + + [Test] + public void Does_return_multiple_ApiKeys() + { + var apiKeys = GetClientWithUserPassword(alwaysSend: true).Get(new GetApiKeys { Environment = "test" }).Results; + Assert.That(apiKeys.Count, Is.EqualTo(apiProvider.KeyTypes.Length)); + apiKeys = GetClientWithUserPassword(alwaysSend: true).Get(new GetApiKeys { Environment = "live" }).Results; + Assert.That(apiKeys.Count, Is.EqualTo(apiProvider.KeyTypes.Length)); + } + + [Test] + public void Regenerating_AuthKeys_invalidates_existing_Keys_and_enables_new_keys() + { + var client = new JsonServiceClient(ListeningOn) + { + Credentials = new NetworkCredential(ApiKey, ""), + }; + + var apiKeyResponse = client.Get(new GetApiKeys { Environment = "live" }); + + var oldApiKey = apiKeyResponse.Results[0].Key; + client = new JsonServiceClient(ListeningOn) + { + BearerToken = oldApiKey, + }; + + //Key IsValid + var request = new Secured { Name = "regenerate" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var regenResponse = client.Send(new RegenerateApiKeys { Environment = "live" }); + + try + { + //Key is no longer valid + apiKeyResponse = client.Get(new GetApiKeys { Environment = "live" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + } + + //Change to new Valid Key + client.BearerToken = regenResponse.Results[0].Key; + apiKeyResponse = client.Get(new GetApiKeys { Environment = "live" }); + + Assert.That(regenResponse.Results.Map(x => x.Key), Is.EquivalentTo( + apiKeyResponse.Results.Map(x => x.Key))); + } + + [Test] + public void Doesnt_allow_using_expired_keys() + { + if (GetType() == typeof(OrmLiteMultitenancyStatelessAuthTests)) + return; + + var client = new JsonServiceClient(ListeningOn) + { + Credentials = new NetworkCredential(ApiKey, ""), + }; + + var authResponse = client.Get(new Authenticate()); + + var apiKeys = apiRepo.GetUserApiKeys(authResponse.UserId) + .Where(x => x.Environment == "test") + .ToList(); + + var oldApiKey = apiKeys[0].Id; + client = new JsonServiceClient(ListeningOn) + { + BearerToken = oldApiKey, + }; + + //Key IsValid + var request = new Secured { Name = "live" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + apiKeys[0].ExpiryDate = DateTime.UtcNow.AddMinutes(-1); + apiRepo.StoreAll(new[] { apiKeys[0] }); + + try + { + //Key is no longer valid + client.Get(new GetApiKeys { Environment = "test" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + } + + client = new JsonServiceClient(ListeningOn) + { + Credentials = new NetworkCredential(ApiKey, ""), + }; + var regenResponse = client.Send(new RegenerateApiKeys { Environment = "test" }); + + //Change to new Valid Key + client.BearerToken = regenResponse.Results[0].Key; + var apiKeyResponse = client.Get(new GetApiKeys { Environment = "test" }); + + Assert.That(regenResponse.Results.Map(x => x.Key), Is.EquivalentTo( + apiKeyResponse.Results.Map(x => x.Key))); + } + + [Test] + public void Doesnt_allow_sending_invalid_APIKeys() + { + var client = new JsonServiceClient(ListeningOn) + { + Credentials = new NetworkCredential("InvalidKey", ""), + }; + + var request = new Secured { Name = "live" }; + try + { + var response = client.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo("NotFound")); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ApiKey does not exist")); + Assert.That(ex.ResponseStatus.StackTrace, Is.Not.Null); + } + } + + [Test] + public void Authenticating_once_with_BasicAuth_does_not_establish_auth_session() + { + var client = GetClientWithUserPassword(alwaysSend: true); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetSessionId(client.GetSessionId()); + try + { + response = newClient.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Authenticating_once_with_JWT_does_not_establish_auth_session() + { + var client = GetClientWithUserPassword(alwaysSend: true); + + var authResponse = client.Send(new Authenticate()); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + + var jwtClient = GetClientWithBearerTokenCookie(client.GetTokenCookie()); + var request = new Secured { Name = "test" }; + var response = jwtClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + response = jwtClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetSessionId(jwtClient.GetSessionId()); + + try + { + response = newClient.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Authenticating_with_JWT_cookie_does_allow_multiple_authenticated_requests() + { + var client = GetClientWithUserPassword(alwaysSend: true); + + var authResponse = client.Send(new Authenticate()); + + var jwtClient = GetClient(); + jwtClient.SetTokenCookie(client.GetTokenCookie()); + + var request = new Secured { Name = "test" }; + var response = jwtClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + var cookieValue = jwtClient.GetTokenCookie(); + newClient.SetTokenCookie(cookieValue); + response = newClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Authenticating_once_with_ApiKeyAuth_does_not_establish_auth_session() + { + var client = GetClientWithApiKey(); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetSessionId(client.GetSessionId()); + try + { + response = newClient.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public async Task Authenticating_once_with_ApiKeyAuth_does_not_establish_auth_session_Async() + { + var client = GetClientWithApiKey(); + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetSessionId(client.GetSessionId()); + try + { + response = await newClient.SendAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Authenticating_once_with_ApiKeyAuth_BearerToken_does_not_establish_auth_session() + { + var client = GetClientWithBearerToken(ApiKey); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetSessionId(client.GetSessionId()); + try + { + response = newClient.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public async Task Authenticating_once_with_ApiKeyAuth_BearerToken_does_not_establish_auth_session_Async() + { + var client = GetClientWithBearerToken(ApiKey); + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetSessionId(client.GetSessionId()); + try + { + response = await newClient.SendAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Authenticating_once_with_CredentialsAuth_does_establish_auth_session() + { + var client = GetClient(); + + try + { + client.Send(new Authenticate()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + + client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + // RememberMe = true, + }); + + client.Send(new Authenticate()); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var bearerToken = client.GetTokenCookie(); + Assert.That(bearerToken, Is.Not.Null); + + var newClient = GetClient(); + newClient.SetTokenCookie(bearerToken); + response = newClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Authenticate_with_ApiKeyAuth_SessionCacheDuration() + { + apiProvider.SessionCacheDuration = TimeSpan.FromSeconds(60); + + var client = GetClientWithBearerToken(ApiKey); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + //Does not preserve UserSession + var newClient = GetClient(); + newClient.SetSessionId(client.GetSessionId()); + try + { + response = newClient.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + + var cachedSession = appHost.GetCacheClient(null).Get(ApiKeyAuthProvider.GetSessionKey(ApiKey)); + Assert.That(cachedSession.IsAuthenticated); + + //Can call multiple times using cached UserSession + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + apiProvider.SessionCacheDuration = null; + } + + public static void AssertNoAccessToSecuredByRoleAndPermission(IServiceClient client) + { + try + { + client.Send(new SecuredByRole { Name = "test" }); + Assert.Fail("Should Throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + } + + try + { + client.Send(new SecuredByPermission { Name = "test" }); + Assert.Fail("Should Throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + } + } + + [Test] + public void Can_not_access_SecuredBy_Role_or_Permission_without_TheRole_or_ThePermission() + { + var client = GetClientWithUserPassword(alwaysSend: true); + AssertNoAccessToSecuredByRoleAndPermission(client); + + client = GetClientWithApiKey(); + AssertNoAccessToSecuredByRoleAndPermission(client); + + var authResponse = client.Get(new Authenticate()); + var bearerToken = client.GetTokenCookie(); + client = GetClientWithBearerToken(bearerToken); + AssertNoAccessToSecuredByRoleAndPermission(client); + + client = GetClient(); + client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + AssertNoAccessToSecuredByRoleAndPermission(client); + } + + public static void AssertAccessToSecuredByRoleAndPermission(IServiceClient client) + { + var roleResponse = client.Send(new SecuredByRole { Name = "test" }); + Assert.That(roleResponse.Result, Is.EqualTo("test")); + + var permResponse = client.Send(new SecuredByPermission { Name = "test" }); + Assert.That(permResponse.Result, Is.EqualTo("test")); + } + + [Test] + public void Can_access_SecuredBy_Role_or_Permission_with_TheRole_and_ThePermission() + { + var client = GetClientWithUserPassword(alwaysSend: true, userName: "user2"); + AssertAccessToSecuredByRoleAndPermission(client); + + client = GetClientWithApiKey(ApiKeyWithRole); + AssertAccessToSecuredByRoleAndPermission(client); + + client.Get(new Authenticate()); + client = GetClientWithBearerTokenCookie(client.GetTokenCookie()); + AssertAccessToSecuredByRoleAndPermission(client); + + client = GetClient(); + client.Post(new Authenticate + { + provider = "credentials", + UserName = "user2", + Password = Password, + }); + AssertAccessToSecuredByRoleAndPermission(client); + } + + [Test] + public void Can_not_access_Secure_service_with_invalidated_token() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + var client = GetClientWithBearerTokenCookie(token); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + jwtProvider.InvalidateTokensIssuedBefore = DateTime.UtcNow.AddSeconds(1); + + try + { + response = client.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(TokenException))); + } + finally + { + jwtProvider.InvalidateTokensIssuedBefore = null; + } + } + + [Test] + public void Can_not_access_Secure_service_with_expired_token() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + jwtProvider.CreatePayloadFilter = (jwtPayload,session) => + jwtPayload["exp"] = DateTime.UtcNow.AddSeconds(-1).ToUnixTime().ToString(); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + jwtProvider.CreatePayloadFilter = null; + + var client = GetClientWithBearerTokenCookie(token); + + try + { + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(TokenException))); + } + } + + [Test] + public void Can_Auto_reconnect_with_BasicAuth_after_expired_token() + { + var authClient = GetClientWithUserPassword(alwaysSend: true); + + var called = 0; + var client = new JsonServiceClient(ListeningOn) + { + BearerToken = CreateExpiredToken(), + }; + client.OnAuthenticationRequired = () => + { + called++; + authClient.Send(new Authenticate()); + client.BearerToken = null; + client.SetTokenCookie(authClient.GetTokenCookie()); + }; + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + Assert.That(called, Is.EqualTo(1)); + } + + [Test] + public async Task Can_Auto_reconnect_with_BasicAuth_after_expired_token_Async() + { + var authClient = GetClientWithUserPassword(alwaysSend: true); + + var called = 0; + var client = new JsonServiceClient(ListeningOn) { + BearerToken = CreateExpiredToken(), + }; + client.OnAuthenticationRequired = () => + { + called++; + authClient.Send(new Authenticate()); + client.BearerToken = null; + client.SetTokenCookie(authClient.GetTokenCookie()); + }; + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + Assert.That(called, Is.EqualTo(1)); + } + + [Test] + public void Can_not_access_Secure_service_on_unsecured_connection_when_RequireSecureConnection() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + jwtProvider.RequireSecureConnection = true; + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + var client = GetClientWithBearerTokenCookie(token); + + try + { + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + Assert.That(ex.ErrorCode, Is.EqualTo("Forbidden")); + } + finally + { + jwtProvider.RequireSecureConnection = false; + } + } + + [Test] + public void Can_ConvertSessionToToken() + { + var client = GetClient(); + + client.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var newClient = GetClient(); + newClient.SetTokenCookie(client.GetTokenCookie()); + client.DeleteTokenCookies(); + + var tokenResponse = newClient.Send(new ConvertSessionToToken()); + var tokenCookie = newClient.GetTokenCookie(); + response = newClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + try + { + response = client.Send(request); + Assert.Fail("should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + + response = newClient.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_ConvertSessionToToken_when_authenticating() + { + var client = GetClient(); + + var authResponse = client.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + + var token = client.GetTokenCookie(); + Assert.That(token, Is.Not.Null); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var clientWithToken = GetClient(); + clientWithToken.SetTokenCookie(client.GetTokenCookie()); + + response = clientWithToken.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var clientWithSession = GetClient(); + clientWithSession.SetSessionId(client.GetSessionId()); + + try + { + response = clientWithSession.Send(request); + Assert.Fail("should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + private static string CreateExpiredToken() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProvider.Name); + jwtProvider.CreatePayloadFilter = (jwtPayload, session) => + jwtPayload["exp"] = DateTime.UtcNow.AddSeconds(-1).ToUnixTime().ToString(); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + jwtProvider.CreatePayloadFilter = null; + return token; + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Benchmarks/RedisMqServerBenchmarks.cs b/tests/ServiceStack.Server.Tests/Benchmarks/RedisMqServerBenchmarks.cs new file mode 100644 index 00000000000..8ff2c5dbe5b --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Benchmarks/RedisMqServerBenchmarks.cs @@ -0,0 +1,84 @@ +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; + +namespace ServiceStack.Server.Tests.Benchmarks +{ + [TestFixture, Category("Benchmarks"), Ignore("Benchmarks")] + public class RedisMqServerBenchmarks + { + public class Incr + { + public int Value { get; set; } + } + + public class IncrBlocking + { + public int Value { get; set; } + } + + private static RedisMqServer CreateMqServer(int noOfRetries = 2) + { + var redisFactory = TestConfig.BasicClientManger; + try + { + redisFactory.Exec(redis => redis.FlushAll()); + } + catch (RedisException rex) + { + Debug.WriteLine("WARNING: Redis not started? \n" + rex.Message); + } + var mqHost = new RedisMqServer(redisFactory, noOfRetries); + return mqHost; + } + + [Test] + public void Can_receive_and_process_same_reply_responses() + { + var mqHost = CreateMqServer(); + var called = 0; + + mqHost.RegisterHandler(m => + { + called++; + return new Incr { Value = m.GetBody().Value + 1 }; + }); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new Incr { Value = 1 }); + + Thread.Sleep(10000); + + Debug.WriteLine("Times called: " + called); + } + + [Test] + public void Can_receive_and_process_same_reply_responses_blocking() + { + var mqHost = CreateMqServer(); + var called = 0; + + mqHost.RegisterHandler(m => + { + called++; + mqHost.CreateMessageQueueClient().Publish(new IncrBlocking { Value = m.GetBody().Value + 1 }); + Thread.Sleep(100); + return null; + }); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new IncrBlocking { Value = 1 }); + + Thread.Sleep(10000); + + Debug.WriteLine("Times called: " + called); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Benchmarks/RedisMqServerServerBenchmarks.cs b/tests/ServiceStack.Server.Tests/Benchmarks/RedisMqServerServerBenchmarks.cs new file mode 100644 index 00000000000..f647094168f --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Benchmarks/RedisMqServerServerBenchmarks.cs @@ -0,0 +1,191 @@ +using System; +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Benchmarks +{ + [Ignore("Benchmarks")] + [TestFixture, Category("Benchmarks")] + public class RedisMqServerServerBenchmarks + { + public class Incr + { + public int Value { get; set; } + } + + public class IncrBlocking + { + public int Value { get; set; } + } + + private static RedisMqServer CreateMqHostServer() + { + var redisFactory = TestConfig.BasicClientManger; + try + { + redisFactory.Exec(redis => redis.FlushAll()); + } + catch (RedisException rex) + { + Debug.WriteLine("WARNING: Redis not started? \n" + rex.Message); + } + var mqHost = new RedisMqServer(redisFactory); + return mqHost; + } + + [Test] + public void Can_receive_and_process_same_reply_responses() + { + var mqHost = CreateMqHostServer(); + var called = 0; + + mqHost.RegisterHandler(m => + { + called++; + return new Incr { Value = m.GetBody().Value + 1 }; + }, noOfThreads: 3); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new Incr { Value = 1 }); + + Thread.Sleep(10000); + + Debug.WriteLine("Times called: " + called); + } + + [Test] + public void Can_receive_and_process_same_reply_responses_blocking() + { + var mqHost = CreateMqHostServer(); + var called = 0; + + mqHost.RegisterHandler(m => + { + called++; + mqHost.CreateMessageQueueClient().Publish(new IncrBlocking { Value = m.GetBody().Value + 1 }); + Thread.Sleep(100); + return null; + }, noOfThreads:5); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new IncrBlocking { Value = 1 }); + + Thread.Sleep(10000); + + Debug.WriteLine("Times called: " + called); + } + + [Test] + public void Can_receive_and_process_same_reply_responses_blocking_and_non_blocking() + { + var mqHost = CreateMqHostServer(); + var nonBlocking = 0; + var blocking = 0; + + mqHost.RegisterHandler(m => + { + nonBlocking++; + return new Incr { Value = m.GetBody().Value + 1 }; + }, 1); //Non-blocking less no of threads the better + + mqHost.RegisterHandler(m => + { + blocking++; + mqHost.CreateMessageQueueClient().Publish(new IncrBlocking { Value = m.GetBody().Value + 1 }); + Thread.Sleep(100); + return null; + }, 5); //Blocking, more threads == better + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new Incr { Value = 1 }); + mqClient.Publish(new IncrBlocking { Value = 1 }); + + Thread.Sleep(10000); + + Debug.WriteLine("Times called: non-blocking: {0}, blocking: {1}".Fmt(nonBlocking, blocking)); + } + + [Test] + public void Test_Blocking_messages_throughput() + { + var mqHost = CreateMqHostServer(); + var blocking = 0; + const int BlockFor = 100; + const int NoOfThreads = 5; + const int SendEvery = BlockFor / NoOfThreads / 4; + + mqHost.RegisterHandler(m => + { + blocking++; + Thread.Sleep(BlockFor); + return null; + }, NoOfThreads); + + mqHost.Start(); + + var startedAt = DateTime.Now; + var mqClient = mqHost.CreateMessageQueueClient(); + while (DateTime.Now - startedAt < TimeSpan.FromSeconds(10)) + { + mqClient.Publish(new IncrBlocking { Value = 1 }); + Thread.Sleep(SendEvery); + } + + Debug.WriteLine("Times called: blocking: {0}".Fmt(blocking)); + } + + [Test] + public void Test_Blocking_and_NonBlocking_messages_throughput() + { + var mqHost = CreateMqHostServer(); + var nonBlocking = 0; + var blocking = 0; + const int BlockFor = 100; + const int NoOfThreads = 5; + const int SendBlockingMsgEvery = BlockFor / NoOfThreads / 4; + + mqHost.RegisterHandler(m => + { + nonBlocking++; + return null; + }, 3); + + mqHost.RegisterHandler(m => + { + blocking++; + Thread.Sleep(BlockFor); + return null; + }, NoOfThreads); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + + var stopWatch = Stopwatch.StartNew(); + long lastBlockingSentAtMs = 0; + + while (stopWatch.ElapsedMilliseconds < 10 * 1000) + { + mqClient.Publish(new Incr { Value = 1 }); + while (stopWatch.ElapsedMilliseconds - lastBlockingSentAtMs > SendBlockingMsgEvery) + { + mqClient.Publish(new IncrBlocking { Value = 1 }); + lastBlockingSentAtMs = stopWatch.ElapsedMilliseconds; + } + } + + Debug.WriteLine("Times called: non-blocking: {0}, blocking: {1}".Fmt(nonBlocking, blocking)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Caching/CacheClientAsyncTests.cs b/tests/ServiceStack.Server.Tests/Caching/CacheClientAsyncTests.cs new file mode 100644 index 00000000000..c6c29907cf5 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Caching/CacheClientAsyncTests.cs @@ -0,0 +1,94 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Server.Tests.Shared; + +namespace ServiceStack.Server.Tests.Caching +{ + public class SqlServerOrmLiteCacheClientAsyncTests : CacheClientTestsAsyncBase + { + public override ICacheClientAsync CreateClient() + { + var cache = new OrmLiteCacheClient + { + DbFactory = new OrmLiteConnectionFactory( + Config.SqlServerConnString, SqlServerDialect.Provider) + }; + + using (var db = cache.DbFactory.Open()) + { + db.DropTable(); + } + + cache.InitSchema(); + + return cache; + } + } + + public class SqliteOrmLiteCacheClientAsyncTests : CacheClientTestsAsyncBase + { + public override ICacheClientAsync CreateClient() + { + var cache = new OrmLiteCacheClient + { + DbFactory = new OrmLiteConnectionFactory( + ":memory:", SqliteDialect.Provider) + }; + cache.InitSchema(); + + return cache; + } + } + + public class MemoryCacheClientAsyncTests : CacheClientTestsAsyncBase + { + public override ICacheClientAsync CreateClient() + { + return new MemoryCacheClient().AsAsync(); + } + + [Test] + public async Task Increments_are_Atomic() + { + var CacheClient = CreateClient(); + + var numThreads = 20; + var numIncr = 10000; + var resetEvent = new ManualResetEvent(false); + var threadsLeft = numThreads; + + for (var i = 0; i < numThreads; i++) + { + new Thread(async () => + { + for (var j = 0; j < numIncr; j++) + { + await CacheClient.IncrementAsync("test", 1); + } + if (Interlocked.Decrement(ref threadsLeft) == 0) + resetEvent.Set(); + }).Start(); + } + + resetEvent.WaitOne(); + + Assert.That(await CacheClient.IncrementAsync("test", 0), Is.EqualTo(numThreads * numIncr)); + } + } + + //TODO: replace with async + public class RedisCacheClientAsyncTests : CacheClientTestsAsyncBase + { + public override ICacheClientAsync CreateClient() + { + return new RedisManagerPool("127.0.0.1").GetCacheClient().AsAsync(); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Caching/CacheClientTests.cs b/tests/ServiceStack.Server.Tests/Caching/CacheClientTests.cs new file mode 100644 index 00000000000..980e98f64bb --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Caching/CacheClientTests.cs @@ -0,0 +1,162 @@ +using System; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Server.Tests.Shared; + +namespace ServiceStack.Server.Tests.Caching +{ + public class SqlServerOrmLiteCacheClientTests : CacheClientTestsBase + { + public override ICacheClient CreateClient() + { + var cache = new OrmLiteCacheClient + { + DbFactory = new OrmLiteConnectionFactory( + Config.SqlServerConnString, SqlServerDialect.Provider) + }; + + using (var db = cache.DbFactory.Open()) + { + db.DropTable(); + } + + cache.InitSchema(); + + return cache; + } + } + + public class SqliteOrmLiteCacheClientTests : CacheClientTestsBase + { + public override ICacheClient CreateClient() + { + var cache = new OrmLiteCacheClient + { + DbFactory = new OrmLiteConnectionFactory( + ":memory:", SqliteDialect.Provider) + }; + cache.InitSchema(); + + return cache; + } + } + + public class MemoryCacheClientTests : CacheClientTestsBase + { + public override ICacheClient CreateClient() + { + return new MemoryCacheClient(); + } + + [Test] + public void Increments_are_Atomic() + { + var CacheClient = CreateClient(); + + var numThreads = 20; + var numIncr = 10000; + var resetEvent = new ManualResetEvent(false); + var threadsLeft = numThreads; + + for (var i = 0; i < numThreads; i++) + { + new Thread(() => + { + for (var j = 0; j < numIncr; j++) + { + CacheClient.Increment("test", 1); + } + if (Interlocked.Decrement(ref threadsLeft) == 0) + resetEvent.Set(); + }).Start(); + } + + resetEvent.WaitOne(); + + Assert.That(CacheClient.Increment("test", 0), Is.EqualTo(numThreads * numIncr)); + } + } + + public class RedisCacheClientTests : CacheClientTestsBase + { + public override ICacheClient CreateClient() + { + return new RedisManagerPool("127.0.0.1").GetCacheClient(); + } + } + + public class SqlServer2014MemoryOptimizedOrmLiteCacheClientTests : CacheClientTestsBase + { + public override ICacheClient CreateClient() + { + var cache = new OrmLiteCacheClient + { + DbFactory = new OrmLiteConnectionFactory( + Config.SqlServerConnString, SqlServer2014Dialect.Provider) + }; + + using (var db = cache.DbFactory.Open()) + { + db.DropTable(); + } + + cache.InitSchema(); + + return cache; + } + } + + [SqlServerMemoryOptimized(SqlServerDurability.SchemaOnly)] + public class SqlServer2014MemoryOptimizedCacheEntry : ICacheEntry + { + [PrimaryKey] + [SqlServerCollate("Latin1_General_100_BIN2")] + [StringLength(512)] + [SqlServerBucketCount(10000000)] + public string Id { get; set; } + [StringLength(4000)] + public string Data { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ExpiryDate { get; set; } + public DateTime ModifiedDate { get; set; } + } + + public class SqlServer2016MemoryOptimizedOrmLiteCacheClientTests : CacheClientTestsBase + { + public override ICacheClient CreateClient() + { + var cache = new OrmLiteCacheClient + { + DbFactory = new OrmLiteConnectionFactory( + Config.SqlServerConnString, SqlServer2016Dialect.Provider) + }; + + using (var db = cache.DbFactory.Open()) + { + db.DropTable(); + } + + cache.InitSchema(); + + return cache; + } + } + + [SqlServerMemoryOptimized(SqlServerDurability.SchemaOnly)] + public class SqlServer2016MemoryOptimizedCacheEntry : ICacheEntry + { + [PrimaryKey] + [StringLength(StringLengthAttribute.MaxText)] + [SqlServerBucketCount(10000000)] + public string Id { get; set; } + [StringLength(StringLengthAttribute.MaxText)] + public string Data { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ExpiryDate { get; set; } + public DateTime ModifiedDate { get; set; } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Config.cs b/tests/ServiceStack.Server.Tests/Config.cs new file mode 100644 index 00000000000..0e9e6025090 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Config.cs @@ -0,0 +1,15 @@ +using System; + +namespace ServiceStack.Server.Tests +{ + public class Config + { + public const string ServiceStackBaseUri = "http://localhost:20000"; + public const string AbsoluteBaseUri = ServiceStackBaseUri + "/"; + public const string ListeningOn = ServiceStackBaseUri + "/"; + + public static readonly string RabbitMQConnString = Environment.GetEnvironmentVariable("CI_RABBITMQ") ?? "localhost"; + public static readonly string SqlServerConnString = Environment.GetEnvironmentVariable("MSSQL_CONNECTION") + ?? "Server=localhost;Database=test;User Id=test;Password=test;"; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Login.cshtml b/tests/ServiceStack.Server.Tests/Login.cshtml new file mode 100644 index 00000000000..f2dd56a9645 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Login.cshtml @@ -0,0 +1,3 @@ +

    Login Page

    + + \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging.cd b/tests/ServiceStack.Server.Tests/Messaging.cd new file mode 100644 index 00000000000..5a8ab6a8ae8 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging.cd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Messaging.Tests/InMemoryTransientMessagingHostTests.cs b/tests/ServiceStack.Server.Tests/Messaging/InMemoryTransientMessagingHostTests.cs similarity index 85% rename from tests/ServiceStack.Messaging.Tests/InMemoryTransientMessagingHostTests.cs rename to tests/ServiceStack.Server.Tests/Messaging/InMemoryTransientMessagingHostTests.cs index dfdd9cba850..0bdddcf0bbf 100644 --- a/tests/ServiceStack.Messaging.Tests/InMemoryTransientMessagingHostTests.cs +++ b/tests/ServiceStack.Server.Tests/Messaging/InMemoryTransientMessagingHostTests.cs @@ -1,6 +1,6 @@ -using System; +using ServiceStack.Messaging; -namespace ServiceStack.Messaging.Tests +namespace ServiceStack.Server.Tests.Messaging { public class InMemoryTransientMessagingHostTests : TransientServiceMessagingTests diff --git a/tests/ServiceStack.Server.Tests/Messaging/InspectingMqTests.cs b/tests/ServiceStack.Server.Tests/Messaging/InspectingMqTests.cs new file mode 100644 index 00000000000..698a24e74e8 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/InspectingMqTests.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; +using ServiceStack.Text; +using ServiceStack.Messaging; + +namespace ServiceStack.Server.Tests.Messaging +{ + public class MessageType1 + { + public string Name { get; set; } + } + + public class MessageType2 + { + public string Name { get; set; } + } + + public class MessageType3 + { + public string Name { get; set; } + } + + public class MessageStat + { + public string MqName { get; set; } + public string MqType { get; set; } + public string MessageType { get; set; } + public int Count { get; set; } + } + + [TestFixture] + public class InspectingMqTests + { + IMessageService mqService; + IRedisClientsManager redisManager; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + redisManager = new BasicRedisClientManager(); + mqService = new RedisMqServer(redisManager, 2, null); + + redisManager.Exec(r => r.FlushAll()); + + using (var mqPublisher = mqService.MessageFactory.CreateMessageProducer()) + { + var i=0; + mqPublisher.Publish(new MessageType1 { Name = "msg-" + i++ }); + mqPublisher.Publish(new MessageType2 { Name = "msg-" + i++ }); + mqPublisher.Publish(new MessageType2 { Name = "msg-" + i++ }); + mqPublisher.Publish(new MessageType3 { Name = "msg-" + i++ }); + mqPublisher.Publish(new MessageType3 { Name = "msg-" + i++ }); + mqPublisher.Publish(new MessageType3 { Name = "msg-" + i++ }); + } + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + mqService.Dispose(); + redisManager.Dispose(); + } + + [Test] + public void Can_get_RedisMq_stats() + { + var redisMqStats = new List(); + using (var redis = redisManager.GetClient()) + { + var keys = redis.SearchKeys("mq:*"); + foreach (var key in keys) + { + if (redis.GetEntryType(key) != RedisKeyType.List) continue; + + + var stat = new MessageStat { + MqName = key, + }; + + redisMqStats.Add(stat); + } + } + + } + } +} + diff --git a/tests/ServiceStack.Messaging.Tests/MessageSerializationTests.cs b/tests/ServiceStack.Server.Tests/Messaging/MessageSerializationTests.cs similarity index 92% rename from tests/ServiceStack.Messaging.Tests/MessageSerializationTests.cs rename to tests/ServiceStack.Server.Tests/Messaging/MessageSerializationTests.cs index 2bc82db0a3a..a2077f001e4 100644 --- a/tests/ServiceStack.Messaging.Tests/MessageSerializationTests.cs +++ b/tests/ServiceStack.Server.Tests/Messaging/MessageSerializationTests.cs @@ -1,10 +1,12 @@ using System; +using System.Reflection; using NUnit.Framework; -using ServiceStack.DesignPatterns.Model; -using ServiceStack.Messaging.Tests.Services; +using ServiceStack.Messaging; +using ServiceStack.Model; +using ServiceStack.Server.Tests.Services; using ServiceStack.Text; -namespace ServiceStack.Messaging.Tests +namespace ServiceStack.Server.Tests.Messaging { [TestFixture] public class MessageSerializationTests @@ -45,8 +47,7 @@ public void Can_Serialize_IMessage_and_Deserialize_into_Message() public void Can_Serialize_and_Message_with_Error() { var message = new Message(new Greet { Name = "Test" }) { - Error = new MessagingException( - "Test Error", new ArgumentNullException("Test")).ToMessageError() + Error = new ArgumentNullException("Test").ToResponseStatus() }; Serialize(message); } diff --git a/tests/ServiceStack.Messaging.Tests/MessagingHostTestBase.cs b/tests/ServiceStack.Server.Tests/Messaging/MessagingHostTestBase.cs similarity index 85% rename from tests/ServiceStack.Messaging.Tests/MessagingHostTestBase.cs rename to tests/ServiceStack.Server.Tests/Messaging/MessagingHostTestBase.cs index f764e97f6b4..05ef5698465 100644 --- a/tests/ServiceStack.Messaging.Tests/MessagingHostTestBase.cs +++ b/tests/ServiceStack.Server.Tests/Messaging/MessagingHostTestBase.cs @@ -1,8 +1,8 @@ using Funq; using NUnit.Framework; -using ServiceStack.Messaging.Tests.Services; +using ServiceStack.Messaging; -namespace ServiceStack.Messaging.Tests +namespace ServiceStack.Server.Tests.Messaging { [TestFixture] public abstract class MessagingHostTestBase diff --git a/tests/ServiceStack.Server.Tests/Messaging/MqAppHostTests.cs b/tests/ServiceStack.Server.Tests/Messaging/MqAppHostTests.cs new file mode 100644 index 00000000000..00a7a7c523a --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/MqAppHostTests.cs @@ -0,0 +1,178 @@ +using System; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.RabbitMq; +using ServiceStack.Server.Tests.Caching; +using TestsConfig = ServiceStack.Server.Tests.Config; + +namespace ServiceStack.Server.Tests.Messaging +{ + public interface IScopedDep + { + } + public class ScopedDep : IScopedDep + { + private static int timesCalled; + public static int TimesCalled + { + get => timesCalled; + set => timesCalled = value; + } + + public ScopedDep() + { + Interlocked.Increment(ref timesCalled); + } + } + + public class MqAppHost : AppSelfHostBase + { + public MqAppHost() + : base(typeof(MqAppHost).Name, typeof(MqAppHostServices).Assembly) {} + + +#if NETCORE + public override void Configure(Microsoft.Extensions.DependencyInjection.IServiceCollection services) + { + Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions + .AddScoped(services); + } +#endif + + + public override void Configure(Container container) + { + var mqServer = new RabbitMqServer(connectionString: TestsConfig.RabbitMQConnString); + + mqServer.RegisterHandler( + ExecuteMessage, + HandleMqCustomException); + + mqServer.RegisterHandler(ExecuteMessage); + + container.Register(c => mqServer); + mqServer.Start(); + } + + protected override void Dispose(bool disposing) + { + Resolve().Dispose(); + base.Dispose(disposing); + } + + public CustomException LastCustomException; + + public void HandleMqCustomException(IMessageHandler mqHandler, IMessage message, Exception ex) + { + LastCustomException = ex.InnerException as CustomException; + + bool requeue = !(ex is UnRetryableMessagingException) + && message.RetryAttempts < 1; + + if (requeue) + { + message.RetryAttempts++; + } + + message.Error = ex.ToResponseStatus(); + mqHandler.MqClient.Nak(message, requeue: requeue, exception: ex); + } + } + + public class CustomException : Exception + { + public CustomException() {} + public CustomException(string message) : base(message) {} + public CustomException(string message, Exception innerException) : base(message, innerException) {} + } + + public class MqCustomException + { + public string Message { get; set; } + } + + public class MqScopeDep : IReturnVoid {} + + public class MqAppHostServices : Service + { + public static int TimesCalled = 0; + + public object Any(MqCustomException request) + { + TimesCalled++; + throw new CustomException("ERROR: " + request.Message); + } + +#if NETCORE + public void Any(MqScopeDep request) + { + var instance1 = Request.TryResolve(); + var instance2 = Request.ResolveScoped(); + if (instance1 != instance2) + throw new Exception("instance1 != instance2"); + } +#endif + + } + + public class MqAppHostTests + { + private readonly MqAppHost appHost; + + public MqAppHostTests() + { + this.appHost = new MqAppHost(); + appHost + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_handle_custom_exception() + { + MqAppHostServices.TimesCalled = 0; + + using (var mqClient = appHost.TryResolve().CreateMessageQueueClient()) + { + mqClient.Publish(new MqCustomException { Message = "foo" }); + + Thread.Sleep(1000); + + Assert.That(MqAppHostServices.TimesCalled, Is.EqualTo(2)); + Assert.That(appHost.LastCustomException.Message, Is.EqualTo("ERROR: foo")); + } + } + +#if NETCORE + [Test] + public void Can_resolve_scoped_deps() + { + ScopedDep.TimesCalled = 0; + + using (var mqClient = appHost.TryResolve().CreateMessageQueueClient()) + { + mqClient.Publish(new MqScopeDep()); + + Thread.Sleep(1000); + + Assert.That(ScopedDep.TimesCalled, Is.EqualTo(1)); + + mqClient.Publish(new MqScopeDep()); + + Thread.Sleep(1000); + + Assert.That(ScopedDep.TimesCalled, Is.EqualTo(2)); + } + } +#endif + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/MqNameTests.cs b/tests/ServiceStack.Server.Tests/Messaging/MqNameTests.cs new file mode 100644 index 00000000000..519fb5b4781 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/MqNameTests.cs @@ -0,0 +1,73 @@ +using NUnit.Framework; +using ServiceStack.Messaging; + +namespace ServiceStack.Server.Tests.Messaging +{ + [TestFixture] + public class MqQueueNamesTests + { + [Test] + public void Does_resolve_the_same_default_QueueNames() + { + Assert.That(new QueueNames(typeof(HelloIntro)).In, Is.EqualTo("mq:HelloIntro.inq")); + Assert.That(QueueNames.In, Is.EqualTo("mq:HelloIntro.inq")); + } + + public class TestPrefix { } + + [Test] + public void Does_resolve_QueueNames_using_QueuePrefix() + { + QueueNames.SetQueuePrefix("site1."); + + Assert.That(new QueueNames(typeof(TestPrefix)).In, Is.EqualTo("site1.mq:TestPrefix.inq")); + Assert.That(QueueNames.In, Is.EqualTo("site1.mq:TestPrefix.inq")); + + QueueNames.SetQueuePrefix(""); + } + + public class TestFilter { } + + [Test] + public void Does_resolve_QueueNames_using_Custom_Filter() + { + QueueNames.ResolveQueueNameFn = (typeName, suffix) => + "SITE.{0}{1}".Fmt(typeName, suffix.ToUpper()); + + Assert.That(new QueueNames(typeof(TestFilter)).In, Is.EqualTo("SITE.TestFilter.INQ")); + Assert.That(QueueNames.In, Is.EqualTo("SITE.TestFilter.INQ")); + + QueueNames.ResolveQueueNameFn = QueueNames.ResolveQueueName; + } + + [Test] + public void Can_determine_TempQueue() + { + var tmpName = QueueNames.GetTempQueueName(); + Assert.That(QueueNames.IsTempQueue(tmpName), Is.True); + } + + [Test] + public void Can_determine_TempQueue_with_Custom_QueuePrefix() + { + QueueNames.SetQueuePrefix("site1."); + + var tmpName = QueueNames.GetTempQueueName(); + Assert.That(QueueNames.IsTempQueue(tmpName), Is.True); + + QueueNames.SetQueuePrefix(""); + } + + [Test] + public void Can_determine_TempQueue_with_Custom_QueueNameFm() + { + QueueNames.ResolveQueueNameFn = (typeName, suffix) => + "SITE.{0}{1}".Fmt(typeName, suffix.ToUpper()); + + var tmpName = QueueNames.GetTempQueueName(); + Assert.That(QueueNames.IsTempQueue(tmpName), Is.True); + + QueueNames.ResolveQueueNameFn = QueueNames.ResolveQueueName; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/MqRequestReplyTests.cs b/tests/ServiceStack.Server.Tests/Messaging/MqRequestReplyTests.cs new file mode 100644 index 00000000000..b5bde43f76f --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/MqRequestReplyTests.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; +using ServiceStack.RabbitMq; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + [Ignore("Integration Tests")] + public class RabbitMqRequestReplyTests : MqRequestReplyTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new RabbitMqServer(connectionString: Config.RabbitMQConnString) { RetryCount = retryCount }; + } + } + + [Ignore("Integration Tests")] + public class RedisMqRequestReplyTests : MqRequestReplyTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new RedisMqServer(new BasicRedisClientManager()) { RetryCount = retryCount }; + } + + [Test] + public void Can_expire_temp_queues() + { + using (var mqServer = (RedisMqServer)CreateMqServer()) + using (var client = mqServer.ClientsManager.GetClient()) + { + client.FlushAll(); + + 100.Times(i => + client.AddItemToList(QueueNames.GetTempQueueName(), i.ToString())); + + var itemsToExpire = mqServer.ExpireTemporaryQueues(afterMs: 100); + + var tmpWildCard = QueueNames.TempMqPrefix + "*"; + Assert.That(itemsToExpire, Is.EqualTo(100)); + Assert.That(client.SearchKeys(tmpWildCard).Count, Is.EqualTo(100)); + Thread.Sleep(200); + Assert.That(client.SearchKeys(tmpWildCard).Count, Is.EqualTo(0)); + } + } + } + + public class InMemoryMqRequestReplyTests : MqRequestReplyTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new InMemoryTransientMessageService { RetryCount = retryCount }; + } + } + + public class BackgroundMqRequestReplyTests : MqRequestReplyTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new BackgroundMqService { RetryCount = retryCount }; + } + } + + [TestFixture] + public abstract class MqRequestReplyTests + { + public abstract IMessageService CreateMqServer(int retryCount = 1); + + [Test] + public void Can_publish_messages_to_the_ReplyTo_temporary_queue() + { + using (var mqServer = CreateMqServer()) + { + mqServer.RegisterHandler(m => + new HelloIntroResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) }); + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + var replyToMq = mqClient.GetTempQueueName(); + mqClient.Publish(new Message(new HelloIntro { Name = "World" }) + { + ReplyTo = replyToMq + }); + + IMessage responseMsg = mqClient.Get(replyToMq); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + } + } + } + + [Test] + public void Can_send_message_with_custom_Header() + { + using (var mqServer = CreateMqServer()) + { + mqServer.RegisterHandler(m => + new Message(new HelloIntroResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) }) { Meta = m.Meta }); + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + var replyToMq = mqClient.GetTempQueueName(); + mqClient.Publish(new Message(new HelloIntro { Name = "World" }) + { + ReplyTo = replyToMq, + Meta = new Dictionary { { "Custom", "Header" } } + }); + + IMessage responseMsg = mqClient.Get(replyToMq); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + Assert.That(responseMsg.Meta["Custom"], Is.EqualTo("Header")); + } + } + } + + [Test] + public void Can_send_message_with_custom_Tag() + { + using (var mqServer = CreateMqServer()) + { + if (mqServer is RabbitMqServer) + return; //Uses DeliveryTag for Tag + + mqServer.RegisterHandler(m => + new Message(new HelloIntroResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) }) { Tag = m.Tag }); + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + var replyToMq = mqClient.GetTempQueueName(); + mqClient.Publish(new Message(new HelloIntro { Name = "World" }) + { + ReplyTo = replyToMq, + Tag = "Custom" + }); + + IMessage responseMsg = mqClient.Get(replyToMq); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + Assert.That(responseMsg.Tag, Is.EqualTo("Custom")); + } + } + } + + public class Incr + { + public long Value { get; set; } + } + + public class IncrResponse + { + public long Result { get; set; } + } + + [Ignore("Takes too long")] + [Test] + public void Can_handle_multiple_rpc_clients() + { + int NoOfClients = 10; + int TimeMs = 5000; + + var errors = new ConcurrentDictionary(); + using (var mqServer = CreateMqServer()) + { + mqServer.RegisterHandler(m => + new IncrResponse { Result = m.GetBody().Value + 1 }); + mqServer.Start(); + + long counter = 0; + int activeClients = 0; + var activeClientsLock = new object(); + + NoOfClients.Times(() => { + ThreadPool.QueueUserWorkItem(_ => { + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + var sw = Stopwatch.StartNew(); + var clientId = Interlocked.Increment(ref activeClients); + while (sw.ElapsedMilliseconds < TimeMs) + { + var next = Interlocked.Increment(ref counter); + try + { + var replyToMq = mqClient.GetTempQueueName(); + mqClient.Publish(new Message(new Incr { Value = next }) + { + ReplyTo = replyToMq + }); + + var responseMsg = mqClient.Get(replyToMq, TimeSpan.FromMilliseconds(TimeMs)); + mqClient.Ack(responseMsg); + + var actual = responseMsg.GetBody().Result; + var expected = next + 1; + if (actual != expected) + { + errors[next] = string.Format("Actual: {1}, Expected: {0}", + actual, expected); + } + + } + catch (Exception ex) + { + errors[next] = ex.Message + "\nStackTrace:\n" + ex.StackTrace; + } + } + + "Client {0} finished".Print(clientId); + if (Interlocked.Decrement(ref activeClients) == 0) + { + "All Clients Finished".Print(); + lock (activeClientsLock) + Monitor.Pulse(activeClientsLock); + } + } + }); + }); + + lock (activeClientsLock) + Monitor.Wait(activeClientsLock); + + "Stopping Server...".Print(); + "Requests: {0}".Print(counter); + } + + Assert.That(errors.Count, Is.EqualTo(0)); + } + } +} diff --git a/tests/ServiceStack.Server.Tests/Messaging/MqServerIntroTests.cs b/tests/ServiceStack.Server.Tests/Messaging/MqServerIntroTests.cs new file mode 100644 index 00000000000..5d6dbd36460 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/MqServerIntroTests.cs @@ -0,0 +1,550 @@ +using System; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Host; +using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; +using ServiceStack.RabbitMq; +using ServiceStack.Redis; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + public class RabbitMqServerIntroTests : MqServerIntroTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + var mqServer = new RabbitMqServer(connectionString: Config.RabbitMQConnString) { RetryCount = retryCount }; + + using var conn = mqServer.ConnectionFactory.CreateConnection(); + using var channel = conn.CreateModel(); + channel.PurgeQueue(); + channel.PurgeQueue(); + return mqServer; + } + } + + public class RedisMqServerIntroTests : MqServerIntroTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + var redisManager = new BasicRedisClientManager(); + using (var redis = redisManager.GetClient()) + { + redis.FlushAll(); + } + return new RedisMqServer(redisManager) { RetryCount = retryCount }; + } + } + + public class InMemoryMqServerIntroTests : MqServerIntroTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new InMemoryTransientMessageService { RetryCount = retryCount }; + } + } + + public class BackgroundMqServerIntroTests : MqServerIntroTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new BackgroundMqService { RetryCount = retryCount }; + } + } + + public class HelloIntro : IReturn + { + public string Name { get; set; } + } + + public class HelloIntroResponse + { + public string Result { get; set; } + } + + public class HelloService : Service + { + public object Any(HelloIntro request) + { + return new HelloIntroResponse { Result = "Hello, {0}!".Fmt(request.Name) }; + } + } + + public class MqAuthOnly : IReturn + { + public string Name { get; set; } + public string SessionId { get; set; } + } + + public class MqAuthOnlyResponse + { + public string Result { get; set; } + } + + public class MqAuthOnlyToken : IHasBearerToken, IReturn + { + public string Name { get; set; } + public string BearerToken { get; set; } + } + + public class MqAuthOnlyService : Service + { + [Authenticate] + public object Any(MqAuthOnly request) + { + var session = base.SessionAs(); + return new MqAuthOnlyResponse + { + Result = $"Hello, {request.Name}! Your UserName is {session.UserAuthName}" + }; + } + + [Authenticate] + public object Any(MqAuthOnlyToken request) + { + var session = base.SessionAs(); + return new MqAuthOnlyResponse + { + Result = $"Hello, {request.Name}! Your UserName is {session.UserName}" + }; + } + } + + [Restrict(RequestAttributes.MessageQueue)] + public class MqRestriction : IReturn + { + public string Name { get; set; } + } + + public class MqRestrictionResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class MqRestrictionService : Service + { + public object Any(MqRestriction request) => + new MqRestrictionResponse { Result = request.Name }; + } + + public class AppHost : AppSelfHostBase + { + private readonly Func createMqServerFn; + + public AppHost(Func createMqServerFn) + : base("Rabbit MQ Test Host", typeof(HelloService).Assembly) + { + this.createMqServerFn = createMqServerFn; + } + + public override void Configure(Container container) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(AppSettings), + new JwtAuthProvider(AppSettings) { + AuthKey = AesUtils.CreateKey(), + RequireSecureConnection = false, + }, + })); + + container.Register(c => new InMemoryAuthRepository()); + var authRepo = container.Resolve(); + + try + { + ((IClearable)authRepo).Clear(); + } + catch { /*ignore*/ } + + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = "mythz", + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, "p@55word"); + + container.Register(c => createMqServerFn()); + + var mqServer = container.Resolve(); + + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.RegisterHandler(m => + { + var req = new BasicRequest + { + Verb = HttpMethods.Post, + Headers = { ["X-ss-id"] = m.GetBody().SessionId } + }; + var response = ExecuteMessage(m, req); + return response; + }); + mqServer.RegisterHandler(ExecuteMessage); + mqServer.Start(); + } + + protected override void Dispose(bool disposable) + { + var mqServer = TryResolve(); + mqServer?.Dispose(); + + base.Dispose(disposable); + } + } + + [TestFixture] + public abstract class MqServerIntroTests + { + public abstract IMessageService CreateMqServer(int retryCount = 1); + + [Test] + public void Messages_with_no_responses_are_published_to_Request_outq_topic() + { + using var mqServer = CreateMqServer(); + mqServer.RegisterHandler(m => + { + "Hello, {0}!".Print(m.GetBody().Name); + return null; + }); + mqServer.Start(); + + using var mqClient = mqServer.CreateMessageQueueClient(); + mqClient.Publish(new HelloIntro { Name = "World" }); + + IMessage msgCopy = mqClient.Get(QueueNames.Out); + mqClient.Ack(msgCopy); + Assert.That(msgCopy.GetBody().Name, Is.EqualTo("World")); + } + + [Test] + public void Message_with_response_are_published_to_Response_inq() + { + using var mqServer = CreateMqServer(); + mqServer.RegisterHandler(m => + new HelloIntroResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) }); + mqServer.Start(); + + using var mqClient = mqServer.CreateMessageQueueClient(); + mqClient.Publish(new HelloIntro { Name = "World" }); + + IMessage responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Message_with_exceptions_are_retried_then_published_to_Request_dlq() + { + using var mqServer = CreateMqServer(retryCount: 1); + var called = 0; + mqServer.RegisterHandler(m => + { + Interlocked.Increment(ref called); + throw new ArgumentException("Name"); + }); + mqServer.Start(); + + using var mqClient = mqServer.CreateMessageQueueClient(); + mqClient.Publish(new HelloIntro { Name = "World" }); + + IMessage dlqMsg = mqClient.Get(QueueNames.Dlq); + mqClient.Ack(dlqMsg); + + Assert.That(called, Is.EqualTo(2)); + Assert.That(dlqMsg.GetBody().Name, Is.EqualTo("World")); + Assert.That(dlqMsg.Error.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(dlqMsg.Error.Message, Is.EqualTo("Name")); + } + + [Test] + public void Message_with_ReplyTo_that_throw_exceptions_are_retried_then_published_to_Request_dlq() + { + using var mqServer = CreateMqServer(retryCount: 1); + var called = 0; + mqServer.RegisterHandler(m => + { + Interlocked.Increment(ref called); + throw new ArgumentException("Name"); + }); + mqServer.Start(); + + using var mqClient = mqServer.CreateMessageQueueClient(); + const string replyToMq = "mq:Hello.replyto"; + mqClient.Publish(new Message(new HelloIntro { Name = "World" }) + { + ReplyTo = replyToMq + }); + + IMessage dlqMsg = mqClient.Get(QueueNames.Dlq); + mqClient.Ack(dlqMsg); + + Assert.That(called, Is.EqualTo(2)); + Assert.That(dlqMsg.GetBody().Name, Is.EqualTo("World")); + Assert.That(dlqMsg.Error.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(dlqMsg.Error.Message, Is.EqualTo("Name")); + } + + [Test] + public void Message_with_ReplyTo_are_published_to_the_ReplyTo_queue() + { + using var mqServer = CreateMqServer(); + mqServer.RegisterHandler(m => + new HelloIntroResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) }); + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + const string replyToMq = "mq:Hello.replyto"; + mqClient.Publish(new Message(new HelloIntro { Name = "World" }) + { + ReplyTo = replyToMq + }); + + IMessage responseMsg = mqClient.Get(replyToMq); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + } + } + + [Test] + public void Does_process_messages_in_HttpListener_AppHost() + { + using var appHost = new AppHost(() => CreateMqServer()).Init().Start(Config.ListeningOn); + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + mqClient.Publish(new HelloIntro { Name = "World" }); + + IMessage responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Does_process_multi_messages_in_HttpListener_AppHost() + { + using var appHost = new AppHost(() => CreateMqServer()).Init().Start(Config.ListeningOn); + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + var requests = new[] + { + new HelloIntro { Name = "Foo" }, + new HelloIntro { Name = "Bar" }, + }; + + var client = (IOneWayClient)mqClient; + client.SendAllOneWay(requests); + + var responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, Foo!")); + + responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, Bar!")); + } + + [Test] + public void Does_allow_MessageQueue_restricted_Services() + { + using var appHost = new AppHost(() => CreateMqServer()).Init().Start(Config.ListeningOn); + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + mqClient.Publish(new MqRestriction + { + Name = "MQ Restriction", + }); + + var responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, + Is.EqualTo("MQ Restriction")); + } + + [Test] + public void Can_make_authenticated_requests_with_MQ() + { + using var appHost = new AppHost(() => CreateMqServer()).Init(); + appHost.Start(Config.ListeningOn); + + var client = new JsonServiceClient(Config.ListeningOn); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "mythz", + Password = "p@55word" + }); + + var sessionId = response.SessionId; + + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + mqClient.Publish(new MqAuthOnly + { + Name = "MQ Auth", + SessionId = sessionId, + }); + + var responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, + Is.EqualTo("Hello, MQ Auth! Your UserName is mythz")); + } + + [Test] + public void Can_make_authenticated_requests_with_MQ_BearerToken() + { + using var appHost = new AppHost(() => CreateMqServer()).Init(); + appHost.Start(Config.ListeningOn); + + var client = new JsonServiceClient(Config.ListeningOn); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "mythz", + Password = "p@55word" + }); + + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + mqClient.Publish(new MqAuthOnlyToken + { + Name = "MQ AuthToken", + BearerToken = response.BearerToken, + }); + + var responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, + Is.EqualTo("Hello, MQ AuthToken! Your UserName is mythz")); + } + + [Test] + public void Does_process_messages_in_BasicAppHost() + { + using var appHost = new BasicAppHost(typeof(HelloService).Assembly) + { + ConfigureAppHost = host => + { + host.Container.Register(c => CreateMqServer()); + + var mqServer = host.Container.Resolve(); + + mqServer.RegisterHandler(host.ExecuteMessage); + mqServer.Start(); + } + }.Init(); + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + mqClient.Publish(new HelloIntro { Name = "World" }); + + IMessage responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + appHost.Resolve().Dispose(); + } + } + + public class RabbitMqServerPostMessageTests : MqServerPostMessageTests + { + public override IMessageService CreateMqServer(IAppHost host, int retryCount = 1) + { + return new RabbitMqServer(connectionString: Config.RabbitMQConnString) + { + RetryCount = retryCount, + ResponseFilter = r => { host.OnEndRequest(null); return r; } + }; + } + } + + public class RedisMqServerPostMessageTests : MqServerPostMessageTests + { + public override IMessageService CreateMqServer(IAppHost host, int retryCount = 1) + { + return new RedisMqServer(new BasicRedisClientManager()) + { + RetryCount = retryCount, + ResponseFilter = r => { host.OnEndRequest(null); return r; } + }; + } + } + + public class HelloIntroWithDep + { + public string Name { get; set; } + } + + public class HelloWithDepService : Service + { + public IDisposableDependency Dependency { get; set; } + + public object Any(HelloIntroWithDep request) + { + return new HelloIntroResponse { Result = "Hello, {0}!".Fmt(request.Name) }; + } + } + + public interface IDisposableDependency : IDisposable + { + + } + + public class DisposableDependency : IDisposableDependency + { + private readonly Action onDispose; + + public DisposableDependency(Action onDispose) + { + this.onDispose = onDispose; + } + + public void Dispose() + { + onDispose?.Invoke(); + } + } + + [TestFixture] + public abstract class MqServerPostMessageTests + { + public abstract IMessageService CreateMqServer(IAppHost host, int retryCount = 1); + + [Test] + public void Does_dispose_request_scope_dependency_in_PostMessageHandler() + { + var disposeCount = 0; + using var appHost = new BasicAppHost(typeof(HelloWithDepService).Assembly) + { + ConfigureAppHost = host => + { +#if !NETCORE + RequestContext.UseThreadStatic = true; +#endif + host.Container.Register(c => new DisposableDependency(() => + { + Interlocked.Increment(ref disposeCount); + })) + .ReusedWithin(ReuseScope.Request); + host.Container.Register(c => CreateMqServer(host)); + + var mqServer = host.Container.Resolve(); + + mqServer.RegisterHandler(host.ExecuteMessage); + mqServer.Start(); + } + }.Init(); + + using var mqClient = appHost.Resolve().CreateMessageQueueClient(); + mqClient.Publish(new HelloIntroWithDep { Name = "World" }); + + IMessage responseMsg = mqClient.Get(QueueNames.In); + mqClient.Ack(responseMsg); + + Assert.That(disposeCount, Is.EqualTo(1)); + appHost.Resolve().Dispose(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/MqServerQueueNameTests.cs b/tests/ServiceStack.Server.Tests/Messaging/MqServerQueueNameTests.cs new file mode 100644 index 00000000000..4e8fd7c37fb --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/MqServerQueueNameTests.cs @@ -0,0 +1,68 @@ +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; +using ServiceStack.RabbitMq; +using ServiceStack.Redis; + +namespace ServiceStack.Server.Tests.Messaging +{ + public abstract class MqServerQueueNameTests + { + public abstract IMessageService CreateMqServer(int retryCount = 1); + + [Test] + public void Can_Send_and_Receive_messages_using_QueueNamePrefix() + { + QueueNames.SetQueuePrefix("site1."); + + Assert.That(QueueNames.TopicIn, Is.EqualTo("site1.mq:topic:in")); + Assert.That(QueueNames.TopicOut, Is.EqualTo("site1.mq:topic:out")); + + using (var mqServer = CreateMqServer()) + { + mqServer.RegisterHandler(m => + new HelloIntroResponse { Result = $"Hello, {m.GetBody().Name}!" }); + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + var request = new HelloIntro { Name = "World" }; + var requestInq = MessageFactory.Create(request).ToInQueueName(); + Assert.That(requestInq, Is.EqualTo("site1.mq:HelloIntro.inq")); + + mqClient.Publish(request); + + var responseInq = QueueNames.In; + Assert.That(responseInq, Is.EqualTo("site1.mq:HelloIntroResponse.inq")); + + IMessage responseMsg = mqClient.Get(responseInq); + mqClient.Ack(responseMsg); + Assert.That(responseMsg.GetBody().Result, Is.EqualTo("Hello, World!")); + } + } + + QueueNames.SetQueuePrefix(""); + } + } + + class RedisMqServerQueueNameTests : MqServerQueueNameTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + var redisManager = new BasicRedisClientManager(); + using (var redis = redisManager.GetClient()) + { + redis.FlushAll(); + } + return new RedisMqServer(redisManager) { RetryCount = retryCount }; + } + } + + class RabbitMqServerQueueNameTests : MqServerQueueNameTests + { + public override IMessageService CreateMqServer(int retryCount = 1) + { + return new RabbitMqServer(connectionString: Config.RabbitMQConnString) { RetryCount = retryCount }; + } + } +} diff --git a/tests/ServiceStack.Server.Tests/Messaging/RabbitMqServerTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RabbitMqServerTests.cs new file mode 100644 index 00000000000..fc4afd306a4 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RabbitMqServerTests.cs @@ -0,0 +1,613 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using RabbitMQ.Client; +using ServiceStack.Logging; +using ServiceStack.Messaging; +using ServiceStack.RabbitMq; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + public class Reverse + { + public string Value { get; set; } + } + + public class Rot13 + { + public string Value { get; set; } + } + + public class AlwaysThrows + { + public string Value { get; set; } + } + + [TestFixture, Category("Integration")] + public class RabbitMqServerTests + { + static readonly string ConnectionString = Config.RabbitMQConnString; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + } + + internal static RabbitMqServer CreateMqServer(int noOfRetries = 2) + { + var mqServer = new RabbitMqServer(ConnectionString); + using var conn = mqServer.ConnectionFactory.CreateConnection(); + using var channel = conn.CreateModel(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + return mqServer; + } + + internal static void Publish_4_messages(IMessageQueueClient mqClient) + { + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Reverse { Value = "ServiceStack" }); + mqClient.Publish(new Reverse { Value = "Redis" }); + } + + private static void Publish_4_Rot13_messages(IMessageQueueClient mqClient) + { + mqClient.Publish(new Rot13 { Value = "Hello" }); + mqClient.Publish(new Rot13 { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + mqClient.Publish(new Rot13 { Value = "Redis" }); + } + + [Test] + public void Utils_publish_Reverse_messages() + { + using (var mqHost = new RabbitMqServer(ConnectionString)) + using (var mqClient = mqHost.CreateMessageQueueClient()) + { + Publish_4_messages(mqClient); + } + } + + [Test] + public void Utils_publish_Rot13_messages() + { + using (var mqHost = new RabbitMqServer(ConnectionString)) + using (var mqClient = mqHost.CreateMessageQueueClient()) + { + Publish_4_Rot13_messages(mqClient); + } + } + + [Test] + public void Only_allows_1_BgThread_to_run_at_a_time() + { + using (var mqHost = CreateMqServer()) + { + mqHost.RegisterHandler(x => x.GetBody().Value.Reverse()); + mqHost.RegisterHandler(x => x.GetBody().Value.ToRot13()); + + 5.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Start())); + ExecUtils.RetryOnException(() => + { + Thread.Sleep(100); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + Assert.That(mqHost.BgThreadCount, Is.EqualTo(1)); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + 10.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Stop())); + ExecUtils.RetryOnException(() => + { + Thread.Sleep(100); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Stopped")); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + ThreadPool.QueueUserWorkItem(y => mqHost.Start()); + ExecUtils.RetryOnException(() => + { + Thread.Sleep(100); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + Assert.That(mqHost.BgThreadCount, Is.EqualTo(2)); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + //Debug.WriteLine(mqHost.GetStats()); + } + } + + [Test] + public void Cannot_Start_a_Disposed_MqHost() + { + var mqHost = CreateMqServer(); + + mqHost.RegisterHandler(x => x.GetBody().Value.Reverse()); + mqHost.Dispose(); + + try + { + mqHost.Start(); + Assert.Fail("Should throw ObjectDisposedException"); + } + catch (ObjectDisposedException) { } + } + + [Test] + public void Cannot_Stop_a_Disposed_MqHost() + { + var mqHost = CreateMqServer(); + + mqHost.RegisterHandler(x => x.GetBody().Value.Reverse()); + mqHost.Start(); + Thread.Sleep(100); + + mqHost.Dispose(); + + try + { + mqHost.Stop(); + Assert.Fail("Should throw ObjectDisposedException"); + } + catch (ObjectDisposedException) { } + } + + public class Incr + { + public int Value { get; set; } + } + + [Test] + public void Can_receive_and_process_same_reply_responses() + { + var called = 0; + using (var mqHost = CreateMqServer()) + { + + using (var conn = mqHost.ConnectionFactory.CreateConnection()) + using (var channel = conn.CreateModel()) + { + channel.PurgeQueue(); + } + + mqHost.RegisterHandler(m => + { + Debug.WriteLine("In Incr #" + m.GetBody().Value); + Interlocked.Increment(ref called); + return m.GetBody().Value > 0 ? new Incr { Value = m.GetBody().Value - 1 } : null; + }); + + mqHost.Start(); + + var incr = new Incr { Value = 5 }; + using (var mqClient = mqHost.CreateMessageQueueClient()) + { + mqClient.Publish(incr); + } + + ExecUtils.RetryOnException(() => + { + Thread.Sleep(300); + Assert.That(called, Is.EqualTo(1 + incr.Value)); + }, TimeSpan.FromSeconds(5)); + } + } + + public class Hello : IReturn + { + public string Name { get; set; } + } + public class HelloNull : IReturn + { + public string Name { get; set; } + } + public class HelloResponse + { + public string Result { get; set; } + } + + [Test] + public void Can_receive_and_process_standard_request_reply_combo() + { + using (var mqHost = CreateMqServer()) + { + using (var conn = mqHost.ConnectionFactory.CreateConnection()) + using (var channel = conn.CreateModel()) + { + channel.PurgeQueue(); + channel.PurgeQueue(); + } + + string messageReceived = null; + + mqHost.RegisterHandler(m => + new HelloResponse { Result = "Hello, " + m.GetBody().Name }); + + mqHost.RegisterHandler(m => + { + messageReceived = m.GetBody().Result; return null; + }); + + mqHost.Start(); + + using (var mqClient = mqHost.CreateMessageQueueClient()) + { + var dto = new Hello { Name = "ServiceStack" }; + mqClient.Publish(dto); + + ExecUtils.RetryOnException(() => + { + Thread.Sleep(300); + Assert.That(messageReceived, Is.EqualTo("Hello, ServiceStack")); + }, TimeSpan.FromSeconds(5)); + } + } + } + + public class Wait + { + public int ForMs { get; set; } + } + + [Test] + public void Can_handle_requests_concurrently_in_4_threads() + { + RunHandlerOnMultipleThreads(noOfThreads: 4, msgs: 10); + } + + private static void RunHandlerOnMultipleThreads(int noOfThreads, int msgs) + { + using var mqHost = CreateMqServer(); + var timesCalled = 0; + + mqHost.RegisterHandler(m => { + Interlocked.Increment(ref timesCalled); + Thread.Sleep(m.GetBody().ForMs); + return null; + }, noOfThreads); + + mqHost.Start(); + + using var mqClient = mqHost.CreateMessageQueueClient(); + var dto = new Wait { ForMs = 100 }; + msgs.Times(i => mqClient.Publish(dto)); + + ExecUtils.RetryOnException(() => + { + Thread.Sleep(300); + Assert.That(timesCalled, Is.EqualTo(msgs)); + }, TimeSpan.FromSeconds(5)); + } + + [Test] + public void Can_publish_and_receive_messages_with_MessageFactory() + { + using (var mqFactory = new RabbitMqMessageFactory(Config.RabbitMQConnString)) + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + mqClient.Publish(new Hello { Name = "Foo" }); + var msg = mqClient.Get(QueueNames.In); + + Assert.That(msg.GetBody().Name, Is.EqualTo("Foo")); + } + } + + [Test] + public void Can_filter_published_and_received_messages() + { + string receivedMsgApp = null; + string receivedMsgType = null; + + using (var mqServer = CreateMqServer()) + { + mqServer.PublishMessageFilter = (queueName, properties, msg) => + { + properties.AppId = "app:{0}".Fmt(queueName); + }; + mqServer.GetMessageFilter = (queueName, basicMsg) => + { + var props = basicMsg.BasicProperties; + receivedMsgType = props.Type; //automatically added by RabbitMqProducer + receivedMsgApp = props.AppId; + }; + + mqServer.RegisterHandler(m => { + return new HelloResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) }; + }); + + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + mqClient.Publish(new Hello { Name = "Bugs Bunny" }); + } + + Thread.Sleep(100); + + Assert.That(receivedMsgApp, Is.EqualTo("app:{0}".Fmt(QueueNames.In))); + Assert.That(receivedMsgType, Is.EqualTo(typeof(Hello).Name)); + + using (IConnection connection = mqServer.ConnectionFactory.CreateConnection()) + using (IModel channel = connection.CreateModel()) + { + var queueName = QueueNames.In; + channel.RegisterQueue(queueName); + + var basicMsg = channel.BasicGet(queueName, autoAck: true); + var props = basicMsg.BasicProperties; + + Assert.That(props.Type, Is.EqualTo(typeof(HelloResponse).Name)); + Assert.That(props.AppId, Is.EqualTo("app:{0}".Fmt(queueName))); + + var msg = basicMsg.ToMessage(); + Assert.That(msg.GetBody().Result, Is.EqualTo("Hello, Bugs Bunny!")); + } + } + } + + [Test] + public void Messages_with_null_Response_is_published_to_OutMQ() + { + int msgsReceived = 0; + using (var mqServer = CreateMqServer()) + { + mqServer.RegisterHandler(m => + { + Interlocked.Increment(ref msgsReceived); + return null; + }); + + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + mqClient.Publish(new HelloNull { Name = "Into the Void" }); + + var msg = mqClient.Get(QueueNames.Out, TimeSpan.FromSeconds(5)); + Assert.That(msg, Is.Not.Null); + + HelloNull response = msg.GetBody(); + + Thread.Sleep(100); + + Assert.That(response.Name, Is.EqualTo("Into the Void")); + Assert.That(msgsReceived, Is.EqualTo(1)); + } + } + } + + [Test] + public void Messages_with_null_responses_are_not_published_when_DisablePublishingToOutq() + { + int msgsReceived = 0; + using (var mqServer = CreateMqServer()) + { + mqServer.DisablePublishingToOutq = true; + mqServer.RegisterHandler(m => + { + Interlocked.Increment(ref msgsReceived); + return null; + }); + + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + mqClient.Publish(new HelloNull { Name = "Into the Void" }); + + var msg = mqClient.Get(QueueNames.Out, TimeSpan.FromSeconds(2)); + Assert.That(msg, Is.Null); + } + } + } + + [Test] + public void Messages_with_null_Response_is_published_to_ReplyMQ() + { + int msgsReceived = 0; + using (var mqServer = CreateMqServer()) + { + mqServer.RegisterHandler(m => + { + Interlocked.Increment(ref msgsReceived); + return null; + }); + + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + var replyMq = mqClient.GetTempQueueName(); + mqClient.Publish(new Message(new HelloNull { Name = "Into the Void" }) + { + ReplyTo = replyMq + }); + + var msg = mqClient.Get(replyMq); + + HelloNull response = msg.GetBody(); + + Thread.Sleep(100); + + Assert.That(response.Name, Is.EqualTo("Into the Void")); + Assert.That(msgsReceived, Is.EqualTo(1)); + } + } + } + } + + [Ignore("These Flaky tests pass when run manually")] + [TestFixture, Category("Integration")] + public class RabbitMqServerFragileTests + { + [Test] + public void Does_process_all_messages_and_Starts_Stops_correctly_with_multiple_threads_racing() + { + using (var mqHost = RabbitMqServerTests.CreateMqServer()) + { + using (var conn = mqHost.ConnectionFactory.CreateConnection()) + using (var channel = conn.CreateModel()) + { + channel.PurgeQueue(); + channel.PurgeQueue(); + } + + var reverseCalled = 0; + var rot13Called = 0; + + mqHost.RegisterHandler(x => + { + "Processing Reverse {0}...".Print(Interlocked.Increment(ref reverseCalled)); + return x.GetBody().Value.Reverse(); + }); + mqHost.RegisterHandler(x => + { + "Processing Rot13 {0}...".Print(Interlocked.Increment(ref rot13Called)); + return x.GetBody().Value.ToRot13(); + }); + + using (var mqClient = mqHost.CreateMessageQueueClient()) + { + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + + mqHost.Start(); + + ExecUtils.RetryOnException(() => + { + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(3)); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + mqClient.Publish(new Reverse { Value = "Foo" }); + mqClient.Publish(new Rot13 { Value = "Bar" }); + + 10.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Start())); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + + 5.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Stop())); + ExecUtils.RetryOnException(() => + { + Assert.That(mqHost.GetStatus(), Is.EqualTo("Stopped")); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + 10.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Start())); + ExecUtils.RetryOnException(() => + { + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + Debug.WriteLine("\n" + mqHost.GetStats()); + + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.GreaterThanOrEqualTo(5)); + Assert.That(reverseCalled, Is.EqualTo(3)); + Assert.That(rot13Called, Is.EqualTo(2)); + } + } + } + + + [Test] + public void Does_retry_messages_with_errors_by_RetryCount() + { + var retryCount = 1; + var totalRetries = 1 + retryCount; //in total, inc. first try + + using (var mqHost = RabbitMqServerTests.CreateMqServer(retryCount)) + { + using (var conn = mqHost.ConnectionFactory.CreateConnection()) + using (var channel = conn.CreateModel()) + { + channel.PurgeQueue(); + channel.PurgeQueue(); + channel.PurgeQueue(); + } + + var reverseCalled = 0; + var rot13Called = 0; + + mqHost.RegisterHandler(x => { Interlocked.Increment(ref reverseCalled); return x.GetBody().Value.Reverse(); }); + mqHost.RegisterHandler(x => { Interlocked.Increment(ref rot13Called); return x.GetBody().Value.ToRot13(); }); + mqHost.RegisterHandler(x => { throw new Exception("Always Throwing! " + x.GetBody().Value); }); + mqHost.Start(); + + using (var mqClient = mqHost.CreateMessageQueueClient()) + { + mqClient.Publish(new AlwaysThrows { Value = "1st" }); + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + + ExecUtils.RetryOnException(() => + { + Assert.That(mqHost.GetStats().TotalMessagesFailed, Is.EqualTo(1 * totalRetries)); + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(2 + 1)); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + + 5.Times(x => mqClient.Publish(new AlwaysThrows { Value = "#" + x })); + + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + } + //Debug.WriteLine(mqHost.GetStatsDescription()); + + ExecUtils.RetryOnException(() => + { + Assert.That(mqHost.GetStats().TotalMessagesFailed, Is.EqualTo((1 + 5) * totalRetries)); + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(6)); + + Assert.That(reverseCalled, Is.EqualTo(2 + 2)); + Assert.That(rot13Called, Is.EqualTo(1 + 1)); + + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + } + } + + [Test] + public void Does_process_messages_sent_before_it_was_started() + { + var reverseCalled = 0; + + using (var mqServer = RabbitMqServerTests.CreateMqServer()) + { + using (var conn = mqServer.ConnectionFactory.CreateConnection()) + using (var channel = conn.CreateModel()) + { + channel.PurgeQueue(); + } + + mqServer.RegisterHandler(x => { Interlocked.Increment(ref reverseCalled); return x.GetBody().Value.Reverse(); }); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + RabbitMqServerTests.Publish_4_messages(mqClient); + + mqServer.Start(); + + ExecUtils.RetryOnException(() => + { + Assert.That(mqServer.GetStats().TotalMessagesProcessed, Is.EqualTo(4)); + Assert.That(reverseCalled, Is.EqualTo(4)); + Thread.Sleep(100); + }, TimeSpan.FromSeconds(5)); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/RedisFailoverTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RedisFailoverTests.cs new file mode 100644 index 00000000000..ac6f99cd0a6 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RedisFailoverTests.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; +using ServiceStack.Text; +using RedisMessageQueueClient = ServiceStack.Messaging.RedisMessageQueueClient; + +namespace ServiceStack.Server.Tests.Messaging +{ + [Ignore("Simulating error conditions")] + [TestFixture] + public class RedisFailoverTests + { + [Test] + public void Can_recover_from_server_terminated_client_connection() + { + const int SleepHoldingClientMs = 5; + const int SleepAfterReleasingClientMs = 0; + const int loop = 1000; + + var admin = new RedisClient("localhost"); + admin.SetConfig("timeout", "0"); + var timeout = admin.GetConfig("timeout"); + timeout.Print("timeout: {0}"); + + int remaining = loop; + var stopwatch = Stopwatch.StartNew(); + + var clientManager = new PooledRedisClientManager(new[] { "localhost" }) + { + + }; + loop.Times(i => + { + ThreadPool.QueueUserWorkItem(x => + { + try + { + using (var client = (RedisClient)clientManager.GetClient()) + { + client.IncrementValue("key"); + var val = client.Get("key"); + "#{0}, isConnected: {1}".Print(val, true); //client.IsSocketConnected() + Thread.Sleep(SleepHoldingClientMs); + } + Thread.Sleep(SleepAfterReleasingClientMs); + } + catch (Exception ex) + { + ex.Message.Print(); + } + finally + { + remaining--; + } + }); + }); + + while (remaining > 0) + { + Thread.Sleep(10); + } + "Elapsed time: {0}ms".Print(stopwatch.ElapsedMilliseconds); + + var managerStats = clientManager.GetStats(); + } + + public class Incr + { + public int Value { get; set; } + } + + [Test] + public void Can_MqServer_recover_from_server_terminated_client_connections() + { + LogManager.LogFactory = new ConsoleLogFactory(); + + var clientManager = new PooledRedisClientManager(new[] { "localhost" }) + { + + }; + var mqHost = new RedisMqServer(clientManager, retryCount: 2); + + var sum = 0; + mqHost.RegisterHandler(c => + { + var dto = c.GetBody(); + sum += dto.Value; + "Received {0}, sum: {1}".Print(dto.Value, sum); + return null; + }); + + mqHost.Start(); + + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(x => { + using (var client = mqHost.CreateMessageQueueClient()) + { + "Publish: {0}...".Print(i); + client.Publish(new Incr { Value = i }); + + Thread.Sleep(10); + } + }); + }); + + ThreadPool.QueueUserWorkItem(_ => + { + using (var client = (RedisClient)clientManager.GetClient()) + { + client.SetConfig("timeout", "1"); + var clientAddrs = client.GetClientsInfo().ConvertAll(x => x["addr"]); + "Killing clients: {0}...".Print(clientAddrs.Dump()); + try + { + clientAddrs.ForEach(client.ClientKill); + } + catch (Exception ex) + { + "Client exception: {0}".Print(ex.Message); + } + } + }); + + 20.Times(i => + { + using (var client = mqHost.CreateMessageQueueClient()) + { + "Publish: {0}...".Print(i); + client.Publish(new Incr { Value = i }); + } + + Thread.Sleep(2000); + }); + + } + + [Test] + public void Can_failover_at_runtime() + { + var failoverHost = "redis-failover:6379"; + string key = "test:failover"; + + var localClient = new RedisClient("localhost"); + localClient.Remove(key); + var failoverClient = new RedisClient(failoverHost); + failoverClient.Remove(key); + + var clientManager = new PooledRedisClientManager(new[] { "localhost" }); + + RunInLoop(clientManager, callback:() => + { + lock (clientManager) + Monitor.Pulse(clientManager); + }); + + Thread.Sleep(100); + + clientManager.FailoverTo(failoverHost); + + lock (clientManager) + Monitor.Wait(clientManager); + + var localIncr = localClient.Get(key); + var failoverIncr = failoverClient.Get(key); + Assert.That(localIncr, Is.GreaterThan(0)); + Assert.That(failoverIncr, Is.GreaterThan(0)); + Assert.That(localIncr + failoverIncr, Is.EqualTo(100)); + } + + public static bool RunInLoop(PooledRedisClientManager clientManager, int iterations = 100, int sleepMs = 10, Action callback=null) + { + int count = 0; + int errors = 0; + + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => + { + while (Interlocked.Decrement(ref iterations) >= 0) + { + using (var client = clientManager.GetClient()) + { + try + { + var result = client.Increment("test:failover", 1); + Interlocked.Increment(ref count); + if (count % (iterations / 10) == 0) + lock (clientManager) + Console.WriteLine(@"count: {0}, errors: {1}", count, errors); + } + catch (Exception) + { + Interlocked.Increment(ref errors); + } + Thread.Sleep(sleepMs); + } + } + + if (callback != null) + { + callback(); + callback = null; + } + }); + }); + + return true; + } + + + public class Msg + { + public string Host { get; set; } + } + + [Test] + public void Can_failover_MqServer_at_runtime() + { + const int iterations = 100; + var failoverHost = "redis-failover:6379"; + var localClient = new RedisClient("localhost:6379"); + + localClient.FlushDb(); + var failoverClient = new RedisClient(failoverHost); + failoverClient.FlushDb(); + + var clientManager = new PooledRedisClientManager(new[] { "localhost" }); + var mqHost = new RedisMqServer(clientManager); + + var map = new Dictionary(); + var received = 0; + mqHost.RegisterHandler(c => + { + var dto = c.GetBody(); + Interlocked.Increment(ref received); + int count; + map.TryGetValue(dto.Host, out count); + map[dto.Host] = count + 1; + + lock (clientManager) + { + "Received #{0} from {1}".Print(received, dto.Host); + if (received == iterations) + Monitor.Pulse(clientManager); + } + + return null; + }); + + mqHost.Start(); + + RunMqInLoop(mqHost, iterations: iterations, callback: () => + { + lock (clientManager) + "{0} msgs were published.".Print(iterations); + }); + + Thread.Sleep(500); + + clientManager.FailoverTo(failoverHost); + + lock (clientManager) + Monitor.Wait(clientManager); + + "localclient inq: {0}, outq: {1}".Print( + localClient.GetListCount("mq:Msg.inq"), + localClient.GetListCount("mq:Msg.outq")); + "failoverClient inq: {0}, outq: {1}".Print( + failoverClient.GetListCount("mq:Msg.inq"), + failoverClient.GetListCount("mq:Msg.outq")); + + Assert.That(received, Is.EqualTo(100)); + Assert.That(map.Count, Is.EqualTo(2)); + var msgsFromAllHosts = 0; + foreach (var count in map.Values) + { + Assert.That(count, Is.GreaterThan(0)); + msgsFromAllHosts += count; + } + Assert.That(msgsFromAllHosts, Is.EqualTo(iterations)); + } + + public static bool RunMqInLoop(RedisMqServer mqServer, int iterations = 100, int sleepMs = 10, Action callback = null) + { + int count = 0; + int errors = 0; + + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => + { + while (Interlocked.Decrement(ref iterations) >= 0) + { + using (var client = mqServer.CreateMessageQueueClient()) + { + try + { + var redis = (RedisNativeClient)((RedisMessageQueueClient)client).ReadWriteClient; + + client.Publish(new Msg { Host = redis.Host + ":" + redis.Port }); + Interlocked.Increment(ref count); + if (count % (iterations / 10) == 0) + lock (mqServer) + "count: {0}, errors: {1}".Print(count, errors); + } + catch (Exception) + { + Interlocked.Increment(ref errors); + } + Thread.Sleep(sleepMs); + } + } + + lock (mqServer) + { + if (callback != null) + { + callback(); + callback = null; + } + } + }); + }); + + return true; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/RedisMqHostSupportTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RedisMqHostSupportTests.cs new file mode 100644 index 00000000000..5d8c8eea7f0 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RedisMqHostSupportTests.cs @@ -0,0 +1,20 @@ +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Server.Tests.Services; + +namespace ServiceStack.Server.Tests.Messaging +{ + [TestFixture, Category("Integration")] + public class RedisMqHostSupportTests + { + [Test] + public void Does_serialize_to_correct_MQ_name() + { + var message = new Message(new Greet {Name = "Test"}) {}; + + var mqClient = new RedisMessageQueueClient(TestConfig.BasicClientManger); + + mqClient.Publish(message); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerSleepServerTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerSleepServerTests.cs new file mode 100644 index 00000000000..08bf32e902b --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerSleepServerTests.cs @@ -0,0 +1,117 @@ +using System; +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + [TestFixture, Category("Integration")] + public class RedisMqServerSleepServerTests + { + public class Counters + { + public int Sleep0; + public int Sleep10; + public int Sleep100; + public int Sleep1000; + } + + class Sleep0 + { + public int Id { get; set; } + } + class Sleep10 + { + public int Id { get; set; } + } + class Sleep100 + { + public int Id { get; set; } + } + class Sleep1000 + { + public int Id { get; set; } + } + + readonly Counters counter = new Counters(); + + RedisMqServer CreateServer() + { + using (var redis = new RedisClient(TestConfig.SingleHost)) + redis.FlushAll(); + + var mqServer = new RedisMqServer(TestConfig.BasicClientManger); + mqServer.RegisterHandler(m => new Sleep0 { Id = Interlocked.Increment(ref counter.Sleep0) }); + + mqServer.RegisterHandler(m => { + Thread.Sleep(10); + return new Sleep10 { Id = Interlocked.Increment(ref counter.Sleep10) }; + }); + mqServer.RegisterHandler(m => { + Thread.Sleep(100); + return new Sleep100 { Id = Interlocked.Increment(ref counter.Sleep100) }; + }); + mqServer.RegisterHandler(m => { + Thread.Sleep(1000); + return new Sleep1000 { Id = Interlocked.Increment(ref counter.Sleep1000) }; + }); + + + return mqServer; + } + + [Test] + public void Run_for_1_seconds() + { + RunFor(TimeSpan.FromSeconds(1)); + } + + [Ignore("Debug Test")] + [Test] + public void Run_for_5_seconds() + { + RunFor(TimeSpan.FromSeconds(5)); + } + + [Ignore("Debug Test")] + [Test] + public void Run_for_10_seconds() + { + RunFor(TimeSpan.FromSeconds(10)); + } + + [Ignore("Debug Test")] + [Test] + public void Run_for_30_seconds() + { + RunFor(TimeSpan.FromSeconds(30)); + } + + private void RunFor(TimeSpan SleepFor) + { + var mqServer = CreateServer(); + + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + mqClient.Publish(new Sleep0()); + mqClient.Publish(new Sleep10()); + mqClient.Publish(new Sleep100()); + mqClient.Publish(new Sleep1000()); + } + + Thread.Sleep(SleepFor); + + Debug.WriteLine(counter.Dump()); + + Debug.WriteLine("Disposing..."); + mqServer.Dispose(); + + Debug.WriteLine(counter.Dump()); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerSpinServerTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerSpinServerTests.cs new file mode 100644 index 00000000000..9b7c765471b --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerSpinServerTests.cs @@ -0,0 +1,120 @@ +using System; +using System.Diagnostics; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + [TestFixture, Category("Integration")] + public class RedisMqServerSpinServerTests + { + public class Counters + { + public int Spin0; + public int Spin10; + public int Spin100; + public int Spin1000; + } + + class Spin0 + { + public int Id { get; set; } + } + class Spin10 + { + public int Id { get; set; } + } + class Spin100 + { + public int Id { get; set; } + } + class Spin1000 + { + public int Id { get; set; } + } + + readonly Counters counter = new Counters(); + + RedisMqServer CreateServer() + { + using (var redis = new RedisClient(TestConfig.SingleHost)) + redis.FlushAll(); + + var mqServer = new RedisMqServer(TestConfig.BasicClientManger); + mqServer.RegisterHandler(m => new Spin0 { Id = Interlocked.Increment(ref counter.Spin0) }); + + mqServer.RegisterHandler(m => { + var sw = Stopwatch.StartNew(); + SpinWait.SpinUntil(() => sw.ElapsedMilliseconds < 10); + return new Spin10 { Id = Interlocked.Increment(ref counter.Spin10) }; + }); + mqServer.RegisterHandler(m => { + var sw = Stopwatch.StartNew(); + SpinWait.SpinUntil(() => sw.ElapsedMilliseconds < 100); + return new Spin100 { Id = Interlocked.Increment(ref counter.Spin100) }; + }); + mqServer.RegisterHandler(m => { + var sw = Stopwatch.StartNew(); + SpinWait.SpinUntil(() => sw.ElapsedMilliseconds < 1000); + return new Spin1000 { Id = Interlocked.Increment(ref counter.Spin1000) }; + }); + + + return mqServer; + } + + [Test] + public void Run_for_1_seconds() + { + RunFor(TimeSpan.FromSeconds(1)); + } + + [Ignore("Debug Test")] + [Test] + public void Run_for_5_seconds() + { + RunFor(TimeSpan.FromSeconds(5)); + } + + [Ignore("Debug Test")] + [Test] + public void Run_for_10_seconds() + { + RunFor(TimeSpan.FromSeconds(10)); + } + + [Ignore("Debug Test")] + [Test] + public void Run_for_30_seconds() + { + RunFor(TimeSpan.FromSeconds(30)); + } + + private void RunFor(TimeSpan SpinFor) + { + var mqServer = CreateServer(); + + mqServer.Start(); + + using (var mqClient = mqServer.CreateMessageQueueClient()) + { + mqClient.Publish(new Spin0()); + mqClient.Publish(new Spin10()); + mqClient.Publish(new Spin100()); + mqClient.Publish(new Spin1000()); + } + + Thread.Sleep(SpinFor); + + Debug.WriteLine(counter.Dump()); + + Debug.WriteLine("Disposing..."); + mqServer.Dispose(); + + Debug.WriteLine(counter.Dump()); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerTests.cs new file mode 100644 index 00000000000..085f6fbd3ad --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RedisMqServerTests.cs @@ -0,0 +1,394 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Messaging +{ + [TestFixture, Category("Integration")] + public class RedisMqServerTests + { + public class Reverse + { + public string Value { get; set; } + } + + public class Rot13 + { + public string Value { get; set; } + } + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + RedisClient.NewFactoryFn = () => new RedisClient(TestConfig.SingleHost); + //LogManager.LogFactory = new ConsoleLogFactory(); + } + + private static RedisMqServer CreateMqServer(int noOfRetries = 2) + { + var redisFactory = TestConfig.BasicClientManger; + try + { + redisFactory.Exec(redis => redis.FlushAll()); + } + catch (RedisException rex) + { + Debug.WriteLine("WARNING: Redis not started? \n" + rex.Message); + } + var mqHost = new RedisMqServer(redisFactory, noOfRetries); + return mqHost; + } + + private static void Publish_4_messages(IMessageQueueClient mqClient) + { + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Reverse { Value = "ServiceStack" }); + mqClient.Publish(new Reverse { Value = "Redis" }); + } + + private static void Publish_4_Rot13_messages(IMessageQueueClient mqClient) + { + mqClient.Publish(new Rot13 { Value = "Hello" }); + mqClient.Publish(new Rot13 { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + mqClient.Publish(new Rot13 { Value = "Redis" }); + } + + [Test] + public void Utils_publish_Reverse_messages() + { + var mqHost = new RedisMqServer(TestConfig.BasicClientManger, 2); + var mqClient = mqHost.CreateMessageQueueClient(); + Publish_4_messages(mqClient); + mqHost.Stop(); + } + + [Test] + public void Utils_publish_Rot13_messages() + { + var mqHost = new RedisMqServer(TestConfig.BasicClientManger, 2); + var mqClient = mqHost.CreateMessageQueueClient(); + Publish_4_Rot13_messages(mqClient); + mqHost.Stop(); + } + + [Test] + public void Does_process_messages_sent_before_it_was_started() + { + var reverseCalled = 0; + + var mqHost = CreateMqServer(); + mqHost.RegisterHandler(x => { Interlocked.Increment(ref reverseCalled); return x.GetBody().Value.Reverse(); }); + + var mqClient = mqHost.CreateMessageQueueClient(); + Publish_4_messages(mqClient); + + mqHost.Start(); + Thread.Sleep(3000); + + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(4)); + Assert.That(reverseCalled, Is.EqualTo(4)); + + mqHost.Dispose(); + } + + [Test] + public void Does_process_all_messages_and_Starts_Stops_correctly_with_multiple_threads_racing() + { + var mqHost = CreateMqServer(); + + var reverseCalled = 0; + var rot13Called = 0; + + mqHost.RegisterHandler(x => { Interlocked.Increment(ref reverseCalled); return x.GetBody().Value.Reverse(); }); + mqHost.RegisterHandler(x => { Interlocked.Increment(ref rot13Called); return x.GetBody().Value.ToRot13(); }); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + + mqHost.Start(); + Thread.Sleep(3000); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(3)); + + mqClient.Publish(new Reverse { Value = "Foo" }); + mqClient.Publish(new Rot13 { Value = "Bar" }); + + 10.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Start())); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + + 5.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Stop())); + Thread.Sleep(1000); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Stopped")); + + 10.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Start())); + Thread.Sleep(3000); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + + Debug.WriteLine("\n" + mqHost.GetStats()); + + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(5)); + Assert.That(reverseCalled, Is.EqualTo(3)); + Assert.That(rot13Called, Is.EqualTo(2)); + + mqHost.Dispose(); + } + + [Test] + public void Only_allows_1_BgThread_to_run_at_a_time() + { + var mqHost = CreateMqServer(); + var redisPubSub = (RedisPubSubServer)mqHost.RedisPubSub; + + mqHost.RegisterHandler(x => x.GetBody().Value.Reverse()); + mqHost.RegisterHandler(x => x.GetBody().Value.ToRot13()); + + 5.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Start())); + Thread.Sleep(1000); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + Assert.That(redisPubSub.BgThreadCount, Is.EqualTo(1)); + + 10.Times(x => ThreadPool.QueueUserWorkItem(y => mqHost.Stop())); + Thread.Sleep(1000); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Stopped")); + + ThreadPool.QueueUserWorkItem(y => mqHost.Start()); + Thread.Sleep(1000); + Assert.That(mqHost.GetStatus(), Is.EqualTo("Started")); + + Assert.That(redisPubSub.BgThreadCount, Is.EqualTo(2)); + + Debug.WriteLine(mqHost.GetStats()); + + mqHost.Dispose(); + } + + [Test] + public void Cannot_Start_a_Disposed_MqHost() + { + var mqHost = CreateMqServer(); + + mqHost.RegisterHandler(x => x.GetBody().Value.Reverse()); + mqHost.Dispose(); + + try + { + mqHost.Start(); + Assert.Fail("Should throw ObjectDisposedException"); + } + catch (ObjectDisposedException) { } + } + + [Test] + public void Cannot_Stop_a_Disposed_MqHost() + { + var mqHost = CreateMqServer(); + + mqHost.RegisterHandler(x => x.GetBody().Value.Reverse()); + mqHost.Start(); + Thread.Sleep(1000); + + mqHost.Dispose(); + + try + { + mqHost.Stop(); + Assert.Fail("Should throw ObjectDisposedException"); + } + catch (ObjectDisposedException) { } + } + + public class AlwaysThrows + { + public string Value { get; set; } + } + + [Test] + public void Does_retry_messages_with_errors_by_RetryCount() + { + var retryCount = 3; + var totalRetries = 1 + retryCount; //in total, inc. first try + + var mqHost = CreateMqServer(retryCount); + + var reverseCalled = 0; + var rot13Called = 0; + + mqHost.RegisterHandler(x => { Interlocked.Increment(ref reverseCalled); return x.GetBody().Value.Reverse(); }); + mqHost.RegisterHandler(x => { Interlocked.Increment(ref rot13Called); return x.GetBody().Value.ToRot13(); }); + mqHost.RegisterHandler(x => { throw new Exception("Always Throwing! " + x.GetBody().Value); }); + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + mqClient.Publish(new AlwaysThrows { Value = "1st" }); + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + + Thread.Sleep(3000); + Assert.That(mqHost.GetStats().TotalMessagesFailed, Is.EqualTo(1 * totalRetries)); + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(2 + 1)); + + 5.Times(x => mqClient.Publish(new AlwaysThrows { Value = "#" + x })); + + mqClient.Publish(new Reverse { Value = "Hello" }); + mqClient.Publish(new Reverse { Value = "World" }); + mqClient.Publish(new Rot13 { Value = "ServiceStack" }); + + Thread.Sleep(5000); + + Debug.WriteLine(mqHost.GetStatsDescription()); + + Assert.That(mqHost.GetStats().TotalMessagesFailed, Is.EqualTo((1 + 5) * totalRetries)); + Assert.That(mqHost.GetStats().TotalMessagesProcessed, Is.EqualTo(6)); + + Assert.That(reverseCalled, Is.EqualTo(2 + 2)); + Assert.That(rot13Called, Is.EqualTo(1 + 1)); + } + + public class Incr + { + public int Value { get; set; } + } + + [Test] + public void Can_receive_and_process_same_reply_responses() + { + var mqHost = CreateMqServer(); + var called = 0; + + mqHost.RegisterHandler(m => { + Debug.WriteLine("In Incr #" + m.GetBody().Value); + Interlocked.Increment(ref called); + return m.GetBody().Value > 0 ? new Incr { Value = m.GetBody().Value - 1 } : null; + }); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + + var incr = new Incr { Value = 5 }; + mqClient.Publish(incr); + + Thread.Sleep(1000); + + Assert.That(called, Is.EqualTo(1 + incr.Value)); + } + + public class Hello { public string Name { get; set; } } + public class HelloResponse { public string Result { get; set; } } + + [Test] + public void Can_receive_and_process_standard_request_reply_combo() + { + var mqHost = CreateMqServer(); + + string messageReceived = null; + + mqHost.RegisterHandler(m => + new HelloResponse { Result = "Hello, " + m.GetBody().Name }); + + mqHost.RegisterHandler(m => { + messageReceived = m.GetBody().Result; return null; + }); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + + var dto = new Hello { Name = "ServiceStack" }; + mqClient.Publish(dto); + + Thread.Sleep(1000); + + Assert.That(messageReceived, Is.EqualTo("Hello, ServiceStack")); + } + + [Test] + public void Can_BlockingPop_from_multiple_queues() + { + const int noOf = 5; + var queueNames = noOf.Times(x => "queue:" + x).ToArray(); + + ThreadPool.QueueUserWorkItem(state => { + Thread.Sleep(100); + var i = 0; + var client = RedisClient.New(); + foreach (var queueName in queueNames) + { + var msgName = "msg:" + Interlocked.Increment(ref i); + Debug.WriteLine("SEND " + msgName); + client.PrependItemToList(queueName, msgName); + } + }); + + var server = RedisClient.New(); + noOf.Times(x => { + Debug.WriteLine("Blocking... " + x); + var result = server.BlockingDequeueItemFromLists(queueNames, TimeSpan.FromSeconds(3)); + Debug.WriteLine("RECV: " + result.Dump()); + }); + } + + public class Wait + { + public int ForMs { get; set; } + } + + [Test] + public void Can_handle_requests_concurrently_in_2_threads() + { + RunHandlerOnMultipleThreads(noOfThreads: 2, msgs: 10); + } + + [Test] + public void Can_handle_requests_concurrently_in_3_threads() + { + RunHandlerOnMultipleThreads(noOfThreads: 3, msgs: 10); + } + + [Test] + public void Can_handle_requests_concurrently_in_4_threads() + { + RunHandlerOnMultipleThreads(noOfThreads: 4, msgs: 10); + } + + private static void RunHandlerOnMultipleThreads(int noOfThreads, int msgs) + { + var timesCalled = 0; + var mqHost = CreateMqServer(); + mqHost.RegisterHandler(m => { + Interlocked.Increment(ref timesCalled); + Thread.Sleep(m.GetBody().ForMs); + return null; + }, noOfThreads); + + mqHost.Start(); + + var mqClient = mqHost.CreateMessageQueueClient(); + + var dto = new Wait { ForMs = 100 }; + msgs.Times(i => mqClient.Publish(dto)); + + const double buffer = 1.1; + + var sleepForMs = (int)((msgs * 100 / (double)noOfThreads) * buffer); + "Sleeping for {0}ms...".Print(sleepForMs); + Thread.Sleep(sleepForMs); + + mqHost.Dispose(); + + Assert.That(timesCalled, Is.EqualTo(msgs)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Messaging/RedisTransientMessagingHostTests.cs b/tests/ServiceStack.Server.Tests/Messaging/RedisTransientMessagingHostTests.cs new file mode 100644 index 00000000000..ae04e24d5e4 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Messaging/RedisTransientMessagingHostTests.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; +using ServiceStack.Redis; + +namespace ServiceStack.Server.Tests.Messaging +{ + [Category("Integration")] + public class RedisTransientMessagingHostTests + : TransientServiceMessagingTests + { + private IRedisClientsManager clientManager; + private RedisTransientMessageFactory factory; + + public override void OnBeforeEachTest() + { + ResetConnections(); + + using (var client = clientManager.GetClient()) + { + client.FlushAll(); + } + + base.OnBeforeEachTest(); + } + + protected override IMessageFactory CreateMessageFactory() + { + return factory; + } + + protected override TransientMessageServiceBase CreateMessagingService() + { + return factory.MessageService; + } + + private void ResetConnections() + { + if (clientManager != null) + { + clientManager.Dispose(); + clientManager = null; + } + + if (factory != null) + { + factory.Dispose(); + factory = null; + } + + clientManager = new BasicRedisClientManager(TestConfig.MasterHosts); + factory = new RedisTransientMessageFactory(clientManager); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Server.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..c95d60616ef --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ServiceStack.Server.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ServiceStack.Server.Tests")] +[assembly: AssemblyCopyright("Copyright (c) ServiceStack 2018")] +[assembly: AssemblyTrademark("Service Stack")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7adefbb0-5b29-4f26-8b65-dc97e6a2864e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("6.0.0.0")] diff --git a/tests/ServiceStack.Server.Tests/ProxyFeatureTests.cs b/tests/ServiceStack.Server.Tests/ProxyFeatureTests.cs new file mode 100644 index 00000000000..c3db8692830 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/ProxyFeatureTests.cs @@ -0,0 +1,410 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.Server.Tests +{ + [TestFixture] + public class ProxyFeatureTests + { + private static string ListeningOn = "http://localhost:20000/"; + //private static string ListeningOn = Config.ListeningOn; + //private static string ListeningOn = "http://localhost:55799/"; + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ProxyFeatureTests), typeof(ProxyFeatureTests).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/test"), + resolveUrl: req => "http://test.servicestack.net" + req.RawUrl.Replace("/test", "/")) + { + TransformRequest = TransformRequest, + TransformResponse = TransformResponse, + }); + + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/techstacks"), + resolveUrl: req => "https://www.techstacks.io" + req.RawUrl.Replace("/techstacks", "/")) + { + TransformRequest = TransformRequest, + TransformResponse = TransformResponse, + }); + + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/imgur-netcore"), + resolveUrl: req => "http://imgur.netcore.io" + req.RawUrl.Replace("/imgur-netcore", "/")) + ); + + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/chat"), + resolveUrl: req => "http://chat.servicestack.net" + req.RawUrl.Replace("/chat", "/")) + ); + + Plugins.Add(new ProxyFeature( + matchingRequests: req => req.PathInfo.StartsWith("/proxy"), + resolveUrl: req => req.RawUrl.Replace("/proxy/", "")) + { + IgnoreResponseHeaders = { "X-Frame-Options" }, + TransformResponse = async (res, responseStream) => { + var enc = res.GetHeader(HttpHeaders.ContentEncoding); + var useStream = responseStream; + if (enc != null) + useStream = responseStream.Decompress(enc); + + using (var reader = new StreamReader(useStream,Encoding.UTF8)) + { + var responseBody = await reader.ReadToEndAsync(); + var replacedBody = responseBody.Replace("http://","/proxy/http://"); + replacedBody = replacedBody.Replace("https://", "/proxy/https://"); + + var bytes = replacedBody.ToUtf8Bytes(); + return MemoryStreamFactory.GetStream(enc != null ? bytes.CompressBytes(enc) : bytes); + } + } + }); + + //Allow this proxy server to issue ss-id/ss-pid Session Cookies + //Plugins.Add(new SessionFeature()); + } + + private async Task TransformRequest(IHttpRequest req, Stream reqStream) + { + var reqReplace = req.QueryString["reqReplace"]; + if (reqReplace != null) + { + var reqBody = await reqStream.ReadToEndAsync(); + var parts = reqReplace.SplitOnFirst(','); + var replacedBody = reqBody.Replace(parts[0], parts[1]); + return MemoryStreamFactory.GetStream(replacedBody.ToUtf8Bytes()); + } + return reqStream; + } + + private async Task TransformResponse(IHttpResponse res, Stream resStream) + { + var req = res.Request; + var resReplace = req.QueryString["resReplace"]; + if (resReplace != null) + { + var resBody = await resStream.ReadToEndAsync(); + var parts = resReplace.SplitOnFirst(','); + var replacedBody = resBody.Replace(parts[0], parts[1]); + return MemoryStreamFactory.GetStream(replacedBody.ToUtf8Bytes()); + } + return resStream; + } + } + + private readonly ServiceStackHost appHost; + + public ProxyFeatureTests() + { + appHost = new AppHost() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + [Route("/echo/types")] + public partial class EchoTypes + : IReturn + { + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual DateTimeOffset DateTimeOffset { get; set; } + public virtual Guid Guid { get; set; } + public virtual Char Char { get; set; } + } + + [Test] + public void Can_proxy_to_test_servicestack() + { + var client = new JsonServiceClient(ListeningOn.CombineWith("test")); + + var request = new EchoTypes + { + Byte = 1, + Short = 2, + Int = 3, + Long = 4, + Float = 1.1f, + String = "foo" + }; + var response = client.Post(request); + + Assert.That(response.Byte, Is.EqualTo(1)); + Assert.That(response.Short, Is.EqualTo(2)); + Assert.That(response.Int, Is.EqualTo(3)); + Assert.That(response.Long, Is.EqualTo(4)); + Assert.That(response.Float, Is.EqualTo(1.1f)); + Assert.That(response.String, Is.EqualTo("foo")); + } + + [Test] + public async Task Can_proxy_to_test_servicestack_Async() + { + var client = new JsonHttpClient(ListeningOn.CombineWith("test")); + + var request = new EchoTypes + { + Byte = 1, + Short = 2, + Int = 3, + Long = 4, + Float = 1.1f, + String = "foo" + }; + var response = await client.PostAsync(request); + + Assert.That(response.Byte, Is.EqualTo(1)); + Assert.That(response.Short, Is.EqualTo(2)); + Assert.That(response.Int, Is.EqualTo(3)); + Assert.That(response.Long, Is.EqualTo(4)); + Assert.That(response.Float, Is.EqualTo(1.1f)); + Assert.That(response.String, Is.EqualTo("foo")); + } + + [Test] + public void Can_TransformRequest_when_proxying_to_test() + { + var request = new EchoTypes + { + Byte = 1, + Short = 2, + Int = 3, + Long = 4, + Float = 1.1f, + String = "foo" + }; + + var url = ListeningOn.CombineWith("test") + .CombineWith("/echo/types") + .AddQueryParam("reqReplace", "foo,bar"); + + var response = url.PostJsonToUrl(request) + .FromJson(); + + Assert.That(response.Byte, Is.EqualTo(1)); + Assert.That(response.Short, Is.EqualTo(2)); + Assert.That(response.Int, Is.EqualTo(3)); + Assert.That(response.Long, Is.EqualTo(4)); + Assert.That(response.Float, Is.EqualTo(1.1f)); + Assert.That(response.String, Is.EqualTo("bar")); + } + + [Test] + public void Can_TransformResponse_when_proxying_to_test() + { + var request = new EchoTypes + { + Byte = 1, + Short = 2, + Int = 3, + Long = 4, + Float = 1.1f, + String = "foo" + }; + + var url = ListeningOn.CombineWith("test") + .CombineWith("/echo/types") + .AddQueryParam("resReplace", "foo,bar"); + + var response = url.PostJsonToUrl(request) + .FromJson(); + + Assert.That(response.Byte, Is.EqualTo(1)); + Assert.That(response.Short, Is.EqualTo(2)); + Assert.That(response.Int, Is.EqualTo(3)); + Assert.That(response.Long, Is.EqualTo(4)); + Assert.That(response.Float, Is.EqualTo(1.1f)); + Assert.That(response.String, Is.EqualTo("bar")); + } + + [Route("/technology/{Slug}")] + public partial class GetTechnology + : IReturn + { + public virtual string Slug { get; set; } + } + + public partial class GetTechnologyResponse + { + public virtual DateTime Created { get; set; } + public virtual Technology Technology { get; set; } + public virtual ResponseStatus ResponseStatus { get; set; } + } + public partial class Technology + : TechnologyBase + { + } + + public partial class TechnologyBase + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + public virtual string VendorName { get; set; } + public virtual string VendorUrl { get; set; } + public virtual string ProductUrl { get; set; } + public virtual string LogoUrl { get; set; } + public virtual string Description { get; set; } + public virtual DateTime Created { get; set; } + public virtual string CreatedBy { get; set; } + public virtual DateTime LastModified { get; set; } + public virtual string LastModifiedBy { get; set; } + public virtual string OwnerId { get; set; } + public virtual string Slug { get; set; } + public virtual bool LogoApproved { get; set; } + public virtual bool IsLocked { get; set; } + public virtual DateTime? LastStatusUpdate { get; set; } + } + + [Test] + public void Can_proxy_to_techstacks() + { + var client = new JsonServiceClient(ListeningOn.CombineWith("techstacks")); + + var request = new GetTechnology + { + Slug = "ServiceStack" + }; + var response = client.Get(request); + + Assert.That(response.Technology.VendorUrl, Is.EqualTo("https://servicestack.net")); + } + + [Test] + public async Task Can_proxy_to_techstacks_Async() + { + var client = new JsonServiceClient(ListeningOn.CombineWith("techstacks")); + + var request = new GetTechnology + { + Slug = "ServiceStack" + }; + var response = await client.GetAsync(request); + + Assert.That(response.Technology.VendorUrl, Is.EqualTo("https://servicestack.net")); + } + + [Test] + public void Can_authenticate_with_downstream_server() + { + var client = new JsonServiceClient(ListeningOn.CombineWith("test")) + { + ResponseFilter = res => + { + var ssId = res.Cookies["ss-id"]; + Assert.That(ssId.Value, Is.Not.Null); + } + }; + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "test", + Password = "test", + }); + + Assert.That(response.UserId, Is.Not.EqualTo(0)); + Assert.That(response.SessionId, Is.Not.Null); + Assert.That(response.UserName, Is.Not.Null); + } + + [Test] + public void Does_proxy_test_Exceptions() + { + var client = new JsonServiceClient(ListeningOn.CombineWith("test")); + + try + { + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "invalid", + Password = "password", + }); + } + catch (WebServiceException webEx) + { + var status = webEx.ResponseStatus; + Assert.That(webEx.StatusCode, Is.EqualTo(401)); + Assert.That(webEx.StatusDescription, Is.EqualTo("Unauthorized")); + Assert.That(status.ErrorCode, Is.EqualTo("Unauthorized")); + Assert.That(status.Message, Is.EqualTo("Invalid UserName or Password")); + } + } + +// [Ignore("Adhoc Integration Test"), Test] + public async Task Try_connect_to_ServerEvents_over_proxy() + { + ServerEventsClient client = null; + var proxyBaseUrl = ListeningOn.CombineWith("chat"); + client = new ServerEventsClient(proxyBaseUrl) + { + OnConnect = async c => + { + var proxyUrl = ListeningOn + c.HeartbeatUrl.Replace("http://chat.servicestack.net", "chat"); + client.ConnectionInfo.HeartbeatIntervalMs = 1000; + client.ConnectionInfo.HeartbeatUrl = proxyUrl; + var response = await proxyUrl.GetStringFromUrlAsync(); + Assert.That(response, Is.Empty); + }, + OnHeartbeat = () => + { + "Received Heartbeat".Print(); + }, + OnException = ex => + { + ex.Message.Print(); + } + }; + + client.Start(); + await client.Connect(); + + Thread.Sleep(TimeSpan.FromSeconds(120)); + } + +// [Ignore("Ephemeral external host + state dependency"), Test] + public void Can_proxy_chunked_encoding_responses() + { + var html = ListeningOn.CombineWith("imgur-netcore").GetStringFromUrl(accept:MimeTypes.Html); + + html.Length.Print(); + + Assert.That(html.Length, Is.GreaterThan(1000)); + } + +// [Ignore("Ephemeral external host + state dependency"), Test] + public void Can_rewrite_compressed_proxy_responses() + { + var url = ListeningOn.CombineWith("proxy/https://www.theverge.com"); + var response = url.GetStringFromUrl(); + response.Print(); + + Assert.That(response, Does.Contain("/proxy/https://")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/SecuredPage.cshtml b/tests/ServiceStack.Server.Tests/SecuredPage.cshtml new file mode 100644 index 00000000000..96208d5fb04 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/SecuredPage.cshtml @@ -0,0 +1,7 @@ +@{ + base.RedirectIfNotAuthenticated(); +} + +

    Secured Page

    + + \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/ServiceStack.Server.Tests.csproj b/tests/ServiceStack.Server.Tests/ServiceStack.Server.Tests.csproj new file mode 100644 index 00000000000..b984a3d1a79 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/ServiceStack.Server.Tests.csproj @@ -0,0 +1,69 @@ + + + net472 + + full + ServiceStack.Server.Tests + Library + ServiceStack.Server.Tests + false + false + false + false + false + false + false + false + + + $(DefineConstants);NETCORE;NET6_0;NET6_0_OR_GREATER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(DefineConstants);NETCORE + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Services/AlwaysFailService.cs b/tests/ServiceStack.Server.Tests/Services/AlwaysFailService.cs new file mode 100644 index 00000000000..bbdd7239752 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Services/AlwaysFailService.cs @@ -0,0 +1,32 @@ +using System; +using System.Runtime.Serialization; + +namespace ServiceStack.Server.Tests.Services +{ + [DataContract] + public class AlwaysFail + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class AlwaysFailResponse + { + [DataMember] + public string Result { get; set; } + } + + public class AlwaysFailService : Service + { + public int TimesCalled { get; set; } + public string Result { get; set; } + + public object Any(AlwaysFail request) + { + this.TimesCalled++; + + throw new NotSupportedException("This service always fails"); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Services/GreetService.cs b/tests/ServiceStack.Server.Tests/Services/GreetService.cs new file mode 100644 index 00000000000..04e4ec8acc3 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Services/GreetService.cs @@ -0,0 +1,33 @@ +using System.Runtime.Serialization; + +namespace ServiceStack.Server.Tests.Services +{ + [DataContract] + public class Greet + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class GreetResponse + { + [DataMember] + public string Result { get; set; } + } + + public class GreetService : Service + { + public int TimesCalled { get; set; } + public string Result { get; set; } + + public object Any(Greet request) + { + this.TimesCalled++; + + Result = "Hello, " + request.Name; + return new GreetResponse { Result = Result }; + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Services/UnRetryableFail.cs b/tests/ServiceStack.Server.Tests/Services/UnRetryableFail.cs new file mode 100644 index 00000000000..b3ea06ed3fd --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Services/UnRetryableFail.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.Serialization; +using ServiceStack.Messaging; + +namespace ServiceStack.Server.Tests.Services +{ + [DataContract] + public class UnRetryableFail + { + [DataMember] + public string Name { get; set; } + } + + [DataContract] + public class UnRetryableFailResponse + { + [DataMember] + public string Result { get; set; } + } + + public class UnRetryableFailService : Service + { + public int TimesCalled { get; set; } + public string Result { get; set; } + + public object Any(UnRetryableFail request) + { + this.TimesCalled++; + + throw new UnRetryableMessagingException( + "This request should not get retried", + new NotSupportedException("This service always fails")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Services/ValueTaskServices.cs b/tests/ServiceStack.Server.Tests/Services/ValueTaskServices.cs new file mode 100644 index 00000000000..78f72487766 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Services/ValueTaskServices.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; + +namespace ServiceStack.Server.Tests.Services +{ + [Route("/async/redis")] + [Route("/async/redis/{Incr}")] + public class AsyncRedis : IReturn + { + public uint Incr { get; set; } + } + + public class SGAsyncRedis1 : IReturn + { + public uint Incr { get; set; } + } + + public class SGAsyncRedis2 : IReturn + { + public uint Incr { get; set; } + } + + public class SGAsyncRedisSync : IReturn + { + public uint Incr { get; set; } + } + + public class ValueTaskServices : Service + { + public async ValueTask Any(AsyncRedis request) + { + await using var redis = await GetRedisAsync(); + await redis.IncrementAsync(nameof(AsyncRedis), request.Incr); + + var response = new IdResponse { + Id = (await redis.GetAsync(nameof(AsyncRedis))).ToString() + }; + return response; + } + + public async ValueTask Any(SGAsyncRedis1 request) + { + return await Gateway.SendAsync(new AsyncRedis { Incr = request.Incr }); + } + + public ValueTask Any(SGAsyncRedis2 request) + { + return new ValueTask(Gateway.SendAsync(new AsyncRedis { Incr = request.Incr })); + } + + public object Any(SGAsyncRedisSync request) + { + return Gateway.Send(new AsyncRedis { Incr = request.Incr }); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Shared/CacheClientTestsAsyncBase.cs b/tests/ServiceStack.Server.Tests/Shared/CacheClientTestsAsyncBase.cs new file mode 100644 index 00000000000..f8f1e89009a --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Shared/CacheClientTestsAsyncBase.cs @@ -0,0 +1,376 @@ +using System; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Shared +{ + [TestFixture] + public abstract class CacheClientTestsAsyncBase + { + private readonly ICacheClientAsync Cache; + + public abstract ICacheClientAsync CreateClient(); + + protected CacheClientTestsAsyncBase() + { + Cache = CreateClient(); + } + + [SetUp] + public async Task SetUp() + { + await Cache.FlushAllAsync(); + } + + [Test] + public async Task Does_flush_all() + { + await 3.TimesAsync(async i => + await Cache.SetAsync(i.ToUrn(), new Item { Id = i, Name = "Name" + i })); + + Assert.That(await Cache.GetAsync(1.ToUrn()), Is.Not.Null); + + await Cache.FlushAllAsync(); + + Assert.That(await Cache.GetAsync(1.ToUrn()), Is.Null); + } + + [Test] + public async Task Can_set_and_remove_entry() + { + var key = 1.ToUrn(); + + var item = await Cache.GetAsync(key); + Assert.That(item, Is.Null); + + var whenNotExists = await Cache.SetAsync(key, new Item { Id = 1, Name = "Foo" }); + Assert.That(whenNotExists, Is.True); + var whenExists = await Cache.SetAsync(key, new Item { Id = 1, Name = "Foo" }); + Assert.That(whenExists, Is.True); + + item = await Cache.GetAsync(key); + Assert.That(item, Is.Not.Null); + Assert.That(item.Name, Is.EqualTo("Foo")); + + whenExists = await Cache.RemoveAsync(key); + Assert.That(whenExists, Is.True); + + whenNotExists = await Cache.RemoveAsync(key); + Assert.That(whenNotExists, Is.False); + } + + [Test] + public async Task Can_update_existing_entry() + { + var key = 1.ToUrn(); + + await Cache.SetAsync(key, new Item { Id = 1, Name = "Foo" }); + await Cache.SetAsync(key, new Item { Id = 2, Name = "Updated" }); + + var item = await Cache.GetAsync(key); + + Assert.That(item.Id, Is.EqualTo(2)); + Assert.That(item.Name, Is.EqualTo("Updated")); + } + + [Test] + public async Task Does_SetAll_and_GetAll() + { + var map = 3.Times(i => new Item { Id = i, Name = "Name" + i }) + .ToSafeDictionary(x => x.ToUrn()); + + await Cache.SetAllAsync(map); + + var cacheMap = await Cache.GetAllAsync(map.Keys); + + Assert.That(cacheMap, Is.EquivalentTo(map)); + } + + [Test] + public async Task Does_not_return_expired_items() + { + var key = 1.ToUrn(); + + await Cache.SetAsync(key, new Item { Id = 1, Name = "Foo" }, DateTime.UtcNow.AddSeconds(-1)); + Assert.That(await Cache.GetAsync(key), Is.Null); + + await Cache.RemoveAsync(key); + + await Cache.SetAsync(key, new Item { Id = 1, Name = "Foo" }, TimeSpan.FromMilliseconds(100)); + var entry = await Cache.GetAsync(key); + Assert.That(entry, Is.Not.Null); + Thread.Sleep(200); + + Assert.That(await Cache.GetAsync(key), Is.Null); + + await Cache.RemoveAsync(key); + + await Cache.SetAsync(key, new Item { Id = 1, Name = "Foo" }, DateTime.UtcNow.AddMilliseconds(200)); + entry = await Cache.GetAsync(key); + Assert.That(entry, Is.Not.Null); + Thread.Sleep(300); + + Assert.That(await Cache.GetAsync(key), Is.Null); + } + + [Test] + public async Task Expired_item_returns_correct_GetTimeToLive() + { + var ormliteCache = Cache as OrmLiteCacheClient; + var key = "int:key"; + + var value = await Cache.GetOrCreateAsync(key, TimeSpan.FromMilliseconds(2000), () => Task.FromResult(1)); + var ttl = await Cache.GetTimeToLiveAsync(key); + + if (ormliteCache != null) + { + using var db = ormliteCache.DbFactory.OpenDbConnection(); + var row = await db.SingleByIdAsync(key); + Assert.That(row, Is.Not.Null); + Assert.That(row.ExpiryDate, Is.Not.Null); + } + + Assert.That(value, Is.EqualTo(1)); + Assert.That(ttl.Value.TotalMilliseconds, Is.GreaterThan(0)); + + await Cache.RemoveAsync(key); + + value = await Cache.GetAsync(key); + ttl = await Cache.GetTimeToLiveAsync(key); + + Assert.That(value, Is.EqualTo(0)); + Assert.That(ttl, Is.Null); + + if (ormliteCache != null) + { + using var db = ormliteCache.DbFactory.OpenDbConnection(); + var row = db.SingleById(key); + Assert.That(row, Is.Null); + } + } + + [Test] + public async Task Can_increment_and_decrement_values() + { + Assert.That(await Cache.IncrementAsync("incr:a", 2), Is.EqualTo(2)); + Assert.That(await Cache.IncrementAsync("incr:a", 3), Is.EqualTo(5)); + + Assert.That(await Cache.DecrementAsync("decr:a", 2), Is.EqualTo(-2)); + Assert.That(await Cache.DecrementAsync("decr:a", 3), Is.EqualTo(-5)); + } + + [Test] + public async Task Can_increment_and_reset_values() + { + Assert.That(await Cache.IncrementAsync("incr:counter", 10), Is.EqualTo(10)); + await Cache.SetAsync("incr:counter", 0); + Assert.That(await Cache.IncrementAsync("incr:counter", 10), Is.EqualTo(10)); + } + + [Test] + public async Task Can_remove_multiple_items() + { + var map = 5.Times(i => new Item { Id = i, Name = "Name" + i }) + .ToSafeDictionary(x => x.ToUrn()); + + await Cache.SetAllAsync(map); + + await Cache.RemoveAllAsync(map.Keys); + + var cacheMap = await Cache.GetAllAsync(map.Keys); + + Assert.That(cacheMap.Count, Is.EqualTo(5)); + Assert.That(cacheMap.Values.All(x => x == null)); + } + + [Test] + public async Task Can_retrieve_IAuthSession() + { + IAuthSession session = new CustomAuthSession + { + Id = "sess-1", + UserAuthId = "1", + Custom = "custom" + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + await Cache.SetAsync(sessionKey, session, SessionFeature.DefaultSessionExpiry); + + var sessionCache = await Cache.GetAsync(sessionKey); + Assert.That(sessionCache, Is.Not.Null); + + var typedSession = sessionCache as CustomAuthSession; + Assert.That(typedSession, Is.Not.Null); + Assert.That(typedSession.Custom, Is.EqualTo("custom")); + } + + [Test] + public async Task Can_retrieve_TimeToLive_on_IAuthSession() + { + IAuthSession session = new CustomAuthSession + { + Id = "sess-1", + UserAuthId = "1", + Custom = "custom" + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + await Cache.RemoveAsync(sessionKey); + + var ttl = await Cache.GetTimeToLiveAsync(sessionKey); + Assert.That(ttl, Is.Null); + + await Cache.SetAsync(sessionKey, session); + ttl = await Cache.GetTimeToLiveAsync(sessionKey); + Assert.That(ttl.Value, Is.EqualTo(TimeSpan.MaxValue)); + + var sessionExpiry = SessionFeature.DefaultSessionExpiry; + await Cache.SetAsync(sessionKey, session, sessionExpiry); + ttl = await Cache.GetTimeToLiveAsync(sessionKey); + Assert.That(ttl.Value, Is.GreaterThan(TimeSpan.FromSeconds(0))); + Assert.That(ttl.Value, Is.LessThan(sessionExpiry). + Or.EqualTo(sessionExpiry).Within(TimeSpan.FromSeconds(1))); + } + + [Test] + public async Task Can_retrieve_IAuthSession_with_global_ExcludeTypeInfo_set() + { + JsConfig.ExcludeTypeInfo = true; + + IAuthSession session = new CustomAuthSession + { + Id = "sess-1", + UserAuthId = "1", + Custom = "custom" + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + await Cache.SetAsync(sessionKey, session, SessionFeature.DefaultSessionExpiry); + + var sessionCache = await Cache.GetAsync(sessionKey); + Assert.That(sessionCache, Is.Not.Null); + + var typedSession = sessionCache as CustomAuthSession; + Assert.That(typedSession, Is.Not.Null); + Assert.That(typedSession.Custom, Is.EqualTo("custom")); + + JsConfig.Reset(); + } + + [Test] + public async Task Can_cache_multiple_items_in_parallel() + { + var cache = CreateClient(); + var fns = 10.TimesAsync(async i => + await cache.SetAsync("concurrent-test", "Data: {0}".Fmt(i)) + ); + + await Task.WhenAll(fns); + + var entry = await cache.GetAsync("concurrent-test"); + Assert.That(entry, Does.StartWith("Data: ")); + } + + [Test] + public async Task Can_GetKeysByPattern() + { + if (!(Cache is ICacheClientExtended)) + return; + + JsConfig.ExcludeTypeInfo = true; + + for (int i = 0; i < 5; i++) + { + IAuthSession session = new CustomAuthSession + { + Id = "sess-" + i, + UserAuthId = i.ToString(), + Custom = "custom" + i + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + await Cache.SetAsync(sessionKey, session, SessionFeature.DefaultSessionExpiry); + await Cache.SetAsync("otherkey" + i, i); + } + + var sessionPattern = IdUtils.CreateUrn(""); + Assert.That(sessionPattern, Is.EqualTo("urn:iauthsession:")); +#if !NETFX + var sessionKeys = await Cache.GetKeysStartingWithAsync(sessionPattern).ToListAsync(); + + Assert.That(sessionKeys.Count, Is.EqualTo(5)); + Assert.That(sessionKeys.All(x => x.StartsWith("urn:iauthsession:"))); + + var allSessions = await Cache.GetAllAsync(sessionKeys); + Assert.That(allSessions.Values.Count(x => x != null), Is.EqualTo(sessionKeys.Count)); + + var allKeys = (await Cache.GetAllKeysAsync().ToListAsync()).ToList(); + Assert.That(allKeys.Count, Is.EqualTo(10)); +#endif + JsConfig.Reset(); + } + + [Test] + public async Task Can_Cache_AllFields() + { + JsConfig.DateHandler = DateHandler.ISO8601; + + var dto = new AllFields + { + Id = 1, + NullableId = 2, + Byte = 3, + Short = 4, + Int = 5, + Long = 6, + UShort = 7, + UInt = 8, + Float = 1.1f, + Double = 2.2d, + Decimal = 3.3m, + String = "String", + DateTime = DateTime.Now, + TimeSpan = new TimeSpan(1, 1, 1, 1, 1), + Guid = Guid.NewGuid(), + NullableTimeSpan = new TimeSpan(2, 2, 2), + NullableGuid = new Guid("4B6BB8AE-57B5-4B5B-8632-0C35AF0B3168"), + }; + + await Cache.SetAsync("allfields", dto); + var fromCache = await Cache.GetAsync("allfields"); + + Assert.That(fromCache.DateTime, Is.EqualTo(dto.DateTime)); + + Assert.That(fromCache.Equals(dto)); + + JsConfig.Reset(); + } + +#if !NETFX + [Test] + public async Task Can_RemoveAll_and_GetKeysStartingWith_with_prefix() + { + var cache = Cache.WithPrefix("prefix."); + + await cache.SetAsync("test_QUERY_Deposit__Query_Deposit_10_1", "A"); + await cache.SetAsync("test_QUERY_Deposit__0_1___CUSTOM", "B"); + + var keys = (await cache.GetKeysStartingWithAsync("test_QUERY_Deposit").ToListAsync()).ToList(); + Assert.That(keys.Count, Is.EqualTo(2)); + + await cache.RemoveAllAsync(keys); + + var newKeys = (await cache.GetKeysStartingWithAsync("test_QUERY_Deposit").ToListAsync()).ToList(); + Assert.That(newKeys.Count, Is.EqualTo(0)); + } +#endif + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Shared/CacheClientTestsBase.cs b/tests/ServiceStack.Server.Tests/Shared/CacheClientTestsBase.cs new file mode 100644 index 00000000000..38e52ef3d35 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Shared/CacheClientTestsBase.cs @@ -0,0 +1,519 @@ +using System; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace ServiceStack.Server.Tests.Shared +{ + public class Item + { + public int Id { get; set; } + + public string Name { get; set; } + + protected bool Equals(Item other) + { + return Id == other.Id && string.Equals(Name, other.Name); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Item)obj); + } + + public override int GetHashCode() + { + unchecked + { + return (Id * 397) ^ (Name != null ? Name.GetHashCode() : 0); + } + } + } + + public class AllFields + { + public int Id { get; set; } + public int? NullableId { get; set; } + public byte Byte { get; set; } + public short Short { get; set; } + public int Int { get; set; } + public long Long { get; set; } + public ushort UShort { get; set; } + public uint UInt { get; set; } + public ulong ULong { get; set; } + public float Float { get; set; } + public double Double { get; set; } + public decimal Decimal { get; set; } + public string String { get; set; } + public DateTime DateTime { get; set; } + public TimeSpan TimeSpan { get; set; } + public Guid Guid { get; set; } + public DateTime? NullableDateTime { get; set; } + public TimeSpan? NullableTimeSpan { get; set; } + public Guid? NullableGuid { get; set; } + + protected bool Equals(AllFields other) + { + return Id == other.Id && + NullableId == other.NullableId && + Byte == other.Byte && + Short == other.Short && + Int == other.Int && + Long == other.Long && + UShort == other.UShort && + UInt == other.UInt && + ULong == other.ULong && + Float.Equals(other.Float) && + Double.Equals(other.Double) && + Decimal == other.Decimal && + string.Equals(String, other.String) && + DateTime.Equals(other.DateTime) && + TimeSpan.Equals(other.TimeSpan) && + Guid.Equals(other.Guid) && + NullableDateTime.Equals(other.NullableDateTime) && + NullableTimeSpan.Equals(other.NullableTimeSpan) && + NullableGuid.Equals(other.NullableGuid); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((AllFields)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Id; + hashCode = (hashCode * 397) ^ NullableId.GetHashCode(); + hashCode = (hashCode * 397) ^ Byte.GetHashCode(); + hashCode = (hashCode * 397) ^ Short.GetHashCode(); + hashCode = (hashCode * 397) ^ Int; + hashCode = (hashCode * 397) ^ Long.GetHashCode(); + hashCode = (hashCode * 397) ^ UShort.GetHashCode(); + hashCode = (hashCode * 397) ^ (int)UInt; + hashCode = (hashCode * 397) ^ ULong.GetHashCode(); + hashCode = (hashCode * 397) ^ Float.GetHashCode(); + hashCode = (hashCode * 397) ^ Double.GetHashCode(); + hashCode = (hashCode * 397) ^ Decimal.GetHashCode(); + hashCode = (hashCode * 397) ^ (String != null ? String.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ DateTime.GetHashCode(); + hashCode = (hashCode * 397) ^ TimeSpan.GetHashCode(); + hashCode = (hashCode * 397) ^ Guid.GetHashCode(); + hashCode = (hashCode * 397) ^ NullableDateTime.GetHashCode(); + hashCode = (hashCode * 397) ^ NullableTimeSpan.GetHashCode(); + hashCode = (hashCode * 397) ^ NullableGuid.GetHashCode(); + return hashCode; + } + } + } + + + public class CustomAuthSession : AuthUserSession + { + [DataMember] + public string Custom { get; set; } + } + + [TestFixture] + public abstract class CacheClientTestsBase + { + private readonly ICacheClient Cache; + + public abstract ICacheClient CreateClient(); + + protected CacheClientTestsBase() + { + Cache = CreateClient(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + Cache.Dispose(); + } + + [SetUp] + public void SetUp() + { + Cache.FlushAll(); + } + + [Test] + public void Does_flush_all() + { + 3.Times(i => + Cache.Set(i.ToUrn(), new Item { Id = i, Name = "Name" + i })); + + Assert.That(Cache.Get(1.ToUrn()), Is.Not.Null); + + Cache.FlushAll(); + + Assert.That(Cache.Get(1.ToUrn()), Is.Null); + } + + [Test] + public void Can_set_and_remove_entry() + { + var key = 1.ToUrn(); + + var item = Cache.Get(key); + Assert.That(item, Is.Null); + + var whenNotExists = Cache.Set(key, new Item { Id = 1, Name = "Foo" }); + Assert.That(whenNotExists, Is.True); + var whenExists = Cache.Set(key, new Item { Id = 1, Name = "Foo" }); + Assert.That(whenExists, Is.True); + + item = Cache.Get(key); + Assert.That(item, Is.Not.Null); + Assert.That(item.Name, Is.EqualTo("Foo")); + + whenExists = Cache.Remove(key); + Assert.That(whenExists, Is.True); + + whenNotExists = Cache.Remove(key); + Assert.That(whenNotExists, Is.False); + } + + [Test] + public void Can_update_existing_entry() + { + var key = 1.ToUrn(); + + Cache.Set(key, new Item { Id = 1, Name = "Foo" }); + Cache.Set(key, new Item { Id = 2, Name = "Updated" }); + + var item = Cache.Get(key); + + Assert.That(item.Id, Is.EqualTo(2)); + Assert.That(item.Name, Is.EqualTo("Updated")); + } + + [Test] + public void Does_SetAll_and_GetAll() + { + var map = 3.Times(i => new Item { Id = i, Name = "Name" + i }) + .ToSafeDictionary(x => x.ToUrn()); + + Cache.SetAll(map); + + var cacheMap = Cache.GetAll(map.Keys); + + Assert.That(cacheMap, Is.EquivalentTo(map)); + } + + [Test] + public void Does_not_return_expired_items() + { + var key = 1.ToUrn(); + + Cache.Set(key, new Item { Id = 1, Name = "Foo" }, DateTime.UtcNow.AddSeconds(-1)); + Assert.That(Cache.Get(key), Is.Null); + + Cache.Remove(key); + + Cache.Set(key, new Item { Id = 1, Name = "Foo" }, TimeSpan.FromMilliseconds(100)); + var entry = Cache.Get(key); + Assert.That(entry, Is.Not.Null); + Thread.Sleep(200); + + Assert.That(Cache.Get(key), Is.Null); + + Cache.Remove(key); + + Cache.Set(key, new Item { Id = 1, Name = "Foo" }, DateTime.UtcNow.AddMilliseconds(200)); + entry = Cache.Get(key); + Assert.That(entry, Is.Not.Null); + Thread.Sleep(300); + + Assert.That(Cache.Get(key), Is.Null); + } + + [Test] + public void Expired_item_returns_correct_GetTimeToLive() + { + var ormliteCache = Cache as OrmLiteCacheClient; + var key = "int:key"; + + var value = Cache.GetOrCreate(key, TimeSpan.FromMilliseconds(2000), () => 1); + var ttl = Cache.GetTimeToLive(key); + + if (ormliteCache != null) + { + using var db = ormliteCache.DbFactory.OpenDbConnection(); + var row = db.SingleById(key); + Assert.That(row, Is.Not.Null); + Assert.That(row.ExpiryDate, Is.Not.Null); + } + + Assert.That(value, Is.EqualTo(1)); + Assert.That(ttl.Value.TotalMilliseconds, Is.GreaterThan(0)); + + Cache.Remove(key); + + value = Cache.Get(key); + ttl = Cache.GetTimeToLive(key); + + Assert.That(value, Is.EqualTo(0)); + Assert.That(ttl, Is.Null); + + if (ormliteCache != null) + { + using var db = ormliteCache.DbFactory.OpenDbConnection(); + var row = db.SingleById(key); + Assert.That(row, Is.Null); + } + } + + [Test] + public void Can_increment_and_decrement_values() + { + Assert.That(Cache.Increment("incr:a", 2), Is.EqualTo(2)); + Assert.That(Cache.Increment("incr:a", 3), Is.EqualTo(5)); + + Assert.That(Cache.Decrement("decr:a", 2), Is.EqualTo(-2)); + Assert.That(Cache.Decrement("decr:a", 3), Is.EqualTo(-5)); + } + + [Test] + public void Can_increment_and_reset_values() + { + Assert.That(Cache.Increment("incr:counter", 10), Is.EqualTo(10)); + Cache.Set("incr:counter", 0); + Assert.That(Cache.Increment("incr:counter", 10), Is.EqualTo(10)); + } + + [Test] + public void Can_remove_multiple_items() + { + var map = 5.Times(i => new Item { Id = i, Name = "Name" + i }) + .ToSafeDictionary(x => x.ToUrn()); + + Cache.SetAll(map); + + Cache.RemoveAll(map.Keys); + + var cacheMap = Cache.GetAll(map.Keys); + + Assert.That(cacheMap.Count, Is.EqualTo(5)); + Assert.That(cacheMap.Values.All(x => x == null)); + } + + [Test] + public void Can_retrieve_IAuthSession() + { + IAuthSession session = new CustomAuthSession + { + Id = "sess-1", + UserAuthId = "1", + Custom = "custom" + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + Cache.Set(sessionKey, session, SessionFeature.DefaultSessionExpiry); + + var sessionCache = Cache.Get(sessionKey); + Assert.That(sessionCache, Is.Not.Null); + + var typedSession = sessionCache as CustomAuthSession; + Assert.That(typedSession, Is.Not.Null); + Assert.That(typedSession.Custom, Is.EqualTo("custom")); + } + + [Test] + public void Can_retrieve_TimeToLive_on_IAuthSession() + { + IAuthSession session = new CustomAuthSession + { + Id = "sess-1", + UserAuthId = "1", + Custom = "custom" + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + Cache.Remove(sessionKey); + + var ttl = Cache.GetTimeToLive(sessionKey); + Assert.That(ttl, Is.Null); + + Cache.Set(sessionKey, session); + ttl = Cache.GetTimeToLive(sessionKey); + Assert.That(ttl.Value, Is.EqualTo(TimeSpan.MaxValue)); + + var sessionExpiry = SessionFeature.DefaultSessionExpiry; + Cache.Set(sessionKey, session, sessionExpiry); + ttl = Cache.GetTimeToLive(sessionKey); + Assert.That(ttl.Value, Is.GreaterThan(TimeSpan.FromSeconds(0))); + Assert.That(ttl.Value, Is.LessThan(sessionExpiry). + Or.EqualTo(sessionExpiry).Within(TimeSpan.FromSeconds(1))); + } + + [Test] + public void Can_retrieve_IAuthSession_with_global_ExcludeTypeInfo_set() + { + JsConfig.ExcludeTypeInfo = true; + + IAuthSession session = new CustomAuthSession + { + Id = "sess-1", + UserAuthId = "1", + Custom = "custom" + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + Cache.Set(sessionKey, session, SessionFeature.DefaultSessionExpiry); + + var sessionCache = Cache.Get(sessionKey); + Assert.That(sessionCache, Is.Not.Null); + + var typedSession = sessionCache as CustomAuthSession; + Assert.That(typedSession, Is.Not.Null); + Assert.That(typedSession.Custom, Is.EqualTo("custom")); + + JsConfig.Reset(); + } + + [Test] + public void Can_cache_multiple_items_in_parallel() + { + var cache = CreateClient(); + var fns = 10.Times(i => (Action)(() => + { + cache.Set("concurrent-test", "Data: {0}".Fmt(i)); + })); + + Parallel.Invoke(fns.ToArray()); + + var entry = cache.Get("concurrent-test"); + Assert.That(entry, Does.StartWith("Data: ")); + } + + [Test] + public void Can_set_get_and_remove_ISession() + { + var sessionA = new SessionFactory(CreateClient()).CreateSession("a"); + var sessionB = new SessionFactory(CreateClient()).CreateSession("b"); + + 3.Times(i => + { + sessionA.Set("key" + i, "value" + i); + sessionB.Set("key" + i, "value" + i); + }); + + var value1 = sessionA.Get("key1"); + Assert.That(value1, Is.EqualTo("value1")); + + sessionA.RemoveAll(); + value1 = sessionA.Get("key1"); + Assert.That(value1, Is.Null); + + value1 = sessionB.Get("key1"); + Assert.That(value1, Is.EqualTo("value1")); + } + + [Test] + public void Can_GetKeysByPattern() + { + if (!(Cache is ICacheClientExtended)) + return; + + JsConfig.ExcludeTypeInfo = true; + + 5.Times(i => + { + IAuthSession session = new CustomAuthSession + { + Id = "sess-" + i, + UserAuthId = i.ToString(), + Custom = "custom" + i + }; + + var sessionKey = SessionFeature.GetSessionKey(session.Id); + Cache.Set(sessionKey, session, SessionFeature.DefaultSessionExpiry); + Cache.Set("otherkey" + i, i); + }); + + var sessionPattern = IdUtils.CreateUrn(""); + Assert.That(sessionPattern, Is.EqualTo("urn:iauthsession:")); + var sessionKeys = Cache.GetKeysStartingWith(sessionPattern).ToList(); + + Assert.That(sessionKeys.Count, Is.EqualTo(5)); + Assert.That(sessionKeys.All(x => x.StartsWith("urn:iauthsession:"))); + + var allSessions = Cache.GetAll(sessionKeys); + Assert.That(allSessions.Values.Count(x => x != null), Is.EqualTo(sessionKeys.Count)); + + var allKeys = Cache.GetAllKeys().ToList(); + Assert.That(allKeys.Count, Is.EqualTo(10)); + + JsConfig.Reset(); + } + + [Test] + public void Can_Cache_AllFields() + { + JsConfig.DateHandler = DateHandler.ISO8601; + + var dto = new AllFields + { + Id = 1, + NullableId = 2, + Byte = 3, + Short = 4, + Int = 5, + Long = 6, + UShort = 7, + UInt = 8, + Float = 1.1f, + Double = 2.2d, + Decimal = 3.3m, + String = "String", + DateTime = DateTime.Now, + TimeSpan = new TimeSpan(1, 1, 1, 1, 1), + Guid = Guid.NewGuid(), + NullableTimeSpan = new TimeSpan(2, 2, 2), + NullableGuid = new Guid("4B6BB8AE-57B5-4B5B-8632-0C35AF0B3168"), + }; + + Cache.Set("allfields", dto); + var fromCache = Cache.Get("allfields"); + + Assert.That(fromCache.DateTime, Is.EqualTo(dto.DateTime)); + + Assert.That(fromCache.Equals(dto)); + + JsConfig.Reset(); + } + + [Test] + public void Can_RemoveAll_and_GetKeysStartingWith_with_prefix() + { + var cache = Cache.WithPrefix("prefix."); + + cache.Set("test_QUERY_Deposit__Query_Deposit_10_1", "A"); + cache.Set("test_QUERY_Deposit__0_1___CUSTOM", "B"); + + var keys = cache.GetKeysStartingWith("test_QUERY_Deposit").ToList(); + Assert.That(keys.Count, Is.EqualTo(2)); + + cache.RemoveAll(keys); + + var newKeys = cache.GetKeysStartingWith("test_QUERY_Deposit").ToList(); + Assert.That(newKeys.Count, Is.EqualTo(0)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/TestConfig.cs b/tests/ServiceStack.Server.Tests/TestConfig.cs new file mode 100644 index 00000000000..45c3bd69384 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/TestConfig.cs @@ -0,0 +1,44 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using ServiceStack.Logging; +using ServiceStack.Redis; +using ServiceStack.Support; + +namespace ServiceStack.Server.Tests +{ + public static class TestConfig + { + static TestConfig() + { + LogManager.LogFactory = new InMemoryLogFactory(); + } + + public const bool IgnoreLongTests = true; + + public const string SingleHost = "localhost"; + public static readonly string[] MasterHosts = new[] { "localhost" }; + public static readonly string[] SlaveHosts = new[] { "localhost" }; + + public const int RedisPort = 6379; + + public static string SingleHostConnectionString + { + get + { + return SingleHost + ":" + RedisPort; + } + } + + public static BasicRedisClientManager BasicClientManger + { + get + { + return new BasicRedisClientManager(new[] { + SingleHostConnectionString + }); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/TestSessionPage.cshtml b/tests/ServiceStack.Server.Tests/TestSessionPage.cshtml new file mode 100644 index 00000000000..d668a6834eb --- /dev/null +++ b/tests/ServiceStack.Server.Tests/TestSessionPage.cshtml @@ -0,0 +1,7 @@ +@{ + var session = base.GetSession(); +} + +IsAuthenticated:@session.IsAuthenticated + + \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/TransientServiceMessagingTests.cs b/tests/ServiceStack.Server.Tests/TransientServiceMessagingTests.cs new file mode 100644 index 00000000000..63bc2b6348d --- /dev/null +++ b/tests/ServiceStack.Server.Tests/TransientServiceMessagingTests.cs @@ -0,0 +1,118 @@ +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Server.Tests.Messaging; +using ServiceStack.Server.Tests.Services; + +namespace ServiceStack.Server.Tests +{ + public abstract class TransientServiceMessagingTests + : MessagingHostTestBase + { + public override void OnBeforeEachTest() + { + base.OnBeforeEachTest(); + + Container.Register(c => new GreetService()); + Container.Register(c => new AlwaysFailService()); + Container.Register(c => new UnRetryableFailService()); + } + + [Test] + public void Normal_GreetService_client_and_server_example() + { + var service = Container.Resolve(); + using (var serviceHost = CreateMessagingService()) + { + serviceHost.RegisterHandler(m => service.Any(m.GetBody())); + + serviceHost.Start(); + + using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) + { + client.Publish(new Greet { Name = "World!" }); + } + + Assert.That(service.Result, Is.EqualTo("Hello, World!")); + Assert.That(service.TimesCalled, Is.EqualTo(1)); + } + } + + [Test] + public void Publish_before_starting_host_GreetService_client_and_server_example() + { + var service = Container.Resolve(); + using (var serviceHost = CreateMessagingService()) + { + using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) + { + client.Publish(new Greet { Name = "World!" }); + } + + serviceHost.RegisterHandler(m => service.Any(m.GetBody())); + serviceHost.Start(); + + Assert.That(service.Result, Is.EqualTo("Hello, World!")); + Assert.That(service.TimesCalled, Is.EqualTo(1)); + } + } + + [Test] + public void AlwaysFailsService_ends_up_in_dlq_after_3_attempts() + { + var service = Container.Resolve(); + var request = new AlwaysFail { Name = "World!" }; + using (var serviceHost = CreateMessagingService()) + { + using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) + { + client.Publish(request); + } + + serviceHost.RegisterHandler(m => service.Any(m.GetBody())); + serviceHost.Start(); + + Assert.That(service.Result, Is.Null); + Assert.That(service.TimesCalled, Is.EqualTo(3)); + + using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) + { + var dlqMessage = client.GetAsync(QueueNames.Dlq); + client.Ack(dlqMessage); + + Assert.That(dlqMessage, Is.Not.Null); + Assert.That(dlqMessage.GetBody().Name, Is.EqualTo(request.Name)); + } + } + } + + [Test] + public void UnRetryableFailService_ends_up_in_dlq_after_1_attempt() + { + var service = Container.Resolve(); + var request = new UnRetryableFail { Name = "World!" }; + using (var serviceHost = CreateMessagingService()) + { + using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) + { + client.Publish(request); + } + + serviceHost.RegisterHandler(m => service.Any(m.GetBody())); + serviceHost.Start(); + + Assert.That(service.Result, Is.Null); + Assert.That(service.TimesCalled, Is.EqualTo(1)); + + using (var client = serviceHost.MessageFactory.CreateMessageQueueClient()) + { + var dlqMessage = client.GetAsync(QueueNames.Dlq); + client.Ack(dlqMessage); + + Assert.That(dlqMessage, Is.Not.Null); + Assert.That(dlqMessage.GetBody().Name, Is.EqualTo(request.Name)); + } + } + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.Server.Tests/Views/Secured.cshtml b/tests/ServiceStack.Server.Tests/Views/Secured.cshtml new file mode 100644 index 00000000000..3f06c4e9165 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Views/Secured.cshtml @@ -0,0 +1,11 @@ +@inherits ViewPage + +@{ + base.RedirectIfNotAuthenticated(); +} + +

    Secure View

    + +

    @Model.Result

    + + \ No newline at end of file diff --git a/tests/RazorRockstars.Console/Views/Shared/_Layout.cshtml b/tests/ServiceStack.Server.Tests/Views/Shared/_Layout.cshtml similarity index 100% rename from tests/RazorRockstars.Console/Views/Shared/_Layout.cshtml rename to tests/ServiceStack.Server.Tests/Views/Shared/_Layout.cshtml diff --git a/tests/ServiceStack.Server.Tests/Views/TestSessionView.cshtml b/tests/ServiceStack.Server.Tests/Views/TestSessionView.cshtml new file mode 100644 index 00000000000..ee2c7e84e05 --- /dev/null +++ b/tests/ServiceStack.Server.Tests/Views/TestSessionView.cshtml @@ -0,0 +1,8 @@ +@inherits ViewPage +@{ + var session = base.GetSession(); +} + +IsAuthenticated:@session.IsAuthenticated + + \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/App.config b/tests/ServiceStack.ServiceHost.Tests/App.config index 69170eedc79..39824fe2bf2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/App.config +++ b/tests/ServiceStack.ServiceHost.Tests/App.config @@ -1,5 +1,8 @@ - + + + + @@ -10,18 +13,35 @@ compilerOptions="" warningLevel="1" />--> - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs b/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs index 13600b5d6f2..1ace56648ec 100644 --- a/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs +++ b/tests/ServiceStack.ServiceHost.Tests/AppData/FormatHelpers.cs @@ -2,19 +2,19 @@ namespace ServiceStack.ServiceHost.Tests.AppData { - public class FormatHelpers - { - public static FormatHelpers Instance = new FormatHelpers(); + public class FormatHelpers + { + public static FormatHelpers Instance = new FormatHelpers(); - public string Money(decimal value) - { - return value.ToString("C"); - } + public string Money(decimal value) + { + return value.ToString("C"); + } - public string ShortDate(DateTime? dateTime) - { - if (dateTime == null) return ""; - return String.Format("{0:dd/MM/yyyy}", dateTime); - } - } + public string ShortDate(DateTime? dateTime) + { + if (dateTime == null) return ""; + return String.Format("{0:dd/MM/yyyy}", dateTime); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindCustomers.cs b/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindCustomers.cs index b41345a1ceb..76f8e03fd93 100644 --- a/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindCustomers.cs +++ b/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindCustomers.cs @@ -1,208 +1,207 @@ using System; using System.Collections.Generic; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.ServiceHost.Tests.AppData { - public class Customers { } - - public class CustomersResponse : IHasResponseStatus - { - public CustomersResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Customers = new List(); - } - public List Customers { get; set; } - public ResponseStatus ResponseStatus { get; set; } - } - - public class CustomerDetails - { - public string Id { get; set; } - } - - public class CustomerDetailsResponse : IHasResponseStatus - { - public CustomerDetailsResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.CustomerOrders = new List(); - } - public Customer Customer { get; set; } - public List CustomerOrders { get; set; } - public ResponseStatus ResponseStatus { get; set; } - } - - public class Orders - { - public int? Page { get; set; } - public string CustomerId { get; set; } - } - - public class OrdersResponse : IHasResponseStatus - { - public OrdersResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Results = new List(); - } - public List Results { get; set; } - public ResponseStatus ResponseStatus { get; set; } - } - - public class Category - { - public int Id { get; set; } - public string CategoryName { get; set; } - public string Description { get; set; } - } - - public class Customer - { - public string Id { get; set; } - public string CompanyName { get; set; } - public string ContactName { get; set; } - public string ContactTitle { get; set; } - public string Address { get; set; } - public string City { get; set; } - public string Region { get; set; } - public string PostalCode { get; set; } - public string Country { get; set; } - public string Phone { get; set; } - public string Fax { get; set; } - public string Email - { - get { return this.ContactName.Replace(" ", ".").ToLower() + "@gmail.com"; } - } - } - - public class CustomerCustomerDemo - { - public string Id { get; set; } - public string CustomerTypeId { get; set; } - } - - public class CustomerDemographic - { - public string Id { get; set; } - public string CustomerDesc { get; set; } - } - - public class CustomerOrder - { - public CustomerOrder() - { - this.OrderDetails = new List(); - } - public Order Order { get; set; } - public List OrderDetails { get; set; } - } - - public class Employee - { - public int Id { get; set; } - public string LastName { get; set; } - public string FirstName { get; set; } - public string Title { get; set; } - public string TitleOfCourtesy { get; set; } - public DateTime? BirthDate { get; set; } - public DateTime? HireDate { get; set; } - public string Address { get; set; } - public string City { get; set; } - public string Region { get; set; } - public string PostalCode { get; set; } - public string Country { get; set; } - public string HomePhone { get; set; } - public string Extension { get; set; } - public byte[] Photo { get; set; } - public string Notes { get; set; } - public int? ReportsTo { get; set; } - public string PhotoPath { get; set; } - } - - public class EmployeeTerritory - { - public string Id { get { return this.EmployeeId + "/" + this.TerritoryId; } } - public int EmployeeId { get; set; } - public string TerritoryId { get; set; } - } - - public class Order - { - public int Id { get; set; } - public string CustomerId { get; set; } - public int EmployeeId { get; set; } - public DateTime? OrderDate { get; set; } - public DateTime? RequiredDate { get; set; } - public DateTime? ShippedDate { get; set; } - public int? ShipVia { get; set; } - public decimal Freight { get; set; } - public string ShipName { get; set; } - public string ShipAddress { get; set; } - public string ShipCity { get; set; } - public string ShipRegion { get; set; } - public string ShipPostalCode { get; set; } - public string ShipCountry { get; set; } - } - - public class OrderDetail - { - public string Id { get { return this.OrderId + "/" + this.ProductId; } } - public int OrderId { get; set; } - public int ProductId { get; set; } - public decimal UnitPrice { get; set; } - public short Quantity { get; set; } - public double Discount { get; set; } - } - - public class Product - { - public int Id { get; set; } - public string ProductName { get; set; } - public int SupplierId { get; set; } - public int CategoryId { get; set; } - public string QuantityPerUnit { get; set; } - public decimal UnitPrice { get; set; } - public short UnitsInStock { get; set; } - public short UnitsOnOrder { get; set; } - public short ReorderLevel { get; set; } - public bool Discontinued { get; set; } - } - - public class Region - { - public int Id { get; set; } - public string RegionDescription { get; set; } - } - - public class Shipper - { - public int Id { get; set; } - public string CompanyName { get; set; } - public string Phone { get; set; } - } - - public class Supplier - { - public int Id { get; set; } - public string CompanyName { get; set; } - public string ContactName { get; set; } - public string ContactTitle { get; set; } - public string Address { get; set; } - public string City { get; set; } - public string Region { get; set; } - public string PostalCode { get; set; } - public string Country { get; set; } - public string Phone { get; set; } - public string Fax { get; set; } - public string HomePage { get; set; } - } - - public class Territory - { - public string Id { get; set; } - public string TerritoryDescription { get; set; } - public int RegionId { get; set; } - } + public class Customers { } + + public class CustomersResponse : IHasResponseStatus + { + public CustomersResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Customers = new List(); + } + public List Customers { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomerDetails + { + public string Id { get; set; } + } + + public class CustomerDetailsResponse : IHasResponseStatus + { + public CustomerDetailsResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.CustomerOrders = new List(); + } + public Customer Customer { get; set; } + public List CustomerOrders { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class Orders + { + public int? Page { get; set; } + public string CustomerId { get; set; } + } + + public class OrdersResponse : IHasResponseStatus + { + public OrdersResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new List(); + } + public List Results { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class Category + { + public int Id { get; set; } + public string CategoryName { get; set; } + public string Description { get; set; } + } + + public class Customer + { + public string Id { get; set; } + public string CompanyName { get; set; } + public string ContactName { get; set; } + public string ContactTitle { get; set; } + public string Address { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string Phone { get; set; } + public string Fax { get; set; } + public string Email + { + get { return this.ContactName.Replace(" ", ".").ToLower() + "@gmail.com"; } + } + } + + public class CustomerCustomerDemo + { + public string Id { get; set; } + public string CustomerTypeId { get; set; } + } + + public class CustomerDemographic + { + public string Id { get; set; } + public string CustomerDesc { get; set; } + } + + public class CustomerOrder + { + public CustomerOrder() + { + this.OrderDetails = new List(); + } + public Order Order { get; set; } + public List OrderDetails { get; set; } + } + + public class Employee + { + public int Id { get; set; } + public string LastName { get; set; } + public string FirstName { get; set; } + public string Title { get; set; } + public string TitleOfCourtesy { get; set; } + public DateTime? BirthDate { get; set; } + public DateTime? HireDate { get; set; } + public string Address { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string HomePhone { get; set; } + public string Extension { get; set; } + public byte[] Photo { get; set; } + public string Notes { get; set; } + public int? ReportsTo { get; set; } + public string PhotoPath { get; set; } + } + + public class EmployeeTerritory + { + public string Id { get { return this.EmployeeId + "/" + this.TerritoryId; } } + public int EmployeeId { get; set; } + public string TerritoryId { get; set; } + } + + public class Order + { + public int Id { get; set; } + public string CustomerId { get; set; } + public int EmployeeId { get; set; } + public DateTime? OrderDate { get; set; } + public DateTime? RequiredDate { get; set; } + public DateTime? ShippedDate { get; set; } + public int? ShipVia { get; set; } + public decimal Freight { get; set; } + public string ShipName { get; set; } + public string ShipAddress { get; set; } + public string ShipCity { get; set; } + public string ShipRegion { get; set; } + public string ShipPostalCode { get; set; } + public string ShipCountry { get; set; } + } + + public class OrderDetail + { + public string Id { get { return this.OrderId + "/" + this.ProductId; } } + public int OrderId { get; set; } + public int ProductId { get; set; } + public decimal UnitPrice { get; set; } + public short Quantity { get; set; } + public double Discount { get; set; } + } + + public class Product + { + public int Id { get; set; } + public string ProductName { get; set; } + public int SupplierId { get; set; } + public int CategoryId { get; set; } + public string QuantityPerUnit { get; set; } + public decimal UnitPrice { get; set; } + public short UnitsInStock { get; set; } + public short UnitsOnOrder { get; set; } + public short ReorderLevel { get; set; } + public bool Discontinued { get; set; } + } + + public class Region + { + public int Id { get; set; } + public string RegionDescription { get; set; } + } + + public class Shipper + { + public int Id { get; set; } + public string CompanyName { get; set; } + public string Phone { get; set; } + } + + public class Supplier + { + public int Id { get; set; } + public string CompanyName { get; set; } + public string ContactName { get; set; } + public string ContactTitle { get; set; } + public string Address { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string Phone { get; set; } + public string Fax { get; set; } + public string HomePage { get; set; } + } + + public class Territory + { + public string Id { get; set; } + public string TerritoryDescription { get; set; } + public int RegionId { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindHelpers.cs b/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindHelpers.cs index ad37b9d00b1..7be13728332 100644 --- a/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindHelpers.cs +++ b/tests/ServiceStack.ServiceHost.Tests/AppData/NorthwindHelpers.cs @@ -1,27 +1,26 @@ using System.Collections.Generic; using System.Linq; -using ServiceStack.Common; namespace ServiceStack.ServiceHost.Tests.AppData { - public class NorthwindHelpers - { - public string OrderTotal(List orderDetails) - { - var total = 0m; - if (!orderDetails.IsEmpty()) - total += orderDetails.Sum(item => item.Quantity * item.UnitPrice); + public class NorthwindHelpers + { + public string OrderTotal(List orderDetails) + { + var total = 0m; + if (!orderDetails.IsEmpty()) + total += orderDetails.Sum(item => item.Quantity * item.UnitPrice); - return FormatHelpers.Instance.Money(total); - } + return FormatHelpers.Instance.Money(total); + } - public string CustomerOrderTotal(List customerOrders) - { - var total = customerOrders - .Sum(x => - x.OrderDetails.Sum(item => item.Quantity*item.UnitPrice)); - - return FormatHelpers.Instance.Money(total); - } - } + public string CustomerOrderTotal(List customerOrders) + { + var total = customerOrders + .Sum(x => + x.OrderDetails.Sum(item => item.Quantity * item.UnitPrice)); + + return FormatHelpers.Instance.Money(total); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/BasicAppHostTests.cs b/tests/ServiceStack.ServiceHost.Tests/BasicAppHostTests.cs index 366ed5a928f..c393af07787 100644 --- a/tests/ServiceStack.ServiceHost.Tests/BasicAppHostTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/BasicAppHostTests.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ServiceStack.ServiceInterface.Testing; -using NUnit.Framework; +using NUnit.Framework; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests { diff --git a/tests/ServiceStack.ServiceHost.Tests/Examples/FunqEasyRegistrationHelper.cs b/tests/ServiceStack.ServiceHost.Tests/Examples/FunqEasyRegistrationHelper.cs index 0bceb053226..1780668a4b2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Examples/FunqEasyRegistrationHelper.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Examples/FunqEasyRegistrationHelper.cs @@ -6,64 +6,64 @@ namespace ServiceStack.ServiceHost.Tests.Examples { - /// - /// Funq helper for easy registration. - /// - public static class FunqEasyRegistrationHelper - { - /// - /// Register a service with the default, look-up-all_dependencies-from-the-container behavior. - /// - /// interface type - /// implementing type - /// Funq container - public static void EasyRegister(this Container container) where implT : interfaceT - { - var lambdaParam = Expression.Parameter(typeof(Container), "ref_to_the_container_passed_into_the_lambda"); + /// + /// Funq helper for easy registration. + /// + public static class FunqEasyRegistrationHelper + { + /// + /// Register a service with the default, look-up-all_dependencies-from-the-container behavior. + /// + /// interface type + /// implementing type + /// Funq container + public static void EasyRegister(this Container container) where implT : interfaceT + { + var lambdaParam = Expression.Parameter(typeof(Container), "ref_to_the_container_passed_into_the_lambda"); - var constructorExpression = BuildImplConstructorExpression(lambdaParam); - var compiledExpression = CompileInterfaceConstructor(lambdaParam, constructorExpression); + var constructorExpression = BuildImplConstructorExpression(lambdaParam); + var compiledExpression = CompileInterfaceConstructor(lambdaParam, constructorExpression); - container.Register(compiledExpression); - } + container.Register(compiledExpression); + } - private static readonly MethodInfo FunqContainerResolveMethod; + private static readonly MethodInfo FunqContainerResolveMethod; - static FunqEasyRegistrationHelper() - { - FunqContainerResolveMethod = typeof(Container).GetMethod("Resolve", new Type[0]); - } + static FunqEasyRegistrationHelper() + { + FunqContainerResolveMethod = typeof(Container).GetMethod("Resolve", new Type[0]); + } - private static NewExpression BuildImplConstructorExpression(Expression lambdaParam) - { - var ctorWithMostParameters = GetConstructorWithMostParameters(); + private static NewExpression BuildImplConstructorExpression(Expression lambdaParam) + { + var ctorWithMostParameters = GetConstructorWithMostParameters(); - var constructorParameterInfos = ctorWithMostParameters.GetParameters(); - var regParams = constructorParameterInfos.Select(pi => GetParameterCreationExpression(pi, lambdaParam)); + var constructorParameterInfos = ctorWithMostParameters.GetParameters(); + var regParams = constructorParameterInfos.Select(pi => GetParameterCreationExpression(pi, lambdaParam)); - return Expression.New(ctorWithMostParameters, regParams.ToArray()); - } + return Expression.New(ctorWithMostParameters, regParams.ToArray()); + } - private static Func CompileInterfaceConstructor(ParameterExpression lambdaParam, Expression constructorExpression) - { - var constructorLambda = Expression.Lambda>(constructorExpression, lambdaParam); - return constructorLambda.Compile(); - } + private static Func CompileInterfaceConstructor(ParameterExpression lambdaParam, Expression constructorExpression) + { + var constructorLambda = Expression.Lambda>(constructorExpression, lambdaParam); + return constructorLambda.Compile(); + } - private static ConstructorInfo GetConstructorWithMostParameters() - { - return typeof(implT) - .GetConstructors() - .OrderBy(x => x.GetParameters().Length) - .Where(ctor => !ctor.IsStatic) - .Last(); - } + private static ConstructorInfo GetConstructorWithMostParameters() + { + return typeof(implT) + .GetConstructors() + .OrderBy(x => x.GetParameters().Length) + .Where(ctor => !ctor.IsStatic) + .Last(); + } - private static MethodCallExpression GetParameterCreationExpression(ParameterInfo pi, Expression lambdaParam) - { - var method = FunqContainerResolveMethod.MakeGenericMethod(pi.ParameterType); - return Expression.Call(lambdaParam, method); - } + private static MethodCallExpression GetParameterCreationExpression(ParameterInfo pi, Expression lambdaParam) + { + var method = FunqContainerResolveMethod.MakeGenericMethod(pi.ParameterType); + return Expression.Call(lambdaParam, method); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Examples/funq_easy_registration.cs b/tests/ServiceStack.ServiceHost.Tests/Examples/funq_easy_registration.cs index 24a3b098c9e..c640081b2d2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Examples/funq_easy_registration.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Examples/funq_easy_registration.cs @@ -4,74 +4,74 @@ namespace ServiceStack.ServiceHost.Tests.Examples { - /// - /// Other examples - ///https://source.db4o.com/db4o/trunk/db4o.net/Libs/compact-3.5/System.Linq.Expressions/Test/System.Linq.Expressions/ExpressionTest_MemberInit.cs - /// - [TestFixture] - public class FunqEasyRegistration - { - public interface IFoo { } + /// + /// Other examples + ///https://source.db4o.com/db4o/trunk/db4o.net/Libs/compact-3.5/System.Linq.Expressions/Test/System.Linq.Expressions/ExpressionTest_MemberInit.cs + /// + [TestFixture] + public class FunqEasyRegistration + { + public interface IFoo { } - public class Foo : IFoo { } + public class Foo : IFoo { } - public interface IBar { } + public interface IBar { } - public class Bar : IBar - { - public IFoo Foo { get; set; } + public class Bar : IBar + { + public IFoo Foo { get; set; } - public Bar(IFoo foo) - { - Foo = foo; - } - } + public Bar(IFoo foo) + { + Foo = foo; + } + } - public interface IBaz { } + public interface IBaz { } - public class Baz : IBaz - { - public IBar Bar { get; set; } + public class Baz : IBaz + { + public IBar Bar { get; set; } - public Baz(IBar bar) - { - Bar = bar; - } - } + public Baz(IBar bar) + { + Bar = bar; + } + } - [Test] - public void should_be_able_to_get_service_impl() - { - var c = new Container(); - c.EasyRegister(); + [Test] + public void should_be_able_to_get_service_impl() + { + var c = new Container(); + c.EasyRegister(); - Assert.IsInstanceOf(c.Resolve()); - } + Assert.IsInstanceOf(c.Resolve()); + } - [Test] - public void should_be_able_to_inject_dependency() - { - var c = new Container(); - c.EasyRegister(); - c.EasyRegister(); + [Test] + public void should_be_able_to_inject_dependency() + { + var c = new Container(); + c.EasyRegister(); + c.EasyRegister(); - var bar = c.Resolve() as Bar; + var bar = c.Resolve() as Bar; - Assert.IsNotNull(bar.Foo); - } + Assert.IsNotNull(bar.Foo); + } - [Test] - public void should_be_able_to_chain_dependencies() - { - var c = new Container(); - var testFoo = new Foo(); - c.Register(testFoo); - c.EasyRegister(); - c.EasyRegister(); - var baz = c.Resolve() as Baz; + [Test] + public void should_be_able_to_chain_dependencies() + { + var c = new Container(); + var testFoo = new Foo(); + c.Register(testFoo); + c.EasyRegister(); + c.EasyRegister(); + var baz = c.Resolve() as Baz; - var bar = baz.Bar as Bar; - Assert.AreSame(bar.Foo, testFoo); - } - } + var bar = baz.Bar as Bar; + Assert.AreSame(bar.Foo, testFoo); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionExampleTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionExampleTests.cs index bdb68a31810..c79a62a5663 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionExampleTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionExampleTests.cs @@ -6,72 +6,72 @@ namespace ServiceStack.ServiceHost.Tests.Formats { - public class Product - { - public Product(){} - public Product(string name, decimal price) - { - Name = name; - Price = price; - } - - public int ProductID { get; set; } - public string Name { get; set; } - public decimal Price { get; set; } - } - - [TestFixture] - public class IntroductionExampleTests : MarkdownTestBase - { - private List products; - Dictionary productArgs; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - this.products = new List { - new Product("Pen", 1.99m), - new Product("Glass", 9.99m), - new Product("Book", 14.99m), - new Product("DVD", 11.99m), - }; - productArgs = new Dictionary { { "products", products } }; - } - - [Test] - public void Basic_Razor_Example() - { - var template = + public class Product + { + public Product() { } + public Product(string name, decimal price) + { + Name = name; + Price = price; + } + + public int ProductID { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + } + + [TestFixture] + public class IntroductionExampleTests : MarkdownTestBase + { + private List products; + Dictionary productArgs; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + this.products = new List { + new Product("Pen", 1.99m), + new Product("Glass", 9.99m), + new Product("Book", 14.99m), + new Product("DVD", 11.99m), + }; + productArgs = new Dictionary { { "products", products } }; + } + + [Test] + public void Basic_Razor_Example() + { + var template = @"# Razor Example ### Hello @name, the year is @DateTime.Now.Year Checkout [this product](/Product/Details/@productId)"; - var expectedHtml = + var expectedHtml = @"

    Razor Example

    -

    Hello Demis, the year is 2013

    +

    Hello Demis, the year is 2022

    Checkout this product

    ".NormalizeNewLines(); - var html = RenderToHtml(template, new Dictionary { - {"name", "Demis"}, {"productId", 10} }); + var html = RenderToHtml(template, new Dictionary { + {"name", "Demis"}, {"productId", 10} }); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Simple_loop() - { - var template = @" + [Test] + public void Simple_loop() + { + var template = @" @foreach (var p in products) { - @p.Name: (@p.Price) } "; - var expectedHtml = + var expectedHtml = @"
    • Pen: (1.99)
    • Glass: (9.99)
    • @@ -80,23 +80,23 @@ public void Simple_loop()
    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Simple_loop_with_parens_free_syntax() - { - var template = @" + [Test] + public void Simple_loop_with_parens_free_syntax() + { + var template = @" @foreach p in products { - @p.Name: (@p.Price) } "; - var expectedHtml = + var expectedHtml = @"
    • Pen: (1.99)
    • Glass: (9.99)
    • @@ -105,17 +105,17 @@ @foreach p in products {
    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void If_Statment() - { - var template = @" + [Test] + public void If_Statment() + { + var template = @" @if (products.Count == 0) { Sorry - no products in this category } else { @@ -123,20 +123,20 @@ public void If_Statment() } "; - var expectedHtml = + var expectedHtml = @"

    We have products for you!

    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void If_Statment_with_parens_free_syntax() - { - var template = @" + [Test] + public void If_Statment_with_parens_free_syntax() + { + var template = @" @if products.Count == 0 { Sorry - no products in this category } else { @@ -144,100 +144,100 @@ public void If_Statment_with_parens_free_syntax() } "; - var expectedHtml = + var expectedHtml = @"

    We have products for you!

    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Multi_variable_declarations() - { - var template = @" + [Test] + public void Multi_variable_declarations() + { + var template = @" @var number = 1 @var message = ""Number is "" + number Your Message: @message "; - var expectedHtml = @"

    Your Message: Number is 1

    + var expectedHtml = @"

    Your Message: Number is 1

    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Integrating_content_and_code() - { - var template = + [Test] + public void Integrating_content_and_code() + { + var template = @"Send mail to demis.bellot@gmail.com telling him the time: @DateTime.Now. "; - var expectedHtml = + var expectedHtml = @"

    Send mail to demis.bellot@gmail.com telling him the time: 02/06/2011 06:38:34.

    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); - Console.WriteLine(html); - Assert.That(html, Is.StringMatching(expectedHtml.Substring(0, expectedHtml.Length - 25))); - } + Console.WriteLine(html); + Assert.That(html, Does.Match(expectedHtml.Substring(0, expectedHtml.Length - 25))); + } - [Test] - public void Identifying_nested_content() - { - var template = + [Test] + public void Identifying_nested_content() + { + var template = @" -@if (DateTime.Now.Year == 2013) { +@if (DateTime.Now.Year == 2022) { -If the year is 2013 then print this +If the year is 2022 then print this multi-line text block and the date: @DateTime.Now } ".NormalizeNewLines(); - var expectedHtml = -@"

    If the year is 2013 then print this + var expectedHtml = +@"

    If the year is 2022 then print this multi-line text block and -the date: 02/06/2013 06:42:45

    +the date: 02/06/2014 06:42:45

    ".NormalizeNewLines(); - var html = RenderToHtml(template, productArgs); + var html = RenderToHtml(template, productArgs); html.Print(); - Assert.That(html.Substring(0,html.Length-27), + Assert.That(html.Substring(0, html.Length - 27), Is.EqualTo(expectedHtml.Substring(0, html.Length - 27))); - } + } - [Test] - public void HTML_encoding() - { - var template = + [Test] + public void HTML_encoding() + { + var template = @" Some Content @stringContainingHtml "; - var expectedHtml = + var expectedHtml = @"

    Some Content <span>html</span>

    ".NormalizeNewLines(); - var html = RenderToHtml(template, new Dictionary { - {"stringContainingHtml", "html"} - }); + var html = RenderToHtml(template, new Dictionary { + {"stringContainingHtml", "html"} + }); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionLayoutTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionLayoutTests.cs index 598c02dd79b..602acbff65c 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionLayoutTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/IntroductionLayoutTests.cs @@ -2,64 +2,78 @@ using System.Collections.Generic; using System.Text; using NUnit.Framework; +using ServiceStack.Formats; using ServiceStack.Html; using ServiceStack.Markdown; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.Support.Markdown; +using ServiceStack.Testing; +using ServiceStack.IO; namespace ServiceStack.ServiceHost.Tests.Formats { - public class ExternalProductHelper - { - //Any helpers returning MvcHtmlString won't be escaped - public MvcHtmlString ProductTable(List products) - { - var sb = new StringBuilder(); - sb.AppendFormat("
    \n"); - products.ForEach(x => - sb.AppendFormat("\n", - x.ProductID, x.Name, x.Price) - ); - sb.AppendFormat("
    IdNamePrice
    {0}{1}{2}
    \n"); - - return MvcHtmlString.Create(sb.ToString()); - } - } - - public class CustomBaseClass : MarkdownViewBase - { - public MvcHtmlString Field(string fieldName, string fieldValue) - { - var sb = new StringBuilder(); - sb.AppendFormat("\n", fieldName); - sb.AppendFormat("\n", fieldName, fieldValue); - - return MvcHtmlString.Create(sb.ToString()); - } - } - - [TestFixture] - public class IntroductionLayoutTests : MarkdownTestBase - { - private InMemoryVirtualPathProvider pathProvider; - private MarkdownFormat markdownFormat; - - [SetUp] - public void SetUp() - { - EndpointHost.VirtualPathProvider = pathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()); - markdownFormat = new MarkdownFormat { + public class ExternalProductHelper + { + //Any helpers returning MvcHtmlString won't be escaped + public MvcHtmlString ProductTable(List products) + { + var sb = new StringBuilder(); + sb.AppendFormat("\n"); + products.ForEach(x => + sb.AppendFormat("\n", + x.ProductID, x.Name, x.Price) + ); + sb.AppendFormat("
    IdNamePrice
    {0}{1}{2}
    \n"); + + return MvcHtmlString.Create(sb.ToString()); + } + } + + public class CustomBaseClass : MarkdownViewBase + { + public MvcHtmlString Field(string fieldName, string fieldValue) + { + var sb = new StringBuilder(); + sb.AppendFormat("\n", fieldName); + sb.AppendFormat("\n", fieldName, fieldValue); + + return MvcHtmlString.Create(sb.ToString()); + } + } + + [TestFixture] + public class IntroductionLayoutTests : MarkdownTestBase + { + private MemoryVirtualFiles pathProvider; + private MarkdownFormat markdownFormat; + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [SetUp] + public void SetUp() + { + ServiceStackHost.Instance.VirtualFileSources = pathProvider = new MemoryVirtualFiles(); + markdownFormat = new MarkdownFormat + { VirtualPathProvider = pathProvider, }; } - [Test] - public void Simple_Layout_Example() - { - var websiteTemplate = + [Test] + public void Simple_Layout_Example() + { + var websiteTemplate = @" @@ -78,7 +92,7 @@ public void Simple_Layout_Example() ".NormalizeNewLines(); - var pageTemplate = + var pageTemplate = @"@Layout websiteTemplate # About this Site @@ -92,7 +106,7 @@ And obviously I can have code in here too. Here is the current date/year: @DateTime.Now.Year ".NormalizeNewLines(); - var expectedHtml = @" + var expectedHtml = @" Simple Site @@ -111,30 +125,30 @@ page of our web-site. We'll use this in conjunction with a layout template. The content you are seeing here comes from ^^^websiteTemplate.

    And obviously I can have code in here too. Here is the -current date/year: 2013

    +current date/year: 2022

    ".NormalizeNewLines(); - - markdownFormat.AddFileAndPage( - new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); - markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); + markdownFormat.AddFileAndPage( + new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); - var html = markdownFormat.RenderDynamicPageHtml(PageName); + markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + var html = markdownFormat.RenderDynamicPageHtml(PageName); + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Layout_MasterPage_Scenarios_Adding_Sections() - { - var websiteTemplate = + + [Test] + public void Layout_MasterPage_Scenarios_Adding_Sections() + { + var websiteTemplate = @" @@ -162,7 +176,7 @@ public void Layout_MasterPage_Scenarios_Adding_Sections() ".NormalizeNewLines(); - var pageTemplate = + var pageTemplate = @"@Layout websiteTemplate # About this Site @@ -185,7 +199,7 @@ @section Footer { } ".NormalizeNewLines(); - var expectedHtml = @" + var expectedHtml = @" Simple Site @@ -212,7 +226,7 @@ page of our web-site. We'll use this in conjunction with a layout template. The content you are seeing here comes from ^^^websiteTemplate.

    And obviously I can have code in here too. Here is the -current date/year: 2013

    +current date/year: 2022

    @@ -225,21 +239,21 @@ comes from ^^^websiteTemplate.

    ".NormalizeNewLines(); - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); + markdownFormat.AddPage( + new MarkdownPage(markdownFormat, @"C:\path\to\page-tpl", PageName, pageTemplate)); - markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); + markdownFormat.AddFileAndTemplate(@"websiteTemplate", websiteTemplate); - var html = markdownFormat.RenderDynamicPageHtml(PageName); + var html = markdownFormat.RenderDynamicPageHtml(PageName); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Encapsulation_and_reuse_with_HTML_helpers() - { - var pageTemplate = + [Test] + public void Encapsulation_and_reuse_with_HTML_helpers() + { + var pageTemplate = @"@model ServiceStack.ServiceHost.Tests.Formats.Product
    Edit Product @@ -251,7 +265,7 @@ public void Encapsulation_and_reuse_with_HTML_helpers()
    ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"
    Edit Product
    @@ -260,17 +274,17 @@ public void Encapsulation_and_reuse_with_HTML_helpers()
    ".NormalizeNewLines(); - var product = new Product {ProductID = 10}; - var html = RenderToHtml(pageTemplate, product); + var product = new Product { ProductID = 10 }; + var html = RenderToHtml(pageTemplate, product); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Using_External_HTML_Helpers() - { - var pageTemplate = + [Test] + public void Using_External_HTML_Helpers() + { + var pageTemplate = @"@model System.Collections.Generic.List @helper Prod: ServiceStack.ServiceHost.Tests.Formats.ExternalProductHelper @@ -279,7 +293,7 @@ public void Using_External_HTML_Helpers() @Prod.ProductTable(Model) ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"
    All Products @@ -290,23 +304,23 @@ public void Using_External_HTML_Helpers()
    IdNamePrice
    ".NormalizeNewLines(); - var products = new List { - new Product("Pen", 1.99m), - new Product("Glass", 9.99m), - new Product("Book", 14.99m), - new Product("DVD", 11.99m), - }; - var html = RenderToHtml(pageTemplate, products); + var products = new List { + new Product("Pen", 1.99m), + new Product("Glass", 9.99m), + new Product("Book", 14.99m), + new Product("DVD", 11.99m), + }; + var html = RenderToHtml(pageTemplate, products); - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Using_Custom_base_class() - { - var pageTemplate = + [Test] + public void Using_Custom_base_class() + { + var pageTemplate = @"@inherits ServiceStack.ServiceHost.Tests.Formats.CustomBaseClass
    @@ -314,18 +328,18 @@ public void Using_Custom_base_class() @Field(""Name"", Model.Name)
    ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"
    All Products
    ".NormalizeNewLines(); - var html = RenderToHtml(pageTemplate, new Product("Pen", 1.99m)); + var html = RenderToHtml(pageTemplate, new Product("Pen", 1.99m)); + + Console.WriteLine(html); + Assert.That(html, Is.EqualTo(expectedHtml)); + } - Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatExtensions.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatExtensions.cs index cf8d81d84c0..34e533d8080 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatExtensions.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatExtensions.cs @@ -1,6 +1,6 @@ -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.Support.Markdown; namespace ServiceStack.ServiceHost.Tests.Formats { @@ -8,15 +8,15 @@ public static class MarkdownFormatExtensions { public static void AddFileAndPage(this MarkdownFormat markdown, MarkdownPage markdownPage) { - var pathProvider = (InMemoryVirtualPathProvider)markdown.VirtualPathProvider; - pathProvider.AddFile(markdownPage.FilePath, markdownPage.Contents); + var pathProvider = (MemoryVirtualFiles)markdown.VirtualPathProvider; + pathProvider.WriteFile(markdownPage.FilePath, markdownPage.Contents); markdown.AddPage(markdownPage); } public static void AddFileAndTemplate(this MarkdownFormat markdown, string filePath, string contents) { - var pathProvider = (InMemoryVirtualPathProvider)markdown.VirtualPathProvider; - pathProvider.AddFile(filePath, contents); + var pathProvider = (MemoryVirtualFiles)markdown.VirtualPathProvider; + pathProvider.WriteFile(filePath, contents); markdown.AddTemplate(filePath, contents); } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs index f102ff7d910..5356d1cbcc2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownFormatTests.cs @@ -2,114 +2,113 @@ using System.Collections.Generic; using System.IO; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Utils; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; namespace ServiceStack.ServiceHost.Tests.Formats { - [TestFixture] - public class MarkdownFormatTests - { - public class Person - { - public string FirstName { get; set; } - public string LastName { get; set; } - } - - private MarkdownFormat markdownFormat; - - string dynamicPagePath; - string dynamicPageContent; - - readonly string[] viewPageNames = new[] { - "Dynamic", "Customer", "CustomerDetailsResponse", "DynamicListTpl", - "DynamicNestedTpl", "DynamicTpl", - }; - readonly string[] sharedViewPageNames = new[] { - "DynamicShared", "DynamicTplShared", - }; - readonly string[] contentPageNames = new[] { - "Static", "StaticTpl", - }; - - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - dynamicPagePath = "~/Views/Template/DynamicTpl.md".MapProjectPath(); - dynamicPageContent = File.ReadAllText(dynamicPagePath); - } - - [SetUp] - public void OnBeforeEachTest() - { - markdownFormat = new MarkdownFormat { - VirtualPathProvider = new FileSystemVirtualPathProvider(new BasicAppHost(), "~/".MapProjectPath()), + [TestFixture] + public class MarkdownFormatTests + { + public class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + + private MarkdownFormat markdownFormat; + + string dynamicPagePath; + string dynamicPageContent; + + readonly string[] viewPageNames = new[] { + "Dynamic", "Customer", "CustomerDetailsResponse", "DynamicListTpl", + "DynamicNestedTpl", "DynamicTpl", }; - } + readonly string[] sharedViewPageNames = new[] { + "DynamicShared", "DynamicTplShared", + }; + readonly string[] contentPageNames = new[] { + "Static", "StaticTpl", + }; + + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + dynamicPagePath = "~/Views/Template/DynamicTpl.md".MapProjectPath(); + dynamicPageContent = File.ReadAllText(dynamicPagePath); + } + + [SetUp] + public void OnBeforeEachTest() + { + markdownFormat = new MarkdownFormat + { + VirtualPathProvider = new FileSystemVirtualFiles("~/".MapProjectPath()), + }; + } - [Test] - public void Can_load_all_markdown_files() - { - markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); + [Test] + public void Can_load_all_markdown_files() + { + markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); - Assert.That(markdownFormat.ViewPages.Count, Is.EqualTo(viewPageNames.Length)); - Assert.That(markdownFormat.ViewSharedPages.Count, Is.EqualTo(sharedViewPageNames.Length)); - Assert.That(markdownFormat.ContentPages.Count, Is.EqualTo(contentPageNames.Length)); - Assert.That(markdownFormat.MasterPageTemplates.Count, Is.EqualTo(4)); + Assert.That(markdownFormat.ViewPages.Count, Is.EqualTo(viewPageNames.Length)); + Assert.That(markdownFormat.ViewSharedPages.Count, Is.EqualTo(sharedViewPageNames.Length)); + Assert.That(markdownFormat.ContentPages.Count, Is.EqualTo(contentPageNames.Length)); + Assert.That(markdownFormat.MasterPageTemplates.Count, Is.EqualTo(4)); - var pageNames = new List(); - markdownFormat.ViewPages.ForEach((k, v) => pageNames.Add(k)); + var pageNames = new List(); + markdownFormat.ViewPages.ForEach((k, v) => pageNames.Add(k)); - Console.WriteLine(pageNames.Dump()); - Assert.That(pageNames.EquivalentTo(viewPageNames)); - } + Console.WriteLine(pageNames.Dump()); + Assert.That(pageNames.EquivalentTo(viewPageNames)); + } - [Test] - public void Can_Render_StaticPage() - { - markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); - var html = markdownFormat.RenderStaticPageHtml("AppData/NoTemplate/Static"); + [Test] + public void Can_Render_StaticPage() + { + markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); + var html = markdownFormat.RenderStaticPageHtml("AppData/NoTemplate/Static"); - Assert.That(html, Is.Not.Null); - Assert.That(html, Is.StringStarting("

    Static Markdown template

    ")); - } + Assert.That(html, Is.Not.Null); + Assert.That(html, Does.StartWith("

    Static Markdown template

    ")); + } - [Test] - public void Can_Render_StaticPage_WithTemplate() - { - markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); - var html = markdownFormat.RenderStaticPageHtml("AppData/Template/StaticTpl"); + [Test] + public void Can_Render_StaticPage_WithTemplate() + { + markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); + var html = markdownFormat.RenderStaticPageHtml("AppData/Template/StaticTpl"); html.Print(); - Assert.That(html, Is.Not.Null); - Assert.That(html, Is.StringStarting("")); - } + Assert.That(html, Is.Not.Null); + Assert.That(html, Does.StartWith("")); + } - [Test] - public void Can_Render_DynamicPage() - { - var person = new Person { FirstName = "Demis", LastName = "Bellot" }; - markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); + [Test] + public void Can_Render_DynamicPage() + { + var person = new Person { FirstName = "Demis", LastName = "Bellot" }; + markdownFormat.RegisterMarkdownPages("~/".MapProjectPath()); - var html = markdownFormat.RenderDynamicPageHtml("Dynamic", person); + var html = markdownFormat.RenderDynamicPageHtml("Dynamic", person); var tplPath = "~/Views/Shared/_Layout.shtml".MapProjectPath(); var tplContent = File.ReadAllText(tplPath); - var expectedHtml = markdownFormat.Transform(dynamicPageContent) - .Replace("@Model.FirstName", person.FirstName) - .Replace("@Model.LastName", person.LastName); + var expectedHtml = markdownFormat.Transform(dynamicPageContent) + .Replace("@Model.FirstName", person.FirstName) + .Replace("@Model.LastName", person.LastName); expectedHtml = tplContent.Replace("", expectedHtml); "Template: {0}".Fmt(html).Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - } + Assert.That(html, Is.EqualTo(expectedHtml)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownTestBase.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownTestBase.cs index 6258896c16d..2da9dcc4fda 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownTestBase.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MarkdownTestBase.cs @@ -1,71 +1,73 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.Support.Markdown; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests.Formats { - public class MarkdownTestBase - { - public const string TemplateName = "Template"; - protected const string PageName = "Page"; + public class MarkdownTestBase + { + public const string TemplateName = "Template"; + protected const string PageName = "Page"; - public MarkdownFormat Create(string websiteTemplate, string pageTemplate) - { - var markdownFormat = new MarkdownFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()) + public MarkdownFormat Create(string websiteTemplate, string pageTemplate) + { + var markdownFormat = new MarkdownFormat + { + VirtualPathProvider = new MemoryVirtualFiles() }; markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate) { + markdownFormat.AddPage( + new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate) + { Template = "websiteTemplate", - }); + }); - return markdownFormat; - } + return markdownFormat; + } - public MarkdownFormat Create(string pageTemplate) - { - var markdownFormat = new MarkdownFormat(); - markdownFormat.AddPage( - new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate)); + public MarkdownFormat Create(string pageTemplate) + { + var markdownFormat = new MarkdownFormat(); + markdownFormat.AddPage( + new MarkdownPage(markdownFormat, "/path/to/tpl", PageName, pageTemplate)); - return markdownFormat; - } + return markdownFormat; + } - public string RenderToHtml(string pageTemplate, Dictionary scopeArgs) - { - var markdown = Create(pageTemplate); - var html = markdown.RenderDynamicPageHtml(PageName, scopeArgs); - return html; - } + public string RenderToHtml(string pageTemplate, Dictionary scopeArgs) + { + var markdown = Create(pageTemplate); + var html = markdown.RenderDynamicPageHtml(PageName, scopeArgs); + return html; + } - public string RenderToHtml(string pageTemplate, Dictionary scopeArgs, string websiteTemplate) - { - var markdown = Create(pageTemplate); - var html = markdown.RenderDynamicPageHtml(PageName, scopeArgs); - return html; - } + public string RenderToHtml(string pageTemplate, Dictionary scopeArgs, string websiteTemplate) + { + var markdown = Create(pageTemplate); + var html = markdown.RenderDynamicPageHtml(PageName, scopeArgs); + return html; + } - public string RenderToHtml(string pageTemplate, object model) - { - var markdown = Create(pageTemplate); - var html = markdown.RenderDynamicPageHtml(PageName, model); - return html; - } - } + public string RenderToHtml(string pageTemplate, object model) + { + var markdown = Create(pageTemplate); + var html = markdown.RenderDynamicPageHtml(PageName, model); + return html; + } + } - public static class MarkdownTestExtensions - { + public static class MarkdownTestExtensions + { public static string NormalizeNewLines(this string text) { return text.Replace("\r\n", "\n"); } - + public static string StripLinesAndWhitespace(this string text) { var sb = new StringBuilder(); diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/MockClass.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/MockClass.cs index 52b87f398e1..08c86b8753b 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/MockClass.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/MockClass.cs @@ -1,63 +1,54 @@ using System; using System.IO; -using System.Text; -using System.Xml; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; using NUnit.Framework; -using ServiceStack.Common.Utils; +using ServiceStack; using ServiceStack.Html; -using ServiceStack.Markdown; namespace CSharpEval { + [TestFixture] + public class _Expr + : ServiceStack.ServiceHost.Tests.Formats.TemplateTests.CustomMarkdownViewBase + { + public MvcHtmlString EvalExpr_0() + { + return null; + } + //[Test] + public void Compare_access() + { + var filePath = "~/AppData/TestsResults/Customer.htm".MapProjectPath(); + const int Times = 10000; - [TestFixture] - public class _Expr - : ServiceStack.ServiceHost.Tests.Formats.TemplateTests.CustomMarkdownViewBase - { - public MvcHtmlString EvalExpr_0() - { - return null; - } + var start = DateTime.Now; + var count = 0; + for (var i = 0; i < Times; i++) + { + var result = File.ReadAllText(filePath); + if (result != null) count++; + } + var timeTaken = DateTime.Now - start; + Console.WriteLine(@"File.ReadAllText: Times {0}: {1}ms", Times, timeTaken.TotalMilliseconds); - //[Test] - public void Compare_access() - { - var filePath = "~/AppData/TestsResults/Customer.htm".MapProjectPath(); - const int Times = 10000; + start = DateTime.Now; + count = 0; + //var fi = new FileInfo(filePath); + for (var i = 0; i < Times; i++) + { + var result = File.GetLastWriteTime(filePath); + if (result != default(DateTime)) count++; + } + timeTaken = DateTime.Now - start; + Console.WriteLine(@"FileInfo.LastWriteTime: Times {0}: {1}ms", Times, timeTaken.TotalMilliseconds); + } - var start = DateTime.Now; - var count = 0; - for (var i=0; i< Times; i++) - { - var result = File.ReadAllText(filePath); - if (result != null) count++; - } - var timeTaken = DateTime.Now - start; - Console.WriteLine("File.ReadAllText: Times {0}: {1}ms", Times, timeTaken.TotalMilliseconds); - - start = DateTime.Now; - count = 0; - //var fi = new FileInfo(filePath); - for (var i=0; i < Times; i++) - { - var result = File.GetLastWriteTime(filePath); - if (result != default(DateTime)) count++; - } - timeTaken = DateTime.Now - start; - Console.WriteLine("FileInfo.LastWriteTime: Times {0}: {1}ms", Times, timeTaken.TotalMilliseconds); - } - - [Test] - public void A() - { - var str = "https://github.com/ServiceStack/ServiceStack.Redis/wiki/RedisPubSub"; - var pos = str.IndexOf("/wiki"); - Console.WriteLine(str.Substring(pos)); - } - } + [Test] + public void A() + { + var str = "https://github.com/ServiceStack/ServiceStack.Redis/wiki/RedisPubSub"; + var pos = str.IndexOf("/wiki"); + Console.WriteLine(str.Substring(pos)); + } + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateExtentionTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateExtentionTests.cs index c4aa5a7affd..c4b0ea7cdbe 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateExtentionTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateExtentionTests.cs @@ -1,18 +1,18 @@ using NUnit.Framework; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.Support.Markdown; namespace ServiceStack.ServiceHost.Tests.Formats { - [TestFixture] - public class TemplateExtentionTests - { - [Test] - public void Does_all_remove_WhiteSpace() - { - var test = "this[ is ]\ta\ntest"; - var result = test.RemoveAllWhiteSpace(); + [TestFixture] + public class TemplateExtentionTests + { + [Test] + public void Does_all_remove_WhiteSpace() + { + var test = "this[ is ]\ta\ntest"; + var result = test.RemoveAllWhiteSpace(); - Assert.That(result, Is.EqualTo("this[is]atest")); - } - } + Assert.That(result, Is.EqualTo("this[is]atest")); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateTests.cs index 5b394243999..da63ba76837 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/TemplateTests.cs @@ -3,15 +3,13 @@ using System.IO; using System.Text; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Utils; +using ServiceStack.Formats; using ServiceStack.Html; using ServiceStack.Markdown; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Support.Markdown; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.IO; namespace ServiceStack.ServiceHost.Tests.Formats { @@ -28,7 +26,7 @@ public class TemplateTests private MarkdownFormat markdownFormat; Dictionary templateArgs; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { staticTemplatePath = "~/Views/Shared/_Layout.shtml".MapProjectPath(); @@ -44,8 +42,9 @@ public void TestFixtureSetUp() [SetUp] public void OnBeforeEachTest() { - markdownFormat = new MarkdownFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()) + markdownFormat = new MarkdownFormat + { + VirtualPathProvider = new MemoryVirtualFiles() }; templateArgs = new Dictionary { { MarkdownPage.ModelName, person } }; } @@ -87,14 +86,15 @@ public Link() public List Labels { get; set; } } - Person person = new Person { + Person person = new Person + { FirstName = "Demis", LastName = "Bellot", Links = new List - { - new Link { Name = "ServiceStack", Href = "http://www.servicestack.net", Labels = {"REST","JSON","XML"} }, - new Link { Name = "AjaxStack", Href = "http://www.ajaxstack.com", Labels = {"HTML5", "AJAX", "SPA"} }, - }, + { + new Link { Name = "ServiceStack", Href = "http://www.servicestack.net", Labels = {"REST","JSON","XML"} }, + new Link { Name = "AjaxStack", Href = "http://www.ajaxstack.com", Labels = {"HTML5", "AJAX", "SPA"} }, + }, }; @@ -355,10 +355,10 @@ Hello @Upper(Model.LastName), @Model.FirstName markdownFormat.MarkdownBaseType = typeof(CustomMarkdownViewBase); - markdownFormat.MarkdownGlobalHelpers = new Dictionary - { - {"Ext", typeof(CustomMarkdownHelper)} - }; + markdownFormat.MarkdownGlobalHelpers = new Dictionary + { + {"Ext", typeof(CustomMarkdownHelper)} + }; markdownFormat.RegisterMarkdownPage(new MarkdownPage(markdownFormat, "/path/to/page", "HeaderLinks", headerTemplate)); @@ -860,7 +860,8 @@ @section Menus { markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); markdownFormat.AddPage( - new MarkdownPage(markdownFormat, "/path/to/page-tpl", "DynamicModelTpl", template) { + new MarkdownPage(markdownFormat, "/path/to/page-tpl", "DynamicModelTpl", template) + { Template = "websiteTemplate" }); @@ -943,7 +944,8 @@ @section Header { markdownFormat.AddFileAndTemplate("websiteTemplate", websiteTemplate); markdownFormat.RegisterMarkdownPage( - new MarkdownPage(markdownFormat, "pagetpl", "StaticTpl", template, MarkdownPageType.ContentPage) { + new MarkdownPage(markdownFormat, "pagetpl", "StaticTpl", template, MarkdownPageType.ContentPage) + { Template = "websiteTemplate" }); diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs index ecdae2b20df..1f222aa59fb 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockTests.cs @@ -2,43 +2,42 @@ using System.Collections.Generic; using System.IO; using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.Formats; +using ServiceStack.Support.Markdown; using ServiceStack.ServiceHost.Tests.Formats_Razor; namespace ServiceStack.ServiceHost.Tests.Formats { - [TestFixture] - public class TextBlockTests - { - string dynamicListPagePath; - string dynamicListPageContent; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - dynamicListPagePath = "~/Views/Template/DynamicListTpl.md".MapProjectPath(); - dynamicListPageContent = File.ReadAllText(dynamicListPagePath); - } + [TestFixture] + public class TextBlockTests + { + string dynamicListPagePath; + string dynamicListPageContent; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + dynamicListPagePath = "~/Views/Template/DynamicListTpl.md".MapProjectPath(); + dynamicListPageContent = File.ReadAllText(dynamicListPagePath); + } - [Test] - public void Does_replace_foreach_statements_with_expr_placeholders() - { - var content = (string)dynamicListPageContent.Clone(); + [Test] + public void Does_replace_foreach_statements_with_expr_placeholders() + { + var content = (string)dynamicListPageContent.Clone(); - var expected = content.ReplaceForeach("@^1"); ; + var expected = content.ReplaceForeach("@^1"); ; - var statements = new List(); - var parsedContent = StatementExprBlock.Extract(content, statements); + var statements = new List(); + var parsedContent = StatementExprBlock.Extract(content, statements); - Console.WriteLine(parsedContent); + Console.WriteLine(parsedContent); - Assert.That(parsedContent, Is.EqualTo(expected)); - Assert.That(statements.Count, Is.EqualTo(1)); - Assert.That(statements[0].Condition, Is.EqualTo("var link in Model.Links")); - Assert.That(statements[0].Statement, Is.EqualTo(" - @link.Name - @link.Href\r\n")); - } + Assert.That(parsedContent, Is.EqualTo(expected)); + Assert.That(statements.Count, Is.EqualTo(1)); + Assert.That(statements[0].Condition, Is.EqualTo("var link in Model.Links")); + Assert.That(statements[0].Statement, Is.EqualTo(" - @link.Name - @link.Href\r\n")); + } [Test] public void Does_handle_foreach_when_enumerable_is_empty_first_time() @@ -51,17 +50,17 @@ public void Does_handle_foreach_when_enumerable_is_empty_first_time() markdownPage.RenderToHtml(scopeArgs); // First time the list is empty var expected = "A new list item"; - model.Links.Add(new Link { Name = expected } ); + model.Links.Add(new Link { Name = expected }); var html = markdownPage.RenderToHtml(scopeArgs); // Second time the list has 1 item Console.WriteLine(html); Assert.That(html, Contains.Substring(expected)); } - [Test] - public void Does_replace_multiple_statements_with_expr_placeholders() - { - string template = @" + [Test] + public void Does_replace_multiple_statements_with_expr_placeholders() + { + string template = @" ## Statement 1 @if (Model.IsValid) { @@ -85,7 +84,7 @@ public void Does_replace_multiple_statements_with_expr_placeholders() # EOF".NormalizeNewLines(); - string expected = @" + string expected = @" ## Statement 1 @^1 @@ -99,27 +98,27 @@ public void Does_replace_multiple_statements_with_expr_placeholders() @^4 # EOF".NormalizeNewLines(); - var statements = new List(); - var content = StatementExprBlock.Extract(template, statements); - - Console.WriteLine(content); - - Assert.That(content, Is.EqualTo(expected)); - Assert.That(statements.Count, Is.EqualTo(4)); - Assert.That(statements[0].Condition, Is.EqualTo("Model.IsValid")); - Assert.That(statements[0].Statement, Is.EqualTo("### This is valid\n")); - Assert.That(statements[1].Condition, Is.EqualTo("var link in Model.Links")); - Assert.That(statements[1].Statement, Is.EqualTo(" - @link.Name - @link.Href\n")); - Assert.That(statements[2].Condition, Is.EqualTo("var text in Model.Texts")); - Assert.That(statements[2].Statement, Is.EqualTo("### @text.Name\n@text.body\n")); - Assert.That(statements[3].Condition, Is.EqualTo("!Model.IsValid")); - Assert.That(statements[3].Statement, Is.EqualTo("### This is not valid\n")); - } - - [Test] - public void Does_parse_parens_free_statements() - { - string template = @" + var statements = new List(); + var content = StatementExprBlock.Extract(template, statements); + + Console.WriteLine(content); + + Assert.That(content, Is.EqualTo(expected)); + Assert.That(statements.Count, Is.EqualTo(4)); + Assert.That(statements[0].Condition, Is.EqualTo("Model.IsValid")); + Assert.That(statements[0].Statement, Is.EqualTo("### This is valid\n")); + Assert.That(statements[1].Condition, Is.EqualTo("var link in Model.Links")); + Assert.That(statements[1].Statement, Is.EqualTo(" - @link.Name - @link.Href\n")); + Assert.That(statements[2].Condition, Is.EqualTo("var text in Model.Texts")); + Assert.That(statements[2].Statement, Is.EqualTo("### @text.Name\n@text.body\n")); + Assert.That(statements[3].Condition, Is.EqualTo("!Model.IsValid")); + Assert.That(statements[3].Statement, Is.EqualTo("### This is not valid\n")); + } + + [Test] + public void Does_parse_parens_free_statements() + { + string template = @" ## Statement 1 @if Model.IsValid { @@ -142,7 +141,7 @@ @foreach text in Model.Texts { } # EOF".NormalizeNewLines(); - + string expected = @" ## Statement 1 @@ -158,40 +157,40 @@ @foreach text in Model.Texts { # EOF".NormalizeNewLines(); - var statements = new List(); - var content = StatementExprBlock.Extract(template, statements); + var statements = new List(); + var content = StatementExprBlock.Extract(template, statements); - Console.WriteLine(content); + Console.WriteLine(content); - Assert.That(content, Is.EqualTo(expected)); - Assert.That(statements.Count, Is.EqualTo(4)); + Assert.That(content, Is.EqualTo(expected)); + Assert.That(statements.Count, Is.EqualTo(4)); - var stat1 = (IfStatementExprBlock)statements[0]; - Assert.That(stat1.Condition, Is.EqualTo("Model.IsValid")); - Assert.That(stat1.Statement, Is.EqualTo("### This is valid\n")); + var stat1 = (IfStatementExprBlock)statements[0]; + Assert.That(stat1.Condition, Is.EqualTo("Model.IsValid")); + Assert.That(stat1.Statement, Is.EqualTo("### This is valid\n")); - var stat2 = (ForEachStatementExprBlock)statements[1]; - Assert.That(stat2.Condition, Is.EqualTo("var link in Model.Links")); - Assert.That(stat2.Statement, Is.EqualTo(" - @link.Name - @link.Href\n")); - Assert.That(stat2.EnumeratorName, Is.EqualTo("link")); - Assert.That(stat2.MemberExpr, Is.EqualTo("Model.Links")); + var stat2 = (ForEachStatementExprBlock)statements[1]; + Assert.That(stat2.Condition, Is.EqualTo("var link in Model.Links")); + Assert.That(stat2.Statement, Is.EqualTo(" - @link.Name - @link.Href\n")); + Assert.That(stat2.EnumeratorName, Is.EqualTo("link")); + Assert.That(stat2.MemberExpr, Is.EqualTo("Model.Links")); - var stat3 = (ForEachStatementExprBlock)statements[2]; - Assert.That(stat3.Condition, Is.EqualTo("text in Model.Texts")); - Assert.That(stat3.Statement, Is.EqualTo("### @text.Name\n@text.body\n")); - Assert.That(stat3.EnumeratorName, Is.EqualTo("text")); - Assert.That(stat3.MemberExpr, Is.EqualTo("Model.Texts")); + var stat3 = (ForEachStatementExprBlock)statements[2]; + Assert.That(stat3.Condition, Is.EqualTo("text in Model.Texts")); + Assert.That(stat3.Statement, Is.EqualTo("### @text.Name\n@text.body\n")); + Assert.That(stat3.EnumeratorName, Is.EqualTo("text")); + Assert.That(stat3.MemberExpr, Is.EqualTo("Model.Texts")); - var stat4 = (IfStatementExprBlock)statements[3]; - Assert.That(stat4.Condition, Is.EqualTo("!Model.IsValid")); - Assert.That(stat4.Statement, Is.EqualTo("### This is not valid\n")); - } + var stat4 = (IfStatementExprBlock)statements[3]; + Assert.That(stat4.Condition, Is.EqualTo("!Model.IsValid")); + Assert.That(stat4.Statement, Is.EqualTo("### This is not valid\n")); + } - [Test] - public void Does_transform_escaped_html_start_tags() - { - var markdownText = - @"#### Showing Results 1 - 5 + [Test] + public void Does_transform_escaped_html_start_tags() + { + var markdownText = + @"#### Showing Results 1 - 5 ^
    @@ -201,25 +200,25 @@ public void Does_transform_escaped_html_start_tags() Text".NormalizeNewLines(); - var expectedHtml = - @"

    Showing Results 1 - 5

    + var expectedHtml = + @"

    Showing Results 1 - 5

    Markdown > About Docs

    Text

    ".NormalizeNewLines(); - var textBlock = new TextBlock(""); - var page = new MarkdownPage { Markdown = new MarkdownFormat() }; - textBlock.DoFirstRun(new PageContext(page, null, true)); + var textBlock = new TextBlock(""); + var page = new MarkdownPage { Markdown = new MarkdownFormat() }; + textBlock.DoFirstRun(new PageContext(page, null, true)); - var html = textBlock.TransformHtml(markdownText); + var html = textBlock.TransformHtml(markdownText); - Console.WriteLine(html); + Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Assert.That(html, Is.EqualTo(expectedHtml)); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockUtils.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockUtils.cs index ab62d15e29a..21e8d4c3ee2 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockUtils.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/TextBlockUtils.cs @@ -1,17 +1,17 @@ namespace ServiceStack.ServiceHost.Tests.Formats { - public static class TextBlockUtils - { - public static string ReplaceForeach(this string tempalte, string replaceWith) - { - var startPos = tempalte.IndexOf("@foreach"); - var endPos = tempalte.IndexOf("}", startPos); + public static class TextBlockUtils + { + public static string ReplaceForeach(this string tempalte, string replaceWith) + { + var startPos = tempalte.IndexOf("@foreach"); + var endPos = tempalte.IndexOf("}", startPos); - var expected = tempalte.Substring(0, startPos) - + replaceWith - + tempalte.Substring(endPos + 1); + var expected = tempalte.Substring(0, startPos) + + replaceWith + + tempalte.Substring(endPos + 1); - return expected; - } - } + return expected; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/UseCaseTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/UseCaseTests.cs index 8b4a24e646c..73bb45b5ace 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/UseCaseTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/UseCaseTests.cs @@ -3,57 +3,55 @@ using System.IO; using System.Linq; using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.ServiceInterface.ServiceModel; using ServiceStack.Text; namespace ServiceStack.ServiceHost.Tests.Formats { - public class Page - { - public Page() - { - this.Tags = new List(); - } - - public string Name { get; set; } - public string Slug { get; set; } - public string Src { get; set; } - public string FilePath { get; set; } - public string Category { get; set; } - public string Content { get; set; } - public DateTime? CreatedDate { get; set; } - public DateTime? ModifiedDate { get; set; } - public List Tags { get; set; } - - public string AbsoluteUrl - { - get { return "http://path.com/to/" + this.Slug; } - } - } - - public class SearchResponse : IHasResponseStatus - { - public SearchResponse() - { - this.Results = new List(); - } - - public string Query { get; set; } - - public List Results { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - - [TestFixture] - public class UseCaseTests : MarkdownTestBase - { - private List Pages; - private SearchResponse SearchResponse; - - string websiteTemplate = + public class Page + { + public Page() + { + this.Tags = new List(); + } + + public string Name { get; set; } + public string Slug { get; set; } + public string Src { get; set; } + public string FilePath { get; set; } + public string Category { get; set; } + public string Content { get; set; } + public DateTime? CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } + public List Tags { get; set; } + + public string AbsoluteUrl + { + get { return "http://path.com/to/" + this.Slug; } + } + } + + public class SearchResponse : IHasResponseStatus + { + public SearchResponse() + { + this.Results = new List(); + } + + public string Query { get; set; } + + public List Results { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + + [TestFixture] + public class UseCaseTests : MarkdownTestBase + { + private List Pages; + private SearchResponse SearchResponse; + + string websiteTemplate = @" @@ -70,23 +68,24 @@ public class UseCaseTests : MarkdownTestBase ".NormalizeNewLines(); - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - var jsonPages = File.ReadAllText("~/AppData/Pages.json".MapProjectPath()); - - Pages = JsonSerializer.DeserializeFromString>(jsonPages); + [OneTimeSetUp] + public void TestFixtureSetUp() + { + var jsonPages = File.ReadAllText("~/AppData/Pages.json".MapProjectPath()); - SearchResponse = new SearchResponse { - Query = "OrmLite", - Results = Pages.Take(5).ToList(), - }; - } + Pages = JsonSerializer.DeserializeFromString>(jsonPages); - [Test] - public void Can_display_search_results_basic() - { - var pageTemplate = @"@var Title = ""Search results for "" + Model.Query + SearchResponse = new SearchResponse + { + Query = "OrmLite", + Results = Pages.Take(5).ToList(), + }; + } + + [Test] + public void Can_display_search_results_basic() + { + var pageTemplate = @"@var Title = ""Search results for "" + Model.Query @if (Model.Results.Count == 0) { @@ -110,7 +109,7 @@ @foreach page in Model.Results { @page.Content }
    "; - var expectedHtml = @" + var expectedHtml = @" Simple Site @@ -133,20 +132,20 @@ @foreach page in Model.Results { ".NormalizeNewLines(); - var markdownFormat = Create(websiteTemplate, pageTemplate); + var markdownFormat = Create(websiteTemplate, pageTemplate); - var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); + var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); - Console.WriteLine(html); + Console.WriteLine(html); - Assert.That(html.NormalizeNewLines(), Is.EqualTo(expectedHtml)); - } + Assert.That(html.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + } - [Test] - public void Can_display_search_results() - { - var pageTemplate = @"@var Title = ""Search results for "" + Model.Query + [Test] + public void Can_display_search_results() + { + var pageTemplate = @"@var Title = ""Search results for "" + Model.Query @if (Model.Results.Count == 0) { @@ -175,7 +174,7 @@ @foreach page in Model.Results { ^ }"; - var expectedHtml = @" + var expectedHtml = @" Simple Site @@ -199,15 +198,15 @@ @foreach page in Model.Results { ".NormalizeNewLines(); - var markdownFormat = Create(websiteTemplate, pageTemplate); + var markdownFormat = Create(websiteTemplate, pageTemplate); - var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); + var html = markdownFormat.RenderDynamicPageHtml(PageName, SearchResponse); - Console.WriteLine(html); + Console.WriteLine(html); - Assert.That(html, Is.EqualTo(expectedHtml)); - } - } + Assert.That(html, Is.EqualTo(expectedHtml)); + } + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats/ViewTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats/ViewTests.cs index 3cc935b7eb4..d0caa6cdbc5 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats/ViewTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats/ViewTests.cs @@ -2,305 +2,261 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.IO; -using System.Linq; +using System.Net; using System.Text; +using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.Html; -using ServiceStack.IO; +using ServiceStack.Formats; +using ServiceStack.Host; using ServiceStack.ServiceHost.Tests.AppData; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Support.Markdown; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Formats; -using ServiceStack.WebHost.Endpoints.Support.Markdown; +using ServiceStack.Web; namespace ServiceStack.ServiceHost.Tests.Formats { - [TestFixture] - public class ViewTests - { - private CustomerDetailsResponse response; - private MarkdownFormat markdownFormat; - private AppHost appHost; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - var json = "~/AppData/ALFKI.json".MapProjectPath().ReadAllText(); - response = JsonSerializer.DeserializeFromString(json); - } - - [SetUp] - public void OnBeforeEachTest() - { - appHost = new AppHost(); - markdownFormat = new MarkdownFormat { - VirtualPathProvider = appHost.VirtualPathProvider + [TestFixture] + public class ViewTests + { + private CustomerDetailsResponse response; + private MarkdownFormat markdownFormat; + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + var json = "~/AppData/ALFKI.json".MapProjectPath().ReadAllText(); + response = JsonSerializer.DeserializeFromString(json); + + appHost = new BasicAppHost + { + Plugins = { new MarkdownFormat() }, + ConfigFilter = config => + { + //Files aren't copied, set RootDirectory to ProjectPath instead. + config.WebHostPhysicalPath = "~".MapProjectPath(); + } + }.Init(); + markdownFormat = appHost.GetPlugin(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public string GetHtml(object dto, string format) + { + var httpReq = new MockHttpRequest + { + Headers = new NameValueCollection(), + OperationName = "OperationName", + QueryString = new NameValueCollection(), }; - markdownFormat.Register(appHost); - } - - public class AppHost : IAppHost - { - public AppHost() - { - this.Config = new EndpointHostConfig { - HtmlReplaceTokens = new Dictionary(), - IgnoreFormatsInMetadata = new HashSet(), - }; - this.ContentTypeFilters = HttpResponseFilter.Instance; - this.ResponseFilters = new List>(); - this.ViewEngines = new List(); - this.CatchAllHandlers = new List(); - this.VirtualPathProvider = new FileSystemVirtualPathProvider(this, "~".MapProjectPath()); - } - - public void Register(T instance) - { - throw new NotImplementedException(); - } - - public void RegisterAs() where T : TAs - { - throw new NotImplementedException(); - } - - public virtual void Release(object instance) { } - - public void OnEndRequest() {} - - public IServiceRoutes Routes { get; private set; } - - public T TryResolve() - { - throw new NotImplementedException(); - } - - public IContentTypeFilter ContentTypeFilters { get; set; } - - public List> PreRequestFilters { get; set; } - - public List> RequestFilters { get; set; } - - public List> ResponseFilters { get; set; } - - public List ViewEngines { get; set; } - - public HandleUncaughtExceptionDelegate ExceptionHandler { get; set; } - - public HandleServiceExceptionDelegate ServiceExceptionHandler { get; set; } - - public List CatchAllHandlers { get; set; } - - public Dictionary> RequestBinders - { - get { throw new NotImplementedException(); } - } - - public EndpointHostConfig Config { get; set; } - - public void RegisterService(Type serviceType, params string[] atRestPaths) - { - Config.ServiceManager.RegisterService(serviceType); - } - - public List Plugins { get; private set; } - - public void LoadPlugin(params IPlugin[] plugins) - { - plugins.ToList().ForEach(x => x.Register(this)); - } - - public IVirtualPathProvider VirtualPathProvider { get; set; } - - public IServiceRunner CreateServiceRunner(ActionContext actionContext) - { - throw new NotImplementedException(); - } - - public virtual string ResolveAbsoluteUrl(string virtualPath, IHttpRequest httpReq) + httpReq.QueryString.Add("format", format); + using (var ms = new MemoryStream()) { - return httpReq.GetAbsoluteUrl(virtualPath); + var httpRes = new HttpResponseStreamWrapper(ms, httpReq); + appHost.ViewEngines[0].ProcessRequestAsync(httpReq, dto, httpRes.OutputStream); + + var html = ms.ReadToEnd(); + return html; } } - public string GetHtml(object dto, string format) - { - var httpReq = new MockHttpRequest { - Headers = new NameValueCollection(), - OperationName = "OperationName", - QueryString = new NameValueCollection(), - }; - httpReq.QueryString.Add("format", format); - using (var ms = new MemoryStream()) - { - var httpRes = new HttpResponseStreamWrapper(ms); - appHost.ViewEngines[0].ProcessRequest(httpReq, httpRes, dto); - - var utf8Bytes = ms.ToArray(); - var html = utf8Bytes.FromUtf8Bytes(); - return html; - } - } - - public string GetHtml(object dto) - { - return GetHtml(dto, "html"); - } - - [Test] - public void Does_serve_dynamic_view_HTML_page_with_template() - { - var html = GetHtml(response); - - Console.WriteLine(html); - //File.WriteAllText("~/AppData/TestsResults/CustomerDetailsResponse.htm".MapAbsolutePath(), html); - - Assert.That(html.StartsWith("")); - Assert.That(html.Contains("Customer Orders Total: $4,596.20")); - } - - [Test] - public void Does_serve_dynamic_view_HTML_page_without_template() - { - var html = GetHtml(response, "html.bare"); - - Console.WriteLine(html); - - Assert.That(html.TrimStart().StartsWith("

    Maria Anders Customer Details (Berlin, Germany)

    ")); - Assert.That(html.Contains("Customer Orders Total: $4,596.20")); - } - - [Test] - public void Does_serve_dynamic_view_Markdown_page_with_template() - { - var html = GetHtml(response, "markdown"); - - Console.WriteLine(html); - //File.WriteAllText("~/AppData/TestsResults/CustomerDetailsResponse.txt".MapAbsolutePath(), html); - - Assert.That(html.StartsWith("")); - Assert.That(html.Contains("# Maria Anders Customer Details (Berlin, Germany)")); - Assert.That(html.Contains("Customer Orders Total: $4,596.20")); - } - - [Test] - public void Does_serve_dynamic_view_Markdown_page_without_template() - { - var html = GetHtml(response, "markdown.bare"); - - Console.WriteLine(html); - - Assert.That(html.TrimStart().StartsWith("# Maria Anders Customer Details (Berlin, Germany)")); - Assert.That(html.Contains("Customer Orders Total: $4,596.20")); - } - - - [Test] - public void Does_serve_dynamic_view_HTML_page_with_ALT_template() - { - var html = GetHtml(response.Customer); + public string GetHtml(object dto) + { + return GetHtml(dto, "html"); + } + + [Test] + public void Does_serve_dynamic_view_HTML_page_with_template() + { + var html = GetHtml(response); html.Print(); - //File.WriteAllText("~/AppData/TestsResults/Customer.htm".MapAbsolutePath(), html); + //File.WriteAllText("~/AppData/TestsResults/CustomerDetailsResponse.htm".MapAbsolutePath(), html); - Assert.That(html.StartsWith("")); - Assert.That(html.Contains("ALT Template")); - Assert.That(html.Contains("
  • Address: Obere Str. 57
  • ")); - } + Assert.That(html.StartsWith("")); + Assert.That(html.Contains("Customer Orders Total: $4,596.20")); + } + + [Test] + public void Does_serve_dynamic_view_HTML_page_without_template() + { + var html = GetHtml(response, "html.bare"); - public class MockHttpResponse : IHttpResponse - { - public MemoryStream MemoryStream { get; set; } + Console.WriteLine(html); - public MockHttpResponse() - { - this.Headers = new Dictionary(); - this.MemoryStream = new MemoryStream(); - this.Cookies = new Cookies(this); - } + Assert.That(html.TrimStart().StartsWith("

    Maria Anders Customer Details (Berlin, Germany)

    ")); + Assert.That(html.Contains("Customer Orders Total: $4,596.20")); + } - public object OriginalResponse - { - get { throw new NotImplementedException(); } - } + [Test] + public void Does_serve_dynamic_view_Markdown_page_with_template() + { + var html = GetHtml(response, "markdown"); - public int StatusCode { set; get; } + Console.WriteLine(html); + //File.WriteAllText("~/AppData/TestsResults/CustomerDetailsResponse.txt".MapAbsolutePath(), html); + + Assert.That(html.StartsWith("")); + Assert.That(html.Contains("# Maria Anders Customer Details (Berlin, Germany)")); + Assert.That(html.Contains("Customer Orders Total: $4,596.20")); + } + + [Test] + public void Does_serve_dynamic_view_Markdown_page_without_template() + { + var html = GetHtml(response, "markdown.bare"); + + Console.WriteLine(html); + + Assert.That(html.TrimStart().StartsWith("# Maria Anders Customer Details (Berlin, Germany)")); + Assert.That(html.Contains("Customer Orders Total: $4,596.20")); + } + + + [Test] + public void Does_serve_dynamic_view_HTML_page_with_ALT_template() + { + var html = GetHtml(response.Customer); + + html.Print(); + //File.WriteAllText("~/AppData/TestsResults/Customer.htm".MapAbsolutePath(), html); + + Assert.That(html.StartsWith("")); + Assert.That(html.Contains("ALT Template")); + Assert.That(html.Contains("
  • Address: Obere Str. 57
  • ")); + } + + public class MockHttpResponse : IHttpResponse + { + public MemoryStream MemoryStream { get; set; } + + public MockHttpResponse(IRequest httpReq) + { + this.Request = httpReq; + this.Headers = new Dictionary(); + this.MemoryStream = new MemoryStream(); + this.Cookies = new Host.Cookies(this); + this.Items = new Dictionary(); + } + + public object OriginalResponse + { + get { throw new NotImplementedException(); } + } + + public IRequest Request { get; private set; } + + public int StatusCode { set; get; } public string StatusDescription { set; get; } - public string ContentType { get; set; } + public string ContentType { get; set; } - private Dictionary Headers { get; set; } + private Dictionary Headers { get; set; } - public ICookies Cookies { get; set; } + public ICookies Cookies { get; set; } - public void AddHeader(string name, string value) - { - this.Headers.Add(name, value); - } + public void AddHeader(string name, string value) + { + this.Headers.Add(name, value); + } - public void Redirect(string url) - { - this.Headers[HttpHeaders.Location] = url; - } + public void RemoveHeader(string name) + { + Headers.Remove(name); + } + + public string GetHeader(string name) + { + this.Headers.TryGetValue(name, out var value); + return value; + } + + public void Redirect(string url) + { + this.Headers[HttpHeaders.Location] = url; + } + + public Stream OutputStream => MemoryStream; + + public object Dto { get; set; } + + public bool UseBufferedStream { get; set; } + + public string Contents { get; set; } + + public void Close() + { + this.Contents = MemoryStream.ReadToEnd(); + MemoryStream.Close(); + this.IsClosed = true; + } + + public Task CloseAsync(CancellationToken token = default(CancellationToken)) + { + Close(); + return TypeConstants.EmptyTask; + } - public Stream OutputStream { get { return MemoryStream; } } + public void End() + { + Close(); + } - public void Write(string text) - { - var bytes = Encoding.UTF8.GetBytes(text); - MemoryStream.Write(bytes, 0, bytes.Length); - } + public void Flush() + { + MemoryStream.Flush(); + } - public string Contents { get; set; } + public Task FlushAsync(CancellationToken token = new CancellationToken()) => MemoryStream.FlushAsync(token); - public void Close() - { - this.Contents = Encoding.UTF8.GetString(MemoryStream.ToArray()); - MemoryStream.Close(); - this.IsClosed = true; - } + public bool IsClosed { get; private set; } - public void End() - { - Close(); - } + public void SetContentLength(long contentLength) + { + Headers[HttpHeaders.ContentLength] = contentLength.ToString(); + } - public void Flush() - { - MemoryStream.Flush(); - } + public bool KeepAlive { get; set; } - public bool IsClosed { get; private set; } + public bool HasStarted { get; set; } - public void SetContentLength(long contentLength) - { - Headers[HttpHeaders.ContentLength] = contentLength.ToString(); - } - } + public Dictionary Items { get; private set; } - [Test] - public void Does_process_Markdown_pages() - { - var markdownHandler = new MarkdownHandler("/AppData/NoTemplate/Static") { - MarkdownFormat = markdownFormat, - }; - var httpReq = new MockHttpRequest { QueryString = new NameValueCollection() }; - var httpRes = new MockHttpResponse(); - markdownHandler.ProcessRequest(httpReq, httpRes, "Static"); + public void SetCookie(Cookie cookie) + { + } - var expectedHtml = markdownFormat.Transform( - File.ReadAllText("~/AppData/NoTemplate/Static.md".MapProjectPath())); + public void ClearCookies() + { + } + } + + [Test] + public void Does_process_Markdown_pages() + { + var markdownHandler = new MarkdownHandler("/AppData/NoTemplate/Static") + { + MarkdownFormat = markdownFormat, + }; + var httpReq = new MockHttpRequest { QueryString = new NameValueCollection() }; + var httpRes = new MockHttpResponse(httpReq); + markdownHandler.ProcessRequestAsync(httpReq, httpRes, "Static").Wait(); - httpRes.Close(); - Assert.That(httpRes.Contents, Is.EqualTo(expectedHtml)); - } + var expectedHtml = markdownFormat.Transform( + File.ReadAllText("~/AppData/NoTemplate/Static.md".MapProjectPath())); + + httpRes.Close(); + Assert.That(httpRes.Contents, Is.EqualTo(expectedHtml)); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/CustomRazorBasePage.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/CustomRazorBasePage.cs index f1e316f0259..08b9feb27dd 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/CustomRazorBasePage.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/CustomRazorBasePage.cs @@ -3,9 +3,9 @@ namespace ServiceStack.ServiceHost.Tests.Formats_Razor { - public abstract class CustomRazorBasePage : ViewPage where TModel : class - { - public FormatHelpers Fmt = new FormatHelpers(); - public NorthwindHelpers Nwnd = new NorthwindHelpers(); - } + public abstract class CustomRazorBasePage : ViewPage + { + public FormatHelpers Fmt = new FormatHelpers(); + public NorthwindHelpers Nwnd = new NorthwindHelpers(); + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionExampleRazorTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionExampleRazorTests.cs index 444e6bab46f..00567946ea4 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionExampleRazorTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionExampleRazorTests.cs @@ -1,60 +1,69 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using NUnit.Framework; +using ServiceStack.IO; using ServiceStack.Razor; using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; namespace ServiceStack.ServiceHost.Tests.Formats_Razor { - public class Product - { - public Product() { } - public Product(string name, decimal price) - { - Name = name; - Price = price; - } - - public int ProductID { get; set; } - public string Name { get; set; } - public decimal Price { get; set; } - } - - [TestFixture] - public class IntroductionExampleRazorTests : RazorTestBase - { - private List products; - object productArgs; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - this.products = new List { - new Product("Pen", 1.99m), - new Product("Glass", 9.99m), - new Product("Book", 14.99m), - new Product("DVD", 11.99m), - }; - productArgs = new { products = products }; - } - + public class Product + { + public Product() { } + public Product(string name, decimal price) + { + Name = name; + Price = price; + } + + public int ProductID { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + } + + [TestFixture] + public class IntroductionExampleRazorTests : RazorTestBase + { + private List products; + object productArgs; + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + this.products = new List { + new Product("Pen", 1.99m), + new Product("Glass", 9.99m), + new Product("Book", 14.99m), + new Product("DVD", 11.99m), + }; + productArgs = new { products = products }; + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + [SetUp] public void SetUp() { RazorFormat.Instance = null; - RazorFormat = new RazorFormat { + RazorFormat = new RazorFormat + { PageBaseType = typeof(CustomRazorBasePage<>), - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), + VirtualFileSources = new MemoryVirtualFiles(), }.Init(); } - [Test] - public void Basic_Razor_Example() - { - var template = + [Test] + public void Basic_Razor_Example() + { + var template = @"

    Razor Example

    Hello @Model.name, the year is @DateTime.Now.Year

    @@ -62,32 +71,31 @@ public void Basic_Razor_Example()

    Checkout this product

    ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"

    Razor Example

    -

    Hello Demis, the year is 2013

    +

    Hello Demis, the year is 2022

    Checkout this product

    ".NormalizeNewLines(); - var html = RazorFormat.CreateAndRenderToHtml(template, model:new { name = "Demis", productId = 10 }); + var html = RazorFormat.CreateAndRenderToHtml(template, model: new { name = "Demis", productId = 10 }); - html.Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void Simple_loop() - { - var template = @"
      + [Test] + public void Simple_loop() + { + var template = @"
        @foreach (var p in Model.products) {
      • @p.Name: (@p.Price)
      • }
      ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"
      • Pen: (1.99)
      • Glass: (9.99)
      • @@ -98,14 +106,13 @@ public void Simple_loop() var html = RazorFormat.CreateAndRenderToHtml(template, model: productArgs); - html.Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Assert.That(html, Is.EqualTo(expectedHtml)); + } - [Test] - public void If_Statment() - { - var template = @" + [Test] + public void If_Statment() + { + var template = @" @if (Model.products.Count == 0) {

        Sorry - no products in this category

        } else { @@ -113,20 +120,19 @@ public void If_Statment() } ".NormalizeNewLines(); - var expectedHtml = @" + var expectedHtml = @"

        We have products for you!

        ".NormalizeNewLines(); var html = RazorFormat.CreateAndRenderToHtml(template, model: productArgs); - html.Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Assert.That(html.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + } - [Test] - public void Multi_variable_declarations() - { - var template = @" + [Test] + public void Multi_variable_declarations() + { + var template = @" @{ var number = 1; var message = ""Number is "" + number; @@ -134,76 +140,72 @@ public void Multi_variable_declarations()

        Your Message: @message

        ".NormalizeNewLines(); - var expectedHtml = @" + var expectedHtml = @"

        Your Message: Number is 1

        ".NormalizeNewLines(); var html = RazorFormat.CreateAndRenderToHtml(template, model: productArgs); - html.Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Assert.That(html.NormalizeNewLines(), Is.EqualTo(expectedHtml)); + } - [Test] - public void Integrating_content_and_code() - { - var template = + [Test] + public void Integrating_content_and_code() + { + var template = @"

        Send mail to demis.bellot@gmail.com telling him the time: @DateTime.Now.

        ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"

        Send mail to demis.bellot@gmail.com telling him the time: 02/06/2011 06:38:34.

        ".NormalizeNewLines(); - var html = RazorFormat.CreateAndRenderToHtml(template, model:productArgs); + var html = RazorFormat.CreateAndRenderToHtml(template, model: productArgs); - html.Print(); - Assert.That(html, Is.StringMatching(expectedHtml.Substring(0, expectedHtml.Length - 25))); - } + Assert.That(html, Does.Match(expectedHtml.Substring(0, expectedHtml.Length - 25))); + } - [Test] - public void Identifying_nested_content() - { - var template = + [Test] + public void Identifying_nested_content() + { + var template = @" -@if (DateTime.Now.Year == 2013) { -

        If the year is 2013 then print this +@if (DateTime.Now.Year == 2022) { +

        If the year is 2022 then print this multi-line text block and the date: @DateTime.Now

        } ".NormalizeNewLines(); - var expectedHtml = -@"

        If the year is 2013 then print this + var expectedHtml = +@"

        If the year is 2022 then print this multi-line text block and the date: 02/06/2013 06:42:45

        ".NormalizeNewLines(); var html = RazorFormat.CreateAndRenderToHtml(template, model: productArgs); - html.Print(); - Assert.That(html, Is.StringMatching(expectedHtml.Substring(0, expectedHtml.Length - 25))); - } + Assert.That(html, Does.Match(expectedHtml.Substring(0, expectedHtml.Length - 25))); + } - [Test] - public void HTML_encoding() - { - var template = + [Test] + public void HTML_encoding() + { + var template = @"

        Some Content @Model.stringContainingHtml

        ".NormalizeNewLines(); - var expectedHtml = + var expectedHtml = @"

        Some Content <span>html</span>

        ".NormalizeNewLines(); var html = RazorFormat.CreateAndRenderToHtml(template, new { stringContainingHtml = "html" }); - html.Print(); - Assert.That(html, Is.EqualTo(expectedHtml)); - } + Assert.That(html, Is.EqualTo(expectedHtml)); + } - } + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionLayoutRazorTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionLayoutRazorTests.cs index b70a9c76d03..8d981e5eeb7 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionLayoutRazorTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/IntroductionLayoutRazorTests.cs @@ -3,11 +3,11 @@ using System.Text; using NUnit.Framework; using ServiceStack.Html; +using ServiceStack.IO; using ServiceStack.Razor; using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; namespace ServiceStack.ServiceHost.Tests.Formats_Razor { @@ -28,7 +28,7 @@ public MvcHtmlString ProductTable(List products) } } - public class CustomBaseClass : ViewPage where T : class + public class CustomBaseClass : ViewPage { public MvcHtmlString Field(string fieldName, string fieldValue) { @@ -47,13 +47,27 @@ public override void Execute() [TestFixture] public class IntroductionLayoutRazorTests : RazorTestBase { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + [SetUp] public void OnBeforeEachTest() { RazorFormat.Instance = null; base.RazorFormat = new RazorFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), + VirtualFileSources = new MemoryVirtualFiles(), }.Init(); } @@ -115,8 +129,7 @@ with a layout template. The content you are seeing here comes from ^^^websiteTemplate.

        And obviously I can have code in here too. Here is the -current date/year: 2013

        - +current date/year: 2022

        @@ -128,8 +141,7 @@ comes from ^^^websiteTemplate.

        var template = RazorFormat.RenderToHtml(dynamicPage); - template.Print(); - Assert.That(template, Is.EqualTo(expectedHtml)); + Assert.That(template.NormalizeNewLines(), Is.EqualTo(expectedHtml)); } [Test] @@ -162,7 +174,6 @@ @section Section1 {
        Menu1
        }" RazorFormat.AddFileAndPage("/views/websiteTemplate1.cshtml", websiteTemplate1); var dynamicPage = RazorFormat.AddFileAndPage(@"/page.cshtml", pageTemplate); var template = RazorFormat.RenderToHtml(dynamicPage); - template.Print(); Assert.That(template, Is.EqualTo(expectedHtml)); } @@ -250,7 +261,7 @@ with a layout template. The content you are seeing here comes from ^^^websiteTemplate.

        And obviously I can have code in here too. Here is the -current date/year: 2013

        +current date/year: 2022

        @@ -272,7 +283,6 @@ comes from ^^^websiteTemplate.

        var html = RazorFormat.RenderToHtml(dynamicPage, layout: "websiteTemplate"); - html.Print(); Assert.That(html, Is.EqualTo(expectedHtml)); } @@ -309,7 +319,6 @@ public void Encapsulation_and_reuse_with_HTML_helpers() var product = new Product { ProductID = 10 }; var html = RazorFormat.CreateAndRenderToHtml(pageTemplate, product); - html.Print(); Assert.That(html, Is.EqualTo(expectedHtml)); } @@ -346,7 +355,6 @@ public void Using_External_HTML_Helpers() var html = RazorFormat.CreateAndRenderToHtml(pageTemplate, model: products); - html.Print(); Assert.That(html, Is.EqualTo(expectedHtml)); } @@ -372,7 +380,6 @@ public void Using_Custom_base_class() var html = RazorFormat.CreateAndRenderToHtml(pageTemplate, new Product("Pen", 1.99m)); - html.Print(); Assert.That(html, Is.EqualTo(expectedHtml)); } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/PrecompiledRazorEngineTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/PrecompiledRazorEngineTests.cs new file mode 100644 index 00000000000..80dc8bb6c13 --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/PrecompiledRazorEngineTests.cs @@ -0,0 +1,84 @@ +using System.Linq; +using System.Web; +using NUnit.Framework; +using ServiceStack.IO; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + [TestFixture] + public class PrecompiledRazorEngineTests : RazorEngineTests + { + public override bool PrecompileEnabled { get { return true; } } + + const string View1Html = "
        @DateTime.Now
        "; + const string View2Html = "
        @DateTime.Now
        "; + const string View3Html = "
        @DateTime.Now
        "; + + protected override void InitializeFileSystem(MemoryVirtualFiles fileSystem) + { + base.InitializeFileSystem(fileSystem); + + fileSystem.WriteFile("/views/v1.cshtml", View1Html); + fileSystem.WriteFile("/views/v2.cshtml", View2Html); + fileSystem.WriteFile("/views/v3.cshtml", View3Html); + } + + [Test] + public void Pages_begin_compilation_on_startup() + { + foreach (var page in new[] { "v1", "v2", "v3" }.Select(name => RazorFormat.GetViewPage(name))) + { + Assert.That(page.MarkedForCompilation || page.IsCompiling || page.IsValid); + } + } + + [Test] + public void New_pages_begin_compilation_when_added() + { + const string template = "This is my sample template, Hello @Model.Name!"; + RazorFormat.AddFileAndPage("/simple.cshtml", template); + + var page = RazorFormat.GetContentPage("/simple.cshtml"); + FuncUtils.WaitWhile(() => page.MarkedForCompilation || page.IsCompiling, millisecondTimeout: 5000); + Assert.That(page.IsValid); + } + + [Test] + public void Pages_with_errors_dont_cause_exceptions_on_thread_starting_the_precompilation() + { + const string template = "This is a bad template, Hello @SomeInvalidMember.Name!"; + RazorFormat.AddFileAndPage("/simple.cshtml", template); + + var page = RazorFormat.GetContentPage("/simple.cshtml"); + FuncUtils.WaitWhile(() => page.MarkedForCompilation || page.IsCompiling, millisecondTimeout: 5000); + Assert.That(page.CompileException, Is.Not.Null); + } + + [Test] + public void Pages_with_errors_still_throw_exceptions_when_rendering() + { + const string template = "This is a bad template, Hello @SomeInvalidMember.Name!"; + + Assert.Throws(() => { + RazorFormat.AddFileAndPage("/simple.cshtml", template); + RazorFormat.RenderToHtml("/simple.cshtml", new { Name = "World" }); + }); + } + } + + [TestFixture] + public class StartupPrecompiledRazorEngineTests : PrecompiledRazorEngineTests + { + public override bool PrecompileEnabled { get { return true; } } + public override bool WaitForPrecompileEnabled { get { return true; } } + + [Test] + public void Precompilation_finishes_before_returning_from_init() + { + foreach (var page in new[] { "v1", "v2", "v3" }.Select(name => RazorFormat.GetViewPage(name))) + { + Assert.That(page.IsValid); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorEngineTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorEngineTests.cs index 7361f52d78c..1486a5a7838 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorEngineTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorEngineTests.cs @@ -1,10 +1,10 @@ -using System; +using System.Threading.Tasks; using NUnit.Framework; using ServiceStack.Html; +using ServiceStack.IO; using ServiceStack.Razor; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; namespace ServiceStack.ServiceHost.Tests.Formats_Razor { @@ -13,27 +13,53 @@ public class RazorEngineTests { const string LayoutHtml = "
        @RenderSection(\"Title\")
        @RenderBody()"; - RazorFormat razorFormat; + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected RazorFormat RazorFormat; + + public virtual bool PrecompileEnabled { get { return false; } } + public virtual bool WaitForPrecompileEnabled { get { return false; } } [SetUp] public void OnBeforeEachTest() { RazorFormat.Instance = null; - razorFormat = new RazorFormat + + var fileSystem = new MemoryVirtualFiles(); + fileSystem.WriteFile("/views/TheLayout.cshtml", LayoutHtml); + InitializeFileSystem(fileSystem); + + RazorFormat = new RazorFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), + VirtualFileSources = fileSystem, PageBaseType = typeof(CustomRazorBasePage<>), EnableLiveReload = false, + PrecompilePages = PrecompileEnabled, + WaitForPrecompilationOnStartup = WaitForPrecompileEnabled, }.Init(); + } - razorFormat.AddFileAndPage("/views/TheLayout.cshtml", LayoutHtml); + protected virtual void InitializeFileSystem(MemoryVirtualFiles fileSystem) + { } [Test] public void Can_compile_simple_template() { const string template = "This is my sample template, Hello @Model.Name!"; - var result = razorFormat.CreateAndRenderToHtml(template, model: new { Name = "World" }); + var result = RazorFormat.CreateAndRenderToHtml(template, model: new { Name = "World" }); Assert.That(result, Is.EqualTo("This is my sample template, Hello World!")); } @@ -42,22 +68,37 @@ public void Can_compile_simple_template() public void Can_compile_simple_template_by_name() { const string template = "This is my sample template, Hello @Model.Name!"; - razorFormat.AddFileAndPage("/simple.cshtml", template); - var result = razorFormat.RenderToHtml("/simple.cshtml", new { Name = "World" }); + RazorFormat.AddFileAndPage("/simple.cshtml", template); + var result = RazorFormat.RenderToHtml("/simple.cshtml", new { Name = "World" }); Assert.That(result, Is.EqualTo("This is my sample template, Hello World!")); } + [Test] + public void Can_compile_simple_view_by_name() + { + const string template = "This is my sample view, Hello @Model.Name!"; + RazorFormat.VirtualFileSources.WriteFile("/Views/simple.cshtml", template); + var addedView = RazorFormat.AddPage("/Views/simple.cshtml"); + var viewPage = RazorFormat.GetViewPage("simple"); + + Assert.That(addedView == viewPage); + + var result = RazorFormat.RenderToHtml(viewPage, new { Name = "World" }); + + Assert.That(result, Is.EqualTo("This is my sample view, Hello World!")); + } + [Test] public void Can_compile_simple_template_by_name_with_layout() { const string template = "@{ Layout = \"TheLayout.cshtml\"; }This is my sample template, Hello @Model.Name!"; - razorFormat.AddFileAndPage("/simple.cshtml", template); + RazorFormat.AddFileAndPage("/simple.cshtml", template); - var result = razorFormat.RenderToHtml("/simple.cshtml", model: new { Name = "World" }); + var result = RazorFormat.RenderToHtml("/simple.cshtml", model: new { Name = "World" }); Assert.That(result, Is.EqualTo("
        This is my sample template, Hello World!")); - var result2 = razorFormat.RenderToHtml("/simple.cshtml", model: new { Name = "World2" }, layout:"bare"); + var result2 = RazorFormat.RenderToHtml("/simple.cshtml", model: new { Name = "World2" }, layout: "bare"); Assert.That(result2, Is.EqualTo("This is my sample template, Hello World2!")); } @@ -65,9 +106,9 @@ public void Can_compile_simple_template_by_name_with_layout() public void Can_get_executed_template_by_name_with_layout() { const string html = "@{ Layout = \"TheLayout.cshtml\"; }This is my sample template, Hello @Model.Name!"; - razorFormat.AddFileAndPage("/simple2.cshtml", html); + RazorFormat.AddFileAndPage("/simple2.cshtml", html); - var result = razorFormat.RenderToHtml("/simple2.cshtml", new { Name = "World" }); + var result = RazorFormat.RenderToHtml("/simple2.cshtml", new { Name = "World" }); Assert.That(result, Is.EqualTo("
        This is my sample template, Hello World!")); } @@ -76,10 +117,10 @@ public void Can_get_executed_template_by_name_with_layout() public void Can_get_executed_template_by_name_with_section() { const string html = "@{ Layout = \"TheLayout.cshtml\"; }This is my sample template, @section Title {

        Hello @Model.Name!

        }"; - var page = razorFormat.AddFileAndPage("/views/simple3.cshtml", html); + var page = RazorFormat.AddFileAndPage("/views/simple3.cshtml", html); IRazorView view; - var result = razorFormat.RenderToHtml(page, out view, model: new { Name = "World" }); + var result = RazorFormat.RenderToHtml(page, out view, model: new { Name = "World" }); Assert.That(result, Is.EqualTo("

        Hello World!

        This is my sample template, ")); @@ -95,13 +136,26 @@ public void Can_get_executed_template_by_name_with_section() public void Can_compile_template_with_RenderBody() { const string html = "@{ Layout = \"TheLayout.cshtml\"; }This is my sample template, @section Title {

        Hello @Model.Name!

        }"; - var page = razorFormat.AddFileAndPage("/views/simple4.cshtml", html); + var page = RazorFormat.AddFileAndPage("/views/simple4.cshtml", html); - var result = razorFormat.RenderToHtml(page, model: new { Name = "World" }); + var result = RazorFormat.RenderToHtml(page, model: new { Name = "World" }); result.Print(); Assert.That(result, Is.EqualTo("

        Hello World!

        This is my sample template, ")); } + [Test] + public void Rendering_is_thread_safe() + { + const string template = "This is my sample template, Hello @Model.Name!"; + RazorFormat.AddFileAndPage("/simple.cshtml", template); + + Parallel.For(0, 10, i => + { + var result = RazorFormat.RenderToHtml("/simple.cshtml", new { Name = "World" }); + Assert.That(result, Is.EqualTo("This is my sample template, Hello World!")); + }); + } + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorPageResolutionTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorPageResolutionTests.cs new file mode 100644 index 00000000000..059715f8689 --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorPageResolutionTests.cs @@ -0,0 +1,330 @@ +using System; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Razor; +using ServiceStack.Testing; + +namespace ServiceStack.ServiceHost.Tests.Formats_Razor +{ + [TestFixture] + public class RazorPageResolutionTests + { + const string SharedLayout = "SharedLayout: @RenderBody()"; + const string RootViewLayout = "RootViewLayout: @RenderBody()"; + const string ChildViewLayout = "ChildViewLayout: @RenderBody()"; + const string RootContentLayout = "RootContentLayout: @RenderBody()"; + const string ChildContentLayout = "ChildContentLayout: @RenderBody()"; + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected RazorFormat RazorFormat; + + [SetUp] + public void OnBeforeEachTest() + { + RazorFormat.Instance = null; + + var fileSystem = new MemoryVirtualFiles(); + + RazorFormat = new RazorFormat + { + VirtualFileSources = fileSystem, + EnableLiveReload = false, + }.Init(); + } + + private void SetupSharedLayout() { RazorFormat.AddFileAndPage("/Views/Shared/_Layout.cshtml", SharedLayout); } + private void SetupRootViewLayout() { RazorFormat.AddFileAndPage("/Views/_Layout.cshtml", RootViewLayout); } + private void SetupChildViewLayout() { RazorFormat.AddFileAndPage("/Views/Child/_Layout.cshtml", ChildViewLayout); } + private void SetupRootContentLayout() { RazorFormat.AddFileAndPage("/content/_Layout.cshtml", RootContentLayout); } + private void SetupChildContentLayout() { RazorFormat.AddFileAndPage("/content/child/_Layout.cshtml", ChildContentLayout); } + + private void SetupAllDefaultLayoutFiles() + { + SetupSharedLayout(); + SetupRootViewLayout(); + SetupChildViewLayout(); + SetupRootContentLayout(); + SetupChildContentLayout(); + } + + [Test] + public void Can_resolve_content_page_by_filename() + { + const string content = "ContentPage"; + RazorFormat.AddFileAndPage("/content/page.cshtml", content); + + var resultWithExtension = ExecuteContentPage("/content/page.cshtml"); + Assert.That(resultWithExtension, Is.EqualTo(content)); + + var resultWithoutExtension = ExecuteContentPage("/content/page"); + Assert.That(resultWithoutExtension, Is.EqualTo(content)); + } + + [Test] + public void Content_page_resolution_is_not_case_sensitive() + { + const string content = "ContentPage"; + RazorFormat.AddFileAndPage("/Content/Page.cshtml", content); + + var result = ExecuteContentPage("/content/page"); + Assert.That(result, Is.EqualTo(content)); + } + + [Test] + public void Default_content_page_resolution_works_at_root() + { + const string content = "DefaultContentPage"; + RazorFormat.AddFileAndPage("/default.cshtml", content); + + var result = ExecuteContentPage("/"); + Assert.That(result, Is.EqualTo(content)); + } + + [Test] + public void Default_content_page_resolution_works_in_folder() + { + const string content = "DefaultContentPage"; + RazorFormat.AddFileAndPage("/content/default.cshtml", content); + + var result = ExecuteContentPage("/content"); + Assert.That(result, Is.EqualTo(content)); + } + + [Test] + public void View_page_can_resolve_sibling_explicit_layout() + { + SetupAllDefaultLayoutFiles(); + + const string layout = "CustomViewLayout: @RenderBody()"; + RazorFormat.AddFileAndPage("/Views/_CustomLayout.cshtml", layout); + + const string viewBody = "@{Layout = \"_CustomLayout\";}ViewPage"; + RazorFormat.AddFileAndPage("/Views/RootView.cshtml", viewBody); + + var result = ExecuteViewPage(); + Assert.That(result, Is.EqualTo("CustomViewLayout: ViewPage")); + } + + [Test] + public void Content_page_can_resolve_sibling_explicit_layout() + { + SetupAllDefaultLayoutFiles(); + + const string layout = "CustomContentLayout: @RenderBody()"; + RazorFormat.AddFileAndPage("/content/_CustomLayout.cshtml", layout); + + const string contentBody = "@{Layout = \"_CustomLayout\";}ContentPage"; + RazorFormat.AddFileAndPage("/content/page.cshtml", contentBody); + + var result = ExecuteContentPage("/content/page"); + Assert.That(result, Is.EqualTo("CustomContentLayout: ContentPage")); + } + + [Test] + public void Content_page_can_resolve_parent_explicit_layout() + { + SetupAllDefaultLayoutFiles(); + + const string layout = "CustomParentContentLayout: @RenderBody()"; + RazorFormat.AddFileAndPage("/content/_CustomParentLayout.cshtml", layout); + + const string contentBody = "@{Layout = \"_CustomParentLayout\";}ChildContentPage"; + RazorFormat.AddFileAndPage("/content/child/page.cshtml", contentBody); + + var result = ExecuteContentPage("/content/child/page"); + Assert.That(result, Is.EqualTo("CustomParentContentLayout: ChildContentPage")); + } + + [Test] + public void Content_page_can_resolve_shared_explicit_layout() + { + SetupAllDefaultLayoutFiles(); + + const string layout = "CustomContentLayout: @RenderBody()"; + RazorFormat.AddFileAndPage("/Views/Shared/_CustomLayout.cshtml", layout); + + const string contentBody = "@{Layout = \"_CustomLayout\";}ContentPage"; + RazorFormat.AddFileAndPage("/content/page.cshtml", contentBody); + + var result = ExecuteContentPage("/content/page"); + Assert.That(result, Is.EqualTo("CustomContentLayout: ContentPage")); + } + + [Test] + public void Root_view_page_can_resolve_sibling_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string viewBody = "RootViewPage"; + RazorFormat.AddFileAndPage("/Views/RootView.cshtml", viewBody); + + var result = ExecuteViewPage(); + Assert.That(result, Is.EqualTo(RootViewLayout.Replace("@RenderBody()", viewBody))); + } + + [Test] + public void Child_view_page_can_resolve_sibling_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string viewBody = "ChildViewPage"; + RazorFormat.AddFileAndPage("/Views/Child/ChildView.cshtml", viewBody); + + var result = ExecuteViewPage(); + Assert.That(result, Is.EqualTo(ChildViewLayout.Replace("@RenderBody()", viewBody))); + } + + [Test] + public void Child_view_page_without_sibling_default_layout_can_resolve_parent_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string viewBody = "ChildViewWithoutSiblingLayoutPage"; + RazorFormat.AddFileAndPage("/Views/ChildWithoutLayout/ChildViewWithoutSiblingLayout.cshtml", viewBody); + + var result = ExecuteViewPage(); + Assert.That(result, Is.EqualTo(RootViewLayout.Replace("@RenderBody()", viewBody))); + } + + [Test] + public void Child_view_page_without_sibling_or_parent_default_layout_can_resolve_shared_default_layout() + { + SetupSharedLayout(); + SetupChildViewLayout(); + + const string viewBody = "ChildViewWithoutSiblingLayoutPage"; + RazorFormat.AddFileAndPage("/Views/ChildWithoutLayout/ChildViewWithoutSiblingLayout.cshtml", viewBody); + + var result = ExecuteViewPage(); + Assert.That(result, Is.EqualTo(SharedLayout.Replace("@RenderBody()", viewBody))); + } + + [Test] + public void Root_content_page_can_resolve_sibling_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string contentBody = "RootContentPage"; + RazorFormat.AddFileAndPage("/content/root-content.cshtml", contentBody); + + var result = ExecuteContentPage("/content/root-content.cshtml"); + Assert.That(result, Is.EqualTo(RootContentLayout.Replace("@RenderBody()", contentBody))); + } + + [Test] + public void Child_content_page_can_resolve_sibling_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string contentBody = "ChildContentPage"; + RazorFormat.AddFileAndPage("/content/child/child-content.cshtml", contentBody); + + var result = ExecuteContentPage("/content/child/child-content"); + Assert.That(result, Is.EqualTo(ChildContentLayout.Replace("@RenderBody()", contentBody))); + } + + [Test] + public void Child_content_page_without_sibling_default_layout_can_resolve_parent_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string contentBody = "ChildContentWithoutSiblingLayoutPage"; + RazorFormat.AddFileAndPage("/content/child-without-layout/child-content.cshtml", contentBody); + + var result = ExecuteContentPage("/content/child-without-layout/child-content"); + Assert.That(result, Is.EqualTo(RootContentLayout.Replace("@RenderBody()", contentBody))); + } + + [Test] + public void Child_content_page_without_sibling_or_parent_default_layout_can_resolve_shared_default_layout() + { + SetupSharedLayout(); + SetupChildContentLayout(); + + const string contentBody = "ChildContentWithoutSiblingLayoutPage"; + RazorFormat.AddFileAndPage("/content/child-without-layout/child-content.cshtml", contentBody); + + var result = ExecuteContentPage("/content/child-without-layout/child-content"); + Assert.That(result, Is.EqualTo(SharedLayout.Replace("@RenderBody()", contentBody))); + } + + [Test] + public void Default_content_page_can_resolve_sibling_default_layout() + { + SetupAllDefaultLayoutFiles(); + + const string contentBody = "RootDefaultContentPage"; + RazorFormat.AddFileAndPage("/content/" + RazorFormat.DefaultPageName, contentBody); + + var result = ExecuteContentPage("/content"); + Assert.That(result, Is.EqualTo(RootContentLayout.Replace("@RenderBody()", contentBody))); + } + + [Test] + [Ignore("Backwards compatibility requirement")] + public void Content_page_does_not_resolve_root_view_folder_default_layout() + { + SetupRootViewLayout(); + + const string contentBody = "ArbitraryContentPage"; + RazorFormat.AddFileAndPage("/content/arbitrary-content.cshtml", contentBody); + + var result = ExecuteContentPage("/content/arbitrary-content"); + Assert.That(result, Is.EqualTo(contentBody)); + } + + [Test] + public void Content_page_without_sibling_or_parent_or_shared_default_layout_can_resolve_root_view_default_layout_for_backwards_compatability() + { + SetupRootViewLayout(); + + const string contentBody = "ChildContentWithoutSiblingLayoutPage"; + RazorFormat.AddFileAndPage("/content/child-without-layout/child-content.cshtml", contentBody); + + var result = ExecuteContentPage("/content/child-without-layout/child-content"); + Assert.That(result, Is.EqualTo(RootViewLayout.Replace("@RenderBody()", contentBody))); + } + + private string ExecuteViewPage() where TRequest : new() + { + var responseDtoType = typeof(TRequest).Assembly.GetType(typeof(TRequest).FullName + "Response"); + var responseDto = Activator.CreateInstance(responseDtoType); + var mockReq = new MockHttpRequest { OperationName = typeof(TRequest).Name, Dto = new TRequest() }; + var mockRes = new MockHttpResponse(mockReq) { Dto = responseDto }; + RazorFormat.ProcessRequest(mockReq, mockRes, responseDto); + return mockRes.ReadAsString(); + } + + private string ExecuteContentPage(string path) + { + var mockReq = new MockHttpRequest + { + OperationName = "Razor_PageResolver", + PathInfo = path, + }; + var mockRes = new MockHttpResponse(mockReq); + RazorFormat.ProcessContentPageRequest(mockReq, mockRes); + return mockRes.ReadAsString(); + } + + public class RootView { } + public class RootViewResponse { } + public class ChildView { } + public class ChildViewResponse { } + public class ChildViewWithoutSiblingLayout { } + public class ChildViewWithoutSiblingLayoutResponse { } + } +} diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorTestBase.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorTestBase.cs index 6aec25de44d..f408584adf3 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorTestBase.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/RazorTestBase.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using ServiceStack.Razor; using ServiceStack.Razor.Managers; -using ServiceStack.VirtualPath; +using ServiceStack.IO; namespace ServiceStack.ServiceHost.Tests.Formats_Razor { @@ -10,17 +10,15 @@ public static class RazorFormatExtensions { public static RazorPage AddFileAndPage(this RazorFormat razorFormat, string filePath, string contents) { - var pathProvider = (IWriteableVirtualPathProvider)razorFormat.VirtualPathProvider; - pathProvider.AddFile(filePath, contents); + razorFormat.VirtualFileSources.WriteFile(filePath, contents); return razorFormat.AddPage(filePath); } } - + public class RazorTestBase - { - public const string TemplateName = "Template"; - protected const string PageName = "Page"; + { + public const string TemplateName = "Template"; + protected const string PageName = "Page"; protected RazorFormat RazorFormat; - } - + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/StandAloneExampleTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/StandAloneExampleTests.cs index 886e9c075bc..901f62b84e8 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/StandAloneExampleTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/StandAloneExampleTests.cs @@ -1,20 +1,35 @@ using NUnit.Framework; +using ServiceStack.IO; using ServiceStack.Razor; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; namespace ServiceStack.ServiceHost.Tests.Formats_Razor { [TestFixture] public class StandAloneExampleTests { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + [Test] public void Simple_static_example() { RazorFormat.Instance = null; - var razor = new RazorFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), + var razor = new RazorFormat + { + VirtualFileSources = new MemoryVirtualFiles(), EnableLiveReload = false, }.Init(); diff --git a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs index 514f7623d10..1f1e12410af 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Formats_Razor/TemplateTests.cs @@ -2,15 +2,14 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Utils; using ServiceStack.Html; +using ServiceStack.IO; using ServiceStack.Razor; using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.VirtualPath; namespace ServiceStack.ServiceHost.Tests.Formats_Razor { @@ -32,7 +31,7 @@ public Link() public List Labels { get; set; } } - public class CustomViewBase : ViewPage where T : class + public class CustomViewBase : ViewPage { public CustomMarkdownHelper Ext = new CustomMarkdownHelper(); public ExternalProductHelper Prod = new ExternalProductHelper(); @@ -67,7 +66,7 @@ public MvcHtmlString Menu(string selectedId) sb.AppendFormat("
      • {0}
      • \n", menuItem, cls); } sb.Append("
      \n"); - + return MvcHtmlString.Create(sb.ToString()); } @@ -126,9 +125,13 @@ public class RazorTemplateTests : RazorTestBase }, }; - [TestFixtureSetUp] + private ServiceStackHost appHost; + + [OneTimeSetUp] public void TestFixtureSetUp() { + appHost = new BasicAppHost().Init(); + staticTemplatePath = "Views/Shared/_Layout.cshtml"; staticTemplateContent = File.ReadAllText("~/{0}".Fmt(staticTemplatePath).MapProjectPath()); @@ -141,12 +144,19 @@ public void TestFixtureSetUp() templateArgs = person; } + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + [SetUp] public void OnBeforeEachTest() { RazorFormat.Instance = null; - base.RazorFormat = new RazorFormat { - VirtualPathProvider = new InMemoryVirtualPathProvider(new BasicAppHost()), + base.RazorFormat = new RazorFormat + { + VirtualFileSources = new MemoryVirtualFiles(), EnableLiveReload = false, }.Init(); } @@ -166,11 +176,10 @@ public void Can_Use_HtmlHelper_In_Page() public void Can_Use_Model_Directive_With_HtmlHelper() { string pageSource = "@model " + typeof(Person).FullName + @" -@Html.TextBoxFor(a => a.FirstName)"; +@Html.TextBoxFor(a => a.FirstName)"; var page = RazorFormat.CreatePage(pageSource); var output = RazorFormat.RenderToHtml(page, model: templateArgs); - output.Print(); Assert.That(output, Is.EqualTo(@"")); } @@ -185,7 +194,6 @@ public void Can_Access_ViewData() var page = RazorFormat.CreatePage(pageSource); var output = RazorFormat.RenderToHtml(page, model: templateArgs).Trim(); - output.Print(); Assert.That(output, Is.EqualTo(val)); } @@ -199,7 +207,6 @@ public void Can_Access_ViewBag_From_Layout() var page = RazorFormat.CreatePage(pageSource); RazorFormat.AddFileAndPage(staticTemplatePath, @"@ViewBag.X@RenderBody()"); var output = RazorFormat.RenderToHtml(page, model: templateArgs).Trim(); - output.Print(); Assert.That(output, Is.EqualTo(@"HelloHello")); } @@ -214,9 +221,8 @@ public void Can_Render_RazorTemplate() var expectedHtml = staticTemplateContent.ReplaceFirst(RazorFormat.TemplatePlaceHolder, mockContents); - var templateOutput = RazorFormat.RenderToHtml(page, model:templateArgs); + var templateOutput = RazorFormat.RenderToHtml(page, model: templateArgs); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -224,7 +230,7 @@ public void Can_Render_RazorTemplate() public void Can_Render_RazorPage() { RazorFormat.AddFileAndPage(staticTemplatePath, staticTemplateContent); - var dynamicPage = RazorFormat.AddFileAndPage(dynamicPagePath, dynamicPageContent); + var dynamicPage = RazorFormat.AddFileAndPage(dynamicPagePath, dynamicPageContent); var expectedHtml = dynamicPageContent .Replace("@Model.FirstName", person.FirstName) @@ -232,9 +238,8 @@ public void Can_Render_RazorPage() expectedHtml = staticTemplateContent.Replace(RazorFormat.TemplatePlaceHolder, expectedHtml); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -255,9 +260,8 @@ public void Can_Render_RazorPage_with_foreach() expectedHtml = staticTemplateContent.Replace(RazorFormat.TemplatePlaceHolder, expectedHtml); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -291,9 +295,8 @@ public void Can_Render_RazorPage_with_IF_statement() var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -351,9 +354,8 @@ public void Can_Render_RazorPage_with_Nested_Statements() var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -437,9 +439,8 @@ public void Can_Render_Razor_with_StaticMethods() var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -462,9 +463,8 @@ public void Can_inherit_from_Generic_RazorViewPage_from_model_directive() var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -494,9 +494,8 @@ public void Can_inherit_from_CustomViewPage_using_inherits_directive() var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -524,9 +523,8 @@ public void Can_Render_RazorPage_with_external_helper() var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -589,9 +587,8 @@ Hello @Upper(lastName), @Model.FirstName var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -627,9 +624,8 @@ Plain text in a comment var dynamicPage = RazorFormat.CreatePage(template); - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -726,13 +722,12 @@ @section Menus { var dynamicPage = RazorFormat.CreatePage(template); IRazorView razorView; - var templateOutput = RazorFormat.RenderToHtml(dynamicPage, out razorView, model:templateArgs).NormalizeNewLines(); + var templateOutput = RazorFormat.RenderToHtml(dynamicPage, out razorView, model: templateArgs).NormalizeNewLines(); - templateOutput.Print(); - Assert.That(templateOutput, Is.EqualTo(expectedHtml)); + Assert.That(templateOutput.NormalizeNewLines(), Is.EqualTo(expectedHtml)); var sectionHtml = razorView.RenderSectionToHtml("Salutations"); - Assert.That(sectionHtml.NormalizeNewLines(), Is.EqualTo("\n

      Hello BELLOT, Demis

      \n")); + Assert.That(sectionHtml.NormalizeNewLines(), Is.EqualTo("

      Hello BELLOT, Demis

      ")); } @@ -847,11 +842,10 @@ @section Menus { RazorFormat.AddFileAndPage("/views/{0}".Fmt(websiteTemplatePath), websiteTemplate); var page = RazorFormat.CreatePage(template); - var result = RazorFormat.RenderToHtml(page, model:person, layout:websiteTemplatePath); + var result = RazorFormat.RenderToHtml(page, model: person, layout: websiteTemplatePath); var templateOutput = result.NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } @@ -936,7 +930,6 @@ @section Header { var templateOutput = RazorFormat.RenderToHtml(staticPage, layout: "websiteTemplate").NormalizeNewLines(); - templateOutput.Print(); Assert.That(templateOutput, Is.EqualTo(expectedHtml)); } diff --git a/tests/ServiceStack.ServiceHost.Tests/HttpRequestAuthenticationTests.cs b/tests/ServiceStack.ServiceHost.Tests/HttpRequestAuthenticationTests.cs new file mode 100644 index 00000000000..5403733c06a --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/HttpRequestAuthenticationTests.cs @@ -0,0 +1,75 @@ +using System.Collections.Specialized; +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; + +namespace ServiceStack.ServiceHost.Tests +{ + [TestFixture] + class HttpRequestAuthenticationTests + { + private readonly ServiceStackHost appHost; + public HttpRequestAuthenticationTests() => appHost = new BasicAppHost().Init(); + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + private static BasicRequest CreateRequest(string authHeader) => new BasicRequest { + Headers = new NameValueCollection { {HttpHeaders.Authorization, authHeader} } + }; + + [Test] + public void Correct_commas_in_digestAuth_parsing() + { + const string authHeader = "Digest username=\"кенкен\", realm=\"SWP\", nonce=\"NjM1MDk1NjA0NjExMjMuMTozOGVkMDcyYWQ1ODY5NzhhYTIxODAwNzkyYzRiNzZmYw==\", uri=\"/api/v1/projects/2969/tests?select=metadata,results\", response=\"5f818c8d263e26e787d75b60b78157d1\", qop=auth, nc=00000001, cnonce=\"7e06df0b911151b2\", "; + var req = CreateRequest(authHeader); + + var res = req.GetDigestAuth(); + + Assert.NotNull(res); + } + + [Test] + public void Should_Return_Null_When_Authorization_Header_Is_Missing() + { + var req = CreateRequest(null); + var bearerToken = req.GetBearerToken(); + + Assert.Null(bearerToken); + } + + [Test] + public void Should_Return_Null_As_Bearer_Token_When_Authorization_Header_Is_Empty() + { + var req = CreateRequest(string.Empty); + var bearerToken = req.GetBearerToken(); + + Assert.Null(bearerToken); + } + + [Test] + public void Should_Return_Null_As_Bearer_Token_When_Authorization_Header_Does_Not_Prefix() + { + var req = CreateRequest("Blablabla"); + var bearerToken = req.GetBearerToken(); + + Assert.Null(bearerToken); + } + + [Test] + public void Should_Return_Null_As_Bearer_Token_When_Authorization_Header_Does_Not_Contain_Bearer() + { + var req = CreateRequest("Basic blablabla"); + var bearerToken = req.GetBearerToken(); + + Assert.Null(bearerToken); + } + + [Test] + public void Can_Return_Bearer_Token() + { + var req = CreateRequest("Bearer blablabla"); + var bearerToken = req.GetBearerToken(); + + Assert.True("blablabla" == bearerToken); + } + } +} diff --git a/tests/ServiceStack.ServiceHost.Tests/HttpRequestAuthenticatonTests.cs b/tests/ServiceStack.ServiceHost.Tests/HttpRequestAuthenticatonTests.cs deleted file mode 100644 index 3d2a43c8e24..00000000000 --- a/tests/ServiceStack.ServiceHost.Tests/HttpRequestAuthenticatonTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Specialized; -using NUnit.Framework; -using Moq; - -namespace ServiceStack.ServiceHost.Tests -{ - [TestFixture] - class HttpRequestAuthenticatonTests - { - [Test] - public void Correct_commas_in_digestAuth_parsing() - { - var requestMock = new Mock(); - const string authHeader = "Digest username=\"кенкен\", realm=\"SWP\", nonce=\"NjM1MDk1NjA0NjExMjMuMTozOGVkMDcyYWQ1ODY5NzhhYTIxODAwNzkyYzRiNzZmYw==\", uri=\"/api/v1/projects/2969/tests?select=metadata,results\", response=\"5f818c8d263e26e787d75b60b78157d1\", qop=auth, nc=00000001, cnonce=\"7e06df0b911151b2\", "; - var headers = new NameValueCollection(); - headers.Add("Authorization", authHeader); - - requestMock.Expect(e => e.Headers).Returns(headers); - - var res = HttpRequestAuthentication.GetDigestAuth(requestMock.Object); - - Assert.NotNull(res); - } - } -} diff --git a/tests/ServiceStack.ServiceHost.Tests/HttpRequestMock.cs b/tests/ServiceStack.ServiceHost.Tests/HttpRequestMock.cs index 12da2559a6d..41302e8869d 100644 --- a/tests/ServiceStack.ServiceHost.Tests/HttpRequestMock.cs +++ b/tests/ServiceStack.ServiceHost.Tests/HttpRequestMock.cs @@ -1,157 +1,182 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using System.Text; -using ServiceStack.Common.Utils; +using System.Threading.Tasks; +using ServiceStack.Web; namespace ServiceStack.ServiceHost.Tests { - class HttpRequestMock : IHttpRequest - { - public object OriginalRequest - { - get { throw new NotImplementedException(); } - } - - public string OperationName - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public string ContentType - { - get { throw new NotImplementedException(); } - } + class HttpRequestMock : IHttpRequest + { + public object OriginalRequest + { + get { throw new NotImplementedException(); } + } + + public IResponse Response { get; private set; } + + public string OperationName { get; set; } + + public string Verb { get; private set; } + public RequestAttributes RequestAttributes { get; set; } + public IRequestPreferences RequestPreferences { get; private set; } + public object Dto { get; set; } + + public string ContentType + { + get { throw new NotImplementedException(); } + } public bool IsLocal { get { return true; } } - public string HttpMethod - { - get { throw new NotImplementedException(); } - } - - public string UserAgent - { - get { throw new NotImplementedException(); } - } - - public IDictionary Cookies - { - get { throw new NotImplementedException(); } - } - - public string ResponseContentType - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public Dictionary Items - { - get { throw new NotImplementedException(); } - } - - public System.Collections.Specialized.NameValueCollection Headers - { - get { throw new NotImplementedException(); } - } - - public System.Collections.Specialized.NameValueCollection QueryString - { - get { throw new NotImplementedException(); } - } - - public System.Collections.Specialized.NameValueCollection FormData - { - get { throw new NotImplementedException(); } - } - - public bool UseBufferedStream { get; set; } - - public string GetRawBody() - { - throw new NotImplementedException(); - } - - public string RawUrl - { - get { throw new NotImplementedException(); } - } - - public string AbsoluteUri - { - get { throw new NotImplementedException(); } - } - - public string UserHostAddress - { - get { throw new NotImplementedException(); } - } - - public string RemoteIp - { - get { throw new NotImplementedException(); } - } + public IHttpResponse HttpResponse { get; private set; } + + public string HttpMethod + { + get { throw new NotImplementedException(); } + } + + public string UserAgent + { + get { throw new NotImplementedException(); } + } + + public IDictionary Cookies + { + get { throw new NotImplementedException(); } + } + + public string ResponseContentType + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public bool HasExplicitResponseContentType { get; private set; } + + public Dictionary Items => throw new NotImplementedException(); + public NameValueCollection Headers => throw new NotImplementedException(); + public NameValueCollection QueryString => throw new NotImplementedException(); + public NameValueCollection FormData => throw new NotImplementedException(); + + public bool UseBufferedStream { get; set; } + + public string GetRawBody() + { + throw new NotImplementedException(); + } + + public Task GetRawBodyAsync() => throw new NotImplementedException(); + + public string RawUrl + { + get { throw new NotImplementedException(); } + } + + public string AbsoluteUri + { + get { throw new NotImplementedException(); } + } + + public string UserHostAddress + { + get { throw new NotImplementedException(); } + } + + public string RemoteIp + { + get { throw new NotImplementedException(); } + } + + public string Authorization + { + get { throw new NotImplementedException(); } + } public string XForwardedFor { get { throw new NotImplementedException(); } } - + + public int? XForwardedPort + { + get { throw new NotImplementedException(); } + } + + public string XForwardedProtocol + { + get { throw new NotImplementedException(); } + } + public string XRealIp { get { throw new NotImplementedException(); } } - public bool IsSecureConnection - { - get { throw new NotImplementedException(); } - } + public string Accept + { + get { throw new NotImplementedException(); } + } - public string[] AcceptTypes - { - get { throw new NotImplementedException(); } - } + public bool IsSecureConnection + { + get => (RequestAttributes & RequestAttributes.Secure) == RequestAttributes.Secure; + set + { + if (value) + RequestAttributes |= RequestAttributes.Secure; + else + RequestAttributes &= ~RequestAttributes.Secure; + } + } - public string PathInfo - { - get { return "index.html"; } - } + public string[] AcceptTypes + { + get { throw new NotImplementedException(); } + } - public System.IO.Stream InputStream - { - get { throw new NotImplementedException(); } - } + public string PathInfo + { + get { return "index.html"; } + } - public long ContentLength - { - get { throw new NotImplementedException(); } - } + public string OriginalPathInfo => PathInfo; - public IFile[] Files - { - get { throw new NotImplementedException(); } - } + public System.IO.Stream InputStream + { + get { throw new NotImplementedException(); } + } - public string ApplicationFilePath - { - get { return "~".MapAbsolutePath(); } - } + public long ContentLength + { + get { throw new NotImplementedException(); } + } + + public IHttpFile[] Files + { + get { throw new NotImplementedException(); } + } - public T TryResolve() - { - throw new NotImplementedException(); - } + public string ApplicationFilePath + { + get { return "~".MapAbsolutePath(); } + } + + public T TryResolve() + { + throw new NotImplementedException(); + } public Uri UrlReferrer { diff --git a/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs b/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs index 37ba526da1a..68adaf07af4 100644 --- a/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/IoCTests.cs @@ -3,66 +3,68 @@ using System.Linq; using System.Text; using NUnit.Framework; +using ServiceStack.Commands; using ServiceStack.ServiceHost.Tests.Support; using Funq; +using ServiceStack.Configuration; namespace ServiceStack.ServiceHost.Tests { - [TestFixture] - public class IoCTests - { - [Test] - public void Can_AutoWire_types_dynamically_with_expressions() - { - var serviceType = typeof(AutoWireService); - - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); - container.Register(c => 100); - - container.RegisterAutoWiredType(serviceType); - - var service = container.Resolve(); - - Assert.That(service.Foo, Is.Not.Null); - Assert.That(service.Bar, Is.Not.Null); - Assert.That(service.Count, Is.EqualTo(0)); - } - - public class Test - { - public IFoo Foo { get; set; } - public IBar Bar { get; set; } - public IFoo Foo2 { get; set; } - public IEnumerable Names { get; set; } - public int Age { get; set; } - - public Test() - { - this.Foo2 = new Foo2(); - this.Names = new List() { "Steffen", "Demis" }; - } - } - - [Test] - public void Can_AutoWire_Existing_Instance() - { - var test = new Test(); - - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); - container.Register(c => 10); - - container.AutoWire(test); - - Assert.That(test.Foo, Is.Not.Null); - Assert.That(test.Bar, Is.Not.Null); - Assert.That(test.Foo2 as Foo, Is.Null); - Assert.That(test.Names, Is.Not.Null); - Assert.That(test.Age, Is.EqualTo(0)); - } + [TestFixture] + public class IoCTests + { + [Test] + public void Can_AutoWire_types_dynamically_with_expressions() + { + var serviceType = typeof(AutoWireService); + + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 100); + + container.RegisterAutoWiredType(serviceType); + + var service = container.Resolve(); + + Assert.That(service.Foo, Is.Not.Null); + Assert.That(service.Bar, Is.Not.Null); + Assert.That(service.Count, Is.EqualTo(0)); + } + + public class Test + { + public IFoo Foo { get; set; } + public IBar Bar { get; set; } + public IFoo Foo2 { get; set; } + public IEnumerable Names { get; set; } + public int Age { get; set; } + + public Test() + { + this.Foo2 = new Foo2(); + this.Names = new List() { "Steffen", "Demis" }; + } + } + + [Test] + public void Can_AutoWire_Existing_Instance() + { + var test = new Test(); + + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 10); + + container.AutoWire(test); + + Assert.That(test.Foo, Is.Not.Null); + Assert.That(test.Bar, Is.Not.Null); + Assert.That(test.Foo2 as Foo, Is.Null); + Assert.That(test.Names, Is.Not.Null); + Assert.That(test.Age, Is.EqualTo(0)); + } public class DependencyWithBuiltInTypes { @@ -75,12 +77,12 @@ public DependencyWithBuiltInTypes() public IFoo Foo { get; set; } public IBar Bar { get; set; } public string String { get; set; } - public int Age { get; set; } + public int Age { get; set; } } - [Test] - public void Does_not_AutoWire_BuiltIn_BCL_and_ValueTypes() - { + [Test] + public void Does_not_AutoWire_BuiltIn_BCL_and_ValueTypes() + { var container = new Container(); container.Register(c => new Foo()); container.Register(c => new Bar()); @@ -91,11 +93,267 @@ public void Does_not_AutoWire_BuiltIn_BCL_and_ValueTypes() container.RegisterAutoWired(); - var test = container.Resolve(); + var test = container.Resolve(); Assert.That(test.Foo, Is.Not.Null); Assert.That(test.Bar, Is.Not.Null); Assert.That(test.String, Is.EqualTo("A String")); Assert.That(test.Age, Is.EqualTo(27)); - } - } + } + + public class FunqTest + { + public FunqTest(Func ctorFoo) + { + this.ctorFoo = ctorFoo; + } + + private Func ctorFoo; + public Func CtorFoo + { + get { return ctorFoo; } + } + + public Func FunqFoo { get; set; } + } + + [Test] + public void Does_Resolve_lazy_Func_types() + { + var container = new Container(); + + container.Register>(c => () => new Foo()); + + container.RegisterAutoWired(); + + var test = container.Resolve(); + Assert.That(test.CtorFoo, Is.Not.Null); + Assert.That(test.CtorFoo(), Is.Not.Null); + Assert.That(test.FunqFoo, Is.Not.Null); + Assert.That(test.FunqFoo(), Is.Not.Null); + } + + [Test] + public void Does_AutoWire_Funq_types() + { + var container = new Container(); + + container.RegisterAutoWiredAs(); + + container.RegisterAutoWired(); + + var test = container.Resolve(); + Assert.That(test.CtorFoo, Is.Not.Null); + Assert.That(test.CtorFoo(), Is.Not.Null); + Assert.That(test.FunqFoo, Is.Not.Null); + Assert.That(test.FunqFoo(), Is.Not.Null); + } + + public class MultiFunqTest + { + public MultiFunqTest(Func ctorFooBar) + { + this.ctorFooBar = ctorFooBar; + } + + private Func ctorFooBar; + public Func CtorFooBar + { + get { return ctorFooBar; } + } + + public Func FunqFooBar { get; set; } + + public Func FunqTestFooBar { get; set; } + } + + [Test] + public void Does_AutoWire_MultiFunq_types() + { + var container = new Container(); + + container.RegisterAutoWiredAs(); + container.RegisterAutoWiredAs(); + container.RegisterAutoWired(); + + var foo = container.Resolve(); + Assert.That(foo, Is.Not.Null); + var bar = container.Resolve(); + Assert.That(bar, Is.Not.Null); + + container.RegisterAutoWired(); + + var test = container.Resolve(); + Assert.That(test.CtorFooBar, Is.Not.Null); + Assert.That(test.CtorFooBar(new Foo()), Is.Not.Null); + Assert.That(test.FunqFooBar, Is.Not.Null); + Assert.That(test.FunqFooBar(new Foo()), Is.Not.Null); + Assert.That(test.FunqTestFooBar, Is.Not.Null); + Assert.That(test.FunqTestFooBar(new Test(), new Foo()), Is.Not.Null); + } + + public class FooCommand : ICommand + { + public Foo Foo { get; set; } + public Foo Execute() + { + return Foo; + } + } + public class BarCommand : ICommand + { + public Bar Bar { get; set; } + public Bar Execute() + { + return Bar; + } + } + + [Test] + public void Can_autowire_generic_type_definitions() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + + GetType().Assembly.GetTypes() + .Where(x => x.IsOrHasGenericInterfaceTypeOf(typeof(ICommand<>))) + .Each(x => container.RegisterAutoWiredType(x)); + + var fooCmd = container.Resolve(); + Assert.That(fooCmd.Execute(), Is.EqualTo(container.Resolve())); + var barCmd = container.Resolve(); + Assert.That(barCmd.Execute(), Is.EqualTo(container.Resolve())); + } + + [Test] + public void Can_resolve_using_untyped_Container_Api() + { + var container = new Container(); + container.Register(c => new Foo()); + + var instance = container.TryResolve(typeof(Foo)); + Assert.That(instance, Is.Not.Null); + } + + class CustomAdapter : IContainerAdapter + { + public T TryResolve() + { + if (typeof(T) == typeof(IFoo)) + return (T)(object)new Foo(); + return default(T); + } + + public T Resolve() + { + throw new NotImplementedException(); + } + } + + [Test] + public void Does_fallback_to_Funq_when_missing_in_Adapter() + { + var container = new Container { Adapter = new CustomAdapter() }; + container.Register(c => new Bar()); + + Assert.That(container.TryResolve(), Is.Not.Null); + Assert.That(container.TryResolve(), Is.Not.Null); + } + + [Test] + public void Can_configure_and_resolve_Named_instances() + { + var container = new Container(); + container.Register("foo1", new Foo()); + container.Register("foo2", new Foo2()); + + Assert.That(container.ResolveNamed("foo1") is Foo); + Assert.That(container.ResolveNamed("foo2") is Foo2); + } + + [Test] + public void Can_autowire_named_instances() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 100); + + container.RegisterAutoWired("one"); + container.RegisterAutoWired("two"); + + var one = container.ResolveNamed("one"); + var two = container.ResolveNamed("two"); + Assert.That(one, Is.Not.Null); + Assert.AreNotSame(one, two); + } + + [Test] + public void Can_autowireAs_named_instances() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 100); + + container.RegisterAutoWiredAs("one"); + container.RegisterAutoWiredAs("two"); + + var one = container.ResolveNamed("one"); + var two = container.ResolveNamed("two"); + Assert.That(one, Is.Not.Null); + Assert.AreNotSame(one, two); + } + + [Test] + public void Can_registerAs_named_instances() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 100); + + container.RegisterAs("one"); + container.RegisterAs("two"); + + var one = container.ResolveNamed("one"); + var two = container.ResolveNamed("two"); + Assert.That(one, Is.Not.Null); + Assert.AreNotSame(one, two); + } + + [Test] + public void Can_registerAutoWiredType_as_named_instance() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 100); + + container.RegisterAutoWiredType("one", typeof(AutoWireService), typeof(IService)); + container.RegisterAutoWiredType("two", typeof(AutoWireService), typeof(IService)); + + var one = container.ResolveNamed("one"); + var two = container.ResolveNamed("two"); + Assert.That(one, Is.Not.Null); + Assert.AreNotSame(one, two); + } + + [Test] + public void Can_registerAutoWiredType_named_instance() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + container.Register(c => 100); + + container.RegisterAutoWiredType("one", typeof(AutoWireService)); + container.RegisterAutoWiredType("two", typeof(AutoWireService)); + + var one = container.ResolveNamed("one"); + var two = container.ResolveNamed("two"); + Assert.That(one, Is.Not.Null); + Assert.AreNotSame(one, two); + } + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/PerfTests.cs b/tests/ServiceStack.ServiceHost.Tests/PerfTests.cs deleted file mode 100644 index ab507bf0e22..00000000000 --- a/tests/ServiceStack.ServiceHost.Tests/PerfTests.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Diagnostics; -using NUnit.Framework; -using ServiceStack.Configuration; -using ServiceStack.ServiceHost.Tests.Support; - -namespace ServiceStack.ServiceHost.Tests -{ - [Ignore("Perf Test Only")] - [TestFixture] - public class PerfTests - { - private const int Times = 100000; - private ServiceController serviceController; - - [SetUp] - public void OnBeforeEachTest() - { - serviceController = new ServiceController(null); - } - - [Test] - public void RunAll() - { - With_Native(); - With_Reflection(); //Very slow - With_Expressions(); - With_CustomFunc(); - With_TypeFactory(); - With_TypedArguments(); - } - - - [Test] - public void With_Native() - { - var request = new BasicRequest(); - - Console.WriteLine("Native(): {0}", Measure(() => new BasicService().Execute(request), Times)); - } - - [Test] - [Ignore("Slow to run")] - public void With_Reflection() - { - var serviceController = new ServiceControllerReflection(); - - serviceController.Register(() => new BasicService()); - var request = new BasicRequest(); - - Console.WriteLine("With_Reflection(): {0}", Measure(() => serviceController.ExecuteReflection(request), Times)); - } - - [Test] - public void With_ServiceStackFunq() - { - serviceController.Register(() => new BasicService()); - var request = new BasicRequest(); - - Console.WriteLine("With_TypedArguments(): {0}", Measure(() => serviceController.Execute(request), Times)); - } - - [Test] - public void With_TypedArguments() - { - serviceController.Register(() => new BasicService()); - var request = new BasicRequest(); - - Console.WriteLine("With_TypedArguments(): {0}", Measure(() => serviceController.Execute(request), Times)); - } - - [Test] - public void With_Expressions() - { - var requestType = typeof(BasicRequest); - - serviceController.Register(requestType, typeof(BasicService)); - var request = new BasicRequest(); - - Console.WriteLine("With_Expressions(): {0}", Measure(() => serviceController.Execute(request), Times)); - } - - [Test] - public void With_CustomFunc() - { - var requestType = typeof(BasicRequest); - - serviceController.Register(requestType, typeof(BasicService), type => new BasicService()); - - var request = new BasicRequest(); - - Console.WriteLine("With_CustomFunc(): {0}", Measure(() => serviceController.Execute(request), Times)); - } - - public class BasicServiceTypeFactory : ITypeFactory - { - public object CreateInstance(Type type) - { - return new BasicService(); - } - } - - [Test] - public void With_TypeFactory() - { - var requestType = typeof(BasicRequest); - serviceController.RegisterGServiceExecutor(requestType, typeof(BasicService), new BasicServiceTypeFactory()); - - var request = new BasicRequest(); - - Console.WriteLine("With_TypeFactory(): {0}", Measure(() => serviceController.Execute(request), Times)); - } - - - private static long Measure(Action action, int iterations) - { - GC.Collect(); - var watch = Stopwatch.StartNew(); - - for (int i = 0; i < iterations; i++) - { - action(); - } - - return watch.ElapsedTicks; - } - } -} diff --git a/tests/ServiceStack.ServiceHost.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.ServiceHost.Tests/Properties/AssemblyInfo.cs index 511c3d5a616..2ab68b278d3 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Properties/AssemblyInfo.cs @@ -10,8 +10,8 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Microsoft")] [assembly: AssemblyProduct("ServiceStack.ServiceHost.Tests")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCopyright("Copyright (c) Microsoft 2009")] +[assembly: AssemblyTrademark("Service Stack")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible @@ -33,4 +33,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("6.0.0.0")] diff --git a/tests/ServiceStack.ServiceHost.Tests/RequestContextExtensionsTest.cs b/tests/ServiceStack.ServiceHost.Tests/RequestContextExtensionsTest.cs index 456b02f42b1..d2f2b3917af 100644 --- a/tests/ServiceStack.ServiceHost.Tests/RequestContextExtensionsTest.cs +++ b/tests/ServiceStack.ServiceHost.Tests/RequestContextExtensionsTest.cs @@ -1,9 +1,6 @@ using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost.Tests.Formats; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Formats; +using ServiceStack.Formats; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests { @@ -25,38 +22,35 @@ public void Can_optimize_csv_result_with_ToOptimizedResult() [Test] public void Can_optimize_json_result_with_ToOptimizedResult() { - CanOptimizeResult(ContentType.Json, null); + CanOptimizeResult(MimeTypes.Json, null); } [Test] public void Can_optimize_xml_result_with_ToOptimizedResult() { - CanOptimizeResult(ContentType.Xml, null); + CanOptimizeResult(MimeTypes.Xml, null); } [Test] public void Can_optimize_jsv_result_with_ToOptimizedResult() { - CanOptimizeResult(ContentType.Jsv, null); + CanOptimizeResult(MimeTypes.Jsv, null); } private static void CanOptimizeResult(string contentType, IPlugin pluginFormat) { - var dto = new TestDto {Name = "test"}; + using var appHost = new BasicAppHost().Init(); + var dto = new TestDto { Name = "test" }; - var httpReq = new MockHttpRequest(); + var httpReq = new MockHttpRequest { + PathInfo = "/" + }; httpReq.Headers.Add(HttpHeaders.AcceptEncoding, "gzip,deflate,sdch"); httpReq.ResponseContentType = contentType; - var httpRes = new ViewTests.MockHttpResponse(); - var httpRequestContext = new HttpRequestContext(httpReq, httpRes, dto); - - var appHost = new TestAppHost(); if (pluginFormat != null) pluginFormat.Register(appHost); - EndpointHost.ContentTypeFilter = appHost.ContentTypeFilters; - - object result = httpRequestContext.ToOptimizedResult(dto); + object result = httpReq.ToOptimizedResult(dto); Assert.IsNotNull(result); Assert.IsTrue(result is CompressedResult); } diff --git a/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs b/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs index 19f948e552c..dbcb8c83ab1 100644 --- a/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/RestPathTests.cs @@ -1,94 +1,111 @@ using System; +using System.Collections.Generic; +using System.Linq; using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; namespace ServiceStack.ServiceHost.Tests { - [TestFixture] - public class RestPathTests - { - public class SimpleType - { - public string Name { get; set; } - } - - [Test] - public void Can_deserialize_SimpleType_path() - { - var restPath = new RestPath(typeof(SimpleType), "/simple/{Name}"); - var request = restPath.CreateRequest("/simple/HelloWorld!") as SimpleType; - - Assert.That(request, Is.Not.Null); - Assert.That(request.Name, Is.EqualTo("HelloWorld!")); - } - - [Test] - public void Can_deserialize_SimpleType_in_middle_of_path() - { - var restPath = new RestPath(typeof(SimpleType), "/simple/{Name}/some-other-literal"); - var request = restPath.CreateRequest("/simple/HelloWorld!/some-other-literal") as SimpleType; - - Assert.That(request, Is.Not.Null); - Assert.That(request.Name, Is.EqualTo("HelloWorld!")); - } - - [Test] - public void ShowAllow() - { - var config = EndpointHostConfig.Instance; - - const string fileName = "/path/to/image.GIF"; - var fileExt = fileName.Substring(fileName.LastIndexOf('.') + 1); - Console.WriteLine(fileExt); - Assert.That(config.AllowFileExtensions.Contains(fileExt)); - } - - - public class ComplexType - { - public int Id { get; set; } - - public string Name { get; set; } - - public Guid UniqueId { get; set; } - } - - [Test] - public void Can_deserialize_ComplexType_path() - { - - var restPath = new RestPath(typeof(ComplexType), - "/Complex/{Id}/{Name}/Unique/{UniqueId}"); - var request = restPath.CreateRequest( - "/complex/5/Is Alive/unique/4583B364-BBDC-427F-A289-C2923DEBD547") as ComplexType; - - Assert.That(request, Is.Not.Null); - Assert.That(request.Id, Is.EqualTo(5)); - Assert.That(request.Name, Is.EqualTo("Is Alive")); - Assert.That(request.UniqueId, Is.EqualTo(new Guid("4583B364-BBDC-427F-A289-C2923DEBD547"))); - } - - public class ComplexTypeWithFields - { - public readonly int Id; - - public readonly string Name; - - public readonly Guid UniqueId; - - public ComplexTypeWithFields(int id, string name, Guid uniqueId) - { - Id = id; - Name = name; - UniqueId = uniqueId; - } - } - - [Test] - public void Can_deserialize_ComplexTypeWithFields_path() - { - using (JsConfig.With(includePublicFields:true)) + [TestFixture] + public class RestPathTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public class SimpleType + { + public string Name { get; set; } + } + + [Test] + public void Can_deserialize_SimpleType_path() + { + var restPath = new RestPath(typeof(SimpleType), "/simple/{Name}"); + var request = restPath.CreateRequest("/simple/HelloWorld!") as SimpleType; + + Assert.That(request, Is.Not.Null); + Assert.That(request.Name, Is.EqualTo("HelloWorld!")); + } + + [Test] + public void Can_deserialize_SimpleType_in_middle_of_path() + { + var restPath = new RestPath(typeof(SimpleType), "/simple/{Name}/some-other-literal"); + var request = restPath.CreateRequest("/simple/HelloWorld!/some-other-literal") as SimpleType; + + Assert.That(request, Is.Not.Null); + Assert.That(request.Name, Is.EqualTo("HelloWorld!")); + } + + [Test] + public void ShowAllow() + { + var config = HostContext.Config; + + const string fileName = "/path/to/image.GIF"; + var fileExt = fileName.Substring(fileName.LastIndexOf('.') + 1); + Console.WriteLine(fileExt); + Assert.That(config.AllowFileExtensions.Contains(fileExt)); + } + + + public class ComplexType + { + public int Id { get; set; } + + public string Name { get; set; } + + public Guid UniqueId { get; set; } + } + + [Test] + public void Can_deserialize_ComplexType_path() + { + + var restPath = new RestPath(typeof(ComplexType), + "/Complex/{Id}/{Name}/Unique/{UniqueId}"); + var request = restPath.CreateRequest( + "/complex/5/Is Alive/unique/4583B364-BBDC-427F-A289-C2923DEBD547") as ComplexType; + + Assert.That(request, Is.Not.Null); + Assert.That(request.Id, Is.EqualTo(5)); + Assert.That(request.Name, Is.EqualTo("Is Alive")); + Assert.That(request.UniqueId, Is.EqualTo(new Guid("4583B364-BBDC-427F-A289-C2923DEBD547"))); + } + + public class ComplexTypeWithFields + { + public readonly int Id; + + public readonly string Name; + + public readonly Guid UniqueId; + + public ComplexTypeWithFields(int id, string name, Guid uniqueId) + { + Id = id; + Name = name; + UniqueId = uniqueId; + } + } + + [Test] + public void Can_deserialize_ComplexTypeWithFields_path() + { + using (JsConfig.With(new Config { IncludePublicFields = true })) { var restPath = new RestPath(typeof(ComplexTypeWithFields), "/Complex/{Id}/{Name}/Unique/{UniqueId}"); @@ -100,131 +117,383 @@ public void Can_deserialize_ComplexTypeWithFields_path() Assert.That(request.Name, Is.EqualTo("Is Alive")); Assert.That(request.UniqueId, Is.EqualTo(new Guid("4583B364-BBDC-427F-A289-C2923DEBD547"))); } - } + } - public class BbcMusicRequest - { - public Guid mbz_guid { get; set; } + public class BbcMusicRequest + { + public Guid mbz_guid { get; set; } - public string release_type { get; set; } + public string release_type { get; set; } - public string content_type { get; set; } - } + public string content_type { get; set; } + } - private static void AssertMatch(string definitionPath, string requestPath, - string firstMatchHashKey, BbcMusicRequest expectedRequest) - { - var restPath = new RestPath(typeof(BbcMusicRequest), definitionPath); + private static void AssertMatch(string definitionPath, string requestPath, + string firstMatchHashKey, BbcMusicRequest expectedRequest) + { + var restPath = new RestPath(typeof(BbcMusicRequest), definitionPath); - var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); - Assert.That(restPath.IsMatch("GET", reqestTestPath), Is.True); + var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); + Assert.That(restPath.IsMatch("GET", reqestTestPath, out _), Is.True); - Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); + Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); - var actualRequest = restPath.CreateRequest(requestPath) as BbcMusicRequest; + var actualRequest = restPath.CreateRequest(requestPath) as BbcMusicRequest; - Assert.That(actualRequest, Is.Not.Null); - Assert.That(actualRequest.mbz_guid, Is.EqualTo(expectedRequest.mbz_guid)); - Assert.That(actualRequest.release_type, Is.EqualTo(expectedRequest.release_type)); - Assert.That(actualRequest.content_type, Is.EqualTo(expectedRequest.content_type)); - } + Assert.That(actualRequest, Is.Not.Null); + Assert.That(actualRequest.mbz_guid, Is.EqualTo(expectedRequest.mbz_guid)); + Assert.That(actualRequest.release_type, Is.EqualTo(expectedRequest.release_type)); + Assert.That(actualRequest.content_type, Is.EqualTo(expectedRequest.content_type)); + } - [Test] - public void Can_support_BBC_REST_Apis() - { - /* - /music/artists/:mbz_guid.[xml|yaml|json] - /music/artists/:mbz_guid/promotions.[json] - /music/artists/:mbz_guid/releases.[xml|yaml|json] - /music/artists/:mbz_guid/releases/[albums|singles|eps|...].[xml|yaml|json] - */ - var mbz = new Guid("E0A387F5-48F0-40E0-AAEA-483DD7EE7484"); + [Test] + public void Can_support_BBC_REST_Apis() + { + /* + /music/artists/:mbz_guid.[xml|yaml|json] + /music/artists/:mbz_guid/promotions.[json] + /music/artists/:mbz_guid/releases.[xml|yaml|json] + /music/artists/:mbz_guid/releases/[albums|singles|eps|...].[xml|yaml|json] + */ + var mbz = new Guid("E0A387F5-48F0-40E0-AAEA-483DD7EE7484"); - AssertMatch("/music/artists/{mbz_guid}.{content_type}", - "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484.xml", - "3/music", - new BbcMusicRequest { mbz_guid = mbz, content_type = "xml" }); + AssertMatch("/music/artists/{mbz_guid}.{content_type}", + "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484.xml", + "3/music", + new BbcMusicRequest { mbz_guid = mbz, content_type = "xml" }); - AssertMatch("/music/artists/{mbz_guid}/promotions.{content_type}", - "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484/promotions.json", - "4/music", - new BbcMusicRequest { mbz_guid = mbz, content_type = "json" }); + AssertMatch("/music/artists/{mbz_guid}/promotions.{content_type}", + "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484/promotions.json", + "4/music", + new BbcMusicRequest { mbz_guid = mbz, content_type = "json" }); - AssertMatch("/music/artists/{mbz_guid}/releases.{content_type}", - "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484/releases.yaml", + AssertMatch("/music/artists/{mbz_guid}/releases.{content_type}", + "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484/releases.yaml", "4/music", - new BbcMusicRequest { mbz_guid = mbz, content_type = "yaml" }); + new BbcMusicRequest { mbz_guid = mbz, content_type = "yaml" }); - AssertMatch("/music/artists/{mbz_guid}/releases/{release_type}.{content_type}", - "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484/releases/albums.json", + AssertMatch("/music/artists/{mbz_guid}/releases/{release_type}.{content_type}", + "/music/artists/E0A387F5-48F0-40E0-AAEA-483DD7EE7484/releases/albums.json", "5/music", - new BbcMusicRequest { mbz_guid = mbz, release_type = "albums", content_type = "json" }); - } + new BbcMusicRequest { mbz_guid = mbz, release_type = "albums", content_type = "json" }); + } - public class RackSpaceRequest - { - public string version { get; set; } + public class RackSpaceRequest + { + public string version { get; set; } - public string id { get; set; } + public string id { get; set; } - public string resource_type { get; set; } + public string resource_type { get; set; } - public string action { get; set; } + public string action { get; set; } - public string content_type { get; set; } - } + public string content_type { get; set; } + } - private static void AssertMatch(string definitionPath, string requestPath, - string firstMatchHashKey, RackSpaceRequest expectedRequest) - { - var restPath = new RestPath(typeof(RackSpaceRequest), definitionPath); + private static void AssertMatch(string definitionPath, string requestPath, + string firstMatchHashKey, RackSpaceRequest expectedRequest) + { + var restPath = new RestPath(typeof(RackSpaceRequest), definitionPath); - var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); - Assert.That(restPath.IsMatch("GET", reqestTestPath), Is.True); + var reqestTestPath = RestPath.GetPathPartsForMatching(requestPath); + Assert.That(restPath.IsMatch("GET", reqestTestPath, out _), Is.True); - Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); + Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); - var actualRequest = restPath.CreateRequest(requestPath) as RackSpaceRequest; + var actualRequest = restPath.CreateRequest(requestPath) as RackSpaceRequest; - Assert.That(actualRequest, Is.Not.Null); - Assert.That(actualRequest.version, Is.EqualTo(expectedRequest.version)); - Assert.That(actualRequest.id, Is.EqualTo(expectedRequest.id)); - Assert.That(actualRequest.resource_type, Is.EqualTo(expectedRequest.resource_type)); - Assert.That(actualRequest.action, Is.EqualTo(expectedRequest.action)); - } + Assert.That(actualRequest, Is.Not.Null); + Assert.That(actualRequest.version, Is.EqualTo(expectedRequest.version)); + Assert.That(actualRequest.id, Is.EqualTo(expectedRequest.id)); + Assert.That(actualRequest.resource_type, Is.EqualTo(expectedRequest.resource_type)); + Assert.That(actualRequest.action, Is.EqualTo(expectedRequest.action)); + } - [Test] - public void Can_support_Rackspace_REST_Apis() - { - /* - * /v1.0/214412/images - * /v1.0/214412/images.xml - * /servers/id/action - * /images/detail - */ + [Test] + public void Can_support_Rackspace_REST_Apis() + { + /* + * /v1.0/214412/images + * /v1.0/214412/images.xml + * /servers/id/action + * /images/detail + */ - AssertMatch("/{version}/{id}/images", "/v1.0/214412/images", - "3/images", - new RackSpaceRequest { version = "v1.0", id = "214412" }); + AssertMatch("/{version}/{id}/images", "/v1.0/214412/images", + "3/images", + new RackSpaceRequest { version = "v1.0", id = "214412" }); - AssertMatch("/{version}/{id}/images.{content_type}", "/v1.0/214412/images.xml", - "3/images", - new RackSpaceRequest { version = "v1.0", id = "214412", content_type = "xml" }); + AssertMatch("/{version}/{id}/images.{content_type}", "/v1.0/214412/images.xml", + "3/images", + new RackSpaceRequest { version = "v1.0", id = "214412", content_type = "xml" }); - AssertMatch("/servers/{id}/{action}", "/servers/214412/delete", + AssertMatch("/servers/{id}/{action}", "/servers/214412/delete", "3/servers", - new RackSpaceRequest { id = "214412", action = "delete" }); - - AssertMatch("/images/{action}", "/images/detail", - "2/images", - new RackSpaceRequest { action = "detail" }); - - AssertMatch("/images/detail", "/images/detail", - "2/images", - new RackSpaceRequest{}); - } + new RackSpaceRequest { id = "214412", action = "delete" }); + + AssertMatch("/images/{action}", "/images/detail", + "2/images", + new RackSpaceRequest { action = "detail" }); + + AssertMatch("/images/detail", "/images/detail", + "2/images", + new RackSpaceRequest { }); + } + + public class SlugRequest + { + public string Slug { get; set; } + public int Version { get; set; } + public string Options { get; set; } + } + + private static void AssertMatch(string definitionPath, string requestPath, string firstMatchHashKey, + SlugRequest expectedRequest, int expectedScore) + { + var restPath = new RestPath(typeof(SlugRequest), definitionPath); + var requestTestPath = RestPath.GetPathPartsForMatching(requestPath); + Assert.That(restPath.IsMatch("GET", requestTestPath, out _), Is.True); + + Assert.That(firstMatchHashKey, Is.EqualTo(restPath.FirstMatchHashKey)); + + var actualRequest = restPath.CreateRequest(requestPath) as SlugRequest; + Assert.That(actualRequest, Is.Not.Null); + Assert.That(actualRequest.Slug, Is.EqualTo(expectedRequest.Slug)); + Assert.That(actualRequest.Version, Is.EqualTo(expectedRequest.Version)); + Assert.That(actualRequest.Options, Is.EqualTo(expectedRequest.Options)); + Assert.That(restPath.MatchScore("GET", requestTestPath), Is.EqualTo(expectedScore)); + } + + private static void AssertNoMatch(string definitionPath, string requestPath) + { + var restPath = new RestPath(typeof(SlugRequest), definitionPath); + var requestTestPath = RestPath.GetPathPartsForMatching(requestPath); + Assert.That(restPath.IsMatch("GET", requestTestPath, out _), Is.False); + } + + [Test] + public void Cannot_have_variable_after_wildcard() + { + Assert.Throws(() => { + AssertMatch("/content/{Slug*}/{Version}", + "/content/wildcard/slug/path/1", "*/content", new SlugRequest(), -1); + }); + } + + [Test] + public void Can_support_internal_wildcard() + { + AssertMatch("/content/{Slug*}/literal", + "/content/wildcard/slug/path/literal", + "*/content", + new SlugRequest { Slug = "wildcard/slug/path" }, + 97901); + + AssertMatch("/content/{Slug*}/version/{Version}", + "/content/wildcard/slug/path/version/1", + "*/content", + new SlugRequest { Slug = "wildcard/slug/path", Version = 1 }, + 97801); + + AssertMatch("/content/{Slug*}/with/{Options*}", + "/content/wildcard/slug/path/with/optionA/optionB", + "*/content", + new SlugRequest { Slug = "wildcard/slug/path", Options = "optionA/optionB" }, + 95801); + + AssertMatch("/{Slug*}/content", "/content", "*/content", new SlugRequest(), 100901); + + AssertMatch("/content/{Slug*}/literal", "/content/literal", "*/content", new SlugRequest(), 100901); + + AssertNoMatch("/content/{Slug*}/literal", "/content/wildcard/slug/path"); + + AssertNoMatch("/content/{Slug*}/literal", "/content/literal/literal"); + } + + [Test] + public void Routes_have_expected_precedence() + { + AssertPrecedence("GET /content", + "GET /content", + "ANY /content", + "GET /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("PUT /content", + "PUT /content", + "ANY /content", + "PUT /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("GET /content/literal", + "GET /content/literal", + "ANY /content/literal", + "GET /content/{Version}", + "ANY /content/{Version}", + "GET /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("PUT /content/literal", + "PUT /content/literal", + "ANY /content/literal", + "PUT /content/{Version}", + "ANY /content/{Version}", + "PUT /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("GET /content/v1", + "GET /content/{Version}", + "ANY /content/{Version}", + "GET /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("PUT /content/v1", + "PUT /content/{Version}", + "ANY /content/{Version}", + "PUT /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("GET /content/v1/literal-after", + "GET /content/v1/literal-after", + "ANY /content/v1/literal-after", + "GET /content/{Version}/literal-after", + "ANY /content/{Version}/literal-after", + "GET /content/{Version}/{Slug}", + "ANY /content/{Version}/{Slug}", + "GET /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("PUT /content/v1/literal-after", + "ANY /content/v1/literal-after", + "ANY /content/{Version}/literal-after", + "ANY /content/{Version}/{Slug}", + "PUT /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("GET /content/literal-before/v1", + "GET /content/literal-before/v1", + "ANY /content/literal-before/v1", + "GET /content/literal-before/{Version}", + "ANY /content/literal-before/{Version}", + "GET /content/{Version}/{Slug}", + "ANY /content/{Version}/{Slug}", + "GET /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("PUT /content/literal-before/v1", + "ANY /content/literal-before/v1", + "ANY /content/literal-before/{Version}", + "ANY /content/{Version}/{Slug}", + "PUT /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("GET /content/v1/literal/slug", + "GET /content/v1/literal/slug", + "ANY /content/v1/literal/slug", + "GET /content/v1/literal/{ignore}", + "GET /content/{ignore}/literal/{ignore}", + "GET /content/{Version*}/literal/{Slug*}", + "ANY /content/{Version*}/literal/{Slug*}", + "GET /content/{Slug*}", + "ANY /content/{Slug*}"); + + AssertPrecedence("PUT /content/v1/literal/slug", + "ANY /content/v1/literal/slug", + "ANY /content/{Version*}/literal/{Slug*}", + "PUT /content/{Slug*}", + "ANY /content/{Slug*}"); + } + + class SlugRoute + { + public static SlugRoute[] Definitions = new[]{ + new SlugRoute("GET /content"), + new SlugRoute("PUT /content"), + new SlugRoute("ANY /content"), + + new SlugRoute("GET /content/literal"), + new SlugRoute("PUT /content/literal"), + new SlugRoute("ANY /content/literal"), + + new SlugRoute("GET /content/{Version}"), + new SlugRoute("PUT /content/{Version}"), + new SlugRoute("ANY /content/{Version}"), + + new SlugRoute("GET /content/{Slug*}"), + new SlugRoute("PUT /content/{Slug*}"), + new SlugRoute("ANY /content/{Slug*}"), + + new SlugRoute("GET /content/v1/literal-after"), + new SlugRoute("ANY /content/v1/literal-after"), + new SlugRoute("GET /content/{Version}/literal-after"), + new SlugRoute("ANY /content/{Version}/literal-after"), + new SlugRoute("GET /content/{Version}/{Slug}"), + new SlugRoute("ANY /content/{Version}/{Slug}"), + + new SlugRoute("GET /content/literal-before/v1"), + new SlugRoute("ANY /content/literal-before/v1"), + new SlugRoute("GET /content/literal-before/{Version}"), + new SlugRoute("ANY /content/literal-before/{Version}"), + + new SlugRoute("GET /content/v1/literal/slug"), + new SlugRoute("ANY /content/v1/literal/slug"), + new SlugRoute("GET /content/v1/literal/{ignore}"), + new SlugRoute("GET /content/{ignore}/literal/{ignore}"), + new SlugRoute("GET /content/{Version*}/literal/{Slug*}"), + new SlugRoute("ANY /content/{Version*}/literal/{Slug*}"), + + }; + + public string Definition { get; set; } + public RestPath RestPath { get; set; } + public int Score { get; set; } + + public SlugRoute(string definition) + { + this.Definition = definition; + var parts = definition.SplitOnFirst(' '); + RestPath = new RestPath(typeof(SlugRequest), path: parts[1], verbs: parts[0] == ActionContext.AnyAction ? null : parts[0]); + } - } + public static List GetOrderedMatchingRules(string withVerb, string forPath) + { + var matchingRoutes = new List(); + + foreach (var definition in Definitions) + { + var pathComponents = RestPath.GetPathPartsForMatching(forPath); + definition.Score = definition.RestPath.MatchScore(withVerb, pathComponents); + if (definition.Score > 0) + { + matchingRoutes.Add(definition); + } + } + + var orderedRoutes = matchingRoutes.OrderByDescending(x => x.Score).ToList(); + return orderedRoutes; + } + } + + public void AssertPrecedence(string requestedDefinition, params string[] expected) + { + var parts = requestedDefinition.SplitOnFirst(' '); + var orderedRoutes = SlugRoute.GetOrderedMatchingRules(parts[0], parts[1]); + var matchingDefinitions = orderedRoutes.ConvertAll(x => x.Definition); + + var isMatch = matchingDefinitions.EquivalentTo(expected); + + Assert.That(isMatch, "Expected:\n{0}\n Actual:\n{1}".Fmt(expected.Join("\n"), matchingDefinitions.Join("\n"))); + } + + [Test] + public void Can_match_lowercase_http_method() + { + var restPath = new RestPath(typeof(ComplexType), "/Complex/{Id}/{Name}/Unique/{UniqueId}", "PUT"); + var withPathInfoParts = RestPath.GetPathPartsForMatching("/complex/5/Is Alive/unique/4583B364-BBDC-427F-A289-C2923DEBD547"); + Assert.That(restPath.IsMatch("put", withPathInfoParts, out _)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Routes/DynamicRouteAttributeTests.cs b/tests/ServiceStack.ServiceHost.Tests/Routes/DynamicRouteAttributeTests.cs new file mode 100644 index 00000000000..640cf8639d3 --- /dev/null +++ b/tests/ServiceStack.ServiceHost.Tests/Routes/DynamicRouteAttributeTests.cs @@ -0,0 +1,33 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System.Linq; +using NUnit.Framework; +using ServiceStack.Testing; + +namespace ServiceStack.ServiceHost.Tests.Routes +{ + [TestFixture] + public class DynamicRouteAttributeTests + { + [Test] + public void Can_register_routes_dynamically() + { + typeof(NewApiRequestDto) + .AddAttributes(new RouteAttribute("/custom/NewApiRequestDto")) + .AddAttributes(new RouteAttribute("/custom/NewApiRequestDto/get-only", "GET")); + + using (var appHost = new BasicAppHost(typeof(NewApiRestServiceWithAllVerbsImplemented).Assembly).Init()) + { + var allVerbs = appHost.RestPaths.First(x => x.Path == "/custom/NewApiRequestDto"); + Assert.That(allVerbs.AllowsAllVerbs); + Assert.That(allVerbs.AllowedVerbs, Is.Null); + + var getOnlyVerb = appHost.RestPaths.First(x => x.Path == "/custom/NewApiRequestDto/get-only"); + Assert.That(getOnlyVerb.AllowedVerbs.Contains("GET")); + Assert.That(!getOnlyVerb.AllowedVerbs.Contains("POST")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/Routes/ServiceRoutesTests.cs b/tests/ServiceStack.ServiceHost.Tests/Routes/ServiceRoutesTests.cs index 0fceb4f8516..ed74c0c61f7 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Routes/ServiceRoutesTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Routes/ServiceRoutesTests.cs @@ -1,36 +1,35 @@ using System.Linq; using NUnit.Framework; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Host; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests.Routes { [TestFixture] public class ServiceRoutesTests { - BasicAppHost loadAppHost; + ServiceStackHost appHost; - [TestFixtureSetUp] + [SetUp] public void TestFixtureSetUp() { - loadAppHost = new BasicAppHost().Init(); + appHost = new BasicAppHost().Init(); } - [TestFixtureTearDown] + [TearDown] public void TestFixtureTearDown() { - loadAppHost.Dispose(); + appHost.Dispose(); } [Test] public void Can_Register_NewApi_Routes_From_Assembly() { - var routes = new ServiceRoutes(); + var routes = new ServiceRoutes(appHost); routes.AddFromAssembly(typeof(NewApiRestServiceWithAllVerbsImplemented).Assembly); RestPath restWithAllMethodsRoute = - (from r in routes.RestPaths + (from r in appHost.RestPaths where r.Path == "/NewApiRequestDto" select r).FirstOrDefault(); @@ -43,7 +42,7 @@ public void Can_Register_NewApi_Routes_From_Assembly() Assert.That(restWithAllMethodsRoute.AllowedVerbs.Contains("PATCH")); RestPath restWithAllMethodsRoute2 = - (from r in routes.RestPaths + (from r in appHost.RestPaths where r.Path == "/NewApiRequestDto2" select r).FirstOrDefault(); @@ -59,17 +58,17 @@ public void Can_Register_NewApi_Routes_From_Assembly() [Test] public void Can_Register_NewApi_Routes_With_Id_and_Any_Fallback_From_Assembly() { - var routes = new ServiceRoutes(); + var routes = new ServiceRoutes(appHost); routes.AddFromAssembly(typeof(NewApiRequestDtoWithIdService).Assembly); - var route = (from r in routes.RestPaths + var route = (from r in appHost.RestPaths where r.Path == "/NewApiRequestDtoWithId" select r).FirstOrDefault(); Assert.That(route, Is.Not.Null); Assert.That(route.AllowedVerbs, Is.Null); - route = (from r in routes.RestPaths + route = (from r in appHost.RestPaths where r.Path == "/NewApiRequestDtoWithId/{Id}" select r).FirstOrDefault(); @@ -77,74 +76,34 @@ public void Can_Register_NewApi_Routes_With_Id_and_Any_Fallback_From_Assembly() Assert.That(route.AllowedVerbs, Is.Null); } - [Test] - public void Can_Register_NewApi_Routes_With_Field_Id_and_Any_Fallback_From_Assembly() - { - var routes = new ServiceRoutes(); - routes.AddFromAssembly(typeof(NewApiRequestDtoWithFieldIdService).Assembly); - - var route = (from r in routes.RestPaths - where r.Path == "/NewApiRequestDtoWithFieldId" - select r).FirstOrDefault(); - - Assert.That(route, Is.Not.Null); - Assert.That(route.AllowedVerbs, Is.Null); - - route = (from r in routes.RestPaths - where r.Path == "/NewApiRequestDtoWithFieldId/{Id}" - select r).FirstOrDefault(); - - Assert.That(route, Is.Not.Null); - Assert.That(route.AllowedVerbs, Is.Null); - } - [Test] - public void Can_Register_OldApi_Routes_From_Assembly() + public void Can_Register_NewApi_Routes_With_Field_Id_and_Any_Fallback_From_Assembly() { - var routes = new ServiceRoutes(); - routes.AddFromAssembly(typeof(OldApiRestServiceWithAllVerbsImplemented).Assembly); - - RestPath restWithAllMethodsRoute = - (from r in routes.RestPaths - where r.Path == "/OldApiRequestDto2" - select r).FirstOrDefault(); - - Assert.That(restWithAllMethodsRoute, Is.Not.Null); - - Assert.That(restWithAllMethodsRoute.AllowedVerbs.Contains("GET")); - Assert.That(restWithAllMethodsRoute.AllowedVerbs.Contains("POST")); - Assert.That(restWithAllMethodsRoute.AllowedVerbs.Contains("PUT")); - Assert.That(restWithAllMethodsRoute.AllowedVerbs.Contains("DELETE")); - Assert.That(restWithAllMethodsRoute.AllowedVerbs.Contains("PATCH")); - } + var routes = new ServiceRoutes(appHost); + routes.AddFromAssembly(typeof(NewApiRequestDtoWithFieldIdService).Assembly); - [Test] - public void Can_Register_OldApi_Routes_With_Partially_Implemented_REST_Verbs() - { - var routes = new ServiceRoutes(); - routes.AddFromAssembly(typeof(OldApiRestServiceWithSomeVerbsImplemented).Assembly); + var route = (from r in appHost.RestPaths + where r.Path == "/NewApiRequestDtoWithFieldId" + select r).FirstOrDefault(); - RestPath restWithAFewMethodsRoute = - (from r in routes.RestPaths - where r.Path == "/OldApiRequestDto" - select r).FirstOrDefault(); + Assert.That(route, Is.Not.Null); + Assert.That(route.AllowedVerbs, Is.Null); - Assert.That(restWithAFewMethodsRoute, Is.Not.Null); + route = (from r in appHost.RestPaths + where r.Path == "/NewApiRequestDtoWithFieldId/{Id}" + select r).FirstOrDefault(); - Assert.That(restWithAFewMethodsRoute.AllowedVerbs.Contains("GET"), Is.True); - Assert.That(restWithAFewMethodsRoute.AllowedVerbs.Contains("POST"), Is.False); - Assert.That(restWithAFewMethodsRoute.AllowedVerbs.Contains("PUT"), Is.True); - Assert.That(restWithAFewMethodsRoute.AllowedVerbs.Contains("DELETE"), Is.False); - Assert.That(restWithAFewMethodsRoute.AllowedVerbs.Contains("PATCH"), Is.False); + Assert.That(route, Is.Not.Null); + Assert.That(route.AllowedVerbs, Is.Null); } [Test] public void Can_Register_Routes_Using_Add_Extension() { - var routes = new ServiceRoutes(); + var routes = new ServiceRoutes(appHost); routes.Add("/Users/{0}/Orders/{1}", ApplyTo.Get, x => x.Name, x => x.OrderId); - var route = routes.RestPaths[0]; - Assert.That(route.Path == "/Users/{Name}/Orders/{OrderId}"); + var route = appHost.RestPaths.Last(); + Assert.That(route.Path, Is.EqualTo("/Users/{Name}/Orders/{OrderId}")); } } diff --git a/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs b/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs index 4e7fba28b07..2d6927205cd 100644 --- a/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs +++ b/tests/ServiceStack.ServiceHost.Tests/Routes/SimpleRestServices.cs @@ -1,61 +1,8 @@ using System.Net; -using ServiceStack.Common.Web; -using ServiceStack.ServiceInterface; +using ServiceStack.Web; namespace ServiceStack.ServiceHost.Tests.Routes { - public class OldApiRequestDto - { - public string Name { get; set; } - } - - public class OldApiRestServiceWithSomeVerbsImplemented : RestServiceBase - { - public override object OnGet(OldApiRequestDto request) - { - return new HttpResult { StatusCode = HttpStatusCode.OK }; - } - - public override object OnPut(OldApiRequestDto request) - { - return new HttpResult { StatusCode = HttpStatusCode.OK }; - } - } - - public class OldApiRequestDto2 - { - public string Name { get; set; } - } - - public class OldApiRestServiceWithAllVerbsImplemented : RestServiceBase - { - public override object OnGet(OldApiRequestDto2 request) - { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnPut(OldApiRequestDto2 request) - { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnPost(OldApiRequestDto2 request) - { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnDelete(OldApiRequestDto2 request) - { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - - public override object OnPatch(OldApiRequestDto2 request) - { - return new HttpResult {StatusCode = HttpStatusCode.OK}; - } - } - - public class NewApiRequestDto { public string Name { get; set; } @@ -137,22 +84,22 @@ public object Any(NewApiRequestDtoWithId request) } } - public class NewApiRequestDtoWithFieldId - { - public int Id { get; set; } - } - - public class NewApiRequestDtoWithFieldIdService : IService - { - public object Get(NewApiRequestDtoWithFieldId request) - { - return new HttpResult { StatusCode = HttpStatusCode.OK }; - } - - public object Any(NewApiRequestDtoWithFieldId request) - { - return new HttpResult { StatusCode = HttpStatusCode.OK }; - } - } + public class NewApiRequestDtoWithFieldId + { + public int Id { get; set; } + } + + public class NewApiRequestDtoWithFieldIdService : IService + { + public object Get(NewApiRequestDtoWithFieldId request) + { + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + + public object Any(NewApiRequestDtoWithFieldId request) + { + return new HttpResult { StatusCode = HttpStatusCode.OK }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceControllerPerfTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceControllerPerfTests.cs index e84f45780c3..2a093855e20 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceControllerPerfTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceControllerPerfTests.cs @@ -7,72 +7,73 @@ namespace ServiceStack.ServiceHost.Tests { - [Ignore("Perf Test Only")] - [TestFixture] - public class ServiceControllerPerfTests - { - private const int Times = 100000; + [Ignore("Perf Test Only")] + [TestFixture] + public class ServiceControllerPerfTests + { + private const int Times = 100000; - [Test] - public void RunAll() - { - With_Funq_and_Expressions(); - With_Native_Funq(); - With_Funq_and_Reflection(); //Very slow - } + [Test] + public void RunAll() + { + With_Funq_and_Expressions(); + With_Native_Funq(); + With_Funq_and_Reflection(); //Very slow + } - [Test] - public void With_Native_Funq() - { - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); + [Test] + public void With_Native_Funq() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); - container.Register( - c => new AutoWireService(c.Resolve()) { - Bar = c.Resolve() - }).ReusedWithin(ReuseScope.None); + container.Register( + c => new AutoWireService(c.Resolve()) + { + Bar = c.Resolve() + }).ReusedWithin(ReuseScope.None); - Console.WriteLine("With_Native_Funq(): {0}", Measure(() => container.Resolve(), Times)); - } + Console.WriteLine("With_Native_Funq(): {0}", Measure(() => container.Resolve(), Times)); + } - [Test] - [Ignore("Slow to run")] - public void With_Funq_and_Reflection() - { - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); + [Test] + [Ignore("Slow to run")] + public void With_Funq_and_Reflection() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); - var funqlet = new ReflectionTypeFunqContainer(container); - funqlet.Register(typeof(AutoWireService)); + var funqlet = new ReflectionTypeFunqContainer(container); + funqlet.Register(typeof(AutoWireService)); - Console.WriteLine("With_Funq_and_Reflection(): {0}", Measure(() => container.Resolve(), Times)); - } + Console.WriteLine("With_Funq_and_Reflection(): {0}", Measure(() => container.Resolve(), Times)); + } - [Test] - public void With_Funq_and_Expressions() - { - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); + [Test] + public void With_Funq_and_Expressions() + { + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); - container.RegisterAutoWiredType(typeof(AutoWireService)); + container.RegisterAutoWiredType(typeof(AutoWireService)); - Console.WriteLine("With_Funq_and_Expressions(): {0}", Measure(() => container.Resolve(), Times)); - } + Console.WriteLine("With_Funq_and_Expressions(): {0}", Measure(() => container.Resolve(), Times)); + } - private static long Measure(Action action, int iterations) - { - GC.Collect(); - var watch = Stopwatch.StartNew(); + private static long Measure(Action action, int iterations) + { + GC.Collect(); + var watch = Stopwatch.StartNew(); - for (int i = 0; i < iterations; i++) - { - action(); - } + for (int i = 0; i < iterations; i++) + { + action(); + } - return watch.ElapsedTicks; - } - } + return watch.ElapsedTicks; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceControllerTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceControllerTests.cs index eecc3057d38..77244c650d0 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceControllerTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceControllerTests.cs @@ -1,201 +1,160 @@ using System; -using System.Reflection; using Funq; using NUnit.Framework; +using ServiceStack.Host; using ServiceStack.ServiceHost.Tests.Support; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests { [TestFixture] public class ServiceControllerTests { - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - EndpointHostConfig.SkipRouteValidation = true; - } - [Test] public void Can_register_all_services_in_an_assembly() { - var serviceManager = new ServiceManager(typeof(BasicService).Assembly); - serviceManager.Init(); - - var container = serviceManager.Container; - container.Register(c => new Foo()); - container.Register(c => new Bar()); - - var serviceController = serviceManager.ServiceController; + using (var appHost = new BasicAppHost(typeof(BasicService).Assembly).Init()) + { + var container = appHost.Container; + var serviceController = appHost.ServiceController; - var request = new AutoWire(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); - var response = serviceController.Execute(request) as AutoWireResponse; + var request = new AutoWire(); + var response = serviceController.Execute(request) as AutoWireResponse; - Assert.That(response, Is.Not.Null); + Assert.That(response, Is.Not.Null); + } } [Test] public void Can_override_service_creation_with_custom_implementation() { - var serviceManager = new ServiceManager(typeof(BasicService).Assembly); - serviceManager.Init(); - - var container = serviceManager.Container; - container.Register(c => new Foo()); - container.Register(c => new Bar()); + using (var appHost = new BasicAppHost(typeof(BasicService).Assembly).Init()) + { + var container = appHost.Container; + var serviceController = appHost.ServiceController; - var serviceController = serviceManager.ServiceController; + container.Register(c => new Foo()); + container.Register(c => new Bar()); - var request = new AutoWire(); + var request = new AutoWire(); - var response = serviceController.Execute(request) as AutoWireResponse; + var response = serviceController.Execute(request) as AutoWireResponse; - Assert.That(response, Is.Not.Null); - Assert.That(response.Foo as Foo, Is.Not.Null); - Assert.That(response.Bar as Bar, Is.Not.Null); + Assert.That(response, Is.Not.Null); + Assert.That(response.Foo as Foo, Is.Not.Null); + Assert.That(response.Bar as Bar, Is.Not.Null); - container.Register(c => - new AutoWireService(new Foo2()) + container.Register(c => new AutoWireService(new Foo2()) { Bar = new Bar2() }); - response = serviceController.Execute(request) as AutoWireResponse; + response = serviceController.Execute(request) as AutoWireResponse; - Assert.That(response, Is.Not.Null); - Assert.That(response.Foo as Foo2, Is.Not.Null); - Assert.That(response.Bar as Bar2, Is.Not.Null); + Assert.That(response, Is.Not.Null); + Assert.That(response.Foo as Foo2, Is.Not.Null); + Assert.That(response.Bar as Bar2, Is.Not.Null); + } } [Test] public void Can_inject_RequestContext_for_IRequiresRequestContext_services() { - var serviceManager = new ServiceManager(typeof(RequiresContextService).Assembly); - serviceManager.Init(); - - var serviceController = serviceManager.ServiceController; + using (var appHost = new BasicAppHost(typeof(RequiresService).Assembly).Init()) + { + var serviceController = appHost.ServiceController; - var request = new RequiresContext(); - var response = serviceController.Execute(request, new HttpRequestContext(request)) - as RequiresContextResponse; + var request = new RequiresContext(); + var response = serviceController.Execute(request, new BasicRequest(request)) + as RequiresContextResponse; - Assert.That(response, Is.Not.Null); + Assert.That(response, Is.Not.Null); + } } [Test] public void Generic_Service_should_not_get_registered_with_generic_parameter() { - var serviceManager = new ServiceManager(typeof(GenericService<>).Assembly); - serviceManager.Init(); - - // We should definately *not* be able to call the generic service with a "T" request object :) - var serviceController = serviceManager.ServiceController; - var requestType = typeof(GenericService<>).GetGenericArguments()[0]; - var exception = Assert.Throws(() => serviceController.GetService(requestType)); + using (var appHost = new BasicAppHost(typeof(GenericService<>).Assembly).Init()) + { + // We should definately *not* be able to call the generic service with a "T" request object :) + var requestType = typeof(GenericService<>).GetGenericArguments()[0]; + var exception = Assert.Throws(() => appHost.ServiceController.GetService(requestType)); - Assert.That(exception.Message, Is.StringContaining("Unable to resolve service")); + Assert.That(exception.Message, Does.Contain("Unable to resolve service")); + } } [Test] public void Generic_service_with_recursive_ceneric_type_should_not_get_registered() { - // Tell manager to register GenericService>, which should not be possible since Generic3<> is an open type - var serviceManager = new ServiceManager(null, new ServiceController(() => new[] { typeof(GenericService<>).MakeGenericType(new[] { typeof(Generic3<>) }) })); - - serviceManager.Init(); - - var serviceController = serviceManager.ServiceController; - var exception = Assert.Throws(() => serviceController.GetService(typeof(Generic3<>))); + using (var appHost = new BasicAppHost + { + UseServiceController = x => + new ServiceController(x, () => new[] { + typeof(GenericService<>).MakeGenericType(new[] { typeof(Generic3<>) }) + }) + }.Init()) + { + // Tell manager to register GenericService>, which should not be possible since Generic3<> is an open type + var exception = Assert.Throws(() => + appHost.ServiceController.GetService(typeof(Generic3<>))); - Assert.That(exception.Message, Is.StringContaining("Unable to resolve service")); + Assert.That(exception.Message, Does.Contain("Unable to resolve service")); + } } [Test] public void Generic_service_can_be_registered_with_closed_types() { - var serviceManager = new ServiceManager(null, new ServiceController(() => new[] + using (var appHost = new BasicAppHost { - typeof(GenericService), - typeof(GenericService<>).MakeGenericType(new[] { typeof (Generic2) }), // GenericService created through reflection - typeof(GenericService>), - typeof(GenericService>), - typeof(GenericService<>).MakeGenericType(new[] { typeof (Generic3<>).MakeGenericType(new[] { typeof(double) }) }), // GenericService> created through reflection - })); - - serviceManager.Init(); - var serviceController = serviceManager.ServiceController; - - Assert.AreEqual(typeof(Generic1).FullName, ((Generic1Response)serviceController.Execute(new Generic1())).Data); - Assert.AreEqual(typeof(Generic2).FullName, ((Generic1Response)serviceController.Execute(new Generic2())).Data); - Assert.AreEqual(typeof(Generic3).FullName, ((Generic1Response)serviceController.Execute(new Generic3())).Data); - Assert.AreEqual(typeof(Generic3).FullName, ((Generic1Response)serviceController.Execute(new Generic3())).Data); - Assert.AreEqual(typeof(Generic3).FullName, ((Generic1Response)serviceController.Execute(new Generic3())).Data); - } - - - [Route("route/{Id}")] - public class NoSlashPrefix : IReturn - { - public long Id { get; set; } - } - - [Route("/route?id={Id}")] - public class UsesQueryString : IReturn - { - public long Id { get; set; } - } - - public class MyService : IService - { - public object Any(NoSlashPrefix request) + UseServiceController = x => new ServiceController(x, () => new[] + { + typeof (GenericService), + typeof (GenericService<>).MakeGenericType(new[] {typeof (Generic2)}), + // GenericService created through reflection + typeof (GenericService>), + typeof (GenericService>), + typeof (GenericService<>).MakeGenericType(new[] + {typeof (Generic3<>).MakeGenericType(new[] {typeof (double)})}), + // GenericService> created through reflection + }) + }.Init()) { - return null; - } + var serviceController = appHost.ServiceController; - public object Any(UsesQueryString request) - { - return null; + Assert.AreEqual(typeof(Generic1).FullName, ((Generic1Response)serviceController.Execute(new Generic1())).Data); + Assert.AreEqual(typeof(Generic2).FullName, ((Generic1Response)serviceController.Execute(new Generic2())).Data); + Assert.AreEqual(typeof(Generic3).FullName, ((Generic1Response)serviceController.Execute(new Generic3())).Data); + Assert.AreEqual(typeof(Generic3).FullName, ((Generic1Response)serviceController.Execute(new Generic3())).Data); + Assert.AreEqual(typeof(Generic3).FullName, ((Generic1Response)serviceController.Execute(new Generic3())).Data); } } - [Test] - public void Does_throw_on_invalid_Route_Definitions() - { - EndpointHostConfig.SkipRouteValidation = false; - - var controller = new ServiceController(() => new[] { typeof(MyService) }); - - Assert.Throws( - () => controller.RegisterRestPaths(typeof(NoSlashPrefix))); - - Assert.Throws( - () => controller.RegisterRestPaths(typeof(UsesQueryString))); - - EndpointHostConfig.SkipRouteValidation = true; - } - [Test] public void Service_with_generic_IGet_marker_interface_can_be_registered_without_DefaultRequestAttribute() { var appHost = new AppHost(); + appHost.ServiceController = new ServiceController(appHost); - var routes = (ServiceRoutes) appHost.Routes; - Assert.That(routes.RestPaths.Count, Is.EqualTo(0)); + Assert.That(appHost.RestPaths.Count, Is.EqualTo(0)); appHost.RegisterService("/route"); - Assert.That(routes.RestPaths.Count, Is.EqualTo(1)); + Assert.That(appHost.RestPaths.Count, Is.EqualTo(1)); } } - public class GetRequest {} + public class GetRequest { } - public class GetRequestResponse {} + public class GetRequestResponse { } [DefaultRequest(typeof(GetRequest))] - public class GetMarkerService : ServiceInterface.Service + public class GetMarkerService : Service { public object Get(GetRequest request) { @@ -205,7 +164,7 @@ public object Get(GetRequest request) public class AppHost : AppHostHttpListenerBase { - public AppHost() : base("Test", typeof(AppHost).Assembly) {} + public AppHost() : base("Test", typeof(AppHost).Assembly) { } public override void Configure(Container container) { diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceCreationTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceCreationTests.cs index 0a12d5b4c3d..6be24229f82 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceCreationTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceCreationTests.cs @@ -1,10 +1,6 @@ using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Caching; using Funq; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; namespace ServiceStack.ServiceHost.Tests { @@ -20,7 +16,7 @@ public class ServiceCreationResponse public int RequestCount { get; set; } } - public class ServiceCreationService : ServiceInterface.Service + public class ServiceCreationService : Service { public int RequestCounter = 0; @@ -55,23 +51,21 @@ public override void Configure(Funq.Container container) AttributeFiltersAppHostHttpListener appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { - EndpointHostConfig.SkipRouteValidation = true; - appHost = new AttributeFiltersAppHostHttpListener(); appHost.Init(); appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); } - protected static IRestClient[] RestClients = + protected static IRestClient[] RestClients = { new JsonServiceClient(ServiceClientBaseUri), new XmlServiceClient(ServiceClientBaseUri), diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceHostTests.cs b/tests/ServiceStack.ServiceHost.Tests/ServiceHostTests.cs index ea01897e7f5..446cd58bb3b 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceHostTests.cs +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceHostTests.cs @@ -1,134 +1,154 @@ using System; using Funq; using NUnit.Framework; +using ServiceStack.Host; using ServiceStack.ServiceHost.Tests.Support; using ServiceStack.ServiceHost.Tests.TypeFactory; -using ServiceStack.Text; -using ServiceStack.Text.Common; +using ServiceStack.Testing; namespace ServiceStack.ServiceHost.Tests { - [TestFixture] - public class ServiceHostTests - { - private ServiceController serviceController; - - [SetUp] - public void OnBeforeEachTest() - { - serviceController = new ServiceController(null); - } - - [Test] - public void Can_execute_BasicService() - { - serviceController.Register(() => new BasicService()); - var result = serviceController.Execute(new BasicRequest()) as BasicRequestResponse; - - Assert.That(result, Is.Not.Null); - } - - [Test] - public void Can_execute_BasicService_from_dynamic_Type() - { - var requestType = typeof(BasicRequest); - - serviceController.Register(requestType, typeof(BasicService)); - - object request = Activator.CreateInstance(requestType); - - var result = serviceController.Execute(request) as BasicRequestResponse; - - Assert.That(result, Is.Not.Null); - } - - [Test] - public void Can_AutoWire_types_dynamically_with_reflection() - { - var serviceType = typeof(AutoWireService); - - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); - - var typeContainer = new ReflectionTypeFunqContainer(container); - typeContainer.Register(serviceType); - - var service = container.Resolve(); - - Assert.That(service.Foo, Is.Not.Null); - Assert.That(service.Bar, Is.Not.Null); - } - - [Test] - public void Can_AutoWire_types_dynamically_with_expressions() - { - var serviceType = typeof(AutoWireService); - - var container = new Container(); - container.Register(c => new Foo()); - container.Register(c => new Bar()); - - container.RegisterAutoWiredType(serviceType); - - var service = container.Resolve(); - - Assert.That(service.Foo, Is.Not.Null); - Assert.That(service.Bar, Is.Not.Null); - } - - [Test] - public void Can_execute_RestTestService() - { - serviceController.Register(() => new RestTestService()); - var result = serviceController.Execute(new RestTest()) as RestTestResponse; - - Assert.That(result, Is.Not.Null); - Assert.That(result.MethodName, Is.EqualTo("Execute")); - } - - [Test] - public void Can_RestTestService_GET() - { - serviceController.Register(() => new RestTestService()); - var result = serviceController.Execute(new RestTest(), - new HttpRequestContext((object)null, EndpointAttributes.HttpGet)) as RestTestResponse; - - Assert.That(result, Is.Not.Null); - Assert.That(result.MethodName, Is.EqualTo("Get")); - } - - [Test] - public void Can_RestTestService_PUT() - { - serviceController.Register(() => new RestTestService()); - var result = serviceController.Execute(new RestTest(), - new HttpRequestContext((object)null, EndpointAttributes.HttpPut)) as RestTestResponse; - - Assert.That(result, Is.Not.Null); - Assert.That(result.MethodName, Is.EqualTo("Put")); - } - - [Test] - public void Can_RestTestService_POST() - { - serviceController.Register(() => new RestTestService()); - var result = serviceController.Execute(new RestTest(), - new HttpRequestContext((object)null, EndpointAttributes.HttpPost)) as RestTestResponse; - - Assert.That(result, Is.Not.Null); - Assert.That(result.MethodName, Is.EqualTo("Post")); - } - - [Test] - public void Can_RestTestService_DELETE() - { - serviceController.Register(() => new RestTestService()); - var result = serviceController.Execute(new RestTest(), - new HttpRequestContext((object)null, EndpointAttributes.HttpDelete)) as RestTestResponse; - - Assert.That(result, Is.Not.Null); - Assert.That(result.MethodName, Is.EqualTo("Delete")); - } - } + [TestFixture] + public class ServiceHostTests + { + private ServiceController serviceController; + private ServiceStackHost appHost; + + [SetUp] + public void SetUp() + { + appHost = new BasicAppHost().Init(); + serviceController = appHost.ServiceController; + } + + [TearDown] + public void TearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_execute_BasicService() + { + serviceController.RegisterService(typeof(BasicService)); + var result = serviceController.Execute(new EmptyRequest()) as EmptyRequestResponse; + + Assert.That(result, Is.Not.Null); + } + + [Test] + public void Can_execute_BasicService_from_dynamic_Type() + { + var requestType = typeof(EmptyRequest); + + serviceController.RegisterService(typeof(BasicService)); + + object request = Activator.CreateInstance(requestType); + + var result = serviceController.Execute(request) as EmptyRequestResponse; + + Assert.That(result, Is.Not.Null); + } + + [Test] + public void Can_AutoWire_types_dynamically_with_reflection() + { + var serviceType = typeof(AutoWireService); + + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + + var typeContainer = new ReflectionTypeFunqContainer(container); + typeContainer.Register(serviceType); + + var service = container.Resolve(); + + Assert.That(service.Foo, Is.Not.Null); + Assert.That(service.Bar, Is.Not.Null); + } + + [Test] + public void Can_AutoWire_types_dynamically_with_expressions() + { + var serviceType = typeof(AutoWireService); + + var container = new Container(); + container.Register(c => new Foo()); + container.Register(c => new Bar()); + + container.RegisterAutoWiredType(serviceType); + + var service = container.Resolve(); + + Assert.That(service.Foo, Is.Not.Null); + Assert.That(service.Bar, Is.Not.Null); + } + + private MockHttpRequest CreateContext(string httpMethod) + { + var ctx = new MockHttpRequest { HttpMethod = httpMethod }; + return ctx; + } + + [Test] + public void Can_execute_RestTestService() + { + serviceController.RegisterService(typeof(RestTestService)); + + var result = serviceController.Execute(new RestTest(), + CreateContext(HttpMethods.Options)) as RestTestResponse; + + Assert.That(result, Is.Not.Null); + Assert.That(result.MethodName, Is.EqualTo("Any")); + } + + [Test] + public void Can_RestTestService_GET() + { + serviceController.RegisterService(typeof(RestTestService)); + + var result = serviceController.Execute(new RestTest(), + CreateContext(HttpMethods.Get)) as RestTestResponse; + + Assert.That(result, Is.Not.Null); + Assert.That(result.MethodName, Is.EqualTo("Get")); + } + + [Test] + public void Can_RestTestService_PUT() + { + serviceController.RegisterService(typeof(RestTestService)); + + var result = serviceController.Execute(new RestTest(), + CreateContext(HttpMethods.Put)) as RestTestResponse; + + Assert.That(result, Is.Not.Null); + Assert.That(result.MethodName, Is.EqualTo("Put")); + } + + [Test] + public void Can_RestTestService_POST() + { + serviceController.RegisterService(typeof(RestTestService)); + + var result = serviceController.Execute(new RestTest(), + CreateContext(HttpMethods.Post)) as RestTestResponse; + + Assert.That(result, Is.Not.Null); + Assert.That(result.MethodName, Is.EqualTo("Post")); + } + + [Test] + public void Can_RestTestService_DELETE() + { + serviceController.RegisterService(typeof(RestTestService)); + + var result = serviceController.Execute(new RestTest(), + CreateContext(HttpMethods.Delete)) as RestTestResponse; + + Assert.That(result, Is.Not.Null); + Assert.That(result.MethodName, Is.EqualTo("Delete")); + } + } } diff --git a/tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj b/tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj index 9a8abc2f064..7f4b8451c56 100644 --- a/tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj +++ b/tests/ServiceStack.ServiceHost.Tests/ServiceStack.ServiceHost.Tests.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -32,6 +32,10 @@ true ..\..\src\ true + v4.7.2 + + + True @@ -43,6 +47,7 @@ 4 AllRules.ruleset false + false pdbonly @@ -52,6 +57,7 @@ prompt 4 AllRules.ruleset + false True @@ -63,6 +69,7 @@ 4 False AllRules.ruleset + false True @@ -74,28 +81,33 @@ 4 False AllRules.ruleset + false + + + bin\Signed\ + TRACE + true + pdbonly + AnyCPU + prompt + AllRules.ruleset + false - - ..\..\lib\tests\Moq.dll - - - ..\..\lib\ServiceStack.OrmLite.dll - - - ..\..\lib\ServiceStack.OrmLite.Sqlite.dll - - - ..\..\lib\ServiceStack.Text.dll - + + + 3.5 + 3.0 + + 3.5 @@ -105,9 +117,6 @@ - - ..\..\lib\tests\nunit.framework.dll - @@ -126,7 +135,9 @@ + + @@ -140,12 +151,12 @@ - + - + @@ -159,7 +170,7 @@ - + @@ -184,10 +195,6 @@ - - sqlite3.dll - PreserveNewest - @@ -204,22 +211,22 @@ + + {c43f583f-abde-4dd4-bbe3-66322817a6ad} + ServiceStack.Client + {982416DB-C143-4028-A0C3-CF41892D18D3} ServiceStack.Common - {42E1C8C0-A163-44CC-92B1-8F416F2C0B01} + {55942102-033a-4da8-a6af-1db7b2f34a2d} ServiceStack.Interfaces {D73274AE-006B-4CEE-BA60-0ECF5873048D} ServiceStack.Razor - - {5A315F92-80D2-4C60-A5A4-22E027AC7E7E} - ServiceStack.ServiceInterface - {680A1709-25EB-4D52-A87F-EE03FFD94BAA} ServiceStack @@ -253,6 +260,25 @@ + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + + diff --git a/tests/ServiceStack.ServiceModel.Tests/XlinqExtensionsTests.cs b/tests/ServiceStack.ServiceModel.Tests/XlinqExtensionsTests.cs index 4afab79fcbb..f23b0babc85 100644 --- a/tests/ServiceStack.ServiceModel.Tests/XlinqExtensionsTests.cs +++ b/tests/ServiceStack.ServiceModel.Tests/XlinqExtensionsTests.cs @@ -1,6 +1,7 @@ using System; using System.Xml.Linq; using NUnit.Framework; +using ServiceStack.Common; namespace ServiceStack.ServiceModel.Tests { @@ -27,21 +28,21 @@ public void xelement_get_int_test() } [Test] - [ExpectedException(typeof(ArgumentNullException))] public void xelement_get_int_null_throws_exception_test() { - var el = CreateEmptyChildElement(); - el.GetInt("child"); - Assert.Fail("Expected ArgumentNullException"); + Assert.Throws(() => { + var el = CreateEmptyChildElement(); + el.GetInt("child"); + }); } [Test] - [ExpectedException(typeof(FormatException))] public void xelement_get_int_text_throws_exception_test() { - var el = CreateChildElement("Non int value"); - el.GetInt("child"); - Assert.Fail("Expected FormatException"); + Assert.Throws(() => { + var el = CreateChildElement("Non int value"); + el.GetInt("child"); + }); } [Test] diff --git a/tests/ServiceStack.Tests/Html/InputExtensionTests.cs b/tests/ServiceStack.Tests/Html/InputExtensionTests.cs deleted file mode 100644 index bf14bdc07ae..00000000000 --- a/tests/ServiceStack.Tests/Html/InputExtensionTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NUnit.Framework; -using ServiceStack.Html; -using ServiceStack.Tests.Html.Support.Types; - -namespace ServiceStack.Tests.Html -{ - [TestFixture] - public class InputExtensionTests - { - HtmlHelper html; - - [SetUp] - public void SetUp() - { - html = new HtmlHelper(); - } - - [Test] - public void TextBoxFor_ValidModelValue_GeneratesBothNameAndIdAttributes() - { - MvcHtmlString result = html.TextBoxFor(p => p.First); - - Assert.AreEqual(@"", result.ToHtmlString()); - } - - [Test] - public void TextBoxFor_NestedProperty_GeneratesNameAttributeWithDotAndIDWithUnderscore() - { - MvcHtmlString result = html.TextBoxFor(p => p.Home.City); - - Assert.AreEqual(@"", result.ToHtmlString()); - } - } -} diff --git a/tests/ServiceStack.Tests/Html/LabelExtensionsTests.cs b/tests/ServiceStack.Tests/Html/LabelExtensionsTests.cs deleted file mode 100644 index c80a38b75cd..00000000000 --- a/tests/ServiceStack.Tests/Html/LabelExtensionsTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NUnit.Framework; -using ServiceStack.Html; -using ServiceStack.Tests.Html.Support.Types; - -namespace ServiceStack.Tests.Html -{ - [TestFixture] - public class LabelExtensionsTests - { - HtmlHelper html; - - [SetUp] - public void SetUp() - { - html = new HtmlHelper(); - } - - [Test] - public void LabelFor_SimpleProperty_ForAttributeIsSameAsName() - { - MvcHtmlString result = html.LabelFor(p => p.First); - - Assert.AreEqual(@"", result.ToHtmlString()); - } - - [Test] - public void LabelFor_NestedProperty_ForAttributeReferencesElementIDWithUnderscores() - { - MvcHtmlString result = html.LabelFor(p => p.Home.City); - - Assert.AreEqual(@"", result.ToHtmlString()); - } - } -} diff --git a/tests/ServiceStack.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 43b5e033e94..00000000000 --- a/tests/ServiceStack.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceStack.Tests")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("bc7db2d8-69a7-403f-99f7-3ad8d9e363d7")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/ServiceStack.Tests/ServiceStack.Tests.csproj b/tests/ServiceStack.Tests/ServiceStack.Tests.csproj deleted file mode 100644 index dec7601792d..00000000000 --- a/tests/ServiceStack.Tests/ServiceStack.Tests.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - - - Debug - AnyCPU - {93AEB5A2-C491-4C12-9014-5BBBEB89B6FF} - Library - Properties - ServiceStack.Tests - ServiceStack.Tests - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\lib\tests\nunit.framework.dll - - - - - - - - - - - - - - {680a1709-25eb-4d52-a87f-ee03ffd94baa} - ServiceStack - - - - - - \ No newline at end of file diff --git a/tests/ServiceStack.Tests/Support/Types/Person.cs b/tests/ServiceStack.Tests/Support/Types/Person.cs deleted file mode 100644 index 274513faec3..00000000000 --- a/tests/ServiceStack.Tests/Support/Types/Person.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace ServiceStack.Tests.Html.Support.Types -{ - class Person - { - public string First { get; set; } - public string Last { get; set; } - - public Address Work { get; set; } - public Address Home { get; set; } - } - - class Address - { - public string Street { get; set; } - public string StreetNo { get; set; } - public string ZIP { get; set; } - public string City { get; set; } - public string State { get; set; } - } -} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ActionResolutionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ActionResolutionTests.cs new file mode 100644 index 00000000000..5c3c9553cce --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ActionResolutionTests.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Admin; +using ServiceStack.Auth; +using ServiceStack.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ActionResolutionTests + { + List ActionVerbs(List actions) => + actions.Map(x => StripAsync(x.Name)).Distinct().ToList(); + string StripAsync(string name) => + name.Replace("Async", ""); + + List StripAsync(IEnumerable names) => + names.Map(StripAsync); + + [Test] + public void Does_resolve_all_AuthenticateService_methods() + { + var actions = typeof(AuthenticateService).GetActions(); + Assert.That(actions.Count, Is.EqualTo(4)); + var verbs = ActionVerbs(actions); + var expected = StripAsync(new[] { + nameof(AuthenticateService.Options), + nameof(AuthenticateService.GetAsync), + nameof(AuthenticateService.PostAsync), + nameof(AuthenticateService.DeleteAsync), + }); + Assert.That(verbs, Is.EquivalentTo(expected)); + } + + [Test] + public void Does_resolve_all_RegisterService_methods() + { + var actions = typeof(RegisterService).GetActions(); + Assert.That(actions.Count, Is.EqualTo(2)); + var verbs = ActionVerbs(actions); + var expected = StripAsync(new[] { + nameof(RegisterService.PutAsync), + nameof(RegisterService.PostAsync), + }); + Assert.That(verbs, Is.EquivalentTo(expected)); + } + + [Test] + public void Does_resolve_all_AdminUsersService_methods() + { + var actions = typeof(AdminUsersService).GetActions(); + Assert.That(actions.Count, Is.EqualTo(5)); + var verbs = ActionVerbs(actions); + var expected = StripAsync(new[] { + nameof(AdminUsersService.Get), + nameof(AdminUsersService.Post), + nameof(AdminUsersService.Put), + nameof(AdminUsersService.Delete), + }); + Assert.That(verbs, Is.EquivalentTo(expected)); + } + + [Test] + public void Does_resolve_all_TestService_methods() + { + var actions = typeof(TestService).GetActions(); + Assert.That(actions.Count, Is.EqualTo(6)); + var verbs = ActionVerbs(actions); + var expected = StripAsync(new[] { + nameof(TestService.Any), + nameof(TestService.Get), + nameof(TestService.GetJson), + }); + Assert.That(verbs, Is.EquivalentTo(expected)); + } + + public class Request1 {} + public class Request2 {} + + public class TestService : Service + { + public object Any(Request1 request) => request; + public object AnyAsync(Request1 request) => request; + public object Get(Request1 request) => request; + public object GetAsync(Request1 request) => request; + public object GetJson(Request1 request) => request; + public object GetJsonAsync(Request1 request) => request; + public object Any(Request2 request) => request; + public object AnyAsync(Request2 request) => request; + public object Get(Request2 request) => request; + public object GetAsync(Request2 request) => request; + public object GetJson(Request2 request) => request; + public object GetJsonAsync(Request2 request) => request; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AdminUsersFeatureTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AdminUsersFeatureTests.cs new file mode 100644 index 00000000000..ffffbc31a1a --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AdminUsersFeatureTests.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Admin; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class MemoryAdminUsersFeatureTests : AdminUsersFeatureTests + { + protected override void Configure(ServiceStackHost appHost) + { + appHost.Register(new InMemoryAuthRepository()); + } + } + + public class OrmLiteAdminUsersFeatureTests : AdminUsersFeatureTests + { + protected override void Configure(ServiceStackHost appHost) + { + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + + appHost.Register(dbFactory); + appHost.Register(new OrmLiteAuthRepository(dbFactory)); + appHost.Resolve().InitSchema(); + } + } + + public abstract class AdminUsersFeatureTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost(); + Configure(appHost); + appHost + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected abstract void Configure(ServiceStackHost appHost); + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(AdminUsersFeatureTests), typeof(AdminUsersFeatureTests).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + AdminAuthSecret = "secretz" + }); + Plugins.Add(new AdminUsersFeature()); + } + } + + [SetUp] + public void SetUp() + { + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + ((IClearable)authRepo).Clear(); + } + } + + JsonServiceClient client = new JsonServiceClient(Config.ListeningOn) { + Headers = { + [HttpHeaders.XParamOverridePrefix + Keywords.AuthSecret] = "secretz" + } + }; + + private static AdminCreateUser CreateUserRequest() => new() { + FirstName = "First", + LastName = "Last", + Email = "user@email.com", + Password = "p@ss", + ProfileUrl = Svg.Images[Svg.Icons.MaleBusiness], + Roles = new List {"TheRole"} + }; + + private static void AssertFirstLastUser(AdminUserResponse response) + { + Assert.That(response.Id, Is.Not.Null); + Assert.That(response.Result[nameof(UserAuth.FirstName)], Is.EqualTo("First")); + Assert.That(response.Result[nameof(UserAuth.LastName)], Is.EqualTo("Last")); + Assert.That(response.Result[nameof(UserAuth.DisplayName)], Is.EqualTo("First Last")); + Assert.That(response.Result[nameof(UserAuth.Email)], Is.EqualTo("user@email.com")); + Assert.That(response.Result[nameof(UserAuth.PrimaryEmail)], Is.EqualTo("user@email.com")); + Assert.That(response.Result[nameof(UserAuth.Roles)], Is.EqualTo(new List {"TheRole"})); + Assert.That(response.Result[nameof(IAuthSession.ProfileUrl)], Is.EqualTo(Svg.Images[Svg.Icons.MaleBusiness])); + Assert.That(response.Result[nameof(IAuthSession.Roles)], Is.EquivalentTo(new[]{ "TheRole" })); + } + + [Test] + public async Task Can_AdminCreateUser() + { + var createUserRequest = CreateUserRequest(); + + var response = client.Post(createUserRequest); + AssertFirstLastUser(response); + + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + Assert.That(authRepo.TryAuthenticate("user@email.com", "p@ss", out _)); + } + + try + { + client.Post(createUserRequest); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.ErrorCode, Is.EqualTo("AlreadyExists")); + } + + response = client.Get(new AdminGetUser { + Id = response.Id + }); + AssertFirstLastUser(response); + } + + [Test] + public async Task Can_AdminUpdateUser() + { + var createUserRequest = CreateUserRequest(); + + var response = client.Post(createUserRequest); + AssertFirstLastUser(response); + + var updateUserRequest = new AdminUpdateUser { + Id = response.Id, + FirstName = "Given", + LastName = "Surname", + DisplayName = "Display Name", + Email = "newuser@email.com", + Password = "newp@ss", + ProfileUrl = Svg.Images[Svg.Icons.FemaleBusiness], + RemoveRoles = new List {"TheRole"}, + AddRoles = new List {"NewRole"}, + AddPermissions = new List {"ThePermission"}, + }; + + var updated = client.Put(updateUserRequest); + Assert.That(updated.Id, Is.EqualTo(response.Id)); + Assert.That(updated.Result[nameof(UserAuth.FirstName)], Is.EqualTo("Given")); + Assert.That(updated.Result[nameof(UserAuth.LastName)], Is.EqualTo("Surname")); + Assert.That(updated.Result[nameof(UserAuth.DisplayName)], Is.EqualTo("Display Name")); + Assert.That(updated.Result[nameof(UserAuth.Email)], Is.EqualTo("newuser@email.com")); + Assert.That(updated.Result[nameof(UserAuth.PrimaryEmail)], Is.EqualTo("newuser@email.com")); + Assert.That(updated.Result[nameof(UserAuth.Roles)], Is.EqualTo(new List {"NewRole"})); + Assert.That(updated.Result[nameof(UserAuth.Permissions)], Is.EqualTo(new List {"ThePermission"})); + Assert.That(updated.Result[nameof(IAuthSession.ProfileUrl)], Is.EqualTo(Svg.Images[Svg.Icons.FemaleBusiness])); + + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + Assert.That(authRepo.TryAuthenticate("newuser@email.com", "newp@ss", out _)); + } + } + + [Test] + public async Task Can_AdminDeleteUser() + { + var createUserRequest = CreateUserRequest(); + + var response = client.Post(createUserRequest); + + client.Delete(new AdminDeleteUser { Id = response.Id }); + + try + { + response = client.Get(new AdminGetUser { + Id = response.Id + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo((int)HttpStatusCode.NotFound)); + } + } + + [Test] + public async Task Can_AdminQueryUsers() + { + var createUserRequest = CreateUserRequest(); + + var response = client.Post(createUserRequest); + + var searchResults = client.Get(new AdminQueryUsers()); + Assert.That(searchResults.Results.Count, Is.GreaterThan(0)); + + searchResults = client.Get(new AdminQueryUsers { + Query = "First" + }); + Assert.That(searchResults.Results.Count, Is.GreaterThan(0)); + + searchResults = client.Get(new AdminQueryUsers { + Query = "Unknown" + }); + Assert.That(searchResults.Results.Count, Is.EqualTo(0)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AlwaysThrowsService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AlwaysThrowsService.cs new file mode 100644 index 00000000000..692eb47da32 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AlwaysThrowsService.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Host; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [DataContract] + public class AlwaysThrows + { + [DataMember] + public int? StatusCode { get; set; } + [DataMember] + public string Value { get; set; } + } + + [Route("/throwslist/{StatusCode}/{Value}")] + [DataContract] + public class AlwaysThrowsList + { + [DataMember] + public int? StatusCode { get; set; } + [DataMember] + public string Value { get; set; } + } + + [Route("/throwsvalidation")] + [DataContract] + public class AlwaysThrowsValidation + { + [DataMember] + public string Value { get; set; } + } + + public class AlwaysThrowsValidator : AbstractValidator + { + public AlwaysThrowsValidator() + { + RuleFor(x => x.Value).NotEmpty(); + } + } + + public class ThrowArgumentException : IReturn + { + public int Id { get; set; } + } + + [DataContract] + public class AlwaysThrowsResponse : IHasResponseStatus + { + public AlwaysThrowsResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public string Result { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract] + public class BasicAuthRequired + { + public string Name { get; set; } + } + + public class AlwaysThrowsService : Service + { + public object Any(AlwaysThrows request) + { + if (request.StatusCode.HasValue) + { + throw new HttpError( + request.StatusCode.Value, + nameof(NotImplementedException), + GetErrorMessage(request.Value)); + } + + throw new NotImplementedException(GetErrorMessage(request.Value)); + } + + public List Any(AlwaysThrowsList request) + { + Any(request.ConvertTo()); + + return new List(); + } + + public List Any(AlwaysThrowsValidation request) + { + return new List(); + } + + public static string GetErrorMessage(string value) + { + return value + " is not implemented"; + } + + public object Any(BasicAuthRequired request) + { + return request; + } + + public object Any(ThrowArgumentException request) + { + throw new ArgumentNullException("Id"); + } + } + + public class AlwaysThrowsAppHost : AppHostHttpListenerBase + { + public AlwaysThrowsAppHost() + : base("Always Throws Service", typeof(AlwaysThrowsService).Assembly) { } + + public override void Configure(Container container) + { +#if !NETCORE + Plugins.Add(new SoapFormat()); +#endif + Plugins.Add(new ValidationFeature()); + + container.RegisterValidators(typeof(AlwaysThrowsValidator).Assembly); + + Plugins.Add(new CustomAuthenticationPlugin()); + } + } + + public class CustomAuthenticationPlugin : IPlugin + { + public void Register(IAppHost appHost) + { + appHost.PreRequestFilters.Add((httpReq, httpResp) => + { + if (httpReq.OperationName != nameof(BasicAuthRequired)) + return; + + var credentials = httpReq.GetBasicAuthUserAndPassword(); + if (!credentials.HasValue) + { + // throw new UnauthorizedAccessException(); + httpResp.StatusCode = (int)HttpStatusCode.Unauthorized; + httpResp.EndRequestWithNoContent(); + return; + } + + string username = credentials.Value.Key; + string password = credentials.Value.Value; + + // TODO: get DI working + // TODO: Use PasswordList.SystemPass in production + var isAuth = password == "p@55word"; + if (!isAuth) + { + // throw new UnauthorizedAccessException(); + httpResp.StatusCode = (int)HttpStatusCode.Unauthorized; + httpResp.EndRequestWithNoContent(); + } + }); + } + } + + /// + /// This base class executes all Web Services ignorant of the endpoints its hosted on. + /// The same tests below are re-used by the Unit and Integration TestFixture's declared below + /// + [TestFixture] + public abstract class WebServicesTests + //: TestBase + { + public const string ListeningOn = "http://localhost:1337/"; + private const string TestString = "ServiceStack"; + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AlwaysThrowsAppHost() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected abstract IServiceClient CreateNewServiceClient(); + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowService() + { + var client = CreateNewServiceClient(); + try + { + var response = client.Send( + new AlwaysThrows { Value = TestString }); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + var response = (AlwaysThrowsResponse)webEx.ResponseDto; + var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); + Assert.That(response.ResponseStatus.ErrorCode, + Is.EqualTo(nameof(NotImplementedException))); + Assert.That(response.ResponseStatus.Message, + Is.EqualTo(expectedError)); + } + } + + [Test] + public void Can_Handle_ThrowArgumentException() + { + var client = CreateNewServiceClient(); + try + { + var response = client.Send( + new ThrowArgumentException()); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(400)); + Assert.That(webEx.StatusDescription, Is.EqualTo(nameof(ArgumentNullException))); + Assert.That(webEx.Message.Replace("\r\n", "\n"), Does.StartWith("Value cannot be null.")); + Assert.That(webEx.ErrorCode, Is.EqualTo(nameof(ArgumentNullException))); + Assert.That(webEx.ErrorMessage.Replace("\r\n", "\n"), Does.StartWith("Value cannot be null.")); + } + } + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowsList_with_GET_route() + { + var client = CreateNewServiceClient(); +#if !NETCORE + if (client is WcfServiceClient) return; +#endif + try + { + var response = client.Get>("/throwslist/404/{0}".Fmt(TestString)); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + + var response = (ErrorResponse)webEx.ResponseDto; + var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); + Assert.That(response.ResponseStatus.ErrorCode, + Is.EqualTo(nameof(NotImplementedException))); + Assert.That(response.ResponseStatus.Message, + Is.EqualTo(expectedError)); + } + } + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowsValidation() + { + var client = CreateNewServiceClient(); + try + { + var response = client.Send>( + new AlwaysThrowsValidation()); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + var response = (ErrorResponse)webEx.ResponseDto; + var status = response.ResponseStatus; + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Value' must not be empty.")); + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Value")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Value' must not be empty.")); + } + } + + [Test] + public void Can_handle_no_content_BasicAuth_exception() + { + var client = CreateNewServiceClient(); + try + { + var response = client.Send( + new BasicAuthRequired { Name = "Test" }); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(webEx.ResponseDto, Is.Null); + } + } + } + + public class XmlIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new XmlServiceClient(ListeningOn); + } + } + + public class JsonIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new JsonServiceClient(ListeningOn); + } + } + + public class JsonHttpIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new JsonHttpClient(ListeningOn); + } + } + + public class JsvIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new JsvServiceClient(ListeningOn); + } + } + +#if !NETCORE + public class Soap11IntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new Soap11ServiceClient(ListeningOn); + } + } + + public class Soap12IntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new Soap12ServiceClient(ListeningOn); + } + } +#endif +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/App.config b/tests/ServiceStack.WebHost.Endpoints.Tests/App.config new file mode 100644 index 00000000000..c0ee9ffef9d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/App.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostConfigTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostConfigTests.cs index 1b5bf86cc91..30b4bd62901 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostConfigTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostConfigTests.cs @@ -1,8 +1,4 @@ -using System; using NUnit.Framework; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; @@ -11,41 +7,32 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class AppHostConfigTests { - protected const string ListeningOn = "http://localhost:85/"; + protected const string ListeningOn = "http://localhost:1337/"; - TestConfigAppHostHttpListener appHost; + ServiceStackHost appHost; - [TestFixtureSetUp] - public void OnTestFixtureSetUp() + [OneTimeSetUp] + public void TestFixtureSetUp() { - LogManager.LogFactory = new ConsoleLogFactory(); - - appHost = new TestConfigAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); + appHost = new TestConfigAppHostHttpListener() + .Init() + .Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { - Dispose(); - } - - public void Dispose() - { - if (appHost == null) return; - appHost.Dispose(); - appHost = null; - } - - + appHost.Dispose(); + } + [Test] public void Actually_uses_the_BclJsonSerializers() { var json = (ListeningOn + "login/user/pass").GetJsonFromUrl(); - Console.WriteLine(json); - Assert.That(json, Is.EqualTo("{\"pwd\":\"pass\",\"uname\":\"user\"}")); + json.Print(); + Assert.That(json, Is.EqualTo("{\"pwd\":\"pass\",\"uname\":\"user\"}") + .Or.EqualTo("{\"uname\":\"user\",\"pwd\":\"pass\"}")); } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs index a78a0af253a..351004dfb43 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostHttpListenerLongRunningBaseTests.cs @@ -1,15 +1,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Net; using System.Threading; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests @@ -17,30 +11,23 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] class AppHostHttpListenerLongRunningBaseTests { - private const string ListeningOn = "http://localhost:82/"; - ExampleAppHostHttpListenerLongRunning appHost; + private const string ListeningOn = "http://localhost:1337/"; + ServiceStackHost appHost; - static AppHostHttpListenerLongRunningBaseTests() - { - LogManager.LogFactory = new ConsoleLogFactory(); - } - - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureStartUp() { - appHost = new ExampleAppHostHttpListenerLongRunning(); - appHost.Init(); - appHost.Start(ListeningOn); + appHost = new ExampleAppHostHttpListenerPool() + .Init() + .Start(ListeningOn); - System.Console.WriteLine("ExampleAppHost Created at {0}, listening on {1}", - DateTime.Now, ListeningOn); + Console.WriteLine(@"ExampleAppHost Created at {0}, listening on {1}", DateTime.Now, ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -60,7 +47,7 @@ public void Can_download_webpage_html_page() [Test] public void Can_download_requestinfo_json() { - var html = (ListeningOn + "_requestinfo").GetStringFromUrl(); + var html = (ListeningOn + "?debug=requestinfo").GetStringFromUrl(); Assert.That(html.Contains("\"Host\":")); } @@ -91,7 +78,7 @@ public void Can_call_GetFactorial_WebService() [Test] public void Can_call_jsv_debug_on_GetFactorial_WebService() { - const string url = ListeningOn + "jsv/syncreply/GetFactorial?ForNumber=3&debug=true"; + const string url = ListeningOn + "jsv/reply/GetFactorial?ForNumber=3&debug=true"; var contents = url.GetStringFromUrl(); @@ -112,7 +99,7 @@ public void Calling_missing_web_service_does_not_break_HttpListener() catch (Exception ex) { errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); } try { @@ -121,7 +108,7 @@ public void Calling_missing_web_service_does_not_break_HttpListener() catch (Exception ex) { errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); } Assert.That(errorCount, Is.EqualTo(2)); @@ -143,7 +130,7 @@ public void Calling_not_implemented_method_returns_405() var client = new JsonServiceClient(ListeningOn); try { - var response = client.Put("movies.zip", new MoviesZip()); + var response = client.Put("all-movies.zip", new MoviesZip()); Assert.Fail("Should throw 405 excetpion"); } catch (WebServiceException ex) @@ -158,27 +145,27 @@ public void Can_GET_single_gethttpresult_using_RestClient_with_JSONP_from_servic var url = ListeningOn + "gethttpresult?callback=cb"; string response; - var webReq = (HttpWebRequest)WebRequest.Create(url); + var webReq = WebRequest.CreateHttp(url); webReq.Accept = "*/*"; using (var webRes = webReq.GetResponse()) { - Assert.That(webRes.ContentType, Is.StringStarting(ContentType.Json)); - response = webRes.DownloadText(); + Assert.That(webRes.ContentType, Does.StartWith(MimeTypes.JavaScript)); + response = webRes.ReadToEnd(); } Assert.That(response, Is.Not.Null, "No response received"); Console.WriteLine(response); - Assert.That(response, Is.StringStarting("cb(")); - Assert.That(response, Is.StringEnding(")")); + Assert.That(response, Does.StartWith("cb(")); + Assert.That(response, Does.EndWith(")")); } - [Test, Ignore] + [Test, Ignore("Helper test")] public void DebugHost() { Thread.Sleep(180 * 1000); } - [Test, Ignore] + [Test, Ignore("Performance test")] public void PerformanceTest() { const int clientCount = 500; @@ -211,4 +198,4 @@ public void PerformanceTest() Trace.TraceInformation("Elapsed time for " + clientCount + " requests : " + sw.Elapsed); } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs index 791743e6279..137db420268 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerBaseTests.cs @@ -1,18 +1,15 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using NUnit.Framework; -using ServiceStack.Common.Web; +#if !NETCORE +using ServiceStack.Host.HttpListener; +#endif using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Support; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests @@ -20,30 +17,28 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class AppHostListenerBaseTests { - private const string ListeningOn = "http://localhost:82/"; - ExampleAppHostHttpListener appHost; + private const string ListeningOn = "http://localhost:1337/"; + ServiceStackHost appHost; static AppHostListenerBaseTests() { LogManager.LogFactory = new ConsoleLogFactory(); } - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureStartUp() { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); + appHost = new ExampleAppHostHttpListener() + .Init() + .Start(ListeningOn); - System.Console.WriteLine("ExampleAppHost Created at {0}, listening on {1}", - DateTime.Now, ListeningOn); + "ExampleAppHost Created at {0}, listening on {1}".Print(DateTime.Now, ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -63,7 +58,7 @@ public void Can_download_webpage_html_page() [Test] public void Can_download_requestinfo_json() { - var html = (ListeningOn + "_requestinfo").GetStringFromUrl(); + var html = (ListeningOn + "?debug=requestinfo").GetStringFromUrl(); Assert.That(html.Contains("\"Host\":")); } @@ -94,10 +89,10 @@ public void Can_call_GetFactorial_WebService() [Test] public void Can_call_jsv_debug_on_GetFactorial_WebService() { - const string url = ListeningOn + "jsv/syncreply/GetFactorial?ForNumber=3&debug=true"; + var url = ListeningOn + "jsv/reply/GetFactorial?ForNumber=3&debug=true"; var contents = url.GetStringFromUrl(); - Console.WriteLine("JSV DEBUG: " + contents); + Console.WriteLine(@"JSV DEBUG: " + contents); Assert.That(contents, Is.Not.Null); } @@ -114,7 +109,7 @@ public void Calling_missing_web_service_does_not_break_HttpListener() catch (Exception ex) { errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); } try { @@ -123,7 +118,7 @@ public void Calling_missing_web_service_does_not_break_HttpListener() catch (Exception ex) { errorCount++; - Console.WriteLine("Error [{0}]: {1}", ex.GetType().Name, ex.Message); + Console.WriteLine(@"Error [{0}]: {1}", ex.GetType().Name, ex.Message); } Assert.That(errorCount, Is.EqualTo(2)); @@ -145,8 +140,8 @@ public void Calling_not_implemented_method_returns_405() var client = new JsonServiceClient(ListeningOn); try { - var response = client.Put("movies.zip", new MoviesZip()); - Assert.Fail("Should throw 405 excetpion"); + var response = client.Put("all-movies.zip", new MoviesZip()); + Assert.Fail("Should throw 405 exception"); } catch (WebServiceException ex) { @@ -160,33 +155,35 @@ public void Can_GET_single_gethttpresult_using_RestClient_with_JSONP_from_servic var url = ListeningOn + "gethttpresult?callback=cb"; string response; - var webReq = (HttpWebRequest)WebRequest.Create(url); + var webReq = WebRequest.CreateHttp(url); webReq.Accept = "*/*"; using (var webRes = webReq.GetResponse()) { - Assert.That(webRes.ContentType, Is.StringStarting(ContentType.Json)); - response = webRes.DownloadText(); + Assert.That(webRes.ContentType, Does.StartWith(MimeTypes.JavaScript)); + response = webRes.ReadToEnd(); } Assert.That(response, Is.Not.Null, "No response received"); Console.WriteLine(response); - Assert.That(response, Is.StringStarting("cb(")); - Assert.That(response, Is.StringEnding(")")); + Assert.That(response, Does.StartWith("cb(")); + Assert.That(response, Does.EndWith(")")); } - [Test, Ignore] + [Test, Ignore("Dubug test")] public void DebugHost() { Thread.Sleep(180 * 1000); } - [Test, Ignore] + [Test, Ignore("Performance test")] public void PerformanceTest() { const int clientCount = 500; var threads = new List(clientCount); +#if !NETCORE ThreadPool.SetMinThreads(500, 50); ThreadPool.SetMaxThreads(1000, 50); +#endif for (int i = 0; i < clientCount; i++) { @@ -213,6 +210,7 @@ public void PerformanceTest() Trace.TraceInformation("Elapsed time for " + clientCount + " requests : " + sw.Elapsed); } +#if !NETCORE [Test] public void Can_infer_handler_path_from_listener_uris() { @@ -228,10 +226,11 @@ public void Can_infer_handler_path_from_listener_uris() foreach (var entry in map) { - var handlerPath = HttpListenerRequestWrapper.GetHandlerPathIfAny(entry.Key); + var handlerPath = ListenerRequest.GetHandlerPathIfAny(entry.Key); Assert.That(handlerPath, Is.EqualTo(entry.Value)); } } +#endif [Test, Ignore("You have to manually check the test output if there where NullReferenceExceptions!")] public void Rapid_Start_Stop_should_not_cause_exceptions() @@ -241,21 +240,22 @@ public void Rapid_Start_Stop_should_not_cause_exceptions() for (int i = 0; i < 100; i++) { localAppHost.Start(GetBaseAddressWithFreePort()); +#if !NETCORE localAppHost.Stop(); +#endif } } private static string GetBaseAddressWithFreePort() { - TcpListener listener = new TcpListener(IPAddress.Loopback, 0); + var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); - IPEndPoint endPoint = listener.LocalEndpoint as IPEndPoint; - if (endPoint != null) + if (listener.LocalEndpoint is IPEndPoint endPoint) { string address = endPoint.Address.ToString(); int port = endPoint.Port; - Uri uri = new UriBuilder(Uri.UriSchemeHttp, address, port).Uri; + Uri uri = new UriBuilder("http://", address, port).Uri; listener.Stop(); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs index ab628fcdff3..bdfdea1cb1e 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppHostListenerEchoRequestTests.cs @@ -1,10 +1,13 @@ -using Funq; +using System.Net; +using System.Text; +using System.Threading; +using Funq; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; +using ServiceStack.Host.Handlers; +#if !NETCORE +using ServiceStack.Host.HttpListener; +#endif using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -14,9 +17,23 @@ public class AppHostListenerEchoRequestTests public class AppHost : AppHostHttpListenerBase { public AppHost() - : base("Echo AppHost", typeof(AppHost).Assembly) { } + : base("Echo AppHost", typeof(AppHost).Assembly) + { + } + + public override void Configure(Container container) { } - public override void Configure(Container container) {} +#if !NETCORE + public override ListenerRequest CreateRequest(HttpListenerContext httpContext, string operationName) + { + var req = new ListenerRequest(httpContext, operationName, RequestAttributes.None) + { + ContentEncoding = Encoding.UTF8 + }; + req.RequestAttributes = req.GetAttributes(); + return req; + } +#endif } [Route("/echo")] @@ -27,7 +44,10 @@ public class Echo : IReturn public string PathInfoParam { get; set; } } - public class EchoService : ServiceInterface.Service + [Route("/customhtml")] + public class CustomHtml {} + + public class EchoService : Service { public Echo Any(Echo request) { @@ -39,11 +59,29 @@ public RequestInfoResponse Any(RequestInfo request) var requestInfo = RequestInfoHandler.GetRequestInfo(base.Request); return requestInfo; } + + public object Any(CustomHtml request) + { + return @" + + + + + + +
      + + + +
      + +"; + } } private AppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new AppHost(); @@ -51,7 +89,7 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); @@ -62,7 +100,7 @@ public void Does_url_decode_raw_QueryString() { var testEncoding = "test://?&% encoding"; var url = "{0}echo?Param={1}".Fmt(Config.AbsoluteBaseUri, testEncoding.UrlEncode()); - Assert.That(url, Is.StringEnding("/echo?Param=test%3a%2f%2f%3f%26%25%20encoding")); + Assert.That(url, Does.EndWith("/echo?Param=test%3a%2f%2f%3f%26%25+encoding")); var json = url.GetJsonFromUrl(); var response = json.FromJson(); @@ -74,7 +112,7 @@ public void Does_url_decode_raw_PathInfo() { var testEncoding = "test encoding"; var url = "{0}echo/{1}".Fmt(Config.AbsoluteBaseUri, testEncoding.UrlEncode()); - Assert.That(url, Is.StringEnding("/echo/test%20encoding")); + Assert.That(url, Does.EndWith("/echo/test+encoding")); var json = url.GetJsonFromUrl(); var response = json.FromJson(); @@ -94,9 +132,9 @@ public void Does_url_transparently_decode_QueryString() public void Does_url_transparently_decode_PathInfo() { var client = new JsonServiceClient(Config.AbsoluteBaseUri); - var request = new Echo { PathInfoParam = "test:?&% encoding" }; + var request = new Echo { PathInfoParam = "test%2Fpath:?&% encoding" }; var response = client.Get(request); - Assert.That(response.Param, Is.EqualTo(request.Param)); + Assert.That(response.PathInfoParam, Is.EqualTo(request.PathInfoParam)); } [Test] @@ -108,5 +146,20 @@ public void Does_url_transparently_decode_RequestBody() Assert.That(response.Param, Is.EqualTo(request.Param)); } + [Test] + public void Can_force_default_UTF8_encoding() + { + const string param = "привіт"; + + var json = Config.AbsoluteBaseUri.CombineWith("/echo").PostStringToUrl( + requestBody: "Param=" + param.UrlEncode(), + contentType: MimeTypes.FormUrlEncoded, accept: MimeTypes.Json); + + var value = JsonObject.Parse(json)["Param"] + ?? JsonObject.Parse(json)["param"]; + + Assert.That(value, Is.EqualTo(param)); + } } + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AppSelfHostTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AppSelfHostTests.cs new file mode 100644 index 00000000000..c1757f59300 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AppSelfHostTests.cs @@ -0,0 +1,97 @@ +using System; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class SpinWait : IReturn + { + public int? Iterations { get; set; } + } + + public class Sleep : IReturn + { + public int? ForMs { get; set; } + } + + public class PerfServices : Service + { + private const int DefaultIterations = 1000 * 1000; + private const int DefaultMs = 100; + + public object Any(SpinWait request) + { +#if NETCORE + int i = request.Iterations.GetValueOrDefault(DefaultIterations); + //SpinWait.SpinUntil(i-- > 0); +#else + Thread.SpinWait(request.Iterations.GetValueOrDefault(DefaultIterations)); +#endif + return request; + } + + public object Any(Sleep request) + { + Thread.Sleep(request.ForMs.GetValueOrDefault(DefaultMs)); + return request; + } + } + + public class AppHostSmartPool : AppHostHttpListenerSmartPoolBase + { + public AppHostSmartPool() : base("SmartPool Test", typeof(PerfServices).Assembly) { } + + public override void Configure(Container container) + { + } + } + + [TestFixture] + public class AppSelfHostTests + { + private readonly ServiceStackHost appHost; + + private readonly string ListeningOn; + + public AppSelfHostTests() + { + var port = HostContext.FindFreeTcpPort(startingFrom: 5000); + if (port < 5000) + throw new Exception("Expected port >= 5000, got: " + port); + + ListeningOn = "http://localhost:{0}/".Fmt(port); + + appHost = new AppHostSmartPool() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_call_SelfHost_Services() + { + var client = new JsonServiceClient(ListeningOn); + + client.Get(new Sleep { ForMs = 100 }); + client.Get(new SpinWait { Iterations = 1000 }); + } + + [Test] + public async Task Can_call_SelfHost_Services_async() + { + var client = new JsonServiceClient(ListeningOn); + + var sleep = await client.GetAsync(new Sleep { ForMs = 100 }); + var spin = await client.GetAsync(new SpinWait { Iterations = 1000 }); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/App_Data/customers.json b/tests/ServiceStack.WebHost.Endpoints.Tests/App_Data/customers.json new file mode 100644 index 00000000000..48b62bf41b2 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/App_Data/customers.json @@ -0,0 +1,5248 @@ +[ + { + "customerId": "ALFKI", + "companyName": "Alfreds Futterkiste", + "address": "Obere Str. 57", + "city": "Berlin", + "postalCode": "12209", + "country": "Germany", + "phone": "030-0074321", + "fax": "030-0076545", + "orders": [ + { + "orderId": 10643, + "orderDate": "1997-08-25T00:00:00", + "total": 814.50 + }, + { + "orderId": 10692, + "orderDate": "1997-10-03T00:00:00", + "total": 878.00 + }, + { + "orderId": 10702, + "orderDate": "1997-10-13T00:00:00", + "total": 330.00 + }, + { + "orderId": 10835, + "orderDate": "1998-01-15T00:00:00", + "total": 845.80 + }, + { + "orderId": 10952, + "orderDate": "1998-03-16T00:00:00", + "total": 471.20 + }, + { + "orderId": 11011, + "orderDate": "1998-04-09T00:00:00", + "total": 933.50 + } + ] + }, + { + "customerId": "ANATR", + "companyName": "Ana Trujillo Emparedados y helados", + "address": "Avda. de la Constituci\u00f3n 2222", + "city": "M\u00e9xico D.F.", + "postalCode": "05021", + "country": "Mexico", + "phone": "(5) 555-4729", + "fax": "(5) 555-3745", + "orders": [ + { + "orderId": 10308, + "orderDate": "1996-09-18T00:00:00", + "total": 88.80 + }, + { + "orderId": 10625, + "orderDate": "1997-08-08T00:00:00", + "total": 479.75 + }, + { + "orderId": 10759, + "orderDate": "1997-11-28T00:00:00", + "total": 320.00 + }, + { + "orderId": 10926, + "orderDate": "1998-03-04T00:00:00", + "total": 514.40 + } + ] + }, + { + "customerId": "ANTON", + "companyName": "Antonio Moreno Taquer\u00eda", + "address": "Mataderos 2312", + "city": "M\u00e9xico D.F.", + "postalCode": "05023", + "country": "Mexico", + "phone": "(5) 555-3932", + "orders": [ + { + "orderId": 10365, + "orderDate": "1996-11-27T00:00:00", + "total": 403.20 + }, + { + "orderId": 10507, + "orderDate": "1997-04-15T00:00:00", + "total": 749.06 + }, + { + "orderId": 10535, + "orderDate": "1997-05-13T00:00:00", + "total": 1940.85 + }, + { + "orderId": 10573, + "orderDate": "1997-06-19T00:00:00", + "total": 2082.00 + }, + { + "orderId": 10677, + "orderDate": "1997-09-22T00:00:00", + "total": 813.36 + }, + { + "orderId": 10682, + "orderDate": "1997-09-25T00:00:00", + "total": 375.50 + }, + { + "orderId": 10856, + "orderDate": "1998-01-28T00:00:00", + "total": 660.00 + } + ] + }, + { + "customerId": "AROUT", + "companyName": "Around the Horn", + "address": "120 Hanover Sq.", + "city": "London", + "postalCode": "WA1 1DP", + "country": "UK", + "phone": "(171) 555-7788", + "fax": "(171) 555-6750", + "orders": [ + { + "orderId": 10355, + "orderDate": "1996-11-15T00:00:00", + "total": 480.00 + }, + { + "orderId": 10383, + "orderDate": "1996-12-16T00:00:00", + "total": 899.00 + }, + { + "orderId": 10453, + "orderDate": "1997-02-21T00:00:00", + "total": 407.70 + }, + { + "orderId": 10558, + "orderDate": "1997-06-04T00:00:00", + "total": 2142.90 + }, + { + "orderId": 10707, + "orderDate": "1997-10-16T00:00:00", + "total": 1641.00 + }, + { + "orderId": 10741, + "orderDate": "1997-11-14T00:00:00", + "total": 228.00 + }, + { + "orderId": 10743, + "orderDate": "1997-11-17T00:00:00", + "total": 319.20 + }, + { + "orderId": 10768, + "orderDate": "1997-12-08T00:00:00", + "total": 1477.00 + }, + { + "orderId": 10793, + "orderDate": "1997-12-24T00:00:00", + "total": 191.10 + }, + { + "orderId": 10864, + "orderDate": "1998-02-02T00:00:00", + "total": 282.00 + }, + { + "orderId": 10920, + "orderDate": "1998-03-03T00:00:00", + "total": 390.00 + }, + { + "orderId": 10953, + "orderDate": "1998-03-16T00:00:00", + "total": 4441.25 + }, + { + "orderId": 11016, + "orderDate": "1998-04-10T00:00:00", + "total": 491.50 + } + ] + }, + { + "customerId": "BERGS", + "companyName": "Berglunds snabbk\u00f6p", + "address": "Berguvsv\u00e4gen 8", + "city": "Lule\u00e5", + "postalCode": "S-958 22", + "country": "Sweden", + "phone": "0921-12 34 65", + "fax": "0921-12 34 67", + "orders": [ + { + "orderId": 10278, + "orderDate": "1996-08-12T00:00:00", + "total": 1488.80 + }, + { + "orderId": 10280, + "orderDate": "1996-08-14T00:00:00", + "total": 613.20 + }, + { + "orderId": 10384, + "orderDate": "1996-12-16T00:00:00", + "total": 2222.40 + }, + { + "orderId": 10444, + "orderDate": "1997-02-12T00:00:00", + "total": 1031.70 + }, + { + "orderId": 10445, + "orderDate": "1997-02-13T00:00:00", + "total": 174.90 + }, + { + "orderId": 10524, + "orderDate": "1997-05-01T00:00:00", + "total": 3192.65 + }, + { + "orderId": 10572, + "orderDate": "1997-06-18T00:00:00", + "total": 1501.08 + }, + { + "orderId": 10626, + "orderDate": "1997-08-11T00:00:00", + "total": 1503.60 + }, + { + "orderId": 10654, + "orderDate": "1997-09-02T00:00:00", + "total": 601.83 + }, + { + "orderId": 10672, + "orderDate": "1997-09-17T00:00:00", + "total": 3815.25 + }, + { + "orderId": 10689, + "orderDate": "1997-10-01T00:00:00", + "total": 472.50 + }, + { + "orderId": 10733, + "orderDate": "1997-11-07T00:00:00", + "total": 1459.00 + }, + { + "orderId": 10778, + "orderDate": "1997-12-16T00:00:00", + "total": 96.50 + }, + { + "orderId": 10837, + "orderDate": "1998-01-16T00:00:00", + "total": 1064.50 + }, + { + "orderId": 10857, + "orderDate": "1998-01-28T00:00:00", + "total": 2048.21 + }, + { + "orderId": 10866, + "orderDate": "1998-02-03T00:00:00", + "total": 1096.20 + }, + { + "orderId": 10875, + "orderDate": "1998-02-06T00:00:00", + "total": 709.55 + }, + { + "orderId": 10924, + "orderDate": "1998-03-04T00:00:00", + "total": 1835.70 + } + ] + }, + { + "customerId": "BLAUS", + "companyName": "Blauer See Delikatessen", + "address": "Forsterstr. 57", + "city": "Mannheim", + "postalCode": "68306", + "country": "Germany", + "phone": "0621-08460", + "fax": "0621-08924", + "orders": [ + { + "orderId": 10501, + "orderDate": "1997-04-09T00:00:00", + "total": 149.00 + }, + { + "orderId": 10509, + "orderDate": "1997-04-17T00:00:00", + "total": 136.80 + }, + { + "orderId": 10582, + "orderDate": "1997-06-27T00:00:00", + "total": 330.00 + }, + { + "orderId": 10614, + "orderDate": "1997-07-29T00:00:00", + "total": 464.00 + }, + { + "orderId": 10853, + "orderDate": "1998-01-27T00:00:00", + "total": 625.00 + }, + { + "orderId": 10956, + "orderDate": "1998-03-17T00:00:00", + "total": 677.00 + }, + { + "orderId": 11058, + "orderDate": "1998-04-29T00:00:00", + "total": 858.00 + } + ] + }, + { + "customerId": "BLONP", + "companyName": "Blondel p\u00e8re et fils", + "address": "24, place Kl\u00e9ber", + "city": "Strasbourg", + "postalCode": "67000", + "country": "France", + "phone": "88.60.15.31", + "fax": "88.60.15.32", + "orders": [ + { + "orderId": 10265, + "orderDate": "1996-07-25T00:00:00", + "total": 1176.00 + }, + { + "orderId": 10297, + "orderDate": "1996-09-04T00:00:00", + "total": 1420.00 + }, + { + "orderId": 10360, + "orderDate": "1996-11-22T00:00:00", + "total": 7390.20 + }, + { + "orderId": 10436, + "orderDate": "1997-02-05T00:00:00", + "total": 1994.52 + }, + { + "orderId": 10449, + "orderDate": "1997-02-18T00:00:00", + "total": 1838.20 + }, + { + "orderId": 10559, + "orderDate": "1997-06-05T00:00:00", + "total": 520.41 + }, + { + "orderId": 10566, + "orderDate": "1997-06-12T00:00:00", + "total": 1761.00 + }, + { + "orderId": 10584, + "orderDate": "1997-06-30T00:00:00", + "total": 593.75 + }, + { + "orderId": 10628, + "orderDate": "1997-08-12T00:00:00", + "total": 450.00 + }, + { + "orderId": 10679, + "orderDate": "1997-09-23T00:00:00", + "total": 660.00 + }, + { + "orderId": 10826, + "orderDate": "1998-01-12T00:00:00", + "total": 730.00 + } + ] + }, + { + "customerId": "BOLID", + "companyName": "B\u00f3lido Comidas preparadas", + "address": "C\/ Araquil, 67", + "city": "Madrid", + "postalCode": "28023", + "country": "Spain", + "phone": "(91) 555 22 82", + "fax": "(91) 555 91 99", + "orders": [ + { + "orderId": 10326, + "orderDate": "1996-10-10T00:00:00", + "total": 982.00 + }, + { + "orderId": 10801, + "orderDate": "1997-12-29T00:00:00", + "total": 3026.85 + }, + { + "orderId": 10970, + "orderDate": "1998-03-24T00:00:00", + "total": 224.00 + } + ] + }, + { + "customerId": "BONAP", + "companyName": "Bon app'", + "address": "12, rue des Bouchers", + "city": "Marseille", + "postalCode": "13008", + "country": "France", + "phone": "91.24.45.40", + "fax": "91.24.45.41", + "orders": [ + { + "orderId": 10331, + "orderDate": "1996-10-16T00:00:00", + "total": 88.50 + }, + { + "orderId": 10340, + "orderDate": "1996-10-29T00:00:00", + "total": 2436.18 + }, + { + "orderId": 10362, + "orderDate": "1996-11-25T00:00:00", + "total": 1549.60 + }, + { + "orderId": 10470, + "orderDate": "1997-03-11T00:00:00", + "total": 1820.80 + }, + { + "orderId": 10511, + "orderDate": "1997-04-18T00:00:00", + "total": 2550.00 + }, + { + "orderId": 10525, + "orderDate": "1997-05-02T00:00:00", + "total": 818.40 + }, + { + "orderId": 10663, + "orderDate": "1997-09-10T00:00:00", + "total": 1930.40 + }, + { + "orderId": 10715, + "orderDate": "1997-10-23T00:00:00", + "total": 1296.00 + }, + { + "orderId": 10730, + "orderDate": "1997-11-05T00:00:00", + "total": 484.26 + }, + { + "orderId": 10732, + "orderDate": "1997-11-06T00:00:00", + "total": 360.00 + }, + { + "orderId": 10755, + "orderDate": "1997-11-26T00:00:00", + "total": 1948.50 + }, + { + "orderId": 10827, + "orderDate": "1998-01-12T00:00:00", + "total": 843.00 + }, + { + "orderId": 10871, + "orderDate": "1998-02-05T00:00:00", + "total": 1979.23 + }, + { + "orderId": 10876, + "orderDate": "1998-02-09T00:00:00", + "total": 917.00 + }, + { + "orderId": 10932, + "orderDate": "1998-03-06T00:00:00", + "total": 1788.63 + }, + { + "orderId": 10940, + "orderDate": "1998-03-11T00:00:00", + "total": 360.00 + }, + { + "orderId": 11076, + "orderDate": "1998-05-06T00:00:00", + "total": 792.75 + } + ] + }, + { + "customerId": "BOTTM", + "companyName": "Bottom-Dollar Markets", + "address": "23 Tsawassen Blvd.", + "city": "Tsawassen", + "region": "BC", + "postalCode": "T2F 8M4", + "country": "Canada", + "phone": "(604) 555-4729", + "fax": "(604) 555-3745", + "orders": [ + { + "orderId": 10389, + "orderDate": "1996-12-20T00:00:00", + "total": 1832.80 + }, + { + "orderId": 10410, + "orderDate": "1997-01-10T00:00:00", + "total": 802.00 + }, + { + "orderId": 10411, + "orderDate": "1997-01-10T00:00:00", + "total": 966.80 + }, + { + "orderId": 10431, + "orderDate": "1997-01-30T00:00:00", + "total": 1892.25 + }, + { + "orderId": 10492, + "orderDate": "1997-04-01T00:00:00", + "total": 851.20 + }, + { + "orderId": 10742, + "orderDate": "1997-11-14T00:00:00", + "total": 3118.00 + }, + { + "orderId": 10918, + "orderDate": "1998-03-02T00:00:00", + "total": 1447.50 + }, + { + "orderId": 10944, + "orderDate": "1998-03-12T00:00:00", + "total": 1025.32 + }, + { + "orderId": 10949, + "orderDate": "1998-03-13T00:00:00", + "total": 4422.00 + }, + { + "orderId": 10975, + "orderDate": "1998-03-25T00:00:00", + "total": 717.50 + }, + { + "orderId": 10982, + "orderDate": "1998-03-27T00:00:00", + "total": 1014.00 + }, + { + "orderId": 11027, + "orderDate": "1998-04-16T00:00:00", + "total": 877.72 + }, + { + "orderId": 11045, + "orderDate": "1998-04-23T00:00:00", + "total": 1309.50 + }, + { + "orderId": 11048, + "orderDate": "1998-04-24T00:00:00", + "total": 525.00 + } + ] + }, + { + "customerId": "BSBEV", + "companyName": "B's Beverages", + "address": "Fauntleroy Circus", + "city": "London", + "postalCode": "EC2 5NT", + "country": "UK", + "phone": "(171) 555-1212", + "orders": [ + { + "orderId": 10289, + "orderDate": "1996-08-26T00:00:00", + "total": 479.40 + }, + { + "orderId": 10471, + "orderDate": "1997-03-11T00:00:00", + "total": 1328.00 + }, + { + "orderId": 10484, + "orderDate": "1997-03-24T00:00:00", + "total": 386.20 + }, + { + "orderId": 10538, + "orderDate": "1997-05-15T00:00:00", + "total": 139.80 + }, + { + "orderId": 10539, + "orderDate": "1997-05-16T00:00:00", + "total": 355.50 + }, + { + "orderId": 10578, + "orderDate": "1997-06-24T00:00:00", + "total": 477.00 + }, + { + "orderId": 10599, + "orderDate": "1997-07-15T00:00:00", + "total": 493.00 + }, + { + "orderId": 10943, + "orderDate": "1998-03-11T00:00:00", + "total": 711.00 + }, + { + "orderId": 10947, + "orderDate": "1998-03-13T00:00:00", + "total": 220.00 + }, + { + "orderId": 11023, + "orderDate": "1998-04-14T00:00:00", + "total": 1500.00 + } + ] + }, + { + "customerId": "CACTU", + "companyName": "Cactus Comidas para llevar", + "address": "Cerrito 333", + "city": "Buenos Aires", + "postalCode": "1010", + "country": "Argentina", + "phone": "(1) 135-5555", + "fax": "(1) 135-4892", + "orders": [ + { + "orderId": 10521, + "orderDate": "1997-04-29T00:00:00", + "total": 225.50 + }, + { + "orderId": 10782, + "orderDate": "1997-12-17T00:00:00", + "total": 12.50 + }, + { + "orderId": 10819, + "orderDate": "1998-01-07T00:00:00", + "total": 477.00 + }, + { + "orderId": 10881, + "orderDate": "1998-02-11T00:00:00", + "total": 150.00 + }, + { + "orderId": 10937, + "orderDate": "1998-03-10T00:00:00", + "total": 644.80 + }, + { + "orderId": 11054, + "orderDate": "1998-04-28T00:00:00", + "total": 305.00 + } + ] + }, + { + "customerId": "CENTC", + "companyName": "Centro comercial Moctezuma", + "address": "Sierras de Granada 9993", + "city": "M\u00e9xico D.F.", + "postalCode": "05022", + "country": "Mexico", + "phone": "(5) 555-3392", + "fax": "(5) 555-7293", + "orders": [ + { + "orderId": 10259, + "orderDate": "1996-07-18T00:00:00", + "total": 100.80 + } + ] + }, + { + "customerId": "CHOPS", + "companyName": "Chop-suey Chinese", + "address": "Hauptstr. 29", + "city": "Bern", + "postalCode": "3012", + "country": "Switzerland", + "phone": "0452-076545", + "orders": [ + { + "orderId": 10254, + "orderDate": "1996-07-11T00:00:00", + "total": 556.62 + }, + { + "orderId": 10370, + "orderDate": "1996-12-03T00:00:00", + "total": 1117.60 + }, + { + "orderId": 10519, + "orderDate": "1997-04-28T00:00:00", + "total": 2314.20 + }, + { + "orderId": 10731, + "orderDate": "1997-11-06T00:00:00", + "total": 1890.50 + }, + { + "orderId": 10746, + "orderDate": "1997-11-19T00:00:00", + "total": 2311.70 + }, + { + "orderId": 10966, + "orderDate": "1998-03-20T00:00:00", + "total": 1098.46 + }, + { + "orderId": 11029, + "orderDate": "1998-04-16T00:00:00", + "total": 1286.80 + }, + { + "orderId": 11041, + "orderDate": "1998-04-22T00:00:00", + "total": 1773.00 + } + ] + }, + { + "customerId": "COMMI", + "companyName": "Com\u00e9rcio Mineiro", + "address": "Av. dos Lus\u00edadas, 23", + "city": "S\u00e3o Paulo", + "region": "SP", + "postalCode": "05432-043", + "country": "Brazil", + "phone": "(11) 555-7647", + "orders": [ + { + "orderId": 10290, + "orderDate": "1996-08-27T00:00:00", + "total": 2169.00 + }, + { + "orderId": 10466, + "orderDate": "1997-03-06T00:00:00", + "total": 216.00 + }, + { + "orderId": 10494, + "orderDate": "1997-04-02T00:00:00", + "total": 912.00 + }, + { + "orderId": 10969, + "orderDate": "1998-03-23T00:00:00", + "total": 108.00 + }, + { + "orderId": 11042, + "orderDate": "1998-04-22T00:00:00", + "total": 405.75 + } + ] + }, + { + "customerId": "CONSH", + "companyName": "Consolidated Holdings", + "address": "Berkeley Gardens, 12 Brewery ", + "city": "London", + "postalCode": "WX1 6LT", + "country": "UK", + "phone": "(171) 555-2282", + "fax": "(171) 555-9199", + "orders": [ + { + "orderId": 10435, + "orderDate": "1997-02-04T00:00:00", + "total": 631.60 + }, + { + "orderId": 10462, + "orderDate": "1997-03-03T00:00:00", + "total": 156.00 + }, + { + "orderId": 10848, + "orderDate": "1998-01-23T00:00:00", + "total": 931.50 + } + ] + }, + { + "customerId": "DRACD", + "companyName": "Drachenblut Delikatessen", + "address": "Walserweg 21", + "city": "Aachen", + "postalCode": "52066", + "country": "Germany", + "phone": "0241-039123", + "fax": "0241-059428", + "orders": [ + { + "orderId": 10363, + "orderDate": "1996-11-26T00:00:00", + "total": 447.20 + }, + { + "orderId": 10391, + "orderDate": "1996-12-23T00:00:00", + "total": 86.40 + }, + { + "orderId": 10797, + "orderDate": "1997-12-25T00:00:00", + "total": 420.00 + }, + { + "orderId": 10825, + "orderDate": "1998-01-09T00:00:00", + "total": 1030.76 + }, + { + "orderId": 11036, + "orderDate": "1998-04-20T00:00:00", + "total": 1692.00 + }, + { + "orderId": 11067, + "orderDate": "1998-05-04T00:00:00", + "total": 86.85 + } + ] + }, + { + "customerId": "DUMON", + "companyName": "Du monde entier", + "address": "67, rue des Cinquante Otages", + "city": "Nantes", + "postalCode": "44000", + "country": "France", + "phone": "40.67.88.88", + "fax": "40.67.89.89", + "orders": [ + { + "orderId": 10311, + "orderDate": "1996-09-20T00:00:00", + "total": 268.80 + }, + { + "orderId": 10609, + "orderDate": "1997-07-24T00:00:00", + "total": 424.00 + }, + { + "orderId": 10683, + "orderDate": "1997-09-26T00:00:00", + "total": 63.00 + }, + { + "orderId": 10890, + "orderDate": "1998-02-16T00:00:00", + "total": 860.10 + } + ] + }, + { + "customerId": "EASTC", + "companyName": "Eastern Connection", + "address": "35 King George", + "city": "London", + "postalCode": "WX3 6FW", + "country": "UK", + "phone": "(171) 555-0297", + "fax": "(171) 555-3373", + "orders": [ + { + "orderId": 10364, + "orderDate": "1996-11-26T00:00:00", + "total": 950.00 + }, + { + "orderId": 10400, + "orderDate": "1997-01-01T00:00:00", + "total": 3063.00 + }, + { + "orderId": 10532, + "orderDate": "1997-05-09T00:00:00", + "total": 796.35 + }, + { + "orderId": 10726, + "orderDate": "1997-11-03T00:00:00", + "total": 655.00 + }, + { + "orderId": 10987, + "orderDate": "1998-03-31T00:00:00", + "total": 2772.00 + }, + { + "orderId": 11024, + "orderDate": "1998-04-15T00:00:00", + "total": 1966.81 + }, + { + "orderId": 11047, + "orderDate": "1998-04-24T00:00:00", + "total": 817.88 + }, + { + "orderId": 11056, + "orderDate": "1998-04-28T00:00:00", + "total": 3740.00 + } + ] + }, + { + "customerId": "ERNSH", + "companyName": "Ernst Handel", + "address": "Kirchgasse 6", + "city": "Graz", + "postalCode": "8010", + "country": "Austria", + "phone": "7675-3425", + "fax": "7675-3426", + "orders": [ + { + "orderId": 10258, + "orderDate": "1996-07-17T00:00:00", + "total": 1614.88 + }, + { + "orderId": 10263, + "orderDate": "1996-07-23T00:00:00", + "total": 1873.80 + }, + { + "orderId": 10351, + "orderDate": "1996-11-11T00:00:00", + "total": 5398.72 + }, + { + "orderId": 10368, + "orderDate": "1996-11-29T00:00:00", + "total": 1689.78 + }, + { + "orderId": 10382, + "orderDate": "1996-12-13T00:00:00", + "total": 2900.00 + }, + { + "orderId": 10390, + "orderDate": "1996-12-23T00:00:00", + "total": 2090.88 + }, + { + "orderId": 10402, + "orderDate": "1997-01-02T00:00:00", + "total": 2713.50 + }, + { + "orderId": 10403, + "orderDate": "1997-01-03T00:00:00", + "total": 855.02 + }, + { + "orderId": 10430, + "orderDate": "1997-01-30T00:00:00", + "total": 4899.20 + }, + { + "orderId": 10442, + "orderDate": "1997-02-11T00:00:00", + "total": 1792.00 + }, + { + "orderId": 10514, + "orderDate": "1997-04-22T00:00:00", + "total": 8623.45 + }, + { + "orderId": 10571, + "orderDate": "1997-06-17T00:00:00", + "total": 550.59 + }, + { + "orderId": 10595, + "orderDate": "1997-07-10T00:00:00", + "total": 4725.00 + }, + { + "orderId": 10633, + "orderDate": "1997-08-15T00:00:00", + "total": 5510.59 + }, + { + "orderId": 10667, + "orderDate": "1997-09-12T00:00:00", + "total": 1536.80 + }, + { + "orderId": 10698, + "orderDate": "1997-10-09T00:00:00", + "total": 3436.44 + }, + { + "orderId": 10764, + "orderDate": "1997-12-03T00:00:00", + "total": 2286.00 + }, + { + "orderId": 10771, + "orderDate": "1997-12-10T00:00:00", + "total": 344.00 + }, + { + "orderId": 10773, + "orderDate": "1997-12-11T00:00:00", + "total": 2030.40 + }, + { + "orderId": 10776, + "orderDate": "1997-12-15T00:00:00", + "total": 6635.28 + }, + { + "orderId": 10795, + "orderDate": "1997-12-24T00:00:00", + "total": 2158.00 + }, + { + "orderId": 10836, + "orderDate": "1998-01-16T00:00:00", + "total": 4705.50 + }, + { + "orderId": 10854, + "orderDate": "1998-01-27T00:00:00", + "total": 2966.50 + }, + { + "orderId": 10895, + "orderDate": "1998-02-18T00:00:00", + "total": 6379.40 + }, + { + "orderId": 10968, + "orderDate": "1998-03-23T00:00:00", + "total": 1408.00 + }, + { + "orderId": 10979, + "orderDate": "1998-03-26T00:00:00", + "total": 4813.50 + }, + { + "orderId": 10990, + "orderDate": "1998-04-01T00:00:00", + "total": 4288.85 + }, + { + "orderId": 11008, + "orderDate": "1998-04-08T00:00:00", + "total": 4680.90 + }, + { + "orderId": 11017, + "orderDate": "1998-04-13T00:00:00", + "total": 6750.00 + }, + { + "orderId": 11072, + "orderDate": "1998-05-05T00:00:00", + "total": 5218.00 + } + ] + }, + { + "customerId": "FAMIA", + "companyName": "Familia Arquibaldo", + "address": "Rua Or\u00f3s, 92", + "city": "S\u00e3o Paulo", + "region": "SP", + "postalCode": "05442-030", + "country": "Brazil", + "phone": "(11) 555-9857", + "orders": [ + { + "orderId": 10347, + "orderDate": "1996-11-06T00:00:00", + "total": 814.42 + }, + { + "orderId": 10386, + "orderDate": "1996-12-18T00:00:00", + "total": 166.00 + }, + { + "orderId": 10414, + "orderDate": "1997-01-14T00:00:00", + "total": 224.83 + }, + { + "orderId": 10512, + "orderDate": "1997-04-21T00:00:00", + "total": 525.30 + }, + { + "orderId": 10581, + "orderDate": "1997-06-26T00:00:00", + "total": 310.00 + }, + { + "orderId": 10650, + "orderDate": "1997-08-29T00:00:00", + "total": 1779.20 + }, + { + "orderId": 10725, + "orderDate": "1997-10-31T00:00:00", + "total": 287.80 + } + ] + }, + { + "customerId": "FISSA", + "companyName": "FISSA Fabrica Inter. Salchichas S.A.", + "address": "C\/ Moralzarzal, 86", + "city": "Madrid", + "postalCode": "28034", + "country": "Spain", + "phone": "(91) 555 94 44", + "fax": "(91) 555 55 93" + }, + { + "customerId": "FOLIG", + "companyName": "Folies gourmandes", + "address": "184, chauss\u00e9e de Tournai", + "city": "Lille", + "postalCode": "59000", + "country": "France", + "phone": "20.16.10.16", + "fax": "20.16.10.17", + "orders": [ + { + "orderId": 10408, + "orderDate": "1997-01-08T00:00:00", + "total": 1622.40 + }, + { + "orderId": 10480, + "orderDate": "1997-03-20T00:00:00", + "total": 756.00 + }, + { + "orderId": 10634, + "orderDate": "1997-08-15T00:00:00", + "total": 4985.50 + }, + { + "orderId": 10763, + "orderDate": "1997-12-03T00:00:00", + "total": 616.00 + }, + { + "orderId": 10789, + "orderDate": "1997-12-22T00:00:00", + "total": 3687.00 + } + ] + }, + { + "customerId": "FOLKO", + "companyName": "Folk och f\u00e4 HB", + "address": "\u00c5kergatan 24", + "city": "Br\u00e4cke", + "postalCode": "S-844 67", + "country": "Sweden", + "phone": "0695-34 67 21", + "orders": [ + { + "orderId": 10264, + "orderDate": "1996-07-24T00:00:00", + "total": 695.62 + }, + { + "orderId": 10327, + "orderDate": "1996-10-11T00:00:00", + "total": 1810.00 + }, + { + "orderId": 10378, + "orderDate": "1996-12-10T00:00:00", + "total": 103.20 + }, + { + "orderId": 10434, + "orderDate": "1997-02-03T00:00:00", + "total": 321.12 + }, + { + "orderId": 10460, + "orderDate": "1997-02-28T00:00:00", + "total": 176.10 + }, + { + "orderId": 10533, + "orderDate": "1997-05-12T00:00:00", + "total": 2222.20 + }, + { + "orderId": 10561, + "orderDate": "1997-06-06T00:00:00", + "total": 2844.50 + }, + { + "orderId": 10703, + "orderDate": "1997-10-14T00:00:00", + "total": 2545.00 + }, + { + "orderId": 10762, + "orderDate": "1997-12-02T00:00:00", + "total": 4337.00 + }, + { + "orderId": 10774, + "orderDate": "1997-12-11T00:00:00", + "total": 868.75 + }, + { + "orderId": 10824, + "orderDate": "1998-01-09T00:00:00", + "total": 250.80 + }, + { + "orderId": 10880, + "orderDate": "1998-02-10T00:00:00", + "total": 1500.00 + }, + { + "orderId": 10902, + "orderDate": "1998-02-23T00:00:00", + "total": 863.43 + }, + { + "orderId": 10955, + "orderDate": "1998-03-17T00:00:00", + "total": 74.40 + }, + { + "orderId": 10977, + "orderDate": "1998-03-26T00:00:00", + "total": 2233.00 + }, + { + "orderId": 10980, + "orderDate": "1998-03-27T00:00:00", + "total": 248.00 + }, + { + "orderId": 10993, + "orderDate": "1998-04-01T00:00:00", + "total": 4895.44 + }, + { + "orderId": 11001, + "orderDate": "1998-04-06T00:00:00", + "total": 2769.00 + }, + { + "orderId": 11050, + "orderDate": "1998-04-27T00:00:00", + "total": 810.00 + } + ] + }, + { + "customerId": "FRANK", + "companyName": "Frankenversand", + "address": "Berliner Platz 43", + "city": "M\u00fcnchen", + "postalCode": "80805", + "country": "Germany", + "phone": "089-0877310", + "fax": "089-0877451", + "orders": [ + { + "orderId": 10267, + "orderDate": "1996-07-29T00:00:00", + "total": 3536.60 + }, + { + "orderId": 10337, + "orderDate": "1996-10-24T00:00:00", + "total": 2467.00 + }, + { + "orderId": 10342, + "orderDate": "1996-10-30T00:00:00", + "total": 1840.64 + }, + { + "orderId": 10396, + "orderDate": "1996-12-27T00:00:00", + "total": 1903.80 + }, + { + "orderId": 10488, + "orderDate": "1997-03-27T00:00:00", + "total": 1512.00 + }, + { + "orderId": 10560, + "orderDate": "1997-06-06T00:00:00", + "total": 1072.42 + }, + { + "orderId": 10623, + "orderDate": "1997-08-07T00:00:00", + "total": 1336.95 + }, + { + "orderId": 10653, + "orderDate": "1997-09-02T00:00:00", + "total": 1083.15 + }, + { + "orderId": 10670, + "orderDate": "1997-09-16T00:00:00", + "total": 2301.75 + }, + { + "orderId": 10675, + "orderDate": "1997-09-19T00:00:00", + "total": 1423.00 + }, + { + "orderId": 10717, + "orderDate": "1997-10-24T00:00:00", + "total": 1270.75 + }, + { + "orderId": 10791, + "orderDate": "1997-12-23T00:00:00", + "total": 1829.76 + }, + { + "orderId": 10859, + "orderDate": "1998-01-29T00:00:00", + "total": 1078.69 + }, + { + "orderId": 10929, + "orderDate": "1998-03-05T00:00:00", + "total": 1174.75 + }, + { + "orderId": 11012, + "orderDate": "1998-04-09T00:00:00", + "total": 2825.30 + } + ] + }, + { + "customerId": "FRANR", + "companyName": "France restauration", + "address": "54, rue Royale", + "city": "Nantes", + "postalCode": "44000", + "country": "France", + "phone": "40.32.21.21", + "fax": "40.32.21.20", + "orders": [ + { + "orderId": 10671, + "orderDate": "1997-09-17T00:00:00", + "total": 920.10 + }, + { + "orderId": 10860, + "orderDate": "1998-01-29T00:00:00", + "total": 519.00 + }, + { + "orderId": 10971, + "orderDate": "1998-03-24T00:00:00", + "total": 1733.06 + } + ] + }, + { + "customerId": "FRANS", + "companyName": "Franchi S.p.A.", + "address": "Via Monte Bianco 34", + "city": "Torino", + "postalCode": "10100", + "country": "Italy", + "phone": "011-4988260", + "fax": "011-4988261", + "orders": [ + { + "orderId": 10422, + "orderDate": "1997-01-22T00:00:00", + "total": 49.80 + }, + { + "orderId": 10710, + "orderDate": "1997-10-20T00:00:00", + "total": 93.50 + }, + { + "orderId": 10753, + "orderDate": "1997-11-25T00:00:00", + "total": 88.00 + }, + { + "orderId": 10807, + "orderDate": "1997-12-31T00:00:00", + "total": 18.40 + }, + { + "orderId": 11026, + "orderDate": "1998-04-15T00:00:00", + "total": 1030.00 + }, + { + "orderId": 11060, + "orderDate": "1998-04-30T00:00:00", + "total": 266.00 + } + ] + }, + { + "customerId": "FURIB", + "companyName": "Furia Bacalhau e Frutos do Mar", + "address": "Jardim das rosas n. 32", + "city": "Lisboa", + "postalCode": "1675", + "country": "Portugal", + "phone": "(1) 354-2534", + "fax": "(1) 354-2535", + "orders": [ + { + "orderId": 10328, + "orderDate": "1996-10-14T00:00:00", + "total": 1168.00 + }, + { + "orderId": 10352, + "orderDate": "1996-11-12T00:00:00", + "total": 136.30 + }, + { + "orderId": 10464, + "orderDate": "1997-03-04T00:00:00", + "total": 1609.28 + }, + { + "orderId": 10491, + "orderDate": "1997-03-31T00:00:00", + "total": 259.50 + }, + { + "orderId": 10551, + "orderDate": "1997-05-28T00:00:00", + "total": 1677.30 + }, + { + "orderId": 10604, + "orderDate": "1997-07-18T00:00:00", + "total": 230.85 + }, + { + "orderId": 10664, + "orderDate": "1997-09-10T00:00:00", + "total": 1288.39 + }, + { + "orderId": 10963, + "orderDate": "1998-03-19T00:00:00", + "total": 57.80 + } + ] + }, + { + "customerId": "GALED", + "companyName": "Galer\u00eda del gastr\u00f3nomo", + "address": "Rambla de Catalu\u00f1a, 23", + "city": "Barcelona", + "postalCode": "08022", + "country": "Spain", + "phone": "(93) 203 4560", + "fax": "(93) 203 4561", + "orders": [ + { + "orderId": 10366, + "orderDate": "1996-11-28T00:00:00", + "total": 136.00 + }, + { + "orderId": 10426, + "orderDate": "1997-01-27T00:00:00", + "total": 338.20 + }, + { + "orderId": 10568, + "orderDate": "1997-06-13T00:00:00", + "total": 155.00 + }, + { + "orderId": 10887, + "orderDate": "1998-02-13T00:00:00", + "total": 70.00 + }, + { + "orderId": 10928, + "orderDate": "1998-03-05T00:00:00", + "total": 137.50 + } + ] + }, + { + "customerId": "GODOS", + "companyName": "Godos Cocina T\u00edpica", + "address": "C\/ Romero, 33", + "city": "Sevilla", + "postalCode": "41101", + "country": "Spain", + "phone": "(95) 555 82 82", + "orders": [ + { + "orderId": 10303, + "orderDate": "1996-09-11T00:00:00", + "total": 1117.80 + }, + { + "orderId": 10550, + "orderDate": "1997-05-28T00:00:00", + "total": 683.30 + }, + { + "orderId": 10629, + "orderDate": "1997-08-12T00:00:00", + "total": 2775.05 + }, + { + "orderId": 10872, + "orderDate": "1998-02-05T00:00:00", + "total": 2058.46 + }, + { + "orderId": 10874, + "orderDate": "1998-02-06T00:00:00", + "total": 310.00 + }, + { + "orderId": 10888, + "orderDate": "1998-02-16T00:00:00", + "total": 605.00 + }, + { + "orderId": 10911, + "orderDate": "1998-02-26T00:00:00", + "total": 858.00 + }, + { + "orderId": 10948, + "orderDate": "1998-03-13T00:00:00", + "total": 2362.25 + }, + { + "orderId": 11009, + "orderDate": "1998-04-08T00:00:00", + "total": 616.50 + }, + { + "orderId": 11037, + "orderDate": "1998-04-21T00:00:00", + "total": 60.00 + } + ] + }, + { + "customerId": "GOURL", + "companyName": "Gourmet Lanchonetes", + "address": "Av. Brasil, 442", + "city": "Campinas", + "region": "SP", + "postalCode": "04876-786", + "country": "Brazil", + "phone": "(11) 555-9482", + "orders": [ + { + "orderId": 10423, + "orderDate": "1997-01-23T00:00:00", + "total": 1020.00 + }, + { + "orderId": 10652, + "orderDate": "1997-09-01T00:00:00", + "total": 318.84 + }, + { + "orderId": 10685, + "orderDate": "1997-09-29T00:00:00", + "total": 801.10 + }, + { + "orderId": 10709, + "orderDate": "1997-10-17T00:00:00", + "total": 3424.00 + }, + { + "orderId": 10734, + "orderDate": "1997-11-07T00:00:00", + "total": 1498.35 + }, + { + "orderId": 10777, + "orderDate": "1997-12-15T00:00:00", + "total": 224.00 + }, + { + "orderId": 10790, + "orderDate": "1997-12-22T00:00:00", + "total": 722.50 + }, + { + "orderId": 10959, + "orderDate": "1998-03-18T00:00:00", + "total": 131.75 + }, + { + "orderId": 11049, + "orderDate": "1998-04-24T00:00:00", + "total": 273.60 + } + ] + }, + { + "customerId": "GREAL", + "companyName": "Great Lakes Food Market", + "address": "2732 Baker Blvd.", + "city": "Eugene", + "region": "OR", + "postalCode": "97403", + "country": "USA", + "phone": "(503) 555-7555", + "orders": [ + { + "orderId": 10528, + "orderDate": "1997-05-06T00:00:00", + "total": 392.20 + }, + { + "orderId": 10589, + "orderDate": "1997-07-04T00:00:00", + "total": 72.00 + }, + { + "orderId": 10616, + "orderDate": "1997-07-31T00:00:00", + "total": 4807.00 + }, + { + "orderId": 10617, + "orderDate": "1997-07-31T00:00:00", + "total": 1402.50 + }, + { + "orderId": 10656, + "orderDate": "1997-09-04T00:00:00", + "total": 604.22 + }, + { + "orderId": 10681, + "orderDate": "1997-09-25T00:00:00", + "total": 1287.40 + }, + { + "orderId": 10816, + "orderDate": "1998-01-06T00:00:00", + "total": 8446.45 + }, + { + "orderId": 10936, + "orderDate": "1998-03-09T00:00:00", + "total": 456.00 + }, + { + "orderId": 11006, + "orderDate": "1998-04-07T00:00:00", + "total": 329.68 + }, + { + "orderId": 11040, + "orderDate": "1998-04-22T00:00:00", + "total": 200.00 + }, + { + "orderId": 11061, + "orderDate": "1998-04-30T00:00:00", + "total": 510.00 + } + ] + }, + { + "customerId": "GROSR", + "companyName": "GROSELLA-Restaurante", + "address": "5\u00aa Ave. Los Palos Grandes", + "city": "Caracas", + "region": "DF", + "postalCode": "1081", + "country": "Venezuela", + "phone": "(2) 283-2951", + "fax": "(2) 283-3397", + "orders": [ + { + "orderId": 10268, + "orderDate": "1996-07-30T00:00:00", + "total": 1101.20 + }, + { + "orderId": 10785, + "orderDate": "1997-12-18T00:00:00", + "total": 387.50 + } + ] + }, + { + "customerId": "HANAR", + "companyName": "Hanari Carnes", + "address": "Rua do Pa\u00e7o, 67", + "city": "Rio de Janeiro", + "region": "RJ", + "postalCode": "05454-876", + "country": "Brazil", + "phone": "(21) 555-0091", + "fax": "(21) 555-8765", + "orders": [ + { + "orderId": 10250, + "orderDate": "1996-07-08T00:00:00", + "total": 1552.60 + }, + { + "orderId": 10253, + "orderDate": "1996-07-10T00:00:00", + "total": 1444.80 + }, + { + "orderId": 10541, + "orderDate": "1997-05-19T00:00:00", + "total": 1946.52 + }, + { + "orderId": 10645, + "orderDate": "1997-08-26T00:00:00", + "total": 1535.00 + }, + { + "orderId": 10690, + "orderDate": "1997-10-02T00:00:00", + "total": 862.50 + }, + { + "orderId": 10770, + "orderDate": "1997-12-09T00:00:00", + "total": 236.25 + }, + { + "orderId": 10783, + "orderDate": "1997-12-18T00:00:00", + "total": 1442.50 + }, + { + "orderId": 10886, + "orderDate": "1998-02-13T00:00:00", + "total": 3127.50 + }, + { + "orderId": 10903, + "orderDate": "1998-02-24T00:00:00", + "total": 932.05 + }, + { + "orderId": 10922, + "orderDate": "1998-03-03T00:00:00", + "total": 742.50 + }, + { + "orderId": 10925, + "orderDate": "1998-03-04T00:00:00", + "total": 475.15 + }, + { + "orderId": 10981, + "orderDate": "1998-03-27T00:00:00", + "total": 15810.00 + }, + { + "orderId": 11022, + "orderDate": "1998-04-14T00:00:00", + "total": 1402.00 + }, + { + "orderId": 11052, + "orderDate": "1998-04-27T00:00:00", + "total": 1332.00 + } + ] + }, + { + "customerId": "HILAA", + "companyName": "HILARI\u00d3N-Abastos", + "address": "Carrera 22 con Ave. Carlos Soublette #8-35", + "city": "San Crist\u00f3bal", + "region": "T\u00e1chira", + "postalCode": "5022", + "country": "Venezuela", + "phone": "(5) 555-1340", + "fax": "(5) 555-1948", + "orders": [ + { + "orderId": 10257, + "orderDate": "1996-07-16T00:00:00", + "total": 1119.90 + }, + { + "orderId": 10395, + "orderDate": "1996-12-26T00:00:00", + "total": 2122.92 + }, + { + "orderId": 10476, + "orderDate": "1997-03-17T00:00:00", + "total": 180.48 + }, + { + "orderId": 10486, + "orderDate": "1997-03-26T00:00:00", + "total": 1272.00 + }, + { + "orderId": 10490, + "orderDate": "1997-03-31T00:00:00", + "total": 3163.20 + }, + { + "orderId": 10498, + "orderDate": "1997-04-07T00:00:00", + "total": 575.00 + }, + { + "orderId": 10552, + "orderDate": "1997-05-29T00:00:00", + "total": 880.50 + }, + { + "orderId": 10601, + "orderDate": "1997-07-16T00:00:00", + "total": 2285.00 + }, + { + "orderId": 10613, + "orderDate": "1997-07-29T00:00:00", + "total": 353.20 + }, + { + "orderId": 10641, + "orderDate": "1997-08-22T00:00:00", + "total": 2054.00 + }, + { + "orderId": 10705, + "orderDate": "1997-10-15T00:00:00", + "total": 378.00 + }, + { + "orderId": 10796, + "orderDate": "1997-12-25T00:00:00", + "total": 2341.36 + }, + { + "orderId": 10863, + "orderDate": "1998-02-02T00:00:00", + "total": 441.15 + }, + { + "orderId": 10901, + "orderDate": "1998-02-23T00:00:00", + "total": 934.50 + }, + { + "orderId": 10957, + "orderDate": "1998-03-18T00:00:00", + "total": 1762.70 + }, + { + "orderId": 10960, + "orderDate": "1998-03-19T00:00:00", + "total": 265.35 + }, + { + "orderId": 10976, + "orderDate": "1998-03-25T00:00:00", + "total": 912.00 + }, + { + "orderId": 11055, + "orderDate": "1998-04-28T00:00:00", + "total": 1727.50 + } + ] + }, + { + "customerId": "HUNGC", + "companyName": "Hungry Coyote Import Store", + "address": "City Center Plaza, 516 Main St.", + "city": "Elgin", + "region": "OR", + "postalCode": "97827", + "country": "USA", + "phone": "(503) 555-6874", + "fax": "(503) 555-2376", + "orders": [ + { + "orderId": 10375, + "orderDate": "1996-12-06T00:00:00", + "total": 338.00 + }, + { + "orderId": 10394, + "orderDate": "1996-12-25T00:00:00", + "total": 442.00 + }, + { + "orderId": 10415, + "orderDate": "1997-01-15T00:00:00", + "total": 102.40 + }, + { + "orderId": 10600, + "orderDate": "1997-07-16T00:00:00", + "total": 479.80 + }, + { + "orderId": 10660, + "orderDate": "1997-09-08T00:00:00", + "total": 1701.00 + } + ] + }, + { + "customerId": "HUNGO", + "companyName": "Hungry Owl All-Night Grocers", + "address": "8 Johnstown Road", + "city": "Cork", + "region": "Co. Cork", + "country": "Ireland", + "phone": "2967 542", + "fax": "2967 3333", + "orders": [ + { + "orderId": 10298, + "orderDate": "1996-09-05T00:00:00", + "total": 2645.00 + }, + { + "orderId": 10309, + "orderDate": "1996-09-19T00:00:00", + "total": 1762.00 + }, + { + "orderId": 10335, + "orderDate": "1996-10-22T00:00:00", + "total": 2036.16 + }, + { + "orderId": 10373, + "orderDate": "1996-12-05T00:00:00", + "total": 1366.40 + }, + { + "orderId": 10380, + "orderDate": "1996-12-12T00:00:00", + "total": 1313.82 + }, + { + "orderId": 10429, + "orderDate": "1997-01-29T00:00:00", + "total": 1441.38 + }, + { + "orderId": 10503, + "orderDate": "1997-04-11T00:00:00", + "total": 2048.50 + }, + { + "orderId": 10516, + "orderDate": "1997-04-24T00:00:00", + "total": 2381.05 + }, + { + "orderId": 10567, + "orderDate": "1997-06-12T00:00:00", + "total": 2519.00 + }, + { + "orderId": 10646, + "orderDate": "1997-08-27T00:00:00", + "total": 1446.00 + }, + { + "orderId": 10661, + "orderDate": "1997-09-09T00:00:00", + "total": 562.60 + }, + { + "orderId": 10687, + "orderDate": "1997-09-30T00:00:00", + "total": 4960.90 + }, + { + "orderId": 10701, + "orderDate": "1997-10-13T00:00:00", + "total": 2864.50 + }, + { + "orderId": 10712, + "orderDate": "1997-10-21T00:00:00", + "total": 1233.48 + }, + { + "orderId": 10736, + "orderDate": "1997-11-11T00:00:00", + "total": 997.00 + }, + { + "orderId": 10897, + "orderDate": "1998-02-19T00:00:00", + "total": 10835.24 + }, + { + "orderId": 10912, + "orderDate": "1998-02-26T00:00:00", + "total": 6200.55 + }, + { + "orderId": 10985, + "orderDate": "1998-03-30T00:00:00", + "total": 2023.38 + }, + { + "orderId": 11063, + "orderDate": "1998-04-30T00:00:00", + "total": 1342.95 + } + ] + }, + { + "customerId": "ISLAT", + "companyName": "Island Trading", + "address": "Garden House, Crowther Way", + "city": "Cowes", + "region": "Isle of Wight", + "postalCode": "PO31 7PJ", + "country": "UK", + "phone": "(198) 555-8888", + "orders": [ + { + "orderId": 10315, + "orderDate": "1996-09-26T00:00:00", + "total": 516.80 + }, + { + "orderId": 10318, + "orderDate": "1996-10-01T00:00:00", + "total": 240.40 + }, + { + "orderId": 10321, + "orderDate": "1996-10-03T00:00:00", + "total": 144.00 + }, + { + "orderId": 10473, + "orderDate": "1997-03-13T00:00:00", + "total": 230.40 + }, + { + "orderId": 10621, + "orderDate": "1997-08-05T00:00:00", + "total": 758.50 + }, + { + "orderId": 10674, + "orderDate": "1997-09-18T00:00:00", + "total": 45.00 + }, + { + "orderId": 10749, + "orderDate": "1997-11-20T00:00:00", + "total": 1080.00 + }, + { + "orderId": 10798, + "orderDate": "1997-12-26T00:00:00", + "total": 446.60 + }, + { + "orderId": 10829, + "orderDate": "1998-01-13T00:00:00", + "total": 1764.00 + }, + { + "orderId": 10933, + "orderDate": "1998-03-06T00:00:00", + "total": 920.60 + } + ] + }, + { + "customerId": "KOENE", + "companyName": "K\u00f6niglich Essen", + "address": "Maubelstr. 90", + "city": "Brandenburg", + "postalCode": "14776", + "country": "Germany", + "phone": "0555-09876", + "orders": [ + { + "orderId": 10323, + "orderDate": "1996-10-07T00:00:00", + "total": 164.40 + }, + { + "orderId": 10325, + "orderDate": "1996-10-09T00:00:00", + "total": 1497.00 + }, + { + "orderId": 10456, + "orderDate": "1997-02-25T00:00:00", + "total": 557.60 + }, + { + "orderId": 10457, + "orderDate": "1997-02-25T00:00:00", + "total": 1584.00 + }, + { + "orderId": 10468, + "orderDate": "1997-03-07T00:00:00", + "total": 717.60 + }, + { + "orderId": 10506, + "orderDate": "1997-04-15T00:00:00", + "total": 415.80 + }, + { + "orderId": 10542, + "orderDate": "1997-05-20T00:00:00", + "total": 469.11 + }, + { + "orderId": 10630, + "orderDate": "1997-08-13T00:00:00", + "total": 903.60 + }, + { + "orderId": 10718, + "orderDate": "1997-10-27T00:00:00", + "total": 3463.00 + }, + { + "orderId": 10799, + "orderDate": "1997-12-26T00:00:00", + "total": 1553.50 + }, + { + "orderId": 10817, + "orderDate": "1998-01-06T00:00:00", + "total": 10952.84 + }, + { + "orderId": 10849, + "orderDate": "1998-01-23T00:00:00", + "total": 967.82 + }, + { + "orderId": 10893, + "orderDate": "1998-02-18T00:00:00", + "total": 5502.11 + }, + { + "orderId": 11028, + "orderDate": "1998-04-16T00:00:00", + "total": 2160.00 + } + ] + }, + { + "customerId": "LACOR", + "companyName": "La corne d'abondance", + "address": "67, avenue de l'Europe", + "city": "Versailles", + "postalCode": "78000", + "country": "France", + "phone": "30.59.84.10", + "fax": "30.59.85.11", + "orders": [ + { + "orderId": 10858, + "orderDate": "1998-01-29T00:00:00", + "total": 649.00 + }, + { + "orderId": 10927, + "orderDate": "1998-03-05T00:00:00", + "total": 800.00 + }, + { + "orderId": 10972, + "orderDate": "1998-03-24T00:00:00", + "total": 251.50 + }, + { + "orderId": 10973, + "orderDate": "1998-03-24T00:00:00", + "total": 291.55 + } + ] + }, + { + "customerId": "LAMAI", + "companyName": "La maison d'Asie", + "address": "1 rue Alsace-Lorraine", + "city": "Toulouse", + "postalCode": "31000", + "country": "France", + "phone": "61.77.61.10", + "fax": "61.77.61.11", + "orders": [ + { + "orderId": 10350, + "orderDate": "1996-11-11T00:00:00", + "total": 642.06 + }, + { + "orderId": 10358, + "orderDate": "1996-11-20T00:00:00", + "total": 429.40 + }, + { + "orderId": 10371, + "orderDate": "1996-12-03T00:00:00", + "total": 72.96 + }, + { + "orderId": 10413, + "orderDate": "1997-01-14T00:00:00", + "total": 2123.20 + }, + { + "orderId": 10425, + "orderDate": "1997-01-24T00:00:00", + "total": 360.00 + }, + { + "orderId": 10454, + "orderDate": "1997-02-21T00:00:00", + "total": 331.20 + }, + { + "orderId": 10493, + "orderDate": "1997-04-02T00:00:00", + "total": 608.40 + }, + { + "orderId": 10500, + "orderDate": "1997-04-09T00:00:00", + "total": 523.26 + }, + { + "orderId": 10610, + "orderDate": "1997-07-25T00:00:00", + "total": 299.25 + }, + { + "orderId": 10631, + "orderDate": "1997-08-14T00:00:00", + "total": 55.80 + }, + { + "orderId": 10787, + "orderDate": "1997-12-19T00:00:00", + "total": 2622.76 + }, + { + "orderId": 10832, + "orderDate": "1998-01-14T00:00:00", + "total": 475.11 + }, + { + "orderId": 10923, + "orderDate": "1998-03-03T00:00:00", + "total": 748.80 + }, + { + "orderId": 11051, + "orderDate": "1998-04-27T00:00:00", + "total": 36.00 + } + ] + }, + { + "customerId": "LAUGB", + "companyName": "Laughing Bacchus Wine Cellars", + "address": "1900 Oak St.", + "city": "Vancouver", + "region": "BC", + "postalCode": "V3F 2K1", + "country": "Canada", + "phone": "(604) 555-3392", + "fax": "(604) 555-7293", + "orders": [ + { + "orderId": 10495, + "orderDate": "1997-04-03T00:00:00", + "total": 278.00 + }, + { + "orderId": 10620, + "orderDate": "1997-08-05T00:00:00", + "total": 57.50 + }, + { + "orderId": 10810, + "orderDate": "1998-01-01T00:00:00", + "total": 187.00 + } + ] + }, + { + "customerId": "LAZYK", + "companyName": "Lazy K Kountry Store", + "address": "12 Orchestra Terrace", + "city": "Walla Walla", + "region": "WA", + "postalCode": "99362", + "country": "USA", + "phone": "(509) 555-7969", + "fax": "(509) 555-6221", + "orders": [ + { + "orderId": 10482, + "orderDate": "1997-03-21T00:00:00", + "total": 147.00 + }, + { + "orderId": 10545, + "orderDate": "1997-05-22T00:00:00", + "total": 210.00 + } + ] + }, + { + "customerId": "LEHMS", + "companyName": "Lehmanns Marktstand", + "address": "Magazinweg 7", + "city": "Frankfurt a.M. ", + "postalCode": "60528", + "country": "Germany", + "phone": "069-0245984", + "fax": "069-0245874", + "orders": [ + { + "orderId": 10279, + "orderDate": "1996-08-13T00:00:00", + "total": 351.00 + }, + { + "orderId": 10284, + "orderDate": "1996-08-19T00:00:00", + "total": 1170.38 + }, + { + "orderId": 10343, + "orderDate": "1996-10-31T00:00:00", + "total": 1584.00 + }, + { + "orderId": 10497, + "orderDate": "1997-04-04T00:00:00", + "total": 1380.60 + }, + { + "orderId": 10522, + "orderDate": "1997-04-30T00:00:00", + "total": 2318.24 + }, + { + "orderId": 10534, + "orderDate": "1997-05-12T00:00:00", + "total": 465.70 + }, + { + "orderId": 10536, + "orderDate": "1997-05-14T00:00:00", + "total": 1645.00 + }, + { + "orderId": 10557, + "orderDate": "1997-06-03T00:00:00", + "total": 1152.50 + }, + { + "orderId": 10592, + "orderDate": "1997-07-08T00:00:00", + "total": 516.47 + }, + { + "orderId": 10593, + "orderDate": "1997-07-09T00:00:00", + "total": 1994.40 + }, + { + "orderId": 10772, + "orderDate": "1997-12-10T00:00:00", + "total": 3603.22 + }, + { + "orderId": 10862, + "orderDate": "1998-01-30T00:00:00", + "total": 581.00 + }, + { + "orderId": 10891, + "orderDate": "1998-02-17T00:00:00", + "total": 368.93 + }, + { + "orderId": 10934, + "orderDate": "1998-03-09T00:00:00", + "total": 500.00 + }, + { + "orderId": 11070, + "orderDate": "1998-05-05T00:00:00", + "total": 1629.98 + } + ] + }, + { + "customerId": "LETSS", + "companyName": "Let's Stop N Shop", + "address": "87 Polk St. Suite 5", + "city": "San Francisco", + "region": "CA", + "postalCode": "94117", + "country": "USA", + "phone": "(415) 555-5938", + "orders": [ + { + "orderId": 10579, + "orderDate": "1997-06-25T00:00:00", + "total": 317.75 + }, + { + "orderId": 10719, + "orderDate": "1997-10-27T00:00:00", + "total": 844.25 + }, + { + "orderId": 10735, + "orderDate": "1997-11-10T00:00:00", + "total": 536.40 + }, + { + "orderId": 10884, + "orderDate": "1998-02-12T00:00:00", + "total": 1378.07 + } + ] + }, + { + "customerId": "LILAS", + "companyName": "LILA-Supermercado", + "address": "Carrera 52 con Ave. Bol\u00edvar #65-98 Llano Largo", + "city": "Barquisimeto", + "region": "Lara", + "postalCode": "3508", + "country": "Venezuela", + "phone": "(9) 331-6954", + "fax": "(9) 331-7256", + "orders": [ + { + "orderId": 10283, + "orderDate": "1996-08-16T00:00:00", + "total": 1414.80 + }, + { + "orderId": 10296, + "orderDate": "1996-09-03T00:00:00", + "total": 1050.60 + }, + { + "orderId": 10330, + "orderDate": "1996-10-16T00:00:00", + "total": 1649.00 + }, + { + "orderId": 10357, + "orderDate": "1996-11-19T00:00:00", + "total": 1167.68 + }, + { + "orderId": 10381, + "orderDate": "1996-12-12T00:00:00", + "total": 112.00 + }, + { + "orderId": 10461, + "orderDate": "1997-02-28T00:00:00", + "total": 1538.70 + }, + { + "orderId": 10499, + "orderDate": "1997-04-08T00:00:00", + "total": 1412.00 + }, + { + "orderId": 10543, + "orderDate": "1997-05-21T00:00:00", + "total": 1504.50 + }, + { + "orderId": 10780, + "orderDate": "1997-12-16T00:00:00", + "total": 720.00 + }, + { + "orderId": 10823, + "orderDate": "1998-01-09T00:00:00", + "total": 2826.00 + }, + { + "orderId": 10899, + "orderDate": "1998-02-20T00:00:00", + "total": 122.40 + }, + { + "orderId": 10997, + "orderDate": "1998-04-03T00:00:00", + "total": 1885.00 + }, + { + "orderId": 11065, + "orderDate": "1998-05-01T00:00:00", + "total": 189.42 + }, + { + "orderId": 11071, + "orderDate": "1998-05-05T00:00:00", + "total": 484.50 + } + ] + }, + { + "customerId": "LINOD", + "companyName": "LINO-Delicateses", + "address": "Ave. 5 de Mayo Porlamar", + "city": "I. de Margarita", + "region": "Nueva Esparta", + "postalCode": "4980", + "country": "Venezuela", + "phone": "(8) 34-56-12", + "fax": "(8) 34-93-93", + "orders": [ + { + "orderId": 10405, + "orderDate": "1997-01-06T00:00:00", + "total": 400.00 + }, + { + "orderId": 10485, + "orderDate": "1997-03-25T00:00:00", + "total": 1584.00 + }, + { + "orderId": 10638, + "orderDate": "1997-08-20T00:00:00", + "total": 2720.05 + }, + { + "orderId": 10697, + "orderDate": "1997-10-08T00:00:00", + "total": 805.42 + }, + { + "orderId": 10729, + "orderDate": "1997-11-04T00:00:00", + "total": 1850.00 + }, + { + "orderId": 10811, + "orderDate": "1998-01-02T00:00:00", + "total": 852.00 + }, + { + "orderId": 10838, + "orderDate": "1998-01-19T00:00:00", + "total": 1938.38 + }, + { + "orderId": 10840, + "orderDate": "1998-01-19T00:00:00", + "total": 211.20 + }, + { + "orderId": 10919, + "orderDate": "1998-03-02T00:00:00", + "total": 1122.80 + }, + { + "orderId": 10954, + "orderDate": "1998-03-17T00:00:00", + "total": 1659.54 + }, + { + "orderId": 11014, + "orderDate": "1998-04-10T00:00:00", + "total": 243.18 + }, + { + "orderId": 11039, + "orderDate": "1998-04-21T00:00:00", + "total": 3090.00 + } + ] + }, + { + "customerId": "LONEP", + "companyName": "Lonesome Pine Restaurant", + "address": "89 Chiaroscuro Rd.", + "city": "Portland", + "region": "OR", + "postalCode": "97219", + "country": "USA", + "phone": "(503) 555-9573", + "fax": "(503) 555-9646", + "orders": [ + { + "orderId": 10307, + "orderDate": "1996-09-17T00:00:00", + "total": 424.00 + }, + { + "orderId": 10317, + "orderDate": "1996-09-30T00:00:00", + "total": 288.00 + }, + { + "orderId": 10544, + "orderDate": "1997-05-21T00:00:00", + "total": 417.20 + }, + { + "orderId": 10662, + "orderDate": "1997-09-09T00:00:00", + "total": 125.00 + }, + { + "orderId": 10665, + "orderDate": "1997-09-11T00:00:00", + "total": 1295.00 + }, + { + "orderId": 10867, + "orderDate": "1998-02-03T00:00:00", + "total": 98.40 + }, + { + "orderId": 10883, + "orderDate": "1998-02-12T00:00:00", + "total": 36.00 + }, + { + "orderId": 11018, + "orderDate": "1998-04-13T00:00:00", + "total": 1575.00 + } + ] + }, + { + "customerId": "MAGAA", + "companyName": "Magazzini Alimentari Riuniti", + "address": "Via Ludovico il Moro 22", + "city": "Bergamo", + "postalCode": "24100", + "country": "Italy", + "phone": "035-640230", + "fax": "035-640231", + "orders": [ + { + "orderId": 10275, + "orderDate": "1996-08-07T00:00:00", + "total": 291.84 + }, + { + "orderId": 10300, + "orderDate": "1996-09-09T00:00:00", + "total": 608.00 + }, + { + "orderId": 10404, + "orderDate": "1997-01-03T00:00:00", + "total": 1591.25 + }, + { + "orderId": 10467, + "orderDate": "1997-03-06T00:00:00", + "total": 235.20 + }, + { + "orderId": 10635, + "orderDate": "1997-08-18T00:00:00", + "total": 1326.22 + }, + { + "orderId": 10754, + "orderDate": "1997-11-25T00:00:00", + "total": 55.20 + }, + { + "orderId": 10784, + "orderDate": "1997-12-18T00:00:00", + "total": 1488.00 + }, + { + "orderId": 10818, + "orderDate": "1998-01-07T00:00:00", + "total": 833.00 + }, + { + "orderId": 10939, + "orderDate": "1998-03-10T00:00:00", + "total": 637.50 + }, + { + "orderId": 10950, + "orderDate": "1998-03-16T00:00:00", + "total": 110.00 + } + ] + }, + { + "customerId": "MAISD", + "companyName": "Maison Dewey", + "address": "Rue Joseph-Bens 532", + "city": "Bruxelles", + "postalCode": "B-1180", + "country": "Belgium", + "phone": "(02) 201 24 67", + "fax": "(02) 201 24 68", + "orders": [ + { + "orderId": 10529, + "orderDate": "1997-05-07T00:00:00", + "total": 946.00 + }, + { + "orderId": 10649, + "orderDate": "1997-08-28T00:00:00", + "total": 1434.00 + }, + { + "orderId": 10760, + "orderDate": "1997-12-01T00:00:00", + "total": 2917.00 + }, + { + "orderId": 10892, + "orderDate": "1998-02-17T00:00:00", + "total": 2090.00 + }, + { + "orderId": 10896, + "orderDate": "1998-02-19T00:00:00", + "total": 750.50 + }, + { + "orderId": 10978, + "orderDate": "1998-03-26T00:00:00", + "total": 1303.20 + }, + { + "orderId": 11004, + "orderDate": "1998-04-07T00:00:00", + "total": 295.38 + } + ] + }, + { + "customerId": "MEREP", + "companyName": "M\u00e8re Paillarde", + "address": "43 rue St. Laurent", + "city": "Montr\u00e9al", + "region": "Qu\u00e9bec", + "postalCode": "H1J 1C3", + "country": "Canada", + "phone": "(514) 555-8054", + "fax": "(514) 555-8055", + "orders": [ + { + "orderId": 10332, + "orderDate": "1996-10-17T00:00:00", + "total": 1786.88 + }, + { + "orderId": 10339, + "orderDate": "1996-10-28T00:00:00", + "total": 3354.00 + }, + { + "orderId": 10376, + "orderDate": "1996-12-09T00:00:00", + "total": 399.00 + }, + { + "orderId": 10424, + "orderDate": "1997-01-23T00:00:00", + "total": 9194.56 + }, + { + "orderId": 10439, + "orderDate": "1997-02-07T00:00:00", + "total": 1078.00 + }, + { + "orderId": 10505, + "orderDate": "1997-04-14T00:00:00", + "total": 147.90 + }, + { + "orderId": 10565, + "orderDate": "1997-06-11T00:00:00", + "total": 639.90 + }, + { + "orderId": 10570, + "orderDate": "1997-06-17T00:00:00", + "total": 2465.25 + }, + { + "orderId": 10590, + "orderDate": "1997-07-07T00:00:00", + "total": 1101.00 + }, + { + "orderId": 10605, + "orderDate": "1997-07-21T00:00:00", + "total": 4109.70 + }, + { + "orderId": 10618, + "orderDate": "1997-08-01T00:00:00", + "total": 2697.50 + }, + { + "orderId": 10619, + "orderDate": "1997-08-04T00:00:00", + "total": 1260.00 + }, + { + "orderId": 10724, + "orderDate": "1997-10-30T00:00:00", + "total": 638.50 + } + ] + }, + { + "customerId": "MORGK", + "companyName": "Morgenstern Gesundkost", + "address": "Heerstr. 22", + "city": "Leipzig", + "postalCode": "04179", + "country": "Germany", + "phone": "0342-023176", + "orders": [ + { + "orderId": 10277, + "orderDate": "1996-08-09T00:00:00", + "total": 1200.80 + }, + { + "orderId": 10575, + "orderDate": "1997-06-20T00:00:00", + "total": 2147.40 + }, + { + "orderId": 10699, + "orderDate": "1997-10-09T00:00:00", + "total": 114.00 + }, + { + "orderId": 10779, + "orderDate": "1997-12-16T00:00:00", + "total": 1335.00 + }, + { + "orderId": 10945, + "orderDate": "1998-03-12T00:00:00", + "total": 245.00 + } + ] + }, + { + "customerId": "NORTS", + "companyName": "North\/South", + "address": "South House, 300 Queensbridge", + "city": "London", + "postalCode": "SW7 1RZ", + "country": "UK", + "phone": "(171) 555-7733", + "fax": "(171) 555-2530", + "orders": [ + { + "orderId": 10517, + "orderDate": "1997-04-24T00:00:00", + "total": 352.00 + }, + { + "orderId": 10752, + "orderDate": "1997-11-24T00:00:00", + "total": 252.00 + }, + { + "orderId": 11057, + "orderDate": "1998-04-29T00:00:00", + "total": 45.00 + } + ] + }, + { + "customerId": "OCEAN", + "companyName": "Oc\u00e9ano Atl\u00e1ntico Ltda.", + "address": "Ing. Gustavo Moncada 8585, Piso 20-A", + "city": "Buenos Aires", + "postalCode": "1010", + "country": "Argentina", + "phone": "(1) 135-5333", + "fax": "(1) 135-5535", + "orders": [ + { + "orderId": 10409, + "orderDate": "1997-01-09T00:00:00", + "total": 319.20 + }, + { + "orderId": 10531, + "orderDate": "1997-05-08T00:00:00", + "total": 110.00 + }, + { + "orderId": 10898, + "orderDate": "1998-02-20T00:00:00", + "total": 30.00 + }, + { + "orderId": 10958, + "orderDate": "1998-03-18T00:00:00", + "total": 781.00 + }, + { + "orderId": 10986, + "orderDate": "1998-03-30T00:00:00", + "total": 2220.00 + } + ] + }, + { + "customerId": "OLDWO", + "companyName": "Old World Delicatessen", + "address": "2743 Bering St.", + "city": "Anchorage", + "region": "AK", + "postalCode": "99508", + "country": "USA", + "phone": "(907) 555-7584", + "fax": "(907) 555-2880", + "orders": [ + { + "orderId": 10260, + "orderDate": "1996-07-19T00:00:00", + "total": 1504.65 + }, + { + "orderId": 10305, + "orderDate": "1996-09-13T00:00:00", + "total": 3741.30 + }, + { + "orderId": 10338, + "orderDate": "1996-10-25T00:00:00", + "total": 934.50 + }, + { + "orderId": 10441, + "orderDate": "1997-02-10T00:00:00", + "total": 1755.00 + }, + { + "orderId": 10594, + "orderDate": "1997-07-09T00:00:00", + "total": 565.50 + }, + { + "orderId": 10680, + "orderDate": "1997-09-24T00:00:00", + "total": 1261.88 + }, + { + "orderId": 10706, + "orderDate": "1997-10-16T00:00:00", + "total": 1893.00 + }, + { + "orderId": 10855, + "orderDate": "1998-01-27T00:00:00", + "total": 2227.89 + }, + { + "orderId": 10965, + "orderDate": "1998-03-20T00:00:00", + "total": 848.00 + }, + { + "orderId": 11034, + "orderDate": "1998-04-20T00:00:00", + "total": 539.40 + } + ] + }, + { + "customerId": "OTTIK", + "companyName": "Ottilies K\u00e4seladen", + "address": "Mehrheimerstr. 369", + "city": "K\u00f6ln", + "postalCode": "50739", + "country": "Germany", + "phone": "0221-0644327", + "fax": "0221-0765721", + "orders": [ + { + "orderId": 10407, + "orderDate": "1997-01-07T00:00:00", + "total": 1194.00 + }, + { + "orderId": 10508, + "orderDate": "1997-04-16T00:00:00", + "total": 240.00 + }, + { + "orderId": 10554, + "orderDate": "1997-05-30T00:00:00", + "total": 1728.52 + }, + { + "orderId": 10580, + "orderDate": "1997-06-26T00:00:00", + "total": 1013.74 + }, + { + "orderId": 10684, + "orderDate": "1997-09-26T00:00:00", + "total": 1768.00 + }, + { + "orderId": 10766, + "orderDate": "1997-12-05T00:00:00", + "total": 2310.00 + }, + { + "orderId": 10833, + "orderDate": "1998-01-15T00:00:00", + "total": 906.93 + }, + { + "orderId": 10999, + "orderDate": "1998-04-03T00:00:00", + "total": 1197.95 + }, + { + "orderId": 11020, + "orderDate": "1998-04-14T00:00:00", + "total": 632.40 + } + ] + }, + { + "customerId": "PARIS", + "companyName": "Paris sp\u00e9cialit\u00e9s", + "address": "265, boulevard Charonne", + "city": "Paris", + "postalCode": "75012", + "country": "France", + "phone": "(1) 42.34.22.66", + "fax": "(1) 42.34.22.77" + }, + { + "customerId": "PERIC", + "companyName": "Pericles Comidas cl\u00e1sicas", + "address": "Calle Dr. Jorge Cash 321", + "city": "M\u00e9xico D.F.", + "postalCode": "05033", + "country": "Mexico", + "phone": "(5) 552-3745", + "fax": "(5) 545-3745", + "orders": [ + { + "orderId": 10322, + "orderDate": "1996-10-04T00:00:00", + "total": 112.00 + }, + { + "orderId": 10354, + "orderDate": "1996-11-14T00:00:00", + "total": 568.80 + }, + { + "orderId": 10474, + "orderDate": "1997-03-13T00:00:00", + "total": 1249.10 + }, + { + "orderId": 10502, + "orderDate": "1997-04-10T00:00:00", + "total": 816.30 + }, + { + "orderId": 10995, + "orderDate": "1998-04-02T00:00:00", + "total": 1196.00 + }, + { + "orderId": 11073, + "orderDate": "1998-05-05T00:00:00", + "total": 300.00 + } + ] + }, + { + "customerId": "PICCO", + "companyName": "Piccolo und mehr", + "address": "Geislweg 14", + "city": "Salzburg", + "postalCode": "5020", + "country": "Austria", + "phone": "6562-9722", + "fax": "6562-9723", + "orders": [ + { + "orderId": 10353, + "orderDate": "1996-11-13T00:00:00", + "total": 8593.28 + }, + { + "orderId": 10392, + "orderDate": "1996-12-24T00:00:00", + "total": 1440.00 + }, + { + "orderId": 10427, + "orderDate": "1997-01-27T00:00:00", + "total": 651.00 + }, + { + "orderId": 10489, + "orderDate": "1997-03-28T00:00:00", + "total": 439.20 + }, + { + "orderId": 10530, + "orderDate": "1997-05-08T00:00:00", + "total": 4180.00 + }, + { + "orderId": 10597, + "orderDate": "1997-07-11T00:00:00", + "total": 718.08 + }, + { + "orderId": 10686, + "orderDate": "1997-09-30T00:00:00", + "total": 1404.45 + }, + { + "orderId": 10747, + "orderDate": "1997-11-19T00:00:00", + "total": 1912.85 + }, + { + "orderId": 10844, + "orderDate": "1998-01-21T00:00:00", + "total": 735.00 + }, + { + "orderId": 11053, + "orderDate": "1998-04-27T00:00:00", + "total": 3055.00 + } + ] + }, + { + "customerId": "PRINI", + "companyName": "Princesa Isabel Vinhos", + "address": "Estrada da sa\u00fade n. 58", + "city": "Lisboa", + "postalCode": "1756", + "country": "Portugal", + "phone": "(1) 356-5634", + "orders": [ + { + "orderId": 10336, + "orderDate": "1996-10-23T00:00:00", + "total": 285.12 + }, + { + "orderId": 10397, + "orderDate": "1996-12-27T00:00:00", + "total": 716.72 + }, + { + "orderId": 10433, + "orderDate": "1997-02-03T00:00:00", + "total": 851.20 + }, + { + "orderId": 10477, + "orderDate": "1997-03-17T00:00:00", + "total": 558.00 + }, + { + "orderId": 10808, + "orderDate": "1998-01-01T00:00:00", + "total": 1411.00 + }, + { + "orderId": 11007, + "orderDate": "1998-04-08T00:00:00", + "total": 2633.90 + } + ] + }, + { + "customerId": "QUEDE", + "companyName": "Que Del\u00edcia", + "address": "Rua da Panificadora, 12", + "city": "Rio de Janeiro", + "region": "RJ", + "postalCode": "02389-673", + "country": "Brazil", + "phone": "(21) 555-4252", + "fax": "(21) 555-4545", + "orders": [ + { + "orderId": 10261, + "orderDate": "1996-07-19T00:00:00", + "total": 448.00 + }, + { + "orderId": 10291, + "orderDate": "1996-08-27T00:00:00", + "total": 497.52 + }, + { + "orderId": 10379, + "orderDate": "1996-12-11T00:00:00", + "total": 863.28 + }, + { + "orderId": 10421, + "orderDate": "1997-01-21T00:00:00", + "total": 1194.27 + }, + { + "orderId": 10587, + "orderDate": "1997-07-02T00:00:00", + "total": 807.38 + }, + { + "orderId": 10647, + "orderDate": "1997-08-27T00:00:00", + "total": 636.00 + }, + { + "orderId": 10720, + "orderDate": "1997-10-28T00:00:00", + "total": 550.00 + }, + { + "orderId": 10794, + "orderDate": "1997-12-24T00:00:00", + "total": 314.76 + }, + { + "orderId": 10989, + "orderDate": "1998-03-31T00:00:00", + "total": 1353.60 + } + ] + }, + { + "customerId": "QUEEN", + "companyName": "Queen Cozinha", + "address": "Alameda dos Can\u00e0rios, 891", + "city": "S\u00e3o Paulo", + "region": "SP", + "postalCode": "05487-020", + "country": "Brazil", + "phone": "(11) 555-1189", + "orders": [ + { + "orderId": 10372, + "orderDate": "1996-12-04T00:00:00", + "total": 9210.90 + }, + { + "orderId": 10406, + "orderDate": "1997-01-07T00:00:00", + "total": 1830.78 + }, + { + "orderId": 10487, + "orderDate": "1997-03-26T00:00:00", + "total": 889.70 + }, + { + "orderId": 10637, + "orderDate": "1997-08-19T00:00:00", + "total": 2761.94 + }, + { + "orderId": 10659, + "orderDate": "1997-09-05T00:00:00", + "total": 1227.02 + }, + { + "orderId": 10704, + "orderDate": "1997-10-14T00:00:00", + "total": 595.50 + }, + { + "orderId": 10728, + "orderDate": "1997-11-04T00:00:00", + "total": 1296.75 + }, + { + "orderId": 10786, + "orderDate": "1997-12-19T00:00:00", + "total": 1531.08 + }, + { + "orderId": 10868, + "orderDate": "1998-02-04T00:00:00", + "total": 1920.60 + }, + { + "orderId": 10913, + "orderDate": "1998-02-26T00:00:00", + "total": 768.75 + }, + { + "orderId": 10914, + "orderDate": "1998-02-27T00:00:00", + "total": 537.50 + }, + { + "orderId": 10961, + "orderDate": "1998-03-19T00:00:00", + "total": 1119.90 + }, + { + "orderId": 11068, + "orderDate": "1998-05-04T00:00:00", + "total": 2027.08 + } + ] + }, + { + "customerId": "QUICK", + "companyName": "QUICK-Stop", + "address": "Taucherstra\u00dfe 10", + "city": "Cunewalde", + "postalCode": "01307", + "country": "Germany", + "phone": "0372-035188", + "orders": [ + { + "orderId": 10273, + "orderDate": "1996-08-05T00:00:00", + "total": 2037.28 + }, + { + "orderId": 10285, + "orderDate": "1996-08-20T00:00:00", + "total": 1743.36 + }, + { + "orderId": 10286, + "orderDate": "1996-08-21T00:00:00", + "total": 3016.00 + }, + { + "orderId": 10313, + "orderDate": "1996-09-24T00:00:00", + "total": 182.40 + }, + { + "orderId": 10345, + "orderDate": "1996-11-04T00:00:00", + "total": 2924.80 + }, + { + "orderId": 10361, + "orderDate": "1996-11-22T00:00:00", + "total": 2046.24 + }, + { + "orderId": 10418, + "orderDate": "1997-01-17T00:00:00", + "total": 1814.80 + }, + { + "orderId": 10451, + "orderDate": "1997-02-19T00:00:00", + "total": 3849.66 + }, + { + "orderId": 10515, + "orderDate": "1997-04-23T00:00:00", + "total": 9921.30 + }, + { + "orderId": 10527, + "orderDate": "1997-05-05T00:00:00", + "total": 1503.00 + }, + { + "orderId": 10540, + "orderDate": "1997-05-19T00:00:00", + "total": 10191.70 + }, + { + "orderId": 10549, + "orderDate": "1997-05-27T00:00:00", + "total": 3554.28 + }, + { + "orderId": 10588, + "orderDate": "1997-07-03T00:00:00", + "total": 3120.00 + }, + { + "orderId": 10658, + "orderDate": "1997-09-05T00:00:00", + "total": 4464.60 + }, + { + "orderId": 10691, + "orderDate": "1997-10-03T00:00:00", + "total": 10164.80 + }, + { + "orderId": 10694, + "orderDate": "1997-10-06T00:00:00", + "total": 4825.00 + }, + { + "orderId": 10721, + "orderDate": "1997-10-29T00:00:00", + "total": 923.88 + }, + { + "orderId": 10745, + "orderDate": "1997-11-18T00:00:00", + "total": 4529.80 + }, + { + "orderId": 10765, + "orderDate": "1997-12-04T00:00:00", + "total": 1515.60 + }, + { + "orderId": 10788, + "orderDate": "1997-12-22T00:00:00", + "total": 731.50 + }, + { + "orderId": 10845, + "orderDate": "1998-01-21T00:00:00", + "total": 3812.70 + }, + { + "orderId": 10865, + "orderDate": "1998-02-02T00:00:00", + "total": 16387.50 + }, + { + "orderId": 10878, + "orderDate": "1998-02-10T00:00:00", + "total": 1539.00 + }, + { + "orderId": 10938, + "orderDate": "1998-03-10T00:00:00", + "total": 2731.88 + }, + { + "orderId": 10962, + "orderDate": "1998-03-19T00:00:00", + "total": 3584.00 + }, + { + "orderId": 10991, + "orderDate": "1998-04-01T00:00:00", + "total": 2296.00 + }, + { + "orderId": 10996, + "orderDate": "1998-04-02T00:00:00", + "total": 560.00 + }, + { + "orderId": 11021, + "orderDate": "1998-04-14T00:00:00", + "total": 6306.24 + } + ] + }, + { + "customerId": "RANCH", + "companyName": "Rancho grande", + "address": "Av. del Libertador 900", + "city": "Buenos Aires", + "postalCode": "1010", + "country": "Argentina", + "phone": "(1) 123-5555", + "fax": "(1) 123-5556", + "orders": [ + { + "orderId": 10448, + "orderDate": "1997-02-17T00:00:00", + "total": 443.40 + }, + { + "orderId": 10716, + "orderDate": "1997-10-24T00:00:00", + "total": 706.00 + }, + { + "orderId": 10828, + "orderDate": "1998-01-13T00:00:00", + "total": 932.00 + }, + { + "orderId": 10916, + "orderDate": "1998-02-27T00:00:00", + "total": 686.70 + }, + { + "orderId": 11019, + "orderDate": "1998-04-13T00:00:00", + "total": 76.00 + } + ] + }, + { + "customerId": "RATTC", + "companyName": "Rattlesnake Canyon Grocery", + "address": "2817 Milton Dr.", + "city": "Albuquerque", + "region": "NM", + "postalCode": "87110", + "country": "USA", + "phone": "(505) 555-5939", + "fax": "(505) 555-3620", + "orders": [ + { + "orderId": 10262, + "orderDate": "1996-07-22T00:00:00", + "total": 584.00 + }, + { + "orderId": 10272, + "orderDate": "1996-08-02T00:00:00", + "total": 1456.00 + }, + { + "orderId": 10294, + "orderDate": "1996-08-30T00:00:00", + "total": 1887.60 + }, + { + "orderId": 10314, + "orderDate": "1996-09-25T00:00:00", + "total": 2094.30 + }, + { + "orderId": 10316, + "orderDate": "1996-09-27T00:00:00", + "total": 2835.00 + }, + { + "orderId": 10346, + "orderDate": "1996-11-05T00:00:00", + "total": 1618.88 + }, + { + "orderId": 10401, + "orderDate": "1997-01-01T00:00:00", + "total": 3868.60 + }, + { + "orderId": 10479, + "orderDate": "1997-03-19T00:00:00", + "total": 10495.60 + }, + { + "orderId": 10564, + "orderDate": "1997-06-10T00:00:00", + "total": 1234.05 + }, + { + "orderId": 10569, + "orderDate": "1997-06-16T00:00:00", + "total": 890.00 + }, + { + "orderId": 10598, + "orderDate": "1997-07-14T00:00:00", + "total": 2388.50 + }, + { + "orderId": 10761, + "orderDate": "1997-12-02T00:00:00", + "total": 507.00 + }, + { + "orderId": 10820, + "orderDate": "1998-01-07T00:00:00", + "total": 1140.00 + }, + { + "orderId": 10852, + "orderDate": "1998-01-26T00:00:00", + "total": 2984.00 + }, + { + "orderId": 10889, + "orderDate": "1998-02-16T00:00:00", + "total": 11380.00 + }, + { + "orderId": 10988, + "orderDate": "1998-03-31T00:00:00", + "total": 3574.80 + }, + { + "orderId": 11000, + "orderDate": "1998-04-06T00:00:00", + "total": 903.75 + }, + { + "orderId": 11077, + "orderDate": "1998-05-06T00:00:00", + "total": 1255.72 + } + ] + }, + { + "customerId": "REGGC", + "companyName": "Reggiani Caseifici", + "address": "Strada Provinciale 124", + "city": "Reggio Emilia", + "postalCode": "42100", + "country": "Italy", + "phone": "0522-556721", + "fax": "0522-556722", + "orders": [ + { + "orderId": 10288, + "orderDate": "1996-08-23T00:00:00", + "total": 80.10 + }, + { + "orderId": 10428, + "orderDate": "1997-01-28T00:00:00", + "total": 192.00 + }, + { + "orderId": 10443, + "orderDate": "1997-02-12T00:00:00", + "total": 517.44 + }, + { + "orderId": 10562, + "orderDate": "1997-06-09T00:00:00", + "total": 488.70 + }, + { + "orderId": 10586, + "orderDate": "1997-07-02T00:00:00", + "total": 23.80 + }, + { + "orderId": 10655, + "orderDate": "1997-09-03T00:00:00", + "total": 154.40 + }, + { + "orderId": 10727, + "orderDate": "1997-11-03T00:00:00", + "total": 1624.50 + }, + { + "orderId": 10812, + "orderDate": "1998-01-02T00:00:00", + "total": 1692.80 + }, + { + "orderId": 10908, + "orderDate": "1998-02-26T00:00:00", + "total": 663.10 + }, + { + "orderId": 10942, + "orderDate": "1998-03-11T00:00:00", + "total": 560.00 + }, + { + "orderId": 11010, + "orderDate": "1998-04-09T00:00:00", + "total": 645.00 + }, + { + "orderId": 11062, + "orderDate": "1998-04-30T00:00:00", + "total": 406.40 + } + ] + }, + { + "customerId": "RICAR", + "companyName": "Ricardo Adocicados", + "address": "Av. Copacabana, 267", + "city": "Rio de Janeiro", + "region": "RJ", + "postalCode": "02389-890", + "country": "Brazil", + "phone": "(21) 555-3412", + "orders": [ + { + "orderId": 10287, + "orderDate": "1996-08-22T00:00:00", + "total": 819.00 + }, + { + "orderId": 10299, + "orderDate": "1996-09-06T00:00:00", + "total": 349.50 + }, + { + "orderId": 10447, + "orderDate": "1997-02-14T00:00:00", + "total": 914.40 + }, + { + "orderId": 10481, + "orderDate": "1997-03-20T00:00:00", + "total": 1472.00 + }, + { + "orderId": 10563, + "orderDate": "1997-06-10T00:00:00", + "total": 965.00 + }, + { + "orderId": 10622, + "orderDate": "1997-08-06T00:00:00", + "total": 560.00 + }, + { + "orderId": 10648, + "orderDate": "1997-08-28T00:00:00", + "total": 372.38 + }, + { + "orderId": 10813, + "orderDate": "1998-01-05T00:00:00", + "total": 602.40 + }, + { + "orderId": 10851, + "orderDate": "1998-01-26T00:00:00", + "total": 2603.00 + }, + { + "orderId": 10877, + "orderDate": "1998-02-09T00:00:00", + "total": 1955.12 + }, + { + "orderId": 11059, + "orderDate": "1998-04-29T00:00:00", + "total": 1838.00 + } + ] + }, + { + "customerId": "RICSU", + "companyName": "Richter Supermarkt", + "address": "Grenzacherweg 237", + "city": "Gen\u00e8ve", + "postalCode": "1203", + "country": "Switzerland", + "phone": "0897-034214", + "orders": [ + { + "orderId": 10255, + "orderDate": "1996-07-12T00:00:00", + "total": 2490.50 + }, + { + "orderId": 10419, + "orderDate": "1997-01-20T00:00:00", + "total": 2097.60 + }, + { + "orderId": 10537, + "orderDate": "1997-05-14T00:00:00", + "total": 1823.80 + }, + { + "orderId": 10666, + "orderDate": "1997-09-12T00:00:00", + "total": 4666.94 + }, + { + "orderId": 10751, + "orderDate": "1997-11-24T00:00:00", + "total": 1631.48 + }, + { + "orderId": 10758, + "orderDate": "1997-11-28T00:00:00", + "total": 1644.60 + }, + { + "orderId": 10931, + "orderDate": "1998-03-06T00:00:00", + "total": 799.20 + }, + { + "orderId": 10951, + "orderDate": "1998-03-16T00:00:00", + "total": 458.76 + }, + { + "orderId": 11033, + "orderDate": "1998-04-17T00:00:00", + "total": 3232.80 + }, + { + "orderId": 11075, + "orderDate": "1998-05-06T00:00:00", + "total": 498.10 + } + ] + }, + { + "customerId": "ROMEY", + "companyName": "Romero y tomillo", + "address": "Gran V\u00eda, 1", + "city": "Madrid", + "postalCode": "28001", + "country": "Spain", + "phone": "(91) 745 6200", + "fax": "(91) 745 6210", + "orders": [ + { + "orderId": 10281, + "orderDate": "1996-08-14T00:00:00", + "total": 86.50 + }, + { + "orderId": 10282, + "orderDate": "1996-08-15T00:00:00", + "total": 155.40 + }, + { + "orderId": 10306, + "orderDate": "1996-09-16T00:00:00", + "total": 498.50 + }, + { + "orderId": 10917, + "orderDate": "1998-03-02T00:00:00", + "total": 365.89 + }, + { + "orderId": 11013, + "orderDate": "1998-04-09T00:00:00", + "total": 361.00 + } + ] + }, + { + "customerId": "SANTG", + "companyName": "Sant\u00e9 Gourmet", + "address": "Erling Skakkes gate 78", + "city": "Stavern", + "postalCode": "4110", + "country": "Norway", + "phone": "07-98 92 35", + "fax": "07-98 92 47", + "orders": [ + { + "orderId": 10387, + "orderDate": "1996-12-18T00:00:00", + "total": 1058.40 + }, + { + "orderId": 10520, + "orderDate": "1997-04-29T00:00:00", + "total": 200.00 + }, + { + "orderId": 10639, + "orderDate": "1997-08-20T00:00:00", + "total": 500.00 + }, + { + "orderId": 10831, + "orderDate": "1998-01-14T00:00:00", + "total": 2684.40 + }, + { + "orderId": 10909, + "orderDate": "1998-02-26T00:00:00", + "total": 670.00 + }, + { + "orderId": 11015, + "orderDate": "1998-04-10T00:00:00", + "total": 622.35 + } + ] + }, + { + "customerId": "SAVEA", + "companyName": "Save-a-lot Markets", + "address": "187 Suffolk Ln.", + "city": "Boise", + "region": "ID", + "postalCode": "83720", + "country": "USA", + "phone": "(208) 555-8097", + "orders": [ + { + "orderId": 10324, + "orderDate": "1996-10-08T00:00:00", + "total": 5275.72 + }, + { + "orderId": 10393, + "orderDate": "1996-12-25T00:00:00", + "total": 2556.95 + }, + { + "orderId": 10398, + "orderDate": "1996-12-30T00:00:00", + "total": 2505.60 + }, + { + "orderId": 10440, + "orderDate": "1997-02-10T00:00:00", + "total": 4924.14 + }, + { + "orderId": 10452, + "orderDate": "1997-02-20T00:00:00", + "total": 2018.50 + }, + { + "orderId": 10510, + "orderDate": "1997-04-18T00:00:00", + "total": 4707.54 + }, + { + "orderId": 10555, + "orderDate": "1997-06-02T00:00:00", + "total": 2944.40 + }, + { + "orderId": 10603, + "orderDate": "1997-07-18T00:00:00", + "total": 1483.00 + }, + { + "orderId": 10607, + "orderDate": "1997-07-22T00:00:00", + "total": 6475.40 + }, + { + "orderId": 10612, + "orderDate": "1997-07-28T00:00:00", + "total": 6375.00 + }, + { + "orderId": 10627, + "orderDate": "1997-08-11T00:00:00", + "total": 1185.75 + }, + { + "orderId": 10657, + "orderDate": "1997-09-04T00:00:00", + "total": 4371.60 + }, + { + "orderId": 10678, + "orderDate": "1997-09-23T00:00:00", + "total": 5256.50 + }, + { + "orderId": 10700, + "orderDate": "1997-10-10T00:00:00", + "total": 1638.40 + }, + { + "orderId": 10711, + "orderDate": "1997-10-21T00:00:00", + "total": 4451.70 + }, + { + "orderId": 10713, + "orderDate": "1997-10-22T00:00:00", + "total": 2827.90 + }, + { + "orderId": 10714, + "orderDate": "1997-10-22T00:00:00", + "total": 2205.75 + }, + { + "orderId": 10722, + "orderDate": "1997-10-29T00:00:00", + "total": 1570.00 + }, + { + "orderId": 10748, + "orderDate": "1997-11-20T00:00:00", + "total": 2196.00 + }, + { + "orderId": 10757, + "orderDate": "1997-11-27T00:00:00", + "total": 3082.00 + }, + { + "orderId": 10815, + "orderDate": "1998-01-05T00:00:00", + "total": 40.00 + }, + { + "orderId": 10847, + "orderDate": "1998-01-22T00:00:00", + "total": 4931.92 + }, + { + "orderId": 10882, + "orderDate": "1998-02-11T00:00:00", + "total": 892.64 + }, + { + "orderId": 10894, + "orderDate": "1998-02-18T00:00:00", + "total": 2753.10 + }, + { + "orderId": 10941, + "orderDate": "1998-03-11T00:00:00", + "total": 4011.75 + }, + { + "orderId": 10983, + "orderDate": "1998-03-27T00:00:00", + "total": 720.90 + }, + { + "orderId": 10984, + "orderDate": "1998-03-30T00:00:00", + "total": 1809.75 + }, + { + "orderId": 11002, + "orderDate": "1998-04-06T00:00:00", + "total": 1811.10 + }, + { + "orderId": 11030, + "orderDate": "1998-04-17T00:00:00", + "total": 12615.05 + }, + { + "orderId": 11031, + "orderDate": "1998-04-17T00:00:00", + "total": 2393.50 + }, + { + "orderId": 11064, + "orderDate": "1998-05-01T00:00:00", + "total": 4330.40 + } + ] + }, + { + "customerId": "SEVES", + "companyName": "Seven Seas Imports", + "address": "90 Wadhurst Rd.", + "city": "London", + "postalCode": "OX15 4NB", + "country": "UK", + "phone": "(171) 555-1717", + "fax": "(171) 555-5646", + "orders": [ + { + "orderId": 10359, + "orderDate": "1996-11-21T00:00:00", + "total": 3471.68 + }, + { + "orderId": 10377, + "orderDate": "1996-12-09T00:00:00", + "total": 863.60 + }, + { + "orderId": 10388, + "orderDate": "1996-12-19T00:00:00", + "total": 1228.80 + }, + { + "orderId": 10472, + "orderDate": "1997-03-12T00:00:00", + "total": 1036.80 + }, + { + "orderId": 10523, + "orderDate": "1997-05-01T00:00:00", + "total": 2444.31 + }, + { + "orderId": 10547, + "orderDate": "1997-05-23T00:00:00", + "total": 1792.80 + }, + { + "orderId": 10800, + "orderDate": "1997-12-26T00:00:00", + "total": 1468.94 + }, + { + "orderId": 10804, + "orderDate": "1997-12-30T00:00:00", + "total": 2278.40 + }, + { + "orderId": 10869, + "orderDate": "1998-02-04T00:00:00", + "total": 1630.00 + } + ] + }, + { + "customerId": "SIMOB", + "companyName": "Simons bistro", + "address": "Vinb\u00e6ltet 34", + "city": "K\u00f8benhavn", + "postalCode": "1734", + "country": "Denmark", + "phone": "31 12 34 56", + "fax": "31 13 35 57", + "orders": [ + { + "orderId": 10341, + "orderDate": "1996-10-29T00:00:00", + "total": 352.60 + }, + { + "orderId": 10417, + "orderDate": "1997-01-16T00:00:00", + "total": 11188.40 + }, + { + "orderId": 10556, + "orderDate": "1997-06-03T00:00:00", + "total": 835.20 + }, + { + "orderId": 10642, + "orderDate": "1997-08-22T00:00:00", + "total": 696.00 + }, + { + "orderId": 10669, + "orderDate": "1997-09-15T00:00:00", + "total": 570.00 + }, + { + "orderId": 10802, + "orderDate": "1997-12-29T00:00:00", + "total": 2942.81 + }, + { + "orderId": 11074, + "orderDate": "1998-05-06T00:00:00", + "total": 232.08 + } + ] + }, + { + "customerId": "SPECD", + "companyName": "Sp\u00e9cialit\u00e9s du monde", + "address": "25, rue Lauriston", + "city": "Paris", + "postalCode": "75016", + "country": "France", + "phone": "(1) 47.55.60.10", + "fax": "(1) 47.55.60.20", + "orders": [ + { + "orderId": 10738, + "orderDate": "1997-11-12T00:00:00", + "total": 52.35 + }, + { + "orderId": 10907, + "orderDate": "1998-02-25T00:00:00", + "total": 108.50 + }, + { + "orderId": 10964, + "orderDate": "1998-03-20T00:00:00", + "total": 2052.50 + }, + { + "orderId": 11043, + "orderDate": "1998-04-22T00:00:00", + "total": 210.00 + } + ] + }, + { + "customerId": "SPLIR", + "companyName": "Split Rail Beer & Ale", + "address": "P.O. Box 555", + "city": "Lander", + "region": "WY", + "postalCode": "82520", + "country": "USA", + "phone": "(307) 555-4680", + "fax": "(307) 555-6525", + "orders": [ + { + "orderId": 10271, + "orderDate": "1996-08-01T00:00:00", + "total": 48.00 + }, + { + "orderId": 10329, + "orderDate": "1996-10-15T00:00:00", + "total": 4578.43 + }, + { + "orderId": 10349, + "orderDate": "1996-11-08T00:00:00", + "total": 141.60 + }, + { + "orderId": 10369, + "orderDate": "1996-12-02T00:00:00", + "total": 2390.40 + }, + { + "orderId": 10385, + "orderDate": "1996-12-17T00:00:00", + "total": 691.20 + }, + { + "orderId": 10432, + "orderDate": "1997-01-31T00:00:00", + "total": 485.00 + }, + { + "orderId": 10756, + "orderDate": "1997-11-27T00:00:00", + "total": 1990.00 + }, + { + "orderId": 10821, + "orderDate": "1998-01-08T00:00:00", + "total": 678.00 + }, + { + "orderId": 10974, + "orderDate": "1998-03-25T00:00:00", + "total": 439.00 + } + ] + }, + { + "customerId": "SUPRD", + "companyName": "Supr\u00eames d\u00e9lices", + "address": "Boulevard Tirou, 255", + "city": "Charleroi", + "postalCode": "B-6000", + "country": "Belgium", + "phone": "(071) 23 67 22 20", + "fax": "(071) 23 67 22 21", + "orders": [ + { + "orderId": 10252, + "orderDate": "1996-07-09T00:00:00", + "total": 3597.90 + }, + { + "orderId": 10302, + "orderDate": "1996-09-10T00:00:00", + "total": 2708.80 + }, + { + "orderId": 10458, + "orderDate": "1997-02-26T00:00:00", + "total": 3891.00 + }, + { + "orderId": 10463, + "orderDate": "1997-03-04T00:00:00", + "total": 713.30 + }, + { + "orderId": 10475, + "orderDate": "1997-03-14T00:00:00", + "total": 1505.18 + }, + { + "orderId": 10767, + "orderDate": "1997-12-05T00:00:00", + "total": 28.00 + }, + { + "orderId": 10841, + "orderDate": "1998-01-20T00:00:00", + "total": 4581.00 + }, + { + "orderId": 10846, + "orderDate": "1998-01-22T00:00:00", + "total": 1112.00 + }, + { + "orderId": 10885, + "orderDate": "1998-02-12T00:00:00", + "total": 1209.00 + }, + { + "orderId": 10930, + "orderDate": "1998-03-06T00:00:00", + "total": 2255.50 + }, + { + "orderId": 11035, + "orderDate": "1998-04-20T00:00:00", + "total": 1754.50 + }, + { + "orderId": 11038, + "orderDate": "1998-04-21T00:00:00", + "total": 732.60 + } + ] + }, + { + "customerId": "THEBI", + "companyName": "The Big Cheese", + "address": "89 Jefferson Way, Suite 2", + "city": "Portland", + "region": "OR", + "postalCode": "97201", + "country": "USA", + "phone": "(503) 555-3612", + "orders": [ + { + "orderId": 10310, + "orderDate": "1996-09-20T00:00:00", + "total": 336.00 + }, + { + "orderId": 10708, + "orderDate": "1997-10-17T00:00:00", + "total": 180.40 + }, + { + "orderId": 10805, + "orderDate": "1997-12-30T00:00:00", + "total": 2775.00 + }, + { + "orderId": 10992, + "orderDate": "1998-04-01T00:00:00", + "total": 69.60 + } + ] + }, + { + "customerId": "THECR", + "companyName": "The Cracker Box", + "address": "55 Grizzly Peak Rd.", + "city": "Butte", + "region": "MT", + "postalCode": "59801", + "country": "USA", + "phone": "(406) 555-5834", + "fax": "(406) 555-8083", + "orders": [ + { + "orderId": 10624, + "orderDate": "1997-08-07T00:00:00", + "total": 1393.24 + }, + { + "orderId": 10775, + "orderDate": "1997-12-12T00:00:00", + "total": 228.00 + }, + { + "orderId": 11003, + "orderDate": "1998-04-06T00:00:00", + "total": 326.00 + } + ] + }, + { + "customerId": "TOMSP", + "companyName": "Toms Spezialit\u00e4ten", + "address": "Luisenstr. 48", + "city": "M\u00fcnster", + "postalCode": "44087", + "country": "Germany", + "phone": "0251-031259", + "fax": "0251-035695", + "orders": [ + { + "orderId": 10438, + "orderDate": "1997-02-06T00:00:00", + "total": 454.00 + }, + { + "orderId": 10446, + "orderDate": "1997-02-14T00:00:00", + "total": 246.24 + }, + { + "orderId": 10548, + "orderDate": "1997-05-26T00:00:00", + "total": 240.10 + }, + { + "orderId": 10608, + "orderDate": "1997-07-23T00:00:00", + "total": 1064.00 + }, + { + "orderId": 10967, + "orderDate": "1998-03-23T00:00:00", + "total": 910.40 + } + ] + }, + { + "customerId": "TORTU", + "companyName": "Tortuga Restaurante", + "address": "Avda. Azteca 123", + "city": "M\u00e9xico D.F.", + "postalCode": "05033", + "country": "Mexico", + "phone": "(5) 555-2933", + "orders": [ + { + "orderId": 10276, + "orderDate": "1996-08-08T00:00:00", + "total": 420.00 + }, + { + "orderId": 10293, + "orderDate": "1996-08-29T00:00:00", + "total": 848.70 + }, + { + "orderId": 10304, + "orderDate": "1996-09-12T00:00:00", + "total": 954.40 + }, + { + "orderId": 10319, + "orderDate": "1996-10-02T00:00:00", + "total": 1191.20 + }, + { + "orderId": 10518, + "orderDate": "1997-04-25T00:00:00", + "total": 4150.05 + }, + { + "orderId": 10576, + "orderDate": "1997-06-23T00:00:00", + "total": 838.45 + }, + { + "orderId": 10676, + "orderDate": "1997-09-22T00:00:00", + "total": 534.85 + }, + { + "orderId": 10842, + "orderDate": "1998-01-20T00:00:00", + "total": 975.00 + }, + { + "orderId": 10915, + "orderDate": "1998-02-27T00:00:00", + "total": 539.50 + }, + { + "orderId": 11069, + "orderDate": "1998-05-04T00:00:00", + "total": 360.00 + } + ] + }, + { + "customerId": "TRADH", + "companyName": "Tradi\u00e7\u00e3o Hipermercados", + "address": "Av. In\u00eas de Castro, 414", + "city": "S\u00e3o Paulo", + "region": "SP", + "postalCode": "05634-030", + "country": "Brazil", + "phone": "(11) 555-2167", + "fax": "(11) 555-2168", + "orders": [ + { + "orderId": 10249, + "orderDate": "1996-07-05T00:00:00", + "total": 1863.40 + }, + { + "orderId": 10292, + "orderDate": "1996-08-28T00:00:00", + "total": 1296.00 + }, + { + "orderId": 10496, + "orderDate": "1997-04-04T00:00:00", + "total": 190.00 + }, + { + "orderId": 10606, + "orderDate": "1997-07-22T00:00:00", + "total": 1130.40 + }, + { + "orderId": 10830, + "orderDate": "1998-01-13T00:00:00", + "total": 1974.00 + }, + { + "orderId": 10834, + "orderDate": "1998-01-15T00:00:00", + "total": 1432.71 + }, + { + "orderId": 10839, + "orderDate": "1998-01-19T00:00:00", + "total": 827.55 + } + ] + }, + { + "customerId": "TRAIH", + "companyName": "Trail's Head Gourmet Provisioners", + "address": "722 DaVinci Blvd.", + "city": "Kirkland", + "region": "WA", + "postalCode": "98034", + "country": "USA", + "phone": "(206) 555-8257", + "fax": "(206) 555-2174", + "orders": [ + { + "orderId": 10574, + "orderDate": "1997-06-19T00:00:00", + "total": 764.30 + }, + { + "orderId": 10577, + "orderDate": "1997-06-23T00:00:00", + "total": 569.00 + }, + { + "orderId": 10822, + "orderDate": "1998-01-08T00:00:00", + "total": 237.90 + } + ] + }, + { + "customerId": "VAFFE", + "companyName": "Vaffeljernet", + "address": "Smagsl\u00f8get 45", + "city": "\u00c5rhus", + "postalCode": "8200", + "country": "Denmark", + "phone": "86 21 32 43", + "fax": "86 22 33 44", + "orders": [ + { + "orderId": 10367, + "orderDate": "1996-11-28T00:00:00", + "total": 834.20 + }, + { + "orderId": 10399, + "orderDate": "1996-12-31T00:00:00", + "total": 1765.60 + }, + { + "orderId": 10465, + "orderDate": "1997-03-05T00:00:00", + "total": 2518.00 + }, + { + "orderId": 10591, + "orderDate": "1997-07-07T00:00:00", + "total": 812.50 + }, + { + "orderId": 10602, + "orderDate": "1997-07-17T00:00:00", + "total": 48.75 + }, + { + "orderId": 10688, + "orderDate": "1997-10-01T00:00:00", + "total": 3160.60 + }, + { + "orderId": 10744, + "orderDate": "1997-11-17T00:00:00", + "total": 736.00 + }, + { + "orderId": 10769, + "orderDate": "1997-12-08T00:00:00", + "total": 1684.28 + }, + { + "orderId": 10921, + "orderDate": "1998-03-03T00:00:00", + "total": 1936.00 + }, + { + "orderId": 10946, + "orderDate": "1998-03-12T00:00:00", + "total": 1407.50 + }, + { + "orderId": 10994, + "orderDate": "1998-04-02T00:00:00", + "total": 940.50 + } + ] + }, + { + "customerId": "VICTE", + "companyName": "Victuailles en stock", + "address": "2, rue du Commerce", + "city": "Lyon", + "postalCode": "69004", + "country": "France", + "phone": "78.32.54.86", + "fax": "78.32.54.87", + "orders": [ + { + "orderId": 10251, + "orderDate": "1996-07-08T00:00:00", + "total": 654.06 + }, + { + "orderId": 10334, + "orderDate": "1996-10-21T00:00:00", + "total": 144.80 + }, + { + "orderId": 10450, + "orderDate": "1997-02-19T00:00:00", + "total": 425.12 + }, + { + "orderId": 10459, + "orderDate": "1997-02-27T00:00:00", + "total": 1659.20 + }, + { + "orderId": 10478, + "orderDate": "1997-03-18T00:00:00", + "total": 471.20 + }, + { + "orderId": 10546, + "orderDate": "1997-05-23T00:00:00", + "total": 2812.00 + }, + { + "orderId": 10806, + "orderDate": "1997-12-31T00:00:00", + "total": 439.60 + }, + { + "orderId": 10814, + "orderDate": "1998-01-05T00:00:00", + "total": 1788.45 + }, + { + "orderId": 10843, + "orderDate": "1998-01-21T00:00:00", + "total": 159.00 + }, + { + "orderId": 10850, + "orderDate": "1998-01-23T00:00:00", + "total": 629.00 + } + ] + }, + { + "customerId": "VINET", + "companyName": "Vins et alcools Chevalier", + "address": "59 rue de l'Abbaye", + "city": "Reims", + "postalCode": "51100", + "country": "France", + "phone": "26.47.15.10", + "fax": "26.47.15.11", + "orders": [ + { + "orderId": 10274, + "orderDate": "1996-08-06T00:00:00", + "total": 538.60 + }, + { + "orderId": 10295, + "orderDate": "1996-09-02T00:00:00", + "total": 121.60 + }, + { + "orderId": 10737, + "orderDate": "1997-11-11T00:00:00", + "total": 139.80 + }, + { + "orderId": 10739, + "orderDate": "1997-11-12T00:00:00", + "total": 240.00 + } + ] + }, + { + "customerId": "WANDK", + "companyName": "Die Wandernde Kuh", + "address": "Adenauerallee 900", + "city": "Stuttgart", + "postalCode": "70563", + "country": "Germany", + "phone": "0711-020361", + "fax": "0711-035428", + "orders": [ + { + "orderId": 10301, + "orderDate": "1996-09-09T00:00:00", + "total": 755.00 + }, + { + "orderId": 10312, + "orderDate": "1996-09-23T00:00:00", + "total": 1614.80 + }, + { + "orderId": 10348, + "orderDate": "1996-11-07T00:00:00", + "total": 363.60 + }, + { + "orderId": 10356, + "orderDate": "1996-11-18T00:00:00", + "total": 1106.40 + }, + { + "orderId": 10513, + "orderDate": "1997-04-22T00:00:00", + "total": 1942.00 + }, + { + "orderId": 10632, + "orderDate": "1997-08-14T00:00:00", + "total": 589.00 + }, + { + "orderId": 10640, + "orderDate": "1997-08-21T00:00:00", + "total": 708.75 + }, + { + "orderId": 10651, + "orderDate": "1997-09-01T00:00:00", + "total": 397.80 + }, + { + "orderId": 10668, + "orderDate": "1997-09-15T00:00:00", + "total": 625.28 + }, + { + "orderId": 11046, + "orderDate": "1998-04-23T00:00:00", + "total": 1485.80 + } + ] + }, + { + "customerId": "WARTH", + "companyName": "Wartian Herkku", + "address": "Torikatu 38", + "city": "Oulu", + "postalCode": "90110", + "country": "Finland", + "phone": "981-443655", + "fax": "981-443655", + "orders": [ + { + "orderId": 10266, + "orderDate": "1996-07-26T00:00:00", + "total": 346.56 + }, + { + "orderId": 10270, + "orderDate": "1996-08-01T00:00:00", + "total": 1376.00 + }, + { + "orderId": 10320, + "orderDate": "1996-10-03T00:00:00", + "total": 516.00 + }, + { + "orderId": 10333, + "orderDate": "1996-10-18T00:00:00", + "total": 877.20 + }, + { + "orderId": 10412, + "orderDate": "1997-01-13T00:00:00", + "total": 334.80 + }, + { + "orderId": 10416, + "orderDate": "1997-01-16T00:00:00", + "total": 720.00 + }, + { + "orderId": 10437, + "orderDate": "1997-02-05T00:00:00", + "total": 393.00 + }, + { + "orderId": 10455, + "orderDate": "1997-02-24T00:00:00", + "total": 2684.00 + }, + { + "orderId": 10526, + "orderDate": "1997-05-05T00:00:00", + "total": 1151.40 + }, + { + "orderId": 10553, + "orderDate": "1997-05-30T00:00:00", + "total": 1546.30 + }, + { + "orderId": 10583, + "orderDate": "1997-06-30T00:00:00", + "total": 2237.50 + }, + { + "orderId": 10636, + "orderDate": "1997-08-19T00:00:00", + "total": 629.50 + }, + { + "orderId": 10750, + "orderDate": "1997-11-21T00:00:00", + "total": 1590.56 + }, + { + "orderId": 10781, + "orderDate": "1997-12-17T00:00:00", + "total": 975.88 + }, + { + "orderId": 11025, + "orderDate": "1998-04-15T00:00:00", + "total": 270.00 + } + ] + }, + { + "customerId": "WELLI", + "companyName": "Wellington Importadora", + "address": "Rua do Mercado, 12", + "city": "Resende", + "region": "SP", + "postalCode": "08737-363", + "country": "Brazil", + "phone": "(14) 555-8122", + "orders": [ + { + "orderId": 10256, + "orderDate": "1996-07-15T00:00:00", + "total": 517.80 + }, + { + "orderId": 10420, + "orderDate": "1997-01-21T00:00:00", + "total": 1707.84 + }, + { + "orderId": 10585, + "orderDate": "1997-07-01T00:00:00", + "total": 142.50 + }, + { + "orderId": 10644, + "orderDate": "1997-08-25T00:00:00", + "total": 1371.80 + }, + { + "orderId": 10803, + "orderDate": "1997-12-30T00:00:00", + "total": 1193.01 + }, + { + "orderId": 10809, + "orderDate": "1998-01-01T00:00:00", + "total": 140.00 + }, + { + "orderId": 10900, + "orderDate": "1998-02-20T00:00:00", + "total": 33.75 + }, + { + "orderId": 10905, + "orderDate": "1998-02-24T00:00:00", + "total": 342.00 + }, + { + "orderId": 10935, + "orderDate": "1998-03-09T00:00:00", + "total": 619.50 + } + ] + }, + { + "customerId": "WHITC", + "companyName": "White Clover Markets", + "address": "305 - 14th Ave. S. Suite 3B", + "city": "Seattle", + "region": "WA", + "postalCode": "98128", + "country": "USA", + "phone": "(206) 555-4112", + "fax": "(206) 555-4115", + "orders": [ + { + "orderId": 10269, + "orderDate": "1996-07-31T00:00:00", + "total": 642.20 + }, + { + "orderId": 10344, + "orderDate": "1996-11-01T00:00:00", + "total": 2296.00 + }, + { + "orderId": 10469, + "orderDate": "1997-03-10T00:00:00", + "total": 956.68 + }, + { + "orderId": 10483, + "orderDate": "1997-03-24T00:00:00", + "total": 668.80 + }, + { + "orderId": 10504, + "orderDate": "1997-04-11T00:00:00", + "total": 1388.50 + }, + { + "orderId": 10596, + "orderDate": "1997-07-11T00:00:00", + "total": 1180.88 + }, + { + "orderId": 10693, + "orderDate": "1997-10-06T00:00:00", + "total": 2071.20 + }, + { + "orderId": 10696, + "orderDate": "1997-10-08T00:00:00", + "total": 996.00 + }, + { + "orderId": 10723, + "orderDate": "1997-10-30T00:00:00", + "total": 468.45 + }, + { + "orderId": 10740, + "orderDate": "1997-11-13T00:00:00", + "total": 1416.00 + }, + { + "orderId": 10861, + "orderDate": "1998-01-30T00:00:00", + "total": 3523.40 + }, + { + "orderId": 10904, + "orderDate": "1998-02-24T00:00:00", + "total": 1924.25 + }, + { + "orderId": 11032, + "orderDate": "1998-04-17T00:00:00", + "total": 8902.50 + }, + { + "orderId": 11066, + "orderDate": "1998-05-01T00:00:00", + "total": 928.75 + } + ] + }, + { + "customerId": "WILMK", + "companyName": "Wilman Kala", + "address": "Keskuskatu 45", + "city": "Helsinki", + "postalCode": "21240", + "country": "Finland", + "phone": "90-224 8858", + "fax": "90-224 8858", + "orders": [ + { + "orderId": 10248, + "orderDate": "1996-07-04T00:00:00", + "total": 440.00 + }, + { + "orderId": 10615, + "orderDate": "1997-07-30T00:00:00", + "total": 120.00 + }, + { + "orderId": 10673, + "orderDate": "1997-09-18T00:00:00", + "total": 412.35 + }, + { + "orderId": 10695, + "orderDate": "1997-10-07T00:00:00", + "total": 642.00 + }, + { + "orderId": 10873, + "orderDate": "1998-02-06T00:00:00", + "total": 336.80 + }, + { + "orderId": 10879, + "orderDate": "1998-02-10T00:00:00", + "total": 611.30 + }, + { + "orderId": 10910, + "orderDate": "1998-02-26T00:00:00", + "total": 452.90 + }, + { + "orderId": 11005, + "orderDate": "1998-04-07T00:00:00", + "total": 586.00 + } + ] + }, + { + "customerId": "WOLZA", + "companyName": "Wolski Zajazd", + "address": "ul. Filtrowa 68", + "city": "Warszawa", + "postalCode": "01-012", + "country": "Poland", + "phone": "(26) 642-7012", + "fax": "(26) 642-7012", + "orders": [ + { + "orderId": 10374, + "orderDate": "1996-12-05T00:00:00", + "total": 459.00 + }, + { + "orderId": 10611, + "orderDate": "1997-07-25T00:00:00", + "total": 808.00 + }, + { + "orderId": 10792, + "orderDate": "1997-12-23T00:00:00", + "total": 399.85 + }, + { + "orderId": 10870, + "orderDate": "1998-02-04T00:00:00", + "total": 160.00 + }, + { + "orderId": 10906, + "orderDate": "1998-02-25T00:00:00", + "total": 427.50 + }, + { + "orderId": 10998, + "orderDate": "1998-04-03T00:00:00", + "total": 686.00 + }, + { + "orderId": 11044, + "orderDate": "1998-04-23T00:00:00", + "total": 591.60 + } + ] + } +] \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncFiltersTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncFiltersTests.cs new file mode 100644 index 00000000000..a96048a2704 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncFiltersTests.cs @@ -0,0 +1,495 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class TestAsyncFilter : IReturn + { + public int? ReturnAt { get; set; } + public int? CancelAt { get; set; } + public int? ErrorAt { get; set; } + public int? DirectErrorAt { get; set; } + public List Results { get; set; } + + public TestAsyncFilter() + { + this.Results = new List(); + } + } + + [Route("/test/async-filter")] + public class TestAsyncFilterRestHandler : TestAsyncFilter { } + + [Route("/test/async-validator")] + public class TestAsyncValidator : IReturn + { + public int Age { get; set; } + public string Name { get; set; } + } + + public class MyTestAsyncValidator : AbstractValidator + { + public MyTestAsyncValidator() + { + RuleSet(ApplyTo.Post, () => + { + RuleFor(x => x.Name).MustAsync(async (s, token) => + { + await Task.Delay(10, token); + return !string.IsNullOrEmpty(s); + }) + .WithMessage("'Name' should not be empty.") + .WithErrorCode("NotEmpty"); + }); + RuleSet(ApplyTo.Put, () => + { + RuleFor(x => x.Name).NotEmpty(); + }); + RuleFor(x => x.Age).GreaterThan(0); + } + } + + [Route("/test/all-async-validator")] + public class TestAllAsyncValidator : IReturn + { + public int Age { get; set; } + public string Name { get; set; } + } + + [Route("/test/async-validator-gateway")] + public class TestAsyncGatewayValidator : IReturn + { + public int Age { get; set; } + public string Name { get; set; } + } + + public class MyTestAsyncGatewayValidator : AbstractValidator + { + public MyTestAsyncGatewayValidator() + { + RuleFor(x => x.Name).MustAsync(async (s, token) => + (await Gateway.SendAsync(new GetStringLength { Value = s })).Result > 0) + .WithMessage("'Name' should not be empty.") + .WithErrorCode("NotEmpty"); + } + } + + public class GetStringLength : IReturn + { + public string Value { get; set; } + } + + public class GetStringLengthResponse + { + public int Result { get; set; } + } + + public class MyAllTestAsyncValidator : AbstractValidator + { + public MyAllTestAsyncValidator() + { + RuleFor(x => x.Name).MustAsync(async (s, token) => + { + await Task.Delay(10, token); + return !string.IsNullOrEmpty(s); + }) + .WithMessage("'Name' should not be empty.") + .WithErrorCode("NotEmpty"); + + RuleFor(x => x.Age).MustAsync(async (age, token) => + { + await Task.Delay(10, token); + return age > 0; + }) + .WithMessage("'Age' must be greater than '0'.") + .WithErrorCode("GreaterThan"); + } + } + public class TestAsyncFilterService : Service + { + public object Any(TestAsyncFilter request) + { + request.Results.Add("Service#" + request.GetType().Name); + return request; + } + + public object Any(TestAsyncFilterRestHandler request) + { + request.Results.Add("Service#" + request.GetType().Name); + return request; + } + + public object Any(TestAsyncValidator request) => request; + + public object Any(TestAllAsyncValidator request) => request; + + public object Any(TestAsyncGatewayValidator request) => request; + + public async Task Any(GetStringLength request) + { + await Task.Yield(); + return new GetStringLengthResponse + { + Result = (request.Value ?? "").Length, + }; + } + } + + public class AsyncFiltersTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(AsyncFiltersTests), typeof(TestAsyncFilterService).Assembly) { } + + public static int CancelledAt = -1; + + public override void Configure(Container container) + { + GlobalRequestFiltersAsync.Add(CreateAsyncFilter(0)); + GlobalRequestFiltersAsync.Add(CreateAsyncFilter(1)); + GlobalRequestFiltersAsync.Add(CreateAsyncFilter(2)); + + Plugins.Add(new ValidationFeature()); + container.RegisterValidators(typeof(MyTestAsyncValidator).Assembly); + } + + private static Func CreateAsyncFilter(int pos) + { + return (req, res, dto) => + { + if (dto is TestAsyncFilter asyncDto) + { + CancelledAt++; + + asyncDto.Results.Add("GlobalRequestFiltersAsync#" + pos); + if (asyncDto.ReturnAt == pos) + { + res.ContentType = MimeTypes.Json; + return res.WriteAsync(asyncDto.ToJson()) + .ContinueWith(t => res.EndRequest(skipHeaders: true)); + } + + if (asyncDto.ErrorAt == pos) + throw new ArgumentException("ErrorAt#" + pos); + + if (asyncDto.DirectErrorAt == pos) + { + res.ContentType = MimeTypes.Json; + return res.WriteError(new ArgumentException("DirectErrorAt#" + pos)); + } + + if (asyncDto.CancelAt == pos) + { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } + + return Task.Delay(10); + } + + return TypeConstants.EmptyTask; + }; + } + } + + private readonly ServiceStackHost appHost; + private JsonServiceClient client; + + public AsyncFiltersTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + client = new JsonServiceClient(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_Execute_all_RequestFilters() + { + var response = client.Post(new TestAsyncFilter()); + + response.PrintDump(); + + Assert.That(response.Results, Is.EquivalentTo(new[] + { + "GlobalRequestFiltersAsync#0", + "GlobalRequestFiltersAsync#1", + "GlobalRequestFiltersAsync#2", + "Service#TestAsyncFilter", + })); + } + + [Test] + public void Does_Execute_all_RequestFilters_RestHandler() + { + var response = client.Post(new TestAsyncFilterRestHandler()); + + response.PrintDump(); + + Assert.That(response.Results, Is.EquivalentTo(new[] + { + "GlobalRequestFiltersAsync#0", + "GlobalRequestFiltersAsync#1", + "GlobalRequestFiltersAsync#2", + "Service#TestAsyncFilterRestHandler", + })); + } + + [Test] + public void Does_Execute_all_RequestFilters_in_AutoBatch_Request() + { + var responseBatch = client.SendAll(new[] + { + new TestAsyncFilter(), + new TestAsyncFilter(), + new TestAsyncFilter(), + }); + + Assert.That(responseBatch.Count, Is.EqualTo(3)); + foreach (var response in responseBatch) + { + Assert.That(response.Results, Is.EquivalentTo(new[] + { + "GlobalRequestFiltersAsync#0", + "GlobalRequestFiltersAsync#1", + "GlobalRequestFiltersAsync#2", + "Service#TestAsyncFilter", + })); + } + } + + [Test] + public void Does_return_Error_in_AsyncFilter() + { + try + { + var response = client.Post(new TestAsyncFilter + { + ErrorAt = 1 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ErrorAt#1")); + } + } + + [Test] + public void Does_return_Error_in_AsyncFilter_in_AutoBatch_Request() + { + try + { + var responseBatch = client.SendAll(new[] + { + new TestAsyncFilter { ErrorAt = 1 }, + new TestAsyncFilter { ErrorAt = 1 }, + new TestAsyncFilter { ErrorAt = 1 }, + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ErrorAt#1")); + } + } + + [Test] + public void Does_return_DirectError_in_AsyncFilter() + { + try + { + var response = client.Post(new TestAsyncFilter + { + DirectErrorAt = 1 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("DirectErrorAt#1")); + } + } + + [Test] + public void Can_Cancel_in_AsyncFilter() + { + AppHost.CancelledAt = -1; + + var client = new JsonServiceClient(Config.ListeningOn) + { + ResponseFilter = res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.PartialContent)); + } + }; + + var response = client.Post(new TestAsyncFilter + { + CancelAt = 1 + }); + + Assert.That(response, Is.Null); + Assert.That(AppHost.CancelledAt, Is.EqualTo(1)); + } + + [Test] + public void Can_Cancel_in_AsyncFilter_in_AutoBatch_Request() + { + AppHost.CancelledAt = -1; + + var client = new JsonServiceClient(Config.ListeningOn) + { + ResponseFilter = res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.PartialContent)); + } + }; + + var responseBatch = client.SendAll(new[] + { + new TestAsyncFilter { CancelAt = 1 }, + new TestAsyncFilter { CancelAt = 1 }, + new TestAsyncFilter { CancelAt = 1 }, + }); + + Assert.That(responseBatch, Is.Null); + Assert.That(AppHost.CancelledAt, Is.EqualTo(1)); + } + + [Test] + public void Does_execute_mixed_async_validator_as_sync() + { + try + { + var response = client.Put(new TestAsyncValidator()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + var status = ex.ResponseStatus; + + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Name' must not be empty.")); + + Assert.That(status.Errors.Count, Is.EqualTo(2)); + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Name' must not be empty.")); + + Assert.That(status.Errors[1].ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(status.Errors[1].FieldName, Is.EqualTo("Age")); + Assert.That(status.Errors[1].Message, Is.EqualTo("'Age' must be greater than '0'.")); + } + } + + [Test] + public void Does_execute_mixed_async_validator_as_async() + { + try + { + var response = client.Post(new TestAsyncValidator()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + var status = ex.ResponseStatus; + + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Name' should not be empty.")); + + Assert.That(status.Errors.Count, Is.EqualTo(2)); + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Name' should not be empty.")); + + Assert.That(status.Errors[1].ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(status.Errors[1].FieldName, Is.EqualTo("Age")); + Assert.That(status.Errors[1].Message, Is.EqualTo("'Age' must be greater than '0'.")); + } + } + + [Test] + public void Can_send_valid_mixed_AsyncValidator_request() + { + var syncResponse = client.Put(new TestAsyncValidator { Age = 1, Name = "one" }); + var asyncResponse = client.Post(new TestAsyncValidator { Age = 2, Name = "two" }); + } + + [Test] + public void Does_execute_all_async_validator() + { + try + { + var response = client.Post(new TestAllAsyncValidator()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + var status = ex.ResponseStatus; + + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Name' should not be empty.")); + + Assert.That(status.Errors.Count, Is.EqualTo(2)); + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Name' should not be empty.")); + + Assert.That(status.Errors[1].ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(status.Errors[1].FieldName, Is.EqualTo("Age")); + Assert.That(status.Errors[1].Message, Is.EqualTo("'Age' must be greater than '0'.")); + } + } + + [Test] + public void Does_execute_async_validator_calling_async_Gateway() + { + try + { + var response = client.Post(new TestAsyncGatewayValidator()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + var status = ex.ResponseStatus; + + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Name' should not be empty.")); + + Assert.That(status.Errors.Count, Is.EqualTo(1)); + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Name' should not be empty.")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncProgressTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncProgressTests.cs new file mode 100644 index 00000000000..bb165985958 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncProgressTests.cs @@ -0,0 +1,122 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AsyncProgressTests + { + private const string ListeningOn = "http://localhost:1337/"; + + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public async Task Can_report_progress_when_downloading_GET_async() + { + var hold = AsyncServiceClient.BufferSize; + AsyncServiceClient.BufferSize = 100; + + try + { + var asyncClient = new JsonServiceClient(ListeningOn); + + var progress = new List(); + + //Note: total = -1 when 'Transfer-Encoding: chunked' + //Available in ASP.NET or in HttpListener when downloading responses with known lengths: + //E.g: Strings, Files, etc. + asyncClient.OnDownloadProgress = (done, total) => + progress.Add("{0}/{1} bytes downloaded".Fmt(done, total)); + + var response = await asyncClient.GetAsync(new TestProgressString()); + + progress.Each(x => x.Print()); + + Assert.That(response.Length, Is.GreaterThan(0)); + Assert.That(progress.Count, Is.GreaterThan(0)); + Assert.That(progress.First(), Is.EqualTo("100/1160 bytes downloaded")); + Assert.That(progress.Last(), Is.EqualTo("1160/1160 bytes downloaded")); + } + finally + { + AsyncServiceClient.BufferSize = hold; + } + } + + [Test] + public async Task Can_report_progress_when_downloading_async_with_Post() + { + await AsyncDownloadWithProgress(new TestProgressString()); + } + + [Test] + public async Task Can_report_progress_when_downloading_async_with_Post_bytes() + { + await AsyncDownloadWithProgress(new TestProgressBytes()); + } + + [Test] + public async Task Can_report_progress_when_downloading_async_with_Post_File_bytes() + { + await AsyncDownloadWithProgress(new TestProgressBinaryFile()); + } + + [Test] + public async Task Can_report_progress_when_downloading_async_with_Post_File_text() + { + await AsyncDownloadWithProgress(new TestProgressTextFile()); + } + + private static async Task AsyncDownloadWithProgress(IReturn requestDto) + { + var hold = AsyncServiceClient.BufferSize; + AsyncServiceClient.BufferSize = 100; + + try + { + var asyncClient = new JsonServiceClient(ListeningOn); + + var progress = new List(); + + //Note: total = -1 when 'Transfer-Encoding: chunked' + //Available in ASP.NET or in HttpListener when downloading responses with known lengths: + //E.g: Strings, Files, etc. + asyncClient.OnDownloadProgress = (done, total) => + progress.Add("{0}/{1} bytes downloaded".Fmt(done, total)); + + var response = await asyncClient.PostAsync(requestDto); + + progress.Each(x => x.Print()); + + Assert.That(progress.Count, Is.GreaterThan(0)); + Assert.That(progress.First(), Is.EqualTo("100/1160 bytes downloaded")); + Assert.That(progress.Last(), Is.EqualTo("1160/1160 bytes downloaded")); + } + finally + { + AsyncServiceClient.BufferSize = hold; + } + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncRestClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncRestClientTests.cs index bd50a9636b1..a9648c66ba2 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncRestClientTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncRestClientTests.cs @@ -1,174 +1,152 @@ using System; using System.Collections.Generic; -using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { - public abstract class AsyncRestClientTests - { - private const string ListeningOn = "http://localhost:82/"; - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - LogManager.LogFactory = new ConsoleLogFactory(); - - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - protected abstract IRestClientAsync CreateAsyncRestClient(); - - private static void FailOnAsyncError(T response, Exception ex) - { - Assert.Fail(ex.Message); - } - - [Test] - public void Can_call_GetAsync_on_GetFactorial_using_RestClientAsync() - { - var asyncClient = CreateAsyncRestClient(); - - GetFactorialResponse response = null; - asyncClient.GetAsync("factorial/3", r => response = r, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(3))); - } - - [Test] - public void Can_call_GetAsync_on_Movies_using_RestClientAsync() - { - var asyncClient = CreateAsyncRestClient(); - - MoviesResponse response = null; - asyncClient.GetAsync("movies", r => response = r, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Movies.EquivalentTo(ResetMoviesService.Top5Movies)); - } - - [Test] - public void Can_call_GetAsync_on_single_Movie_using_RestClientAsync() - { - var asyncClient = CreateAsyncRestClient(); - - MovieResponse response = null; - asyncClient.GetAsync("movies/1", r => response = r, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Movie.Id, Is.EqualTo(1)); - } - - [Test] - public void Can_call_PostAsync_to_add_new_Movie_using_RestClientAsync() - { - var asyncClient = CreateAsyncRestClient(); - - var newMovie = new Movie - { - ImdbId = "tt0450259", - Title = "Blood Diamond", - Rating = 8.0m, - Director = "Edward Zwick", - ReleaseDate = new DateTime(2007, 1, 26), - TagLine = "A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.", - Genres = new List { "Adventure", "Drama", "Thriller" }, - }; - - MovieResponse response = null; - asyncClient.PostAsync("movies", newMovie, - r => response = r, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - - var createdMovie = response.Movie; - Assert.That(createdMovie.Id, Is.GreaterThan(0)); - Assert.That(createdMovie.ImdbId, Is.EqualTo(newMovie.ImdbId)); - } - - [Test] - public void Can_call_DeleteAsync_to_delete_Movie_using_RestClientAsync() - { - var asyncClient = CreateAsyncRestClient(); - - var newMovie = new Movie - { - ImdbId = "tt0450259", - Title = "Blood Diamond", - Rating = 8.0m, - Director = "Edward Zwick", - ReleaseDate = new DateTime(2007, 1, 26), - TagLine = "A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.", - Genres = new List { "Adventure", "Drama", "Thriller" }, - }; - - MovieResponse response = null; - Movie createdMovie = null; - asyncClient.PostAsync("movies", newMovie, - r => - { - createdMovie = r.Movie; - asyncClient.DeleteAsync("movies/" + createdMovie.Id, - dr => response = dr, FailOnAsyncError); - }, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(createdMovie, Is.Not.Null); - Assert.That(response.Movie, Is.Null); - } - - [TestFixture] - public class JsonAsyncRestServiceClientTests : AsyncRestClientTests - { - protected override IRestClientAsync CreateAsyncRestClient() - { - return new JsonRestClientAsync(ListeningOn); - } - } - - [TestFixture] - public class JsvAsyncRestServiceClientTests : AsyncRestClientTests - { - protected override IRestClientAsync CreateAsyncRestClient() - { - return new JsvRestClientAsync(ListeningOn); - } - } - - [TestFixture] - public class XmlAsyncRestServiceClientTests : AsyncRestClientTests - { - protected override IRestClientAsync CreateAsyncRestClient() - { - return new XmlRestClientAsync(ListeningOn); - } - } - } -} \ No newline at end of file + public abstract class AsyncRestClientTests + { + private const string ListeningOn = "http://localhost:1337/"; + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + protected abstract IHttpRestClientAsync CreateAsyncRestClient(); + + [Test] + public async Task Can_call_GetAsync_on_GetFactorial_using_RestClientAsync() + { + var asyncClient = CreateAsyncRestClient(); + + var response = await asyncClient.GetAsync("factorial/3"); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(3))); + } + + [Test] + public async Task Can_call_GetAsync_on_Movies_using_RestClientAsync() + { + var asyncClient = CreateAsyncRestClient(); + + var response = await asyncClient.GetAsync("all-movies"); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Movies.EquivalentTo(ResetMoviesService.Top5Movies)); + } + + [Test] + public async Task Can_call_GetAsync_on_single_Movie_using_RestClientAsync() + { + var asyncClient = CreateAsyncRestClient(); + + var response = await asyncClient.GetAsync("all-movies/1"); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Movie.Id, Is.EqualTo(1)); + } + + [Test] + public async Task Can_call_PostAsync_to_add_new_Movie_using_RestClientAsync() + { + var asyncClient = CreateAsyncRestClient(); + + var newMovie = new Support.Host.Movie + { + ImdbId = "tt0450259", + Title = "Blood Diamond", + Rating = 8.0m, + Director = "Edward Zwick", + ReleaseDate = new DateTime(2007, 1, 26), + TagLine = "A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.", + Genres = new List { "Adventure", "Drama", "Thriller" }, + }; + + var response = await asyncClient.PostAsync("all-movies", newMovie); + + Assert.That(response, Is.Not.Null, "No response received"); + + var createdMovie = response.Movie; + Assert.That(createdMovie.Id, Is.GreaterThan(0)); + Assert.That(createdMovie.ImdbId, Is.EqualTo(newMovie.ImdbId)); + } + + [Test] + public async Task Can_call_DeleteAsync_to_delete_Movie_using_RestClientAsync() + { + var asyncClient = CreateAsyncRestClient(); + + var newMovie = new Support.Host.Movie + { + ImdbId = "tt0450259", + Title = "Blood Diamond", + Rating = 8.0m, + Director = "Edward Zwick", + ReleaseDate = new DateTime(2007, 1, 26), + TagLine = "A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.", + Genres = new List { "Adventure", "Drama", "Thriller" }, + }; + + var response = await asyncClient.PostAsync("all-movies", newMovie); + + var createdMovie = response.Movie; + + response = await asyncClient.DeleteAsync("all-movies/" + createdMovie.Id); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(createdMovie, Is.Not.Null); + Assert.That(response.Movie, Is.Null); + } + + [TestFixture] + public class JsonAsyncRestServiceClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateAsyncRestClient() + { + return new JsonServiceClient(ListeningOn); + } + } + + [TestFixture] + public class JsonAsyncRestServiceHttpClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateAsyncRestClient() + { + return new JsonHttpClient(ListeningOn); + } + } + + [TestFixture] + public class JsvAsyncRestServiceClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateAsyncRestClient() + { + return new JsvServiceClient(ListeningOn); + } + } + + [TestFixture] + public class XmlAsyncRestServiceClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateAsyncRestClient() + { + return new XmlServiceClient(ListeningOn); + } + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncServiceClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncServiceClientTests.cs index e082288b9aa..cca9a4165a0 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncServiceClientTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncServiceClientTests.cs @@ -1,81 +1,92 @@ -using System; -using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { - public abstract class AsyncServiceClientTests - { - protected const string ListeningOn = "http://localhost:82/"; - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - protected abstract IServiceClient CreateServiceClient(); - - private static void FailOnAsyncError(T response, Exception ex) - { - Assert.Fail(ex.Message); - } - - [Test] - public void Can_call_SendAsync_on_ServiceClient() - { - var jsonClient = new JsonServiceClient(ListeningOn); - - var request = new GetFactorial { ForNumber = 3 }; - GetFactorialResponse response = null; - jsonClient.SendAsync(request, r => response = r, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); - } - - [TestFixture] - public class JsonAsyncServiceClientTests : AsyncServiceClientTests - { - protected override IServiceClient CreateServiceClient() - { - return new JsonServiceClient(ListeningOn); - } - } - - [TestFixture] - public class JsvAsyncServiceClientTests : AsyncServiceClientTests - { - protected override IServiceClient CreateServiceClient() - { - return new JsvServiceClient(ListeningOn); - } - } - - [TestFixture] - public class XmlAsyncServiceClientTests : AsyncServiceClientTests - { - protected override IServiceClient CreateServiceClient() - { - return new XmlServiceClient(ListeningOn); - } - } - } - - -} \ No newline at end of file + public abstract class AsyncServiceClientTests + { + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() => appHost.Dispose(); + + protected abstract IServiceClient CreateServiceClient(string compressionType=null); + + [Test] + public async Task Can_call_SendAsync_on_ServiceClient() + { + var client = CreateServiceClient(); + + var request = new GetFactorial { ForNumber = 3 }; + var response = await client.SendAsync(request); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); + } + + +#if NET6_0_OR_GREATER + [TestCase(CompressionTypes.Brotli)] +#endif + [TestCase(CompressionTypes.Deflate)] + [TestCase(CompressionTypes.GZip)] + public async Task Can_call_SendAsync_with_compression_on_ServiceClient(string compressionType) + { + var jsonClient = CreateServiceClient(compressionType); + + var request = new GetFactorial { ForNumber = 3 }; + var response = await jsonClient.SendAsync(request); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(request.ForNumber))); + } + +#if NET6_0_OR_GREATER + [TestFixture] + public class JsonAsyncApiClientTests : AsyncServiceClientTests + { + protected override IServiceClient CreateServiceClient(string compressionType=null) => + new JsonApiClient(Config.ListeningOn) { RequestCompressionType = compressionType }; + } +#endif + + [TestFixture] + public class JsonAsyncServiceClientTests : AsyncServiceClientTests + { + protected override IServiceClient CreateServiceClient(string compressionType=null) => + new JsonServiceClient(Config.ListeningOn) { RequestCompressionType = compressionType }; + } + + [TestFixture] + public class JsonAsyncHttpClientTests : AsyncServiceClientTests + { + protected override IServiceClient CreateServiceClient(string compressionType=null) => + new JsonHttpClient(Config.ListeningOn) { RequestCompressionType = compressionType }; + } + + [TestFixture] + public class JsvAsyncServiceClientTests : AsyncServiceClientTests + { + protected override IServiceClient CreateServiceClient(string compressionType=null) => + new JsvServiceClient(Config.ListeningOn) { RequestCompressionType = compressionType }; + } + + [TestFixture] + public class XmlAsyncServiceClientTests : AsyncServiceClientTests + { + protected override IServiceClient CreateServiceClient(string compressionType=null) => + new XmlServiceClient(Config.ListeningOn) { RequestCompressionType = compressionType }; + } + } + + +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncTaskTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncTaskTests.cs new file mode 100644 index 00000000000..9d02ee539f0 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AsyncTaskTests.cs @@ -0,0 +1,460 @@ +using System; +using System.Net; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public abstract class AsyncTaskTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AsyncTaskAppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + protected abstract IServiceClient CreateServiceClient(); + + private const int Param = 3; + + public class AsyncTaskAppHost : AppHostHttpListenerBase + { + public AsyncTaskAppHost() + : base(typeof(AsyncTaskAppHost).Name, typeof(AsyncTaskAppHost).Assembly) {} + + public override void Configure(Container container) {} + } + + [Test] + public void GetSync_GetFactorialGenericSync() + { + var response = CreateServiceClient().Get(new GetFactorialSync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialGenericAsync() + { + var response = CreateServiceClient().Get(new GetFactorialGenericAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialObjectAsync() + { + var response = CreateServiceClient().Get(new GetFactorialObjectAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialAwaitAsync() + { + var response = CreateServiceClient().Get(new GetFactorialAwaitAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialDelayAsync() + { + var response = CreateServiceClient().Get(new GetFactorialDelayAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + + [Test] + public async Task GetAsync_GetFactorialGenericSync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialSync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialGenericAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialGenericAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialObjectAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialObjectAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialAwaitAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialAwaitAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialDelayAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialDelayAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialNewTaskAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialNewTaskAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialNewTcsAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialNewTcsAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_ThrowErrorAwaitAsync() + { + try + { + var response = await CreateServiceClient().GetAsync(new ThrowErrorAwaitAsync { Message = "Forbidden Test" }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + Assert.That(ex.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(ex.ErrorMessage, Is.EqualTo("Forbidden Test")); + } + } + + [Test] + public async Task VoidAsync() + { + await CreateServiceClient() + .GetAsync(new VoidAsync { Message = "VoidAsync" }); + } + + [TestFixture] + public class JsonAsyncTaskTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsonServiceClient(Config.ListeningOn); + } + } + + [TestFixture] + public class JsonHttpClientAsyncTaskTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsonHttpClient(Config.ListeningOn); + } + } + + [TestFixture] + public class JsvAsyncRestServiceClientTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsvServiceClient(Config.ListeningOn); + } + } + + [TestFixture] + public class XmlAsyncRestServiceClientTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new XmlServiceClient(Config.ListeningOn); + } + } + } + + [Route("/factorial/sync/{ForNumber}")] + [DataContract] + public class GetFactorialSync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/async/{ForNumber}")] + [DataContract] + public class GetFactorialGenericAsync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/object/{ForNumber}")] + [DataContract] + public class GetFactorialObjectAsync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/await/{ForNumber}")] + [DataContract] + public class GetFactorialAwaitAsync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/delay/{ForNumber}")] + [DataContract] + public class GetFactorialDelayAsync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/newtask/{ForNumber}")] + [DataContract] + public class GetFactorialNewTaskAsync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/newtcs/{ForNumber}")] + [DataContract] + public class GetFactorialNewTcsAsync : IReturn + { + [DataMember] + public long ForNumber { get; set; } + } + + [DataContract] + public class GetFactorialResponse + { + [DataMember] + public long Result { get; set; } + } + + [Route("/factorial/throwerror")] + [DataContract] + public class ThrowErrorAwaitAsync : IReturn + { + [DataMember] + public string Message { get; set; } + } + + [Route("/voidasync")] + [DataContract] + public class VoidAsync : IReturnVoid + { + [DataMember] + public string Message { get; set; } + } + + public class GetFactorialAsyncService : IService + { + public object Any(GetFactorialSync request) + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + } + + public Task Any(GetFactorialGenericAsync request) + { + return Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public object Any(GetFactorialObjectAsync request) + { + return Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public async Task Any(GetFactorialAwaitAsync request) + { + return await Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public async Task Any(GetFactorialDelayAsync request) + { + await Task.Delay(1000); + + return await Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public Task Any(GetFactorialNewTaskAsync request) + { + return new Task(() => + new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }); + } + + public Task Any(GetFactorialNewTcsAsync request) + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }.AsTaskResult(); + } + + public async Task Any(ThrowErrorAwaitAsync request) + { + await Task.Delay(0); + throw new HttpError(HttpStatusCode.Forbidden, HttpStatusCode.Forbidden.ToString(), request.Message ?? "Request is forbidden"); + } + + public async Task Any(VoidAsync request) + { + await Task.Delay(1); + } + + public static long GetFactorial(long n) + { + return n > 1 ? n * GetFactorial(n - 1) : 1; + } + } + + [Ignore("Load Test"), TestFixture] + public class AsyncLoadTests + { + const int NoOfTimes = 1000; + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AsyncTaskTests.AsyncTaskAppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + + [Test] + public void Load_test_GetFactorialSync_sync() + { + var client = new JsonServiceClient(Config.ListeningOn); + + for (var i = 0; i < NoOfTimes; i++) + { + var response = client.Get(new GetFactorialSync { ForNumber = 3 }); + if (i % 100 == 0) + { + "{0}: {1}".Print(i, response.Result); + } + } + } + + [Test] + public void Load_test_GetFactorialSync_HttpClient_sync() + { + var client = new JsonHttpClient(Config.ListeningOn); + + for (var i = 0; i < NoOfTimes; i++) + { + var response = client.Get(new GetFactorialSync { ForNumber = 3 }); + if (i % 100 == 0) + { + "{0}: {1}".Print(i, response.Result); + } + } + } + + [Test] + public async Task Load_test_GetFactorialSync_async() + { + var client = new JsonServiceClient(Config.ListeningOn); + + int i = 0; + + var fetchTasks = NoOfTimes.Times(() => + client.GetAsync(new GetFactorialSync { ForNumber = 3 }) + .ContinueWith(t => + { + if (++i % 100 == 0) + { + "{0}: {1}".Print(i, t.Result.Result); + } + })); + + await Task.WhenAll(fetchTasks); + } + + [Test] + public async Task Load_test_GetFactorialSync_HttpClient_async() + { + var client = new JsonHttpClient(Config.ListeningOn); + + int i = 0; + + var fetchTasks = NoOfTimes.Times(() => + client.GetAsync(new GetFactorialSync { ForNumber = 3 }) + .ContinueWith(t => + { + if (++i % 100 == 0) + { + "{0}: {1}".Print(i, t.Result.Result); + } + })); + + await Task.WhenAll(fetchTasks); + } + + [Test] + public void Load_test_GetFactorialGenericAsync_sync() + { + var client = new JsonServiceClient(Config.ListeningOn); + + for (var i = 0; i < NoOfTimes; i++) + { + var response = client.Get(new GetFactorialGenericAsync { ForNumber = 3 }); + if (i % 100 == 0) + { + "{0}: {1}".Print(i, response.Result); + } + } + } + + [Test] + public async Task Load_test_GetFactorialGenericAsync_async() + { + var client = new JsonServiceClient(Config.ListeningOn); + + int i = 0; + + var fetchTasks = NoOfTimes.Times(() => + client.GetAsync(new GetFactorialGenericAsync { ForNumber = 3 }) + .ContinueWith(t => + { + if (++i % 100 == 0) + { + "{0}: {1}".Print(i, t.Result.Result); + } + })); + + await Task.WhenAll(fetchTasks); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTest.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTest.cs index a442d331259..a379c9ca499 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTest.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTest.cs @@ -1,27 +1,18 @@ using System; using System.Collections.Generic; -using System.Data; -using System.IO; using System.Linq; -using System.Text; +using ServiceStack.Caching; using ServiceStack.Common.Tests.ServiceClient.Web; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Service; -using ServiceStack.ServiceInterface; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Support.WebHost; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Utils; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { //Always executed - public class FilterTestAttribute : Attribute, IHasRequestFilter + public class FilterTestAttribute : AttributeBase, IHasRequestFilter { private static ICacheClient previousCache; @@ -29,7 +20,7 @@ public class FilterTestAttribute : Attribute, IHasRequestFilter public int Priority { get; set; } - public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto) + public void RequestFilter(IRequest req, IResponse res, object requestDto) { var dto = (AttributeFiltered)requestDto; dto.AttrsExecuted.Add(GetType().Name); @@ -41,10 +32,7 @@ public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto previousCache = Cache; } - public IHasRequestFilter Copy() - { - return (IHasRequestFilter)this.MemberwiseClone(); - } + public IRequestFilterBase Copy() => (IRequestFilterBase)this.MemberwiseClone(); } //Only executed for the provided HTTP methods (GET, POST) @@ -55,7 +43,7 @@ public ContextualFilterTestAttribute(ApplyTo applyTo) { } - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) + public override void Execute(IRequest req, IResponse res, object requestDto) { var dto = (AttributeFiltered)requestDto; dto.AttrsExecuted.Add(GetType().Name); @@ -75,12 +63,13 @@ public AttributeFiltered() public bool RequestFilterExecuted { get; set; } public bool ContextualRequestFilterExecuted { get; set; } + public bool InheritedRequestFilterExecuted { get; set; } public bool RequestFilterDependenyIsResolved { get; set; } public List AttrsExecuted { get; set; } } //Always executed - public class ResponseFilterTestAttribute : Attribute, IHasResponseFilter + public class ResponseFilterTestAttribute : AttributeBase, IHasResponseFilter { private static ICacheClient previousCache; @@ -88,19 +77,16 @@ public class ResponseFilterTestAttribute : Attribute, IHasResponseFilter public int Priority { get; set; } - public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response) + public void ResponseFilter(IRequest req, IResponse res, object response) { - var dto = response.ToResponseDto() as AttributeFilteredResponse; + var dto = response.GetResponseDto() as AttributeFilteredResponse; dto.ResponseFilterExecuted = true; dto.ResponseFilterDependencyIsResolved = Cache != null && !Cache.Equals(previousCache); previousCache = Cache; } - public IHasResponseFilter Copy() - { - return (IHasResponseFilter)this.MemberwiseClone(); - } + public IResponseFilterBase Copy() => (IResponseFilterBase)this.MemberwiseClone(); } //Only executed for the provided HTTP methods (GET, POST) @@ -111,7 +97,7 @@ public ContextualResponseFilterTestAttribute(ApplyTo applyTo) { } - public override void Execute(IHttpRequest req, IHttpResponse res, object responseDto) + public override void Execute(IRequest req, IResponse res, object responseDto) { var dto = responseDto as AttributeFilteredResponse; dto.ContextualResponseFilterExecuted = true; @@ -120,7 +106,7 @@ public override void Execute(IHttpRequest req, IHttpResponse res, object respons public class ThrowingFilterAttribute : RequestFilterAttribute { - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) + public override void Execute(IRequest req, IResponse res, object requestDto) { throw new ArgumentException("exception message"); } @@ -140,28 +126,76 @@ public object Any(ThrowingAttributeFiltered request) } } - [ResponseFilterTest] - [ContextualResponseFilterTest(ApplyTo.Delete | ApplyTo.Put)] public class AttributeFilteredResponse { - public bool ResponseFilterExecuted { get; set; } - public bool ContextualResponseFilterExecuted { get; set; } - public bool RequestFilterExecuted { get; set; } + public bool InheritedRequestFilterExecuted { get; set; } public bool ContextualRequestFilterExecuted { get; set; } + public bool ResponseFilterExecuted { get; set; } + public bool ContextualResponseFilterExecuted { get; set; } + public bool InheritedResponseFilterExecuted { get; set; } + public bool RequestFilterDependenyIsResolved { get; set; } public bool ResponseFilterDependencyIsResolved { get; set; } + + } + + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class PriorityAttribute : RequestFilterAttribute + { + public string Name { get; set; } + + public PriorityAttribute(int priority, string name) + { + Priority = priority; + Name = name; + } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var dto = (PriorityAttributeTest)requestDto; + dto.Names.Add(Name); + } + } + + public class PriorityAttributeTest : IReturn + { + public PriorityAttributeTest() + { + this.Names = new List(); + } + + public List Names { get; set; } } - public class AttributeFilteredService : IService + public class PriortyAttributeService : Service { - public object Execute(AttributeFiltered request) + [Priority(3, "3rd")] + [Priority(2, "2nd")] + [Priority(1, "1st")] + public object Any(PriorityAttributeTest request) { - return new AttributeFilteredResponse() { + return request; + } + } + + [InheritedRequestFilter] + [InheritedResponseFilter] + public class AttributeFilteredServiceBase : IService { } + + public class AttributeAttributeFilteredService : AttributeFilteredServiceBase + { + [ResponseFilterTest] + [ContextualResponseFilterTest(ApplyTo.Delete | ApplyTo.Put)] + public object Any(AttributeFiltered request) + { + return new AttributeFilteredResponse + { ResponseFilterExecuted = false, ContextualResponseFilterExecuted = false, RequestFilterExecuted = request.RequestFilterExecuted, + InheritedRequestFilterExecuted = request.InheritedRequestFilterExecuted, ContextualRequestFilterExecuted = request.ContextualRequestFilterExecuted, RequestFilterDependenyIsResolved = request.RequestFilterDependenyIsResolved, ResponseFilterDependencyIsResolved = false @@ -169,29 +203,48 @@ public object Execute(AttributeFiltered request) } } + public class InheritedRequestFilterAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFiltered)requestDto; + dto.InheritedRequestFilterExecuted = true; + } + } + + public class InheritedResponseFilterAttribute : ResponseFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object responseDto) + { + var dto = (AttributeFilteredResponse)responseDto; + dto.InheritedResponseFilterExecuted = true; + } + } + [TestFixture] public class AttributeFiltersTest { - private const string ListeningOn = "http://localhost:82/"; - private const string ServiceClientBaseUri = "http://localhost:82/"; + private const string ListeningOn = "http://localhost:1337/"; + private const string ServiceClientBaseUri = "http://localhost:1337/"; public class AttributeFiltersAppHostHttpListener : AppHostHttpListenerBase { public AttributeFiltersAppHostHttpListener() - : base("Attribute Filters Tests", typeof(AttributeFilteredService).Assembly) { } + : base("Attribute Filters Tests", typeof(AttributeAttributeFilteredService).Assembly) + { } public override void Configure(Funq.Container container) { container.Register(c => new MemoryCacheClient()).ReusedWithin(Funq.ReuseScope.None); - SetConfig(new EndpointHostConfig { DebugMode = true }); //show stacktraces + SetConfig(new HostConfig { DebugMode = true }); //show stacktraces } } AttributeFiltersAppHostHttpListener appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { appHost = new AttributeFiltersAppHostHttpListener(); @@ -199,13 +252,18 @@ public void OnTestFixtureSetUp() appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); } - static IServiceClient[] ServiceClients = + public IServiceClient GetServiceClient() + { + return new JsonServiceClient(ServiceClientBaseUri); + } + + static IServiceClient[] ServiceClients = { new JsonServiceClient(ServiceClientBaseUri), new XmlServiceClient(ServiceClientBaseUri), @@ -222,13 +280,15 @@ public void Request_and_Response_Filters_are_executed_using_ServiceClient(IServi new AttributeFiltered { RequestFilterExecuted = false }); Assert.IsTrue(response.RequestFilterExecuted); Assert.IsTrue(response.ResponseFilterExecuted); + Assert.IsTrue(response.InheritedRequestFilterExecuted); + Assert.IsTrue(response.InheritedResponseFilterExecuted); Assert.IsFalse(response.ContextualRequestFilterExecuted); Assert.IsFalse(response.ContextualResponseFilterExecuted); Assert.IsTrue(response.RequestFilterDependenyIsResolved); Assert.IsTrue(response.ResponseFilterDependencyIsResolved); } - static IRestClient[] RestClients = + static IRestClient[] RestClients = { new JsonServiceClient(ServiceClientBaseUri), new XmlServiceClient(ServiceClientBaseUri), @@ -288,6 +348,18 @@ public void Multi_Contextual_Request_and_Response_Filters_are_executed_using_Res Assert.IsTrue(response.ResponseFilterDependencyIsResolved); } + [Test] + public void Does_order_action_attributes_by_priority() + { + var client = GetServiceClient(); + + var response = client.Post(new PriorityAttributeTest()); + + response.PrintDump(); + + Assert.That(response.Names, Is.EqualTo(new[] { "1st", "2nd", "3rd" })); + } + public class ExecutedFirstAttribute : RequestFilterAttribute { public ExecutedFirstAttribute() @@ -295,7 +367,7 @@ public ExecutedFirstAttribute() Priority = int.MinValue; } - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) + public override void Execute(IRequest req, IResponse res, object requestDto) { var dto = (AttributeFiltered)requestDto; dto.AttrsExecuted.Add(GetType().Name); @@ -312,15 +384,13 @@ public class DummyHolder { } [Test] public void RequestFilters_are_prioritized() { - EndpointHost.ServiceManager = new ServiceManager(typeof(DummyHolder).Assembly); - - EndpointHost.ServiceManager.Metadata.Add(typeof(AttributeFilteredService), typeof(DummyHolder), null); + appHost.Metadata.Add(typeof(AttributeAttributeFilteredService), typeof(DummyHolder), null); var attributes = FilterAttributeCache.GetRequestFilterAttributes(typeof(DummyHolder)); var attrPriorities = attributes.ToList().ConvertAll(x => x.Priority); - Assert.That(attrPriorities, Is.EquivalentTo(new[] { int.MinValue, -100, -90, -80, 0 })); + Assert.That(attrPriorities, Is.EquivalentTo(new[] { int.MinValue, -100, -90, -80, 0, 0 })); - var execOrder = new IHasRequestFilter[attributes.Length]; + var execOrder = new IRequestFilterBase[attributes.Length]; var i = 0; for (; i < attributes.Length && attributes[i].Priority < 0; i++) { @@ -337,8 +407,7 @@ public void RequestFilters_are_prioritized() } var execOrderPriorities = execOrder.ToList().ConvertAll(x => x.Priority); - Console.WriteLine(execOrderPriorities.Dump()); - Assert.That(execOrderPriorities, Is.EquivalentTo(new[] { int.MinValue, -100, -90, -80, 0 })); + Assert.That(execOrderPriorities, Is.EquivalentTo(new[] { int.MinValue, -100, -90, -80, 0, 0 })); } } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTestAsync.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTestAsync.cs new file mode 100644 index 00000000000..a8d1be763a7 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AttributeFiltersTestAsync.cs @@ -0,0 +1,419 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using ServiceStack.Caching; +using ServiceStack.Common.Tests.ServiceClient.Web; +using NUnit.Framework; +using ServiceStack.Support.WebHost; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + + //Always executed + public class FilterTestAsyncAttribute : AttributeBase, IHasRequestFilterAsync + { + private static ICacheClient previousCache; + + public ICacheClient Cache { get; set; } + + public int Priority { get; set; } + + public Task RequestFilterAsync(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFilteredAsync)requestDto; + dto.AttrsExecuted.Add(GetType().Name); + dto.RequestFilterExecuted = true; + + //Check for equality to previous cache to ensure a filter attribute is no singleton + dto.RequestFilterDependenyIsResolved = Cache != null && !Cache.Equals(previousCache); + + previousCache = Cache; + return TypeConstants.EmptyTask; + } + + public IRequestFilterBase Copy() => (IRequestFilterBase)this.MemberwiseClone(); + } + + //Only executed for the provided HTTP methods (GET, POST) + public class ContextualFilterTestAsyncAttribute : RequestFilterAsyncAttribute + { + public ContextualFilterTestAsyncAttribute(ApplyTo applyTo) + : base(applyTo) {} + + public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFilteredAsync)requestDto; + dto.AttrsExecuted.Add(GetType().Name); + dto.ContextualRequestFilterExecuted = true; + return TypeConstants.EmptyTask; + } + } + + [Route("/attributefiltered-async")] + [FilterTestAsync] + [ContextualFilterTestAsync(ApplyTo.Delete | ApplyTo.Put)] + public class AttributeFilteredAsync + { + public AttributeFilteredAsync() + { + this.AttrsExecuted = new List(); + } + + public bool RequestFilterExecuted { get; set; } + public bool ContextualRequestFilterExecuted { get; set; } + public bool InheritedRequestFilterExecuted { get; set; } + public bool RequestFilterDependenyIsResolved { get; set; } + public List AttrsExecuted { get; set; } + } + + //Always executed + public class ResponseFilterTestAsyncAttribute : AttributeBase, IHasResponseFilterAsync + { + private static ICacheClient previousCache; + + public ICacheClient Cache { get; set; } + + public int Priority { get; set; } + + public Task ResponseFilterAsync(IRequest req, IResponse res, object response) + { + var dto = response.GetResponseDto() as AttributeFilteredAsyncResponse; + dto.ResponseFilterExecuted = true; + dto.ResponseFilterDependencyIsResolved = Cache != null && !Cache.Equals(previousCache); + + previousCache = Cache; + return TypeConstants.EmptyTask; + } + + public IResponseFilterBase Copy() => (IResponseFilterBase)this.MemberwiseClone(); + } + + //Only executed for the provided HTTP methods (GET, POST) + public class ContextualResponseFilterTestAsyncAttribute : ResponseFilterAsyncAttribute + { + public ContextualResponseFilterTestAsyncAttribute(ApplyTo applyTo) + : base(applyTo) + { + } + + public override Task ExecuteAsync(IRequest req, IResponse res, object responseDto) + { + var dto = responseDto as AttributeFilteredAsyncResponse; + dto.ContextualResponseFilterExecuted = true; + return TypeConstants.EmptyTask; + } + } + + public class ThrowingFilterAsyncAttribute : RequestFilterAsyncAttribute + { + public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto) + { + throw new ArgumentException("exception message"); + } + } + + [Route("/throwingattributefiltered-async")] + public class ThrowingAttributeFilteredAsync : IReturn + { + } + + [ThrowingFilter] + public class ThrowingAttributeFilteredAsyncService : IService + { + public object Any(ThrowingAttributeFilteredAsync request) + { + return "OK"; + } + } + + public class AttributeFilteredAsyncResponse + { + public bool RequestFilterExecuted { get; set; } + public bool InheritedRequestFilterExecuted { get; set; } + public bool ContextualRequestFilterExecuted { get; set; } + + public bool ResponseFilterExecuted { get; set; } + public bool ContextualResponseFilterExecuted { get; set; } + public bool InheritedResponseFilterExecuted { get; set; } + + public bool RequestFilterDependenyIsResolved { get; set; } + public bool ResponseFilterDependencyIsResolved { get; set; } + + } + + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class PriorityAsyncAttribute : RequestFilterAsyncAttribute + { + public string Name { get; set; } + + public PriorityAsyncAttribute(int priority, string name) + { + Priority = priority; + Name = name; + } + + public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto) + { + var dto = (PriorityAttributeTestAsync)requestDto; + dto.Names.Add(Name); + return TypeConstants.EmptyTask; + } + } + + public class PriorityAttributeTestAsync : IReturn + { + public PriorityAttributeTestAsync() + { + this.Names = new List(); + } + + public List Names { get; set; } + } + + public class PriorityAttributeAsyncService : Service + { + [PriorityAsync(3, "3rd")] + [PriorityAsync(2, "2nd")] + [PriorityAsync(1, "1st")] + public object Any(PriorityAttributeTestAsync request) + { + return request; + } + } + + [InheritedRequestFilterAsync] + [InheritedResponseFilterAsync] + public class AttributeFilteredServiceAsyncBase : IService { } + + public class AttributeFilteredAsyncService : AttributeFilteredServiceAsyncBase + { + [ResponseFilterTestAsync] + [ContextualResponseFilterTestAsync(ApplyTo.Delete | ApplyTo.Put)] + public object Any(AttributeFilteredAsync request) + { + return new AttributeFilteredAsyncResponse + { + ResponseFilterExecuted = false, + ContextualResponseFilterExecuted = false, + RequestFilterExecuted = request.RequestFilterExecuted, + InheritedRequestFilterExecuted = request.InheritedRequestFilterExecuted, + ContextualRequestFilterExecuted = request.ContextualRequestFilterExecuted, + RequestFilterDependenyIsResolved = request.RequestFilterDependenyIsResolved, + ResponseFilterDependencyIsResolved = false + }; + } + } + + public class InheritedRequestFilterAsyncAttribute : RequestFilterAsyncAttribute + { + public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFilteredAsync)requestDto; + dto.InheritedRequestFilterExecuted = true; + return TypeConstants.EmptyTask; + } + } + + public class InheritedResponseFilterAsyncAttribute : ResponseFilterAsyncAttribute + { + public override Task ExecuteAsync(IRequest req, IResponse res, object responseDto) + { + var dto = (AttributeFilteredAsyncResponse)responseDto; + dto.InheritedResponseFilterExecuted = true; + return TypeConstants.EmptyTask; + } + } + + [TestFixture] + public class AttributeFiltersAsyncTest + { + private const string ListeningOn = "http://localhost:1337/"; + private const string ServiceClientBaseUri = "http://localhost:1337/"; + + public class AppHost + : AppHostHttpListenerBase + { + + public AppHost() + : base("Attribute Filters Tests", typeof(AttributeAttributeFilteredService).Assembly) {} + + public override void Configure(Funq.Container container) + { + container.Register(c => new MemoryCacheClient()).ReusedWithin(Funq.ReuseScope.None); + SetConfig(new HostConfig { DebugMode = true }); //show stacktraces + } + } + + AppHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new AppHost(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + public IServiceClient GetServiceClient() + { + return new JsonServiceClient(ServiceClientBaseUri); + } + + static IServiceClient[] ServiceClients = + { + new JsonServiceClient(ServiceClientBaseUri), + new XmlServiceClient(ServiceClientBaseUri), + new JsvServiceClient(ServiceClientBaseUri) + //SOAP not supported in HttpListener + //new Soap11ServiceClient(ServiceClientBaseUri), + //new Soap12ServiceClient(ServiceClientBaseUri) + }; + + [Test, TestCaseSource("ServiceClients")] + public void Request_and_Response_Filters_are_executed_using_ServiceClient(IServiceClient client) + { + var response = client.Send( + new AttributeFilteredAsync { RequestFilterExecuted = false }); + Assert.IsTrue(response.RequestFilterExecuted); + Assert.IsTrue(response.ResponseFilterExecuted); + Assert.IsTrue(response.InheritedRequestFilterExecuted); + Assert.IsTrue(response.InheritedResponseFilterExecuted); + Assert.IsFalse(response.ContextualRequestFilterExecuted); + Assert.IsFalse(response.ContextualResponseFilterExecuted); + Assert.IsTrue(response.RequestFilterDependenyIsResolved); + Assert.IsTrue(response.ResponseFilterDependencyIsResolved); + } + + static IRestClient[] RestClients = + { + new JsonServiceClient(ServiceClientBaseUri), + new XmlServiceClient(ServiceClientBaseUri), + new JsvServiceClient(ServiceClientBaseUri) + }; + + [Test] + public void Proper_exception_is_serialized_to_client() + { + var client = new HtmlServiceClient(ServiceClientBaseUri); + client.SetBaseUri(ServiceClientBaseUri); + + try + { + client.Get(new ThrowingAttributeFilteredAsync()); + } + catch (WebServiceException e) + { + //Ensure we have stack trace present + Assert.IsTrue(e.ResponseBody.Contains("ThrowingFilterAttribute"), "No stack trace in the response (it's probably empty)"); + } + } + + [Test, TestCaseSource("RestClients")] + public void Request_and_Response_Filters_are_executed_using_RestClient(IRestClient client) + { + var response = client.Post("attributefiltered-async", new AttributeFilteredAsync { RequestFilterExecuted = false }); + Assert.IsTrue(response.RequestFilterExecuted); + Assert.IsTrue(response.ResponseFilterExecuted); + Assert.IsFalse(response.ContextualRequestFilterExecuted); + Assert.IsFalse(response.ContextualResponseFilterExecuted); + Assert.IsTrue(response.RequestFilterDependenyIsResolved); + Assert.IsTrue(response.ResponseFilterDependencyIsResolved); + } + + [Test, TestCaseSource("RestClients")] + public void Contextual_Request_and_Response_Filters_are_executed_using_RestClient(IRestClient client) + { + var response = client.Delete("attributefiltered-async"); + Assert.IsTrue(response.RequestFilterExecuted); + Assert.IsTrue(response.ResponseFilterExecuted); + Assert.IsTrue(response.ContextualRequestFilterExecuted); + Assert.IsTrue(response.ContextualResponseFilterExecuted); + Assert.IsTrue(response.RequestFilterDependenyIsResolved); + Assert.IsTrue(response.ResponseFilterDependencyIsResolved); + } + + [Test, TestCaseSource("RestClients")] + public void Multi_Contextual_Request_and_Response_Filters_are_executed_using_RestClient(IRestClient client) + { + var response = client.Put("attributefiltered-async", new AttributeFilteredAsync { RequestFilterExecuted = false }); + Assert.IsTrue(response.RequestFilterExecuted); + Assert.IsTrue(response.ResponseFilterExecuted); + Assert.IsTrue(response.ContextualRequestFilterExecuted); + Assert.IsTrue(response.ContextualResponseFilterExecuted); + Assert.IsTrue(response.RequestFilterDependenyIsResolved); + Assert.IsTrue(response.ResponseFilterDependencyIsResolved); + } + + [Test] + public void Does_order_action_attributes_by_priority() + { + var client = GetServiceClient(); + + var response = client.Post(new PriorityAttributeTestAsync()); + + response.PrintDump(); + + Assert.That(response.Names, Is.EqualTo(new[] { "1st", "2nd", "3rd" })); + } + + public class ExecutedFirstAsyncAttribute : RequestFilterAsyncAttribute + { + public ExecutedFirstAsyncAttribute() + { + Priority = int.MinValue; + } + + public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto) + { + var dto = (AttributeFilteredAsync)requestDto; + dto.AttrsExecuted.Add(GetType().Name); + return TypeConstants.EmptyTask; + } + } + + [ExecutedFirstAsync] + [FilterTestAsync] + [RequiredRole("test")] + [Authenticate] + [RequiredPermission("test")] + public class DummyHolderAsync { } + + [Test] + public void RequestFilters_are_prioritized() + { + appHost.Metadata.Add(typeof(AttributeFilteredAsyncService), typeof(DummyHolderAsync), null); + + var attributes = FilterAttributeCache.GetRequestFilterAttributes(typeof(DummyHolderAsync)); + var attrPriorities = attributes.ToList().ConvertAll(x => x.Priority); + Assert.That(attrPriorities, Is.EquivalentTo(new[] { int.MinValue, -100, -90, -80, 0, 0 })); + + var execOrder = new IRequestFilterBase[attributes.Length]; + var i = 0; + for (; i < attributes.Length && attributes[i].Priority < 0; i++) + { + execOrder[i] = attributes[i]; + Console.WriteLine(attributes[i].Priority); + } + + Console.WriteLine("break;"); + + for (; i < attributes.Length; i++) + { + execOrder[i] = attributes[i]; + Console.WriteLine(attributes[i].Priority); + } + + var execOrderPriorities = execOrder.ToList().ConvertAll(x => x.Priority); + Assert.That(execOrderPriorities, Is.EquivalentTo(new[] { int.MinValue, -100, -90, -80, 0, 0 })); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthCaseInsensitiveUserNameTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthCaseInsensitiveUserNameTests.cs new file mode 100644 index 00000000000..37763f00acc --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthCaseInsensitiveUserNameTests.cs @@ -0,0 +1,286 @@ +using System; +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AuthSaveUserNameAsLowerCaseTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(AuthCaseInsensitiveUserNameTests), typeof(AuthCaseInsensitiveUserNameTests).Assembly) {} + + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new [] + { + new CredentialsAuthProvider(AppSettings), + }) + { + IncludeRegistrationService = true, + SaveUserNamesInLowerCase = true, + }); + } + } + + private readonly ServiceStackHost appHost; + public AuthSaveUserNameAsLowerCaseTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_register_and_authenticate_with_exact_UserName() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var registerResponse = client.Post(new Register + { + UserName = "Exact", + Email = "exact@gmail.com", + FirstName = "First", + LastName = "Last", + DisplayName = "DisplayName", + Password = "test" + }); + + var response = client.Post(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "Exact", + Password = "test" + }); + + Assert.That(response.UserName, Is.EqualTo("Exact")); + } + + [Test] + public void Can_register_and_login_using_different_cases() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var registerResponse = client.Post(new Register + { + UserName = "Mythz", + Email = "mythz@gmail.com", + FirstName = "First", + LastName = "Last", + DisplayName = "DisplayName", + Password = "test" + }); + + var response = client.Post(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "MythZ", + Password = "test" + }); + + Assert.That(response.UserName, Is.EqualTo("MythZ")); + } + } + + public class AuthCaseInsensitiveUserNameTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(AuthCaseInsensitiveUserNameTests), typeof(AuthCaseInsensitiveUserNameTests).Assembly) {} + + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new [] + { + new CredentialsAuthProvider(AppSettings), + }) + { + IncludeRegistrationService = true, + }); + } + } + + private readonly ServiceStackHost appHost; + public AuthCaseInsensitiveUserNameTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_register_and_authenticate_with_exact_UserName() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var registerResponse = client.Post(new Register + { + UserName = "Exact", + Email = "exact@gmail.com", + FirstName = "First", + LastName = "Last", + DisplayName = "DisplayName", + Password = "test" + }); + + var response = client.Post(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "Exact", + Password = "test" + }); + + Assert.That(response.UserName, Is.EqualTo("Exact")); + } + + [Test] + public void Can_register_and_login_using_different_cases_using_case_insensitive_fallback() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var registerResponse = client.Post(new Register + { + UserName = "Mythz", + Email = "mythz@gmail.com", + FirstName = "First", + LastName = "Last", + DisplayName = "DisplayName", + Password = "test" + }); + + var response = client.Post(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "MythZ", + Password = "test" + }); + + Assert.That(response.UserName, Is.EqualTo("MythZ")); + } + } + + public class AuthCaseSensitiveUserNameTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(AuthCaseInsensitiveUserNameTests), typeof(AuthCaseInsensitiveUserNameTests).Assembly) {} + + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve()) + { + ForceCaseInsensitiveUserNameSearch = false, + }); + + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new [] + { + new CredentialsAuthProvider(AppSettings), + }) + { + IncludeRegistrationService = true, + }); + } + } + + private readonly ServiceStackHost appHost; + public AuthCaseSensitiveUserNameTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_register_and_authenticate_with_exact_UserName() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var registerResponse = client.Post(new Register + { + UserName = "Exact", + Email = "exact@gmail.com", + FirstName = "First", + LastName = "Last", + DisplayName = "DisplayName", + Password = "test" + }); + + var response = client.Post(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "Exact", + Password = "test" + }); + + Assert.That(response.UserName, Is.EqualTo("Exact")); + } + + [Test] + public void Can_disable_non_index_fallback() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var registerResponse = client.Post(new Register + { + UserName = "Mythz", + Email = "mythz@gmail.com", + FirstName = "First", + LastName = "Last", + DisplayName = "DisplayName", + Password = "test" + }); + + try + { + var response = client.Post(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "MythZ", + Password = "test" + }); + + Assert.Fail("Should fail"); + } + catch (WebServiceException) {} + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthDigestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthDigestTests.cs new file mode 100644 index 00000000000..a85c9330888 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthDigestTests.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AuthDigestTests + { + protected virtual string VirtualDirectory { get { return ""; } } + protected virtual string ListeningOn { get { return "http://localhost:1337/"; } } + protected virtual string WebHostUrl { get { return "http://mydomain.com"; } } + + public class AuthDigestAppHost : AuthAppHost + { + public AuthDigestAppHost(string webHostUrl, Action configureFn = null) + : base(webHostUrl, configureFn) + { } + + public override IAuthProvider[] GetAuthProviders() + { + return new[] { new DigestAuthProvider(AppSettings) }; + } + } + + ServiceStackHost appHost; + [OneTimeSetUp] + public void OnTestFixtureSetUp() => + appHost = new AuthDigestAppHost(WebHostUrl, Configure) + .Init() + .Start(ListeningOn); + + [OneTimeTearDown] + public void OnTestFixtureTearDown() => appHost.Dispose(); + + public virtual void Configure(Container container) { } + + IServiceClient GetClientWithUserPassword() + { + return new JsonServiceClient(ListeningOn) + { + UserName = AuthTests.UserName, + Password = AuthTests.Password + }; + } + + [Test] + public void Does_work_with_DigestAuth() + { + try + { + var client = GetClientWithUserPassword(); + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public async Task Does_work_with_DigestAuth_Async() + { + try + { + var client = GetClientWithUserPassword(); + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryQueryTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryQueryTests.cs new file mode 100644 index 00000000000..73beefbf664 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryQueryTests.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Script; +using ServiceStack.Testing; + +using Raven.Client; +using ServiceStack.Authentication.RavenDb; +using ServiceStack.DataAnnotations; +using Raven.Client.Documents; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class MemoryAuthRepositoryQueryTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) => + new MemoryAuthRepositoryTests().ConfigureAuthRepo(container); + } + + public class RedisAuthRepositoryQueryTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) => + new RedisAuthRepositoryTests().ConfigureAuthRepo(container); + } + + public class OrmLiteAuthRepositoryQueryTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) => + new OrmLiteAuthRepositoryTests().ConfigureAuthRepo(container); + } + + public class OrmLiteAuthRepositoryQueryDistinctRolesTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + new OrmLiteAuthRepositoryDistinctRolesTests().ConfigureAuthRepo(container); + } + } + + [NUnit.Framework.Ignore("Requires RavenDB")] + public class RavenDbAuthRepositoryQueryTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) => + new RavenDbAuthRepositoryTests().ConfigureAuthRepo(container); + } + + [NUnit.Framework.Ignore("Requires MongoDB")] + public class MongoDbAuthRepositoryQueryTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) => + new MongoDbAuthRepositoryTests().ConfigureAuthRepo(container); + } + + [NUnit.Framework.Ignore("Requires DynamoDB")] + public class DynamoDbAuthRepositoryQueryTests : AuthRepositoryQueryTestsBase + { + public override void ConfigureAuthRepo(Container container) => + new DynamoDbAuthRepositoryTests().ConfigureAuthRepo(container); + } + + [TestFixture] + public abstract class AuthRepositoryQueryTestsBase + { + protected ServiceStackHost appHost; + + public abstract void ConfigureAuthRepo(Container container); + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost(typeof(AuthRepositoryQueryTestsBase).Assembly) + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { + new CredentialsAuthProvider(), + }) + { + IncludeRegistrationService = true, + }); + + host.Plugins.Add(new SharpPagesFeature()); + }, + ConfigureContainer = container => { + + ConfigureAuthRepo(container); + + var authRepo = container.Resolve(); + if (authRepo is IClearable clearable) + { + try { clearable.Clear(); } catch {} + } + + authRepo.InitSchema(); + + SeedData(authRepo); + } + }.Init(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + void SeedData(IAuthRepository authRepo) + { + var newUser = authRepo.CreateUserAuth(new AppUser + { + Id = 1, + DisplayName = "Test User", + Email = "user@gmail.com", + FirstName = "Test", + LastName = "User", + }, "p@55wOrd"); + + newUser = authRepo.CreateUserAuth(new AppUser + { + Id = 2, + DisplayName = "Test Manager", + Email = "manager@gmail.com", + FirstName = "Test", + LastName = "Manager", + }, "p@55wOrd"); + authRepo.AssignRoles(newUser, roles:new[]{ "Manager" }); + + newUser = authRepo.CreateUserAuth(new AppUser + { + Id = 3, + DisplayName = "Admin User", + Email = "admin@gmail.com", + FirstName = "Admin", + LastName = "Super User", + }, "p@55wOrd"); + authRepo.AssignRoles(newUser, roles:new[]{ "Admin" }); + } + + private static bool IsRavenDb(IAuthRepository authRepo) => authRepo.GetType().Name.StartsWith("Raven"); + + private static void AssertHasIdentity(IAuthRepository authRepo, List allUsers) + { + Assert.That(IsRavenDb(authRepo) + ? allUsers.Cast().All(x => x.Key != null) + : allUsers.All(x => x.Id > 0)); + } + + [Test] + public void Can_QueryUserAuth_GetUserAuths() + { + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + var allUsers = authRepo.GetUserAuths(); + Assert.That(allUsers.Count, Is.EqualTo(3)); + AssertHasIdentity(authRepo, allUsers); + + Assert.That(allUsers.All(x => x.Email != null)); + + allUsers = authRepo.GetUserAuths(skip:1); + Assert.That(allUsers.Count, Is.EqualTo(2)); + allUsers = authRepo.GetUserAuths(take:2); + Assert.That(allUsers.Count, Is.EqualTo(2)); + allUsers = authRepo.GetUserAuths(skip:1,take:2); + Assert.That(allUsers.Count, Is.EqualTo(2)); + } + } + + [Test] + public void Can_QueryUserAuth_GetUserAuths_OrderBy() + { + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + var allUsers = authRepo.GetUserAuths(orderBy:nameof(UserAuth.Id)); + Assert.That(allUsers.Count, Is.EqualTo(3)); + Assert.That(allUsers[0].Email, Is.EqualTo("user@gmail.com")); + + var idField = IsRavenDb(authRepo) + ? nameof(AppUser.Key) + : nameof(UserAuth.Id); + allUsers = authRepo.GetUserAuths(orderBy: idField + " DESC"); + Assert.That(allUsers.Count, Is.EqualTo(3)); + Assert.That(allUsers[0].Email, Is.EqualTo("admin@gmail.com")); + + allUsers = authRepo.GetUserAuths(orderBy:nameof(UserAuth.DisplayName)); + Assert.That(allUsers.Count, Is.EqualTo(3)); + Assert.That(allUsers[0].DisplayName, Is.EqualTo("Admin User")); + + allUsers = authRepo.GetUserAuths(orderBy:nameof(UserAuth.Email)); + Assert.That(allUsers.Count, Is.EqualTo(3)); + Assert.That(allUsers[0].Email, Is.EqualTo("admin@gmail.com")); + + allUsers = authRepo.GetUserAuths(orderBy:nameof(UserAuth.CreatedDate) + " DESC"); + Assert.That(allUsers.Count, Is.EqualTo(3)); + Assert.That(allUsers[0].DisplayName, Is.EqualTo("Admin User")); + } + } + + [Test] + public void Can_QueryUserAuth_SearchUserAuths() + { + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + var allUsers = authRepo.SearchUserAuths("gmail.com"); + Assert.That(allUsers.Count, Is.EqualTo(3)); + AssertHasIdentity(authRepo, allUsers); + Assert.That(allUsers.All(x => x.Email != null)); + + allUsers = authRepo.SearchUserAuths(query:"gmail.com",skip:1); + Assert.That(allUsers.Count, Is.EqualTo(2)); + allUsers = authRepo.SearchUserAuths(query:"gmail.com",take:2); + Assert.That(allUsers.Count, Is.EqualTo(2)); + allUsers = authRepo.SearchUserAuths(query:"gmail.com",skip:1,take:2); + Assert.That(allUsers.Count, Is.EqualTo(2)); + + if (!IsRavenDb(authRepo)) // RavenDB only searches UserName/Email and only StartsWith/EndsWith + { + allUsers = authRepo.SearchUserAuths(query:"Test"); + Assert.That(allUsers.Count, Is.EqualTo(2)); + + allUsers = authRepo.SearchUserAuths(query:"Admin"); + Assert.That(allUsers.Count, Is.EqualTo(1)); + + allUsers = authRepo.SearchUserAuths(query:"Test",skip:1,take:1,orderBy:nameof(UserAuth.Email)); + Assert.That(allUsers.Count, Is.EqualTo(1)); + Assert.That(allUsers[0].Email, Is.EqualTo("user@gmail.com")); + } + } + } + + [Test] + public void Can_QueryUserAuth_in_Script() + { + var context = appHost.AssertPlugin(); + Assert.That(context.EvaluateScript("{{ authRepo.getUserAuths() | count }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ authRepo.getUserAuths({ orderBy:'Id' }) | map => it.Id | join }}"), Is.EqualTo("1,2,3")); + Assert.That(context.EvaluateScript("{{ authRepo.getUserAuths({ skip:1, orderBy:'Id' }) | map => it.Id | join }}"), Is.EqualTo("2,3")); + Assert.That(context.EvaluateScript("{{ authRepo.getUserAuths({ take:2, orderBy:'Id' }) | map => it.Id | join }}"), Is.EqualTo("1,2")); + Assert.That(context.EvaluateScript("{{ authRepo.getUserAuths({ skip:1, take:2, orderBy:'Id' }) | map => it.Id | join }}"), Is.EqualTo("2,3")); + + Assert.That(context.EvaluateScript("{{ authRepo.searchUserAuths({ query:'gmail.com',orderBy:'Id'}) | map => it.Id | join }}"), Is.EqualTo("1,2,3")); + Assert.That(context.EvaluateScript("{{ authRepo.searchUserAuths({ query:'gmail.com',skip:1,take:1,orderBy:'Id'}) | map => it.Id | join }}"), Is.EqualTo("2")); + + if (!IsRavenDb(appHost.TryResolve())) + { + Assert.That(context.EvaluateScript("{{ authRepo.searchUserAuths({ query:'gmail.com', orderBy:'LastName DESC' }) | map => it.Id | join }}"), Is.EqualTo("1,3,2")); + Assert.That(context.EvaluateScript("{{ authRepo.searchUserAuths({ query:'Test', orderBy:'Email' }) | map => it.Id | join }}"), Is.EqualTo("2,1")); + Assert.That(context.EvaluateScript("{{ authRepo.searchUserAuths({ query:'Test', orderBy:'Id' }) | map => it.Id | join }}"), Is.EqualTo("1,2")); + } + } + + [Test] + public void Can_fetch_roles_and_permissions() + { + var authRepo = appHost.GetAuthRepository(); + using (authRepo as IDisposable) + { + if (authRepo is IManageRoles manageRoles) + { + manageRoles.GetRolesAndPermissions("3", + out var roles, out var permissions); + + Assert.That(roles, Is.EquivalentTo(new[] { "Admin" })); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryTests.cs new file mode 100644 index 00000000000..89908f997fd --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryTests.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections.Generic; +using System.Net; +using Amazon.DynamoDBv2; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Testing; +using ServiceStack.DataAnnotations; + +using MongoDB.Driver; +using ServiceStack.Authentication.MongoDb; + +using ServiceStack.Authentication.RavenDb; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Text; +using Raven.Client; +using Raven.Client.Documents; +using Raven.Client.Documents.Operations; +using Raven.Client.Documents.Queries; +using ServiceStack.Aws.DynamoDb; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + // Custom UserAuth Data Model with extended Metadata properties + [Index(Name = nameof(Key))] + public class AppUser : UserAuth + { + public string Key { get; set; } + public string ProfileUrl { get; set; } + public string LastLoginIp { get; set; } + public DateTime? LastLoginDate { get; set; } + } + + [Index(Name = nameof(Key))] + public class AppUserDetails : UserAuthDetails + { + public string Key { get; set; } + } + + public class MemoryAuthRepositoryTests : AuthRepositoryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => new InMemoryAuthRepository()); + } + } + + public class RedisAuthRepositoryTests : AuthRepositoryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => new RedisManagerPool()); + container.Register(c => + new RedisAuthRepository(c.Resolve())); + } + } + + public class OrmLiteAuthRepositoryTests : AuthRepositoryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider) { + AutoDisposeConnection = false, + }); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + } + } + + public class OrmLiteAuthRepositoryDistinctRolesTests : AuthRepositoryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider) { + AutoDisposeConnection = false, + }); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve()) { + UseDistinctRoleTables = true, + }); + } + } + + [NUnit.Framework.Ignore("Requires RavenDB")] + public class RavenDbAuthRepositoryTests : AuthRepositoryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + var store = new DocumentStore + { + Urls = new[] // URL to the Server, + { // or list of URLs + "http://localhost:8080" // to all Cluster Servers (Nodes) + }, + Database = "test", // Default database that DocumentStore will interact with + Conventions = { + } + }; + store.Conventions.FindIdentityProperty = RavenDbUserAuthRepository.FindIdentityProperty; + + container.AddSingleton(store.Initialize()); + + container.Register(c => + new RavenDbUserAuthRepository(c.Resolve())); + + var response = $"http://localhost:8080/databases/test/queries?allowStale=False&maxOpsPerSec=&details=False" + .SendStringToUrl(HttpMethods.Delete, "{\"Query\":\"from AppUsers\",\"QueryParameters\":null}"); + } + } + + [NUnit.Framework.Ignore("Requires MongoDB")] + public class MongoDbAuthRepositoryTests : AuthRepositoryTestsBase + { + public override void ConfigureAuthRepo(Container container) + { + var mongoClient = new MongoClient(); + mongoClient.DropDatabase("MyApp"); + IMongoDatabase mongoDatabase = mongoClient.GetDatabase("MyApp"); + + container.AddSingleton(mongoDatabase); + container.AddSingleton(c => + new MongoDbAuthRepository(c.Resolve(), createMissingCollections:true)); + } + } + + [NUnit.Framework.Ignore("Requires DynamoDB")] + public class DynamoDbAuthRepositoryTests : AuthRepositoryTestsBase + { + public static IPocoDynamo CreatePocoDynamo() + { + var dynamoClient = CreateDynamoDbClient(); + var db = new PocoDynamo(dynamoClient); + return db; + } + + public static string DynamoDbUrl = Environment.GetEnvironmentVariable("CI_DYNAMODB") + ?? "http://localhost:8000"; + + public static AmazonDynamoDBClient CreateDynamoDbClient() + { + var dynamoClient = new AmazonDynamoDBClient("keyId", "key", new AmazonDynamoDBConfig { + ServiceURL = DynamoDbUrl, + }); + return dynamoClient; + } + + public override void ConfigureAuthRepo(Container container) + { + var db = CreatePocoDynamo(); + container.AddSingleton(db); + container.Register(c => + new DynamoDbAuthRepository(c.Resolve())); + } + } + + public abstract class AuthRepositoryTestsBase + { + private ServiceStackHost appHost; + + public abstract void ConfigureAuthRepo(Container container); + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost(typeof(AuthRepositoryQueryTestsBase).Assembly) + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { + new CredentialsAuthProvider(), + }) + { + IncludeRegistrationService = true, + }); + + host.Plugins.Add(new SharpPagesFeature()); + }, + ConfigureContainer = container => { + ConfigureAuthRepo(container); + var authRepo = container.Resolve(); + + if (authRepo is IClearable clearable) + { + try { clearable.Clear(); } catch {} + } + + authRepo.InitSchema(); + } + }.Init(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + const string Password = "p@55wOrd"; + + [Test] + public void Can_CreateUserAuth() + { + var authRepo = appHost.TryResolve(); + + var newUser = authRepo.CreateUserAuth(new AppUser + { + DisplayName = "Test User", + Email = "user@gmail.com", + FirstName = "Test", + LastName = "User", + }, Password); + + Assert.That(newUser.Email, Is.EqualTo("user@gmail.com")); + + var fromDb = authRepo.GetUserAuth((newUser as AppUser)?.Key ?? newUser.Id.ToString()); + Assert.That(fromDb.Email, Is.EqualTo("user@gmail.com")); + + newUser.FirstName = "Updated"; + authRepo.SaveUserAuth(newUser); + + var newSession = SessionFeature.CreateNewSession(null, "SESSION_ID"); + newSession.PopulateSession(newUser); + + var updatedUser = authRepo.GetUserAuth(newSession.UserAuthId); + Assert.That(updatedUser, Is.Not.Null); + Assert.That(updatedUser.FirstName, Is.EqualTo("Updated")); + + Assert.That(authRepo.TryAuthenticate(newUser.Email, Password, out var authUser)); + Assert.That(authUser.FirstName, Is.EqualTo(updatedUser.FirstName)); + + authRepo.DeleteUserAuth(newSession.UserAuthId); + var deletedUserAuth = authRepo.GetUserAuth(newSession.UserAuthId); + Assert.That(deletedUserAuth, Is.Null); + } + + [Test] + public void Can_AddUserAuthDetails() + { + var authRepo = appHost.TryResolve(); + + var newUser = authRepo.CreateUserAuth(new AppUser + { + DisplayName = "Facebook User", + Email = "user@fb.com", + FirstName = "Face", + LastName = "Book", + }, "p@55wOrd"); + + var newSession = SessionFeature.CreateNewSession(null, "SESSION_ID"); + newSession.PopulateSession(newUser); + Assert.That(newSession.Email, Is.EqualTo("user@fb.com")); + + var fbAuthTokens = new AuthTokens + { + Provider = FacebookAuthProvider.Name, + AccessTokenSecret = "AAADDDCCCoR848BAMkQIZCRIKnVWZAvcKWqo7Ibvec8ebV9vJrfZAz8qVupdu5EbjFzmMmbwUFDbcNDea9H6rOn5SVn8es7KYZD", + UserId = "123456", + DisplayName = "FB User", + FirstName = "FB", + LastName = "User", + Email = "user@fb.com", + }; + + var userAuthDetails = authRepo.CreateOrMergeAuthSession(newSession, fbAuthTokens); + Assert.That(userAuthDetails.Email, Is.EqualTo("user@fb.com")); + + var userAuthDetailsList = authRepo.GetUserAuthDetails(newSession.UserAuthId); + Assert.That(userAuthDetailsList.Count, Is.EqualTo(1)); + Assert.That(userAuthDetailsList[0].Email, Is.EqualTo("user@fb.com")); + + authRepo.DeleteUserAuth(newSession.UserAuthId); + userAuthDetailsList = authRepo.GetUserAuthDetails(newSession.UserAuthId); + Assert.That(userAuthDetailsList, Is.Empty); + var deletedUserAuth = authRepo.GetUserAuth(newSession.UserAuthId); + Assert.That(deletedUserAuth, Is.Null); + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryTestsAsync.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryTestsAsync.cs new file mode 100644 index 00000000000..bf34db65e4f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthRepositoryTestsAsync.cs @@ -0,0 +1,280 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Testing; +using ServiceStack.DataAnnotations; + +using MongoDB.Driver; +using ServiceStack.Authentication.MongoDb; + +using ServiceStack.Authentication.RavenDb; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Text; +using Raven.Client; +using Raven.Client.Documents; +using Raven.Client.Documents.Operations; +using Raven.Client.Documents.Queries; +using ServiceStack.Aws.DynamoDb; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class MemoryAuthRepositoryTestsAsync : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => new InMemoryAuthRepository()); + } + } + + public class UserAuthRepositoryAsyncWrapperTests : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => + new UserAuthRepositoryAsyncWrapper(new InMemoryAuthRepository())); + } + } + + public class RedisAuthRepositoryTestsAsync : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => new RedisManagerPool()); + container.Register(c => + new RedisAuthRepository(c.Resolve())); + } + } + + public class OrmLiteAuthRepositoryTestsAsync : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider) { + AutoDisposeConnection = false, + }); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + } + } + + public class OrmLiteAuthRepositoryDistinctRolesTestsAsync : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider) { + AutoDisposeConnection = false, + }); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve()) { + UseDistinctRoleTables = true, + }); + } + } + + [NUnit.Framework.Ignore("Requires RavenDB")] + public class RavenDbAuthRepositoryTestsAsync : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + var store = new DocumentStore + { + Urls = new[] // URL to the Server, + { // or list of URLs + "http://localhost:8080" // to all Cluster Servers (Nodes) + }, + Database = "test", // Default database that DocumentStore will interact with + Conventions = { + } + }; + store.Conventions.FindIdentityProperty = RavenDbUserAuthRepository.FindIdentityProperty; + + container.AddSingleton(store.Initialize()); + + container.Register(c => + new RavenDbUserAuthRepository(c.Resolve())); + + var response = $"http://localhost:8080/databases/test/queries?allowStale=False&maxOpsPerSec=&details=False" + .SendStringToUrl(HttpMethods.Delete, "{\"Query\":\"from AppUsers\",\"QueryParameters\":null}"); + } + } + + [NUnit.Framework.Ignore("Requires MongoDB")] + public class MongoDbAuthRepositoryTestsAsync : AuthRepositoryTestsAsyncBase + { + public override void ConfigureAuthRepo(Container container) + { + var mongoClient = new MongoClient(); + mongoClient.DropDatabase("MyApp"); + IMongoDatabase mongoDatabase = mongoClient.GetDatabase("MyApp"); + + container.AddSingleton(mongoDatabase); + container.AddSingleton(c => + new MongoDbAuthRepository(c.Resolve(), createMissingCollections:true)); + } + } + + [NUnit.Framework.Ignore("Requires DynamoDB")] + public class DynamoDbAuthRepositoryTestsAsync : AuthRepositoryTestsAsyncBase + { + public static IPocoDynamo CreatePocoDynamo() + { + var dynamoClient = CreateDynamoDbClient(); + var db = new PocoDynamo(dynamoClient); + return db; + } + + public static string DynamoDbUrl = Environment.GetEnvironmentVariable("CI_DYNAMODB") + ?? "http://localhost:8000"; + + public static AmazonDynamoDBClient CreateDynamoDbClient() + { + var dynamoClient = new AmazonDynamoDBClient("keyId", "key", new AmazonDynamoDBConfig { + ServiceURL = DynamoDbUrl, + }); + return dynamoClient; + } + + public override void ConfigureAuthRepo(Container container) + { + var db = CreatePocoDynamo(); + container.AddSingleton(db); + container.Register(c => + new DynamoDbAuthRepository(c.Resolve())); + } + } + + public abstract class AuthRepositoryTestsAsyncBase + { + private ServiceStackHost appHost; + + public abstract void ConfigureAuthRepo(Container container); + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost(typeof(AuthRepositoryQueryTestsBase).Assembly) + { + ConfigureAppHost = host => + { + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { + new CredentialsAuthProvider(), + }) + { + IncludeRegistrationService = true, + }); + + host.Plugins.Add(new SharpPagesFeature()); + }, + ConfigureContainer = container => { + ConfigureAuthRepo(container); + var authRepo = container.TryResolve() + ?? container.TryResolve() as IAuthRepositoryAsync + ?? new UserAuthRepositoryAsyncWrapper(container.TryResolve()); + + if (authRepo is IClearableAsync clearable) + { + try { clearable.ClearAsync().Wait(); } catch {} + } + + authRepo.InitSchema(); + } + }.Init(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + const string Password = "p@55wOrd"; + + [Test] + public async Task Can_CreateUserAuth() + { + var authRepo = appHost.GetAuthRepositoryAsync(); + + var newUser = await authRepo.CreateUserAuthAsync(new AppUser + { + DisplayName = "Test User", + Email = "user@gmail.com", + FirstName = "Test", + LastName = "User", + }, Password); + + Assert.That(newUser.Email, Is.EqualTo("user@gmail.com")); + + var fromDb = await authRepo.GetUserAuthAsync((newUser as AppUser)?.Key ?? newUser.Id.ToString()); + Assert.That(fromDb.Email, Is.EqualTo("user@gmail.com")); + + newUser.FirstName = "Updated"; + await authRepo.SaveUserAuthAsync(newUser); + + var newSession = SessionFeature.CreateNewSession(null, "SESSION_ID"); + newSession.PopulateSession(newUser); + + var updatedUser = await authRepo.GetUserAuthAsync(newSession.UserAuthId); + Assert.That(updatedUser, Is.Not.Null); + Assert.That(updatedUser.FirstName, Is.EqualTo("Updated")); + + var authUser = await authRepo.TryAuthenticateAsync(newUser.Email, Password); + Assert.That(authUser, Is.Not.Null); + Assert.That(authUser.FirstName, Is.EqualTo(updatedUser.FirstName)); + + await authRepo.DeleteUserAuthAsync(newSession.UserAuthId); + var deletedUserAuth = await authRepo.GetUserAuthAsync(newSession.UserAuthId); + Assert.That(deletedUserAuth, Is.Null); + } + + [Test] + public async Task Can_AddUserAuthDetails() + { + var authRepo = appHost.GetAuthRepositoryAsync(); + + var newUser = await authRepo.CreateUserAuthAsync(new AppUser + { + DisplayName = "Facebook User", + Email = "user@fb.com", + FirstName = "Face", + LastName = "Book", + }, "p@55wOrd"); + + var newSession = SessionFeature.CreateNewSession(null, "SESSION_ID"); + newSession.PopulateSession(newUser); + Assert.That(newSession.Email, Is.EqualTo("user@fb.com")); + + var fbAuthTokens = new AuthTokens + { + Provider = FacebookAuthProvider.Name, + AccessTokenSecret = "AAADDDCCCoR848BAMkQIZCRIKnVWZAvcKWqo7Ibvec8ebV9vJrfZAz8qVupdu5EbjFzmMmbwUFDbcNDea9H6rOn5SVn8es7KYZD", + UserId = "123456", + DisplayName = "FB User", + FirstName = "FB", + LastName = "User", + Email = "user@fb.com", + }; + + var userAuthDetails = await authRepo.CreateOrMergeAuthSessionAsync(newSession, fbAuthTokens); + Assert.That(userAuthDetails.Email, Is.EqualTo("user@fb.com")); + + var userAuthDetailsList = await authRepo.GetUserAuthDetailsAsync(newSession.UserAuthId); + Assert.That(userAuthDetailsList.Count, Is.EqualTo(1)); + Assert.That(userAuthDetailsList[0].Email, Is.EqualTo("user@fb.com")); + + await authRepo.DeleteUserAuthAsync(newSession.UserAuthId); + userAuthDetailsList = await authRepo.GetUserAuthDetailsAsync(newSession.UserAuthId); + Assert.That(userAuthDetailsList, Is.Empty); + var deletedUserAuth = await authRepo.GetUserAuthAsync(newSession.UserAuthId); + Assert.That(deletedUserAuth, Is.Null); + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthTests.cs index 130ed0a5a2b..9d105557388 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/AuthTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AuthTests.cs @@ -2,21 +2,17 @@ using System.IO; using System.Net; using System.Threading; +using System.Threading.Tasks; using System.Web; using Funq; using NUnit.Framework; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; +using ServiceStack.Auth; +using ServiceStack.Caching; using ServiceStack.Common.Tests.ServiceClient.Web; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Data; +using ServiceStack.OrmLite; using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; using ServiceStack.WebHost.IntegrationTests.Services; using System.Collections.Generic; @@ -24,7 +20,7 @@ namespace ServiceStack.WebHost.Endpoints.Tests { [Route("/secured")] - public class Secured + public class Secured : IReturn { public string Name { get; set; } } @@ -44,7 +40,7 @@ public class SecuredFileUpload } [Authenticate] - public class SecuredService : ServiceInterface.Service + public class SecuredService : Service { public object Post(Secured request) { @@ -58,13 +54,13 @@ public object Get(Secured request) public object Post(SecuredFileUpload request) { - var file = this.RequestContext.Files[0]; + var file = this.Request.Files[0]; return new FileUploadResponse { FileName = file.FileName, ContentLength = file.ContentLength, ContentType = file.ContentType, - Contents = new StreamReader(file.InputStream).ReadToEnd(), + Contents = file.InputStream.ReadToEnd(), CustomerId = request.CustomerId, CustomerName = request.CustomerName }; @@ -84,7 +80,7 @@ public class RequiresRoleResponse } [RequiredRole("TheRole")] - public class RequiresRoleService : ServiceInterface.Service + public class RequiresRoleService : Service { public object Any(RequiresRole request) { @@ -115,7 +111,7 @@ public RequiresAnyRoleResponse() } [RequiresAnyRole("TheRole", "TheRole2")] - public class RequiresAnyRoleService : ServiceInterface.Service + public class RequiresAnyRoleService : Service { public object Any(RequiresAnyRole request) { @@ -136,7 +132,7 @@ public class RequiresPermissionResponse } [RequiredPermission("ThePermission")] - public class RequiresPermissionService : ServiceInterface.Service + public class RequiresPermissionService : Service { public RequiresPermissionResponse Any(RequiresPermission request) { @@ -167,7 +163,7 @@ public RequiresAnyPermissionResponse() } [RequiresAnyPermission("ThePermission", "ThePermission2")] - public class RequiresAnyPermissionService : ServiceInterface.Service + public class RequiresAnyPermissionService : Service { public RequiresAnyPermissionResponse Any(RequiresAnyPermission request) { @@ -175,13 +171,39 @@ public RequiresAnyPermissionResponse Any(RequiresAnyPermission request) } } - public class CustomUserSession : AuthUserSession + public class CustomUserSession : WebSudoAuthUserSession { - public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, System.Collections.Generic.Dictionary authInfo) + public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, System.Collections.Generic.Dictionary authInfo) { - if (session.UserName == AuthTests.UserNameWithSessionRedirect) + if (session.UserAuthName == AuthTests.UserNameWithSessionRedirect) session.ReferrerUrl = AuthTests.SessionRedirectUrl; } + + public int Counter { get; set; } + } + + public class IncrSession : IReturn + { + public int? By { get; set; } + } + + [Route("/unsecure")] + public class Unsecure : IReturn + { + public string Name { get; set; } + } + + public class CustomUserSessionService : Service + { + public object Any(IncrSession request) + { + var session = SessionAs(); + session.Counter += request.By.GetValueOrDefault(1); + Request.SaveSession(session); + return session; + } + + public object Any(Unsecure request) => request; } public class CustomAuthProvider : AuthProvider @@ -191,12 +213,13 @@ public CustomAuthProvider() this.Provider = "custom"; } - public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null) + public override bool IsAuthorized(IAuthSession session, IAuthTokens tokens, Authenticate request = null) { return false; } - public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request) + public override Task AuthenticateAsync(IServiceBase authService, IAuthSession session, Authenticate request, + CancellationToken token = default) { throw new NotImplementedException(); } @@ -215,7 +238,7 @@ public class RequiresCustomAuthResponse } [Authenticate(Provider = "custom")] - public class RequiresCustomAuthService : ServiceInterface.Service + public class RequiresCustomAuthService : Service { public RequiresCustomAuthResponse Any(RequiresCustomAuth request) { @@ -223,16 +246,16 @@ public RequiresCustomAuthResponse Any(RequiresCustomAuth request) } } - public class CustomAuthenticateAttribute : ServiceStack.ServiceInterface.AuthenticateAttribute + public class CustomAuthenticateAttribute : AuthenticateAttribute { - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) + public override Task ExecuteAsync(IRequest req, IResponse res, object requestDto) { //Need to run SessionFeature filter since its not executed before this attribute (Priority -100) SessionFeature.AddSessionIdToRequestFilter(req, res, null); //Required to get req.GetSessionId() req.Items["TriedMyOwnAuthFirst"] = true; // let's simulate some sort of auth _before_ relaying to base class. - base.Execute(req, res, requestDto); + return base.ExecuteAsync(req, res, requestDto); } } @@ -249,7 +272,7 @@ public class CustomAuthAttrResponse } [CustomAuthenticate] - public class CustomAuthAttrService : ServiceInterface.Service + public class CustomAuthAttrService : Service { public CustomAuthAttrResponse Any(CustomAuthAttr request) { @@ -260,86 +283,152 @@ public CustomAuthAttrResponse Any(CustomAuthAttr request) } } - public class AuthTests + public class RequiresWebSudo : IReturn { - private const string ListeningOn = "http://localhost:82/"; + public string Name { get; set; } + } - private const string UserName = "user"; - private const string Password = "p@55word"; - public const string UserNameWithSessionRedirect = "user2"; - public const string PasswordForSessionRedirect = "p@55word2"; - public const string SessionRedirectUrl = "specialLandingPage.html"; - public const string LoginUrl = "specialLoginPage.html"; - public const string WebHostUrl = "http://mydomain.com"; - private const string EmailBasedUsername = "user@email.com"; - private const string PasswordForEmailBasedAccount = "p@55word3"; + public class RequiresWebSudoResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [WebSudoRequired] + public class RequiresWebSudoService : Service + { + public object Any(RequiresWebSudo request) + { + return new RequiresWebSudoResponse { Result = request.Name }; + } + } + + public class RequiresAuthAction : IReturn {} + public class RequiresRoleAction : IReturn {} + public class RequiresAuthRoleAction : IReturn {} + + public class ActionFilterAuthServices : Service + { + [Authenticate] + public object Any(RequiresAuthAction request) => request; + [RequiredRole(nameof(RequiresRoleAction))] + public object Any(RequiresRoleAction request) => request; + [Authenticate,RequiredRole(nameof(RequiresAuthRoleAction))] + public object Any(RequiresAuthRoleAction request) => request; + } + + public class AuthAppHost + : AppSelfHostBase + { + private readonly string webHostUrl; + private readonly Action configureFn; - public class AuthAppHostHttpListener - : AppHostHttpListenerBase + public AuthAppHost(string webHostUrl, Action configureFn = null) + : base("Validation Tests", typeof(CustomerService).Assembly) { - public AuthAppHostHttpListener() - : base("Validation Tests", typeof(CustomerService).Assembly) { } + this.webHostUrl = webHostUrl; + this.configureFn = configureFn; + } - private InMemoryAuthRepository userRep; + private InMemoryAuthRepository userRep; - public override void Configure(Container container) - { - SetConfig(new EndpointHostConfig { WebHostUrl = WebHostUrl }); + public override void Configure(Container container) + { + SetConfig(new HostConfig { WebHostUrl = webHostUrl, DebugMode = true }); - Plugins.Add(new AuthFeature(() => new CustomUserSession(), - new IAuthProvider[] { //Www-Authenticate should contain basic auth, therefore register this provider first - new BasicAuthProvider(), //Sign-in with Basic Auth - new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials - new CustomAuthProvider() - }, "~/" + LoginUrl)); + Plugins.Add(new AuthFeature(() => new CustomUserSession(), + GetAuthProviders(), "~/" + AuthTests.LoginUrl) + { + AllowGetAuthenticateRequests = req => true, + RegisterPlugins = { new WebSudoFeature() }, + }); - container.Register(new MemoryCacheClient()); - userRep = new InMemoryAuthRepository(); - container.Register(userRep); + container.Register(new MemoryCacheClient()); + userRep = new InMemoryAuthRepository(); + container.Register(userRep); - CreateUser(1, UserName, null, Password, new List { "TheRole" }, new List { "ThePermission" }); - CreateUser(2, UserNameWithSessionRedirect, null, PasswordForSessionRedirect); - CreateUser(3, null, EmailBasedUsername, PasswordForEmailBasedAccount); + if (configureFn != null) + { + configureFn(container); } - private void CreateUser(int id, string username, string email, string password, List roles = null, List permissions = null) + CreateUser(1, AuthTests.UserName, null, AuthTests.Password, new List { "TheRole" }, new List { "ThePermission" }); + CreateUser(2, AuthTests.UserNameWithSessionRedirect, null, AuthTests.PasswordForSessionRedirect); + CreateUser(3, null, AuthTests.EmailBasedUsername, AuthTests.PasswordForEmailBasedAccount); + } + + public virtual IAuthProvider[] GetAuthProviders() + { + return new IAuthProvider[] { //Www-Authenticate should contain basic auth, therefore register this provider first + new BasicAuthProvider(), //Sign-in with Basic Auth + new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials + new CustomAuthProvider() + }; + } + + private void CreateUser(int id, string username, string email, string password, List roles = null, List permissions = null) + { + new SaltedHash().GetHashAndSaltString(password, out var hash, out var salt); + + userRep.CreateUserAuth(new UserAuth { - string hash; - string salt; - new SaltedHash().GetHashAndSaltString(password, out hash, out salt); + Id = id, + DisplayName = "DisplayName", + Email = email ?? "as@if{0}.com".Fmt(id), + UserName = username, + FirstName = "FirstName", + LastName = "LastName", + PasswordHash = hash, + Salt = salt, + Roles = roles, + Permissions = permissions + }, password); + } - userRep.CreateUserAuth(new UserAuth - { - Id = id, - DisplayName = "DisplayName", - Email = email ?? "as@if{0}.com".Fmt(id), - UserName = username, - FirstName = "FirstName", - LastName = "LastName", - PasswordHash = hash, - Salt = salt, - Roles = roles, - Permissions = permissions - }, password); - } + protected override void Dispose(bool disposing) + { + // Needed so that when the derived class tests run the same users can be added again. + userRep.Clear(); + base.Dispose(disposing); } + } + + public class AuthTests + { + protected virtual string VirtualDirectory => ""; + protected virtual string ListeningOn => "http://localhost:1337/"; + protected virtual string WebHostUrl => "http://mydomain.com"; - AuthAppHostHttpListener appHost; + public const string UserName = "user"; + public const string Password = "p@55word"; + public const string UserNameWithSessionRedirect = "user2"; + public const string PasswordForSessionRedirect = "p@55word2"; + public const string SessionRedirectUrl = "specialLandingPage.html"; + public const string LoginUrl = "specialLoginPage.html"; + public const string EmailBasedUsername = "user@email.com"; + public const string PasswordForEmailBasedAccount = "p@55word3"; - [TestFixtureSetUp] + ServiceStackHost appHost; + + [OneTimeSetUp] public void OnTestFixtureSetUp() { - appHost = new AuthAppHostHttpListener(); + appHost = new AuthAppHost(WebHostUrl, Configure); appHost.Init(); appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); } + public virtual void Configure(Container container) + { + } + private static void FailOnAsyncError(T response, Exception ex) { Assert.Fail(ex.Message); @@ -352,7 +441,7 @@ IServiceClient GetClient() IServiceClient GetHtmlClient() { - return new HtmlServiceClient(ListeningOn); + return new HtmlServiceClient(ListeningOn) { BaseUri = ListeningOn }; } IServiceClient GetClientWithUserPassword() @@ -364,31 +453,81 @@ IServiceClient GetClientWithUserPassword() }; } - [Test] - public void No_Credentials_throws_UnAuthorized() + private void AssertDoesThrowUnauthorized(Action send) { try { - var client = GetClient(); - var request = new Secured { Name = "test" }; - var response = client.Send(request); + send(GetClient()); Assert.Fail("Shouldn't be allowed"); } catch (WebServiceException webEx) { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(webEx.StatusCode, Is.EqualTo((int) HttpStatusCode.Unauthorized)); Console.WriteLine(webEx.ResponseDto.Dump()); } } + private void AssertDoesThrowForbidden(Action send) + { + try + { + var client = (ServiceClientBase)GetClientWithUserPassword(); + client.AlwaysSendBasicAuthHeader = true; + send(client); + + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int) HttpStatusCode.Forbidden)); + // Console.WriteLine(webEx.ResponseDto.Dump()); + } + } + + [Test] + public void No_Credentials_throws_UnAuthorized() + { + AssertDoesThrowUnauthorized(client => client.Send(new Secured { Name = "test" })); + } + + [Test] + public void ActionFilters_throw_Unauthorized_on_RequiresAuthAction() + { + AssertDoesThrowUnauthorized(client => client.Send(new RequiresAuthAction())); + } + + [Test] + public void ActionFilters_throw_Unauthorized_on_RequiresRoleAction() + { + AssertDoesThrowUnauthorized(client => client.Send(new RequiresRoleAction())); + } + + [Test] + public void ActionFilters_throw_Unauthorized_on_RequiresAuthRoleAction() + { + AssertDoesThrowUnauthorized(client => client.Send(new RequiresAuthRoleAction())); + } + + [Test] + public void ActionFilters_throw_Forbidden_on_RequiresRoleAction() + { + AssertDoesThrowForbidden(client => client.Send(new RequiresRoleAction())); + } + + [Test] + public void ActionFilters_throw_Forbidden_on_RequiresAuthRoleAction() + { + AssertDoesThrowForbidden(client => client.Send(new RequiresAuthRoleAction())); + } + [Test] public void Authenticate_attribute_respects_provider() { try { var client = GetClient(); - var authResponse = client.Send(new Auth + var authResponse = client.Send(new Authenticate { provider = CredentialsAuthProvider.Name, UserName = "user", @@ -414,7 +553,7 @@ public void PostFile_with_no_Credentials_throws_UnAuthorized() try { var client = GetClient(); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); client.PostFile(ListeningOn + "/securedfileupload", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); Assert.Fail("Shouldn't be allowed"); @@ -430,9 +569,9 @@ public void PostFile_with_no_Credentials_throws_UnAuthorized() public void PostFile_does_work_with_BasicAuth() { var client = GetClientWithUserPassword(); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); + var expectedContents = uploadFile.OpenRead().ReadToEnd(); var response = client.PostFile(ListeningOn + "/securedfileupload", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); @@ -444,9 +583,9 @@ public void PostFileWithRequest_does_work_with_BasicAuth() { var client = GetClientWithUserPassword(); var request = new SecuredFileUpload { CustomerId = 123, CustomerName = "Foo" }; - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); + var expectedContents = uploadFile.OpenRead().ReadToEnd(); var response = client.PostFileWithRequest(ListeningOn + "/securedfileupload", uploadFile, request); Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); @@ -471,6 +610,22 @@ public void Does_work_with_BasicAuth() } } + [Test] + public async Task Does_work_with_BasicAuth_Async() + { + try + { + var client = GetClientWithUserPassword(); + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + [Test] public void Does_always_send_BasicAuth() { @@ -478,16 +633,108 @@ public void Does_always_send_BasicAuth() { var client = (ServiceClientBase)GetClientWithUserPassword(); client.AlwaysSendBasicAuthHeader = true; - client.LocalHttpWebRequestFilter = req => + client.RequestFilter = req => + Assert.That(req.Headers[HttpHeaders.Authorization], Is.Not.Null); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void Authenticating_once_with_BasicAuth_does_not_establish_auth_session() + { + var client = (ServiceClientBase)GetClientWithUserPassword(); + client.AlwaysSendBasicAuthHeader = true; + client.RequestFilter = req => + Assert.That(req.Headers[HttpHeaders.Authorization], Is.Not.Null); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var nonBasicAuthClient = GetClient(); + nonBasicAuthClient.SetSessionId(client.GetSessionId()); + try + { + response = nonBasicAuthClient.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Does_return_SessionId_Cookies() + { + var client = GetClient(); + var authResponse = client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + }); + var cookies = client.GetCookieValues(); + Assert.That(authResponse.SessionId, Is.EqualTo(cookies["ss-id"])); + + client = GetClient(); + authResponse = client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + cookies = client.GetCookieValues(); + Assert.That(authResponse.SessionId, Is.EqualTo(cookies["ss-pid"])); + } + + [Test] + public async Task Does_return_SessionId_Cookies_Async() + { + var client = GetClient(); + var authResponse = await client.PostAsync(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + }); + var cookies = client.GetCookieValues(); + Assert.That(authResponse.SessionId, Is.EqualTo(cookies["ss-id"])); + + client = GetClient(); + authResponse = await client.PostAsync(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + cookies = client.GetCookieValues(); + Assert.That(authResponse.SessionId, Is.EqualTo(cookies["ss-pid"])); + } + + [Test] + public void Does_work_with_CredentialsAuth() + { + try + { + var client = GetClient(); + + var authResponse = client.Send(new Authenticate { - bool hasAuthentication = false; - foreach (var key in req.Headers.Keys) - { - if (key.ToString() == "Authorization") - hasAuthentication = true; - } - Assert.IsTrue(hasAuthentication); - }; + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); var request = new Secured { Name = "test" }; var response = client.Send(request); @@ -500,13 +747,13 @@ public void Does_always_send_BasicAuth() } [Test] - public void Does_work_with_CredentailsAuth() + public void Can_sent_Session_using_Headers() { try { var client = GetClient(); - var authResponse = client.Send(new Auth + var authResponse = client.Send(new Authenticate { provider = CredentialsAuthProvider.Name, UserName = "user", @@ -514,10 +761,12 @@ public void Does_work_with_CredentailsAuth() RememberMe = true, }); - authResponse.PrintDump(); + var clientWithHeaders = (JsonServiceClient)GetClient(); + clientWithHeaders.Headers["X-ss-pid"] = authResponse.SessionId; + clientWithHeaders.Headers["X-ss-opt"] = "perm"; var request = new Secured { Name = "test" }; - var response = client.Send(request); + var response = clientWithHeaders.Send(request); Assert.That(response.Result, Is.EqualTo(request.Name)); } catch (WebServiceException webEx) @@ -527,27 +776,22 @@ public void Does_work_with_CredentailsAuth() } [Test] - public void Does_work_with_CredentailsAuth_Async() + public async Task Does_work_with_CredentialsAuth_Async() { var client = GetClient(); var request = new Secured { Name = "test" }; - SecureResponse response = null; - - client.SendAsync(new Auth - { - provider = CredentialsAuthProvider.Name, - UserName = "user", - Password = "p@55word", - RememberMe = true, - }, authResponse => - { - authResponse.PrintDump(); - client.SendAsync(request, r => response = r, FailOnAsyncError); + var authResponse = await client.SendAsync( + new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); - }, FailOnAsyncError); + var response = await client.SendAsync(request); - Thread.Sleep(TimeSpan.FromSeconds(1)); Assert.That(response.Result, Is.EqualTo(request.Name)); } @@ -567,6 +811,56 @@ public void Can_call_RequiredRole_service_with_BasicAuth() } } + [Test] + public void Can_call_RequiredRole_service_with_CredentialsAuth_with_Role() + { + try + { + var client = GetClient(); + var authResponse = client.Send( + new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserName, // Has Role + Password = Password, + RememberMe = true, + }); + + var request = new RequiresRole { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void Does_not_allow_RequiredRole_service_with_CredentialsAuth_without_Role() + { + try + { + var client = GetClient(); + var authResponse = client.Send( + new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user2", // Does not have Role + Password = "p@55word2", + RememberMe = true, + }); + + var request = new RequiresRole { Name = "test" }; + var response = client.Send(request); + Assert.Fail("Should Throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + } + } + [Test] public void RequiredRole_service_returns_unauthorized_if_no_basic_auth_header_exists() { @@ -658,13 +952,69 @@ public void RequiredPermission_service_returns_forbidden_if_basic_auth_header_ex } [Test] - public void Does_work_with_CredentailsAuth_Multiple_Times() + public void Does_return_empty_response_on_forbidden_access() + { + string downloadBasicAuth(string urlSuffix) => + ListeningOn.CombineWith("/json/reply", urlSuffix) + .GetStringFromUrl(requestFilter:req => req.AddBasicAuth(EmailBasedUsername, PasswordForEmailBasedAccount)); + + try + { + downloadBasicAuth(nameof(RequiresRole).AddQueryParam("Name", "test")); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + AssertStatus(e, HttpStatusCode.Forbidden); + } + + try + { + downloadBasicAuth(nameof(RequiresAnyRole).AddQueryParam("Name", "test")); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + AssertStatus(e, HttpStatusCode.Forbidden); + } + + try + { + downloadBasicAuth(nameof(RequiresPermission).AddQueryParam("Name", "test")); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + AssertStatus(e, HttpStatusCode.Forbidden); + } + + try + { + downloadBasicAuth(nameof(RequiresAnyPermission).AddQueryParam("Name", "test")); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + AssertStatus(e, HttpStatusCode.Forbidden); + } + } + + private static void AssertStatus(Exception e, HttpStatusCode statusCode) + { + Assert.That(e.GetStatus(), Is.EqualTo(statusCode)); +#if NETFX + Assert.That(e.GetResponseBody(), Does.Not.Contain("{")); +#endif + } + + [Test] + public void Does_work_with_CredentialsAuth_Multiple_Times() { try { var client = GetClient(); - var authResponse = client.Send(new Auth + var authResponse = client.Send(new Authenticate { provider = CredentialsAuthProvider.Name, UserName = "user", @@ -674,7 +1024,7 @@ public void Does_work_with_CredentailsAuth_Multiple_Times() Console.WriteLine(authResponse.Dump()); - for (int i = 0; i < 500; i++) + for (int i = 0; i < 10; i++) { var request = new Secured { Name = "test" }; var response = client.Send(request); @@ -688,6 +1038,57 @@ public void Does_work_with_CredentailsAuth_Multiple_Times() } } + [Test] + public void Does_generate_new_SessionCookies_when_Authenticating_multiple_times() + { + var client = GetClient(); + string lastPermId = null; + + 3.Times(x => + { + var authResponse = client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + var permId = client.GetCookieValues()[SessionFeature.PermanentSessionId]; + Assert.That(permId, Is.Not.EqualTo(lastPermId)); + + var ssOpt = client.GetCookieValues()[SessionFeature.SessionOptionsKey]; + Assert.That(ssOpt, Is.Not.Null); + + lastPermId = permId; + }); + } + + [Test] + public void Does_retain_Session_after_authenticating_multiple_times() + { + var client = GetClient(); + CustomUserSession lastSession = null; + 3.Times(x => + { + var authResponse = client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + var customSession = client.Send(new IncrSession { By = 1 }); + Assert.That(customSession.Counter, + lastSession == null ? Is.EqualTo(1) : Is.EqualTo(lastSession.Counter + 1)); + + lastSession = customSession; + }); + + Assert.That(lastSession.Counter, Is.EqualTo(3)); + } + [Test] public void Exceptions_thrown_are_received_by_client_when_AlwaysSendBasicAuthHeader_is_false() { @@ -728,16 +1129,31 @@ public void Html_clients_receive_redirect_to_login_page_when_accessing_unauthent var client = (ServiceClientBase)GetHtmlClient(); client.AllowAutoRedirect = false; string lastResponseLocationHeader = null; - client.LocalHttpWebResponseFilter = response => + client.ResponseFilter = response => { lastResponseLocationHeader = response.Headers["Location"]; }; var request = new Secured { Name = "test" }; - client.Send(request); + try + { + client.Send(request); + } +#if NETCORE + catch (WebServiceException ex) + { + //AllowAutoRedirect=false is not implemented in .NET Core and throws NotFound exception + if (ex.StatusCode == (int)HttpStatusCode.Found) + return; + throw; + } +#else + catch (WebServiceException) {} +#endif var locationUri = new Uri(lastResponseLocationHeader); - Assert.That(locationUri.AbsolutePath, Contains.Substring(LoginUrl)); + var loginPath = "/".CombineWith(VirtualDirectory).CombineWith(LoginUrl); + Assert.That(locationUri.AbsolutePath, Is.EqualTo(loginPath).IgnoreCase); } [Test] @@ -746,24 +1162,80 @@ public void Html_clients_receive_secured_url_attempt_in_login_page_redirect_quer var client = (ServiceClientBase)GetHtmlClient(); client.AllowAutoRedirect = false; string lastResponseLocationHeader = null; - client.LocalHttpWebResponseFilter = response => + client.ResponseFilter = response => { lastResponseLocationHeader = response.Headers["Location"]; }; var request = new Secured { Name = "test" }; - client.Send(request); + try + { + client.Send(request); + } +#if NETCORE + catch (WebServiceException ex) + { + //AllowAutoRedirect=false is not implemented in .NET Core and throws NotFound exception + if (ex.StatusCode == (int)HttpStatusCode.Found) + return; + } +#else + catch (WebServiceException) {} +#endif var locationUri = new Uri(lastResponseLocationHeader); var queryString = HttpUtility.ParseQueryString(locationUri.Query); - var redirectQueryString = queryString["redirect"]; + var redirectQueryString = queryString[Keywords.Redirect]; var redirectUri = new Uri(redirectQueryString); // Should contain the url attempted to access before the redirect to the login page. - Assert.That(redirectUri.AbsolutePath, Contains.Substring("/secured").IgnoreCase); - // Should also obey the WebHostUrl setting. - var schemeAndHost = redirectUri.Scheme + "://" + redirectUri.Authority; - Assert.That(schemeAndHost, Contains.Substring(WebHostUrl).IgnoreCase); + var securedPath = "/".CombineWith(VirtualDirectory).CombineWith("secured"); + Assert.That(redirectUri.AbsolutePath, Is.EqualTo(securedPath).IgnoreCase); + // The url should also obey the WebHostUrl setting for the domain. + var redirectSchemeAndHost = redirectUri.Scheme + "://" + redirectUri.Authority; + var webHostUri = new Uri(WebHostUrl); + var webHostSchemeAndHost = webHostUri.Scheme + "://" + webHostUri.Authority; + Assert.That(redirectSchemeAndHost, Is.EqualTo(webHostSchemeAndHost).IgnoreCase); + } + + [Test] + public void Html_clients_receive_secured_url_including_query_string_within_login_page_redirect_query_string() + { + var client = (ServiceClientBase)GetHtmlClient(); + client.AllowAutoRedirect = false; + string lastResponseLocationHeader = null; + client.ResponseFilter = response => + { + lastResponseLocationHeader = response.Headers["Location"]; + }; + + var request = new Secured { Name = "test" }; + // Perform a GET so that the Name DTO field is encoded as query string. + try + { + client.Get(request); + } +#if NETCORE + catch (WebServiceException ex) + { + //AllowAutoRedirect=false is not implemented in .NET Core and throws NotFound exception + if (ex.StatusCode == (int)HttpStatusCode.Found) + return; + } +#else + catch (WebServiceException) {} +#endif + + var locationUri = new Uri(lastResponseLocationHeader); + var locationUriQueryString = HttpUtility.ParseQueryString(locationUri.Query); + var redirectQueryItem = locationUriQueryString[Keywords.Redirect]; + var redirectUri = new Uri(redirectQueryItem); + + // Should contain the url attempted to access before the redirect to the login page, + // including the 'Name=test' query string. + var redirectUriQueryString = HttpUtility.ParseQueryString(redirectUri.Query); + Assert.That(redirectUriQueryString.AllKeys, Contains.Item("name")); + Assert.That(redirectUriQueryString["name"], Is.EqualTo("test")); } [Test] @@ -772,18 +1244,31 @@ public void Html_clients_receive_session_ReferrerUrl_on_successful_authenticatio var client = (ServiceClientBase)GetHtmlClient(); client.AllowAutoRedirect = false; string lastResponseLocationHeader = null; - client.LocalHttpWebResponseFilter = response => + client.ResponseFilter = response => { lastResponseLocationHeader = response.Headers["Location"]; }; - client.Send(new Auth + try { - provider = CredentialsAuthProvider.Name, - UserName = UserNameWithSessionRedirect, - Password = PasswordForSessionRedirect, - RememberMe = true, - }); + client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserNameWithSessionRedirect, + Password = PasswordForSessionRedirect, + RememberMe = true, + }); + } +#if NETCORE + catch (WebServiceException ex) + { + //AllowAutoRedirect=false is not implemented in .NET Core and throws NotFound exception + if (ex.StatusCode == (int)HttpStatusCode.Found) + return; + } +#else + catch (WebServiceException) {} +#endif Assert.That(lastResponseLocationHeader, Is.EqualTo(SessionRedirectUrl)); } @@ -792,7 +1277,7 @@ public void Already_authenticated_session_returns_correct_username() { var client = GetClient(); - var authRequest = new Auth + var authRequest = new Authenticate { provider = CredentialsAuthProvider.Name, UserName = UserName, @@ -800,9 +1285,9 @@ public void Already_authenticated_session_returns_correct_username() RememberMe = true, }; var initialLoginResponse = client.Send(authRequest); - var alreadyLogggedInResponse = client.Send(authRequest); + var alreadyLoggedInResponse = client.Send(authRequest); - Assert.That(alreadyLogggedInResponse.UserName, Is.EqualTo(UserName)); + Assert.That(alreadyLoggedInResponse.UserName, Is.EqualTo(UserName)); } @@ -811,7 +1296,7 @@ public void AuthResponse_returns_email_as_username_if_user_registered_with_email { var client = GetClient(); - var authRequest = new Auth + var authRequest = new Authenticate { provider = CredentialsAuthProvider.Name, UserName = EmailBasedUsername, @@ -828,7 +1313,7 @@ public void Already_authenticated_session_returns_correct_username_when_user_reg { var client = GetClient(); - var authRequest = new Auth + var authRequest = new Authenticate { provider = CredentialsAuthProvider.Name, UserName = EmailBasedUsername, @@ -836,10 +1321,10 @@ public void Already_authenticated_session_returns_correct_username_when_user_reg RememberMe = true, }; var initialLoginResponse = client.Send(authRequest); - var alreadyLogggedInResponse = client.Send(authRequest); + var alreadyLoggedInResponse = client.Send(authRequest); Assert.That(initialLoginResponse.UserName, Is.EqualTo(EmailBasedUsername)); - Assert.That(alreadyLogggedInResponse.UserName, Is.EqualTo(EmailBasedUsername)); + Assert.That(alreadyLoggedInResponse.UserName, Is.EqualTo(EmailBasedUsername)); } [Test] @@ -974,7 +1459,7 @@ public void Calling_AddSessionIdToRequest_from_a_custom_auth_attribute_does_not_ WebHeaderCollection headers = null; var client = GetClientWithUserPassword(); ((ServiceClientBase)client).AlwaysSendBasicAuthHeader = true; - ((ServiceClientBase)client).LocalHttpWebResponseFilter = x => headers = x.Headers; + ((ServiceClientBase)client).ResponseFilter = x => headers = x.Headers; var response = client.Send(new CustomAuthAttr() { Name = "Hi You" }); Assert.That(response.Result, Is.EqualTo("Hi You")); Assert.That( @@ -982,5 +1467,181 @@ public void Calling_AddSessionIdToRequest_from_a_custom_auth_attribute_does_not_ Is.EqualTo(1) ); } + + [Test] + public void Meaningful_Exception_for_Unknown_Auth_Header() + { + Assert.Throws(() => new AuthenticationInfo("Negotiate,NTLM")); + } + + [Test] + public void Can_parse_windowsauth_header() + { + var auth = new AuthenticationInfo("windowsauth realm=\"/auth/windowsauth\""); + auth.PrintDump(); + } + + [Test] + public void Can_logout_using_CredentialsAuth() + { + Assert.That(AuthenticateService.LogoutAction, Is.EqualTo("logout")); + + try + { + var client = GetClient(); + + var authResponse = client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "p@55word", + RememberMe = true, + }); + + Assert.That(authResponse.SessionId, Is.Not.Null); + + var logoutResponse = client.Get("/auth/logout"); + + Assert.That(logoutResponse.ResponseStatus?.ErrorCode, Is.Null); + + logoutResponse = client.Send(new Authenticate + { + provider = AuthenticateService.LogoutAction, + }); + + Assert.That(logoutResponse.ResponseStatus?.ErrorCode, Is.Null); + } + catch (WebServiceException webEx) + { + Assert.Fail(webEx.Message); + } + } + + [Test] + public void WebSudoRequired_service_returns_PaymentRequired_if_not_re_authenticated() + { + try + { + var client = GetClient(); + var authRequest = new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserName, + Password = Password, + RememberMe = true, + }; + client.Send(authRequest); + var request = new RequiresWebSudo { Name = "test" }; + var response = client.Send(request); + + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.PaymentRequired)); + Console.WriteLine(webEx.ToString()); + } + } + + [Test] + public void WebSudoRequired_service_succeeds_if_re_authenticated() + { + var client = GetClient(); + var authRequest = new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserName, + Password = Password, + RememberMe = true, + }; + client.Send(authRequest); + + var request = new RequiresWebSudo { Name = "test" }; + try + { + client.Send(request); + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException) + { + client.Send(authRequest); + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + } + + [Test] + public void Failed_re_authentication_does_not_logout_user() + { + var client = GetClient(); + var authRequest = new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserName, + Password = Password, + RememberMe = true, + }; + client.Send(authRequest); + var request = new RequiresWebSudo { Name = "test" }; + try + { + client.Send(request); + Assert.Fail("Shouldn't be allowed"); + } + catch + { + // ignore the first 402 + } + try + { + client.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = UserName, + Password = "some other password", + RememberMe = true, + }); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Console.WriteLine(webEx.ResponseDto.Dump()); + } + + // Should still be authenticated, but not elevated + try + { + client.Send(request); + Assert.Fail("Shouldn't be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.PaymentRequired)); + Console.WriteLine(webEx.ToString()); + } + } + } + + public class AuthTestsWithinVirtualDirectory : AuthTests + { + protected override string VirtualDirectory { get { return "somevirtualdirectory"; } } + protected override string ListeningOn { get { return "http://localhost:1337/" + VirtualDirectory + "/"; } } + protected override string WebHostUrl { get { return "http://mydomain.com/" + VirtualDirectory; } } + } + + public class AuthTestsWithinOrmLiteCache : AuthTests + { + protected override string VirtualDirectory { get { return "somevirtualdirectory"; } } + protected override string ListeningOn { get { return "http://localhost:1337/" + VirtualDirectory + "/"; } } + protected override string WebHostUrl { get { return "http://mydomain.com/" + VirtualDirectory; } } + + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.RegisterAs(); + container.Resolve().InitSchema(); + } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoBatchTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoBatchTests.cs new file mode 100644 index 00000000000..0f2fcb8cc3c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoBatchTests.cs @@ -0,0 +1,176 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AutoBatchAppHost : AppSelfHostBase + { + public AutoBatchAppHost() + : base(typeof(AutoBatchTests).Name, typeof(AutoBatchIndexServices).Assembly) + { + } + + public override void Configure(Container container) + { + GlobalRequestFilters.Add((req, res, dto) => + { + var autoBatchIndex = req.GetItem(Keywords.AutoBatchIndex)?.ToString(); + if (autoBatchIndex != null) + { + res.RemoveHeader("GlobalRequestFilterAutoBatchIndex"); + res.AddHeader("GlobalRequestFilterAutoBatchIndex", autoBatchIndex); + } + }); + + GlobalResponseFilters.Add((req, res, dto) => + { + var autoBatchIndex = req.GetItem(Keywords.AutoBatchIndex)?.ToString(); + + if (autoBatchIndex != null) + { + if (dto is IMeta response) + { + response.Meta = new Dictionary + { + ["GlobalResponseFilterAutoBatchIndex"] = autoBatchIndex + }; + } + } + }); + } + } + + public class GetAutoBatchIndex : IReturn + { + } + + public class GetCustomAutoBatchIndex : IReturn + { + } + + public class GetAutoBatchIndexResponse : IMeta + { + public string Index { get; set; } + public Dictionary Meta { get; set; } + } + + public class AutoBatchIndexServices : Service + { + public object Any(GetAutoBatchIndex request) + { + var autoBatchIndex = Request.GetItem(Keywords.AutoBatchIndex)?.ToString(); + return new GetAutoBatchIndexResponse + { + Index = autoBatchIndex + }; + } + + public GetAutoBatchIndexResponse Any(GetCustomAutoBatchIndex request) + { + var autoBatchIndex = Request.GetItem(Keywords.AutoBatchIndex)?.ToString(); + return new GetAutoBatchIndexResponse + { + Index = autoBatchIndex + }; + } + + public object Any(GetCustomAutoBatchIndex[] requests) + { + var responses = new List(); + + Request.EachRequest(dto => + { + responses.Add(Any(dto)); + }); + + return responses; + } + } + + [TestFixture] + public class AutoBatchTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AutoBatchAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Single_requests_dont_set_AutoBatchIndex() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + WebHeaderCollection responseHeaders = null; + + client.ResponseFilter = resp => { responseHeaders = resp.Headers; }; + + var response = client.Send(new GetAutoBatchIndex()); + + Assert.Null(response.Index); + Assert.Null(response.Meta); + Assert.IsFalse(responseHeaders.AllKeys.Contains("GlobalRequestFilterAutoBatchIndex")); + } + + [Test] + public void Multi_requests_set_AutoBatchIndex() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + WebHeaderCollection responseHeaders = null; + + client.ResponseFilter = response => { responseHeaders = response.Headers; }; + + var responses = client.SendAll(new[] + { + new GetAutoBatchIndex(), + new GetAutoBatchIndex() + }); + + Assert.AreEqual("0", responses[0].Index); + Assert.AreEqual("0", responses[0].Meta["GlobalResponseFilterAutoBatchIndex"]); + + Assert.AreEqual("1", responses[1].Index); + Assert.AreEqual("1", responses[1].Meta["GlobalResponseFilterAutoBatchIndex"]); + + Assert.AreEqual("1", responseHeaders["GlobalRequestFilterAutoBatchIndex"]); + } + + [Test] + public void Custom_multi_requests_set_AutoBatchIndex() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + WebHeaderCollection responseHeaders = null; + + client.ResponseFilter = response => { responseHeaders = response.Headers; }; + + var responses = client.SendAll(new[] + { + new GetCustomAutoBatchIndex(), + new GetCustomAutoBatchIndex() + }); + + Assert.AreEqual("0", responses[0].Index); + Assert.AreEqual("0", responses[0].Meta["GlobalResponseFilterAutoBatchIndex"]); + + Assert.AreEqual("1", responses[1].Index); + Assert.AreEqual("1", responses[1].Meta["GlobalResponseFilterAutoBatchIndex"]); + + Assert.AreEqual("1", responseHeaders["GlobalRequestFilterAutoBatchIndex"]); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudModels.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudModels.cs new file mode 100644 index 00000000000..7d514d82507 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudModels.cs @@ -0,0 +1,646 @@ +using System; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using ServiceStack.DataAnnotations; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public abstract class RockstarBase + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + [Alias(nameof(Rockstar))] + public class RockstarAuto : RockstarBase + { + [AutoIncrement] + public int Id { get; set; } + } + + public class RockstarAutoGuid : RockstarBase + { + [AutoId] + public Guid Id { get; set; } + } + + public class RockstarAudit : RockstarBase + { + [AutoIncrement] + public int Id { get; set; } + public DateTime CreatedDate { get; set; } + public string CreatedBy { get; set; } + public string CreatedInfo { get; set; } + public DateTime ModifiedDate { get; set; } + public string ModifiedBy { get; set; } + public string ModifiedInfo { get; set; } + } + + public interface IAudit + { + DateTime CreatedDate { get; set; } + string CreatedBy { get; set; } + string CreatedInfo { get; set; } + DateTime ModifiedDate { get; set; } + string ModifiedBy { get; set; } + string ModifiedInfo { get; set; } + DateTime? SoftDeletedDate { get; set; } + string SoftDeletedBy { get; set; } + string SoftDeletedInfo { get; set; } + } + + public interface IAuditTenant : IAudit + { + int TenantId { get; set; } + } + + public abstract class AuditBase : IAudit + { + public DateTime CreatedDate { get; set; } + [Required] + public string CreatedBy { get; set; } + [Required] + public string CreatedInfo { get; set; } + + public DateTime ModifiedDate { get; set; } + [Required] + public string ModifiedBy { get; set; } + [Required] + public string ModifiedInfo { get; set; } + + [Index] //Check if Deleted + public DateTime? SoftDeletedDate { get; set; } + public string SoftDeletedBy { get; set; } + public string SoftDeletedInfo { get; set; } + } + + public class RockstarAuditTenant : AuditBase + { + [Index] + public int TenantId { get; set; } + [AutoIncrement] + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class RockstarVersion : RockstarBase + { + [AutoIncrement] + public int Id { get; set; } + public ulong RowVersion { get; set; } + } + + public class CreateRockstarWithId : Rockstar, ICreateDb, IReturn + { + } + + public class CreateRockstar : RockstarBase, ICreateDb, IReturn + { + } + + public class CreateRockstarResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateRockstarWithReturn : RockstarBase, ICreateDb, IReturn + { + } + public class CreateRockstarWithVoidReturn : RockstarBase, ICreateDb, IReturnVoid + { + } + + public class CreateRockstarWithAutoGuid : RockstarBase, ICreateDb, IReturn + { + } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(RockstarAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public class CreateRockstarAudit : RockstarBase, ICreateDb, IReturn + { + } + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class CreateAuditBase : ICreateDb, IReturn {} + + [AutoPopulate(nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class CreateAuditTenantBase : CreateAuditBase {} + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class UpdateAuditBase : IUpdateDb
      , IReturn {} + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class UpdateAuditTenantBase : UpdateAuditBase {} + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class PatchAuditBase : IPatchDb
      , IReturn {} + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class PatchAuditTenantBase : PatchAuditBase {} + + [ValidateRequest("IsAuthenticated")] + [AutoPopulate(nameof(IAudit.SoftDeletedDate), Eval = "utcNow")] + [AutoPopulate(nameof(IAudit.SoftDeletedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(IAudit.SoftDeletedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public abstract class SoftDeleteAuditBase : IUpdateDb
      , IReturn {} + + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class SoftDeleteAuditTenantBase : SoftDeleteAuditBase {} + + [ValidateRequest("IsAuthenticated")] + [AutoFilter(QueryTerm.Ensure, nameof(IAudit.SoftDeletedDate), Template = SqlTemplate.IsNull)] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public abstract class QueryDbTenant : QueryDb {} + + public class CreateRockstarAuditTenant : CreateAuditTenantBase, IHasBearerToken + { + public string BearerToken { get; set; } //Authenticate MQ Requests + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class UpdateRockstarAuditTenant : UpdateAuditTenantBase, IHasBearerToken + { + public string BearerToken { get; set; } //Authenticate MQ Requests + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class PatchRockstarAuditTenant : PatchAuditTenantBase, IHasBearerToken + { + public string BearerToken { get; set; } //Authenticate MQ Requests + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class CreateRockstarAuditTenantGateway : IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class UpdateRockstarAuditTenantGateway : IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class PatchRockstarAuditTenantGateway : IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class RealDeleteAuditTenantGateway : IReturn + { + public int Id { get; set; } + } + + public class SoftDeleteAuditTenant : SoftDeleteAuditTenantBase + { + public int Id { get; set; } + } + + [Authenticate] + public class CreateRockstarAuditTenantMq : IReturnVoid + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + [Authenticate] + public class UpdateRockstarAuditTenantMq : IReturnVoid + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class PatchRockstarAuditTenantMq : IReturnVoid + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + public class RealDeleteAuditTenantMq : IReturnVoid + { + public int Id { get; set; } + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.CreatedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.CreatedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.CreatedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public class CreateRockstarAuditMqToken : RockstarBase, ICreateDb, IReturn, IHasBearerToken + { + public string BearerToken { get; set; } + } + + + [Authenticate] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public class RealDeleteAuditTenant : IDeleteDb, IReturn, IHasBearerToken + { + public string BearerToken { get; set; } //Authenticate MQ Requests + public int Id { get; set; } + public int? Age { get; set; } + } + + public class QueryRockstarAudit : QueryDbTenant + { + public int? Id { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [AutoFilter(QueryTerm.Ensure, nameof(AuditBase.SoftDeletedDate), SqlTemplate.IsNull)] + [AutoFilter(QueryTerm.Ensure, nameof(IAuditTenant.TenantId), Eval = "Request.Items.TenantId")] + public class QueryRockstarAuditSubOr : QueryDb + { + public string FirstNameStartsWith { get; set; } + public int? AgeOlderThan { get; set; } + } + + public class CreateRockstarVersion : RockstarBase, ICreateDb, IReturn + { + } + + public class RockstarWithIdResponse + { + public int Id { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + public class RockstarWithIdAndCountResponse + { + public int Id { get; set; } + public int Count { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class RockstarWithIdAndRowVersionResponse + { + public int Id { get; set; } + public uint RowVersion { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class RockstarWithIdAndResultResponse + { + public int Id { get; set; } + public RockstarAuto Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateRockstarWithReturnGuidResponse + { + public Guid Id { get; set; } + public RockstarAutoGuid Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateRockstarAdhocNonDefaults : ICreateDb, IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + [AutoDefault(Value = 21)] + public int? Age { get; set; } + [AutoDefault(Expression = "date(2001,1,1)")] + public DateTime DateOfBirth { get; set; } + [AutoDefault(Eval = "utcNow")] + public DateTime? DateDied { get; set; } + [AutoDefault(Value = global::ServiceStack.WebHost.Endpoints.Tests.LivingStatus.Dead)] + public LivingStatus? LivingStatus { get; set; } + } + + public class CreateRockstarAutoMap : ICreateDb, IReturn + { + [AutoMap(nameof(RockstarAuto.FirstName))] + public string MapFirstName { get; set; } + + [AutoMap(nameof(RockstarAuto.LastName))] + public string MapLastName { get; set; } + + [AutoMap(nameof(RockstarAuto.Age))] + [AutoDefault(Value = 21)] + public int? MapAge { get; set; } + + [AutoMap(nameof(RockstarAuto.DateOfBirth))] + [AutoDefault(Expression = "date(2001,1,1)")] + public DateTime MapDateOfBirth { get; set; } + + [AutoMap(nameof(RockstarAuto.DateDied))] + [AutoDefault(Eval = "utcNow")] + public DateTime? MapDateDied { get; set; } + + [AutoMap(nameof(RockstarAuto.LivingStatus))] + [AutoDefault(Value = LivingStatus.Dead)] + public LivingStatus? MapLivingStatus { get; set; } + } + + public class UpdateRockstar : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + } + + [Authenticate] + [AutoPopulate(nameof(RockstarAudit.ModifiedDate), Eval = "utcNow")] + [AutoPopulate(nameof(RockstarAudit.ModifiedBy), Eval = "userAuthName")] //or userAuthId + [AutoPopulate(nameof(RockstarAudit.ModifiedInfo), Eval = "`${userSession.DisplayName} (${userSession.City})`")] + public class UpdateRockstarAudit : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + public string FirstName { get; set; } + public LivingStatus? LivingStatus { get; set; } + } + + [Authenticate] + public class DeleteRockstarAudit : IDeleteDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateRockstarVersion : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + public ulong RowVersion { get; set; } + } + + public class PatchRockstar : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateRockstarAdhocNonDefaults : IUpdateDb, IReturn + { + public int Id { get; set; } + [AutoUpdate(AutoUpdateStyle.NonDefaults)] + public string FirstName { get; set; } + public string LastName { get; set; } + [AutoDefault(Value = 21)] + public int? Age { get; set; } + [AutoDefault(Expression = "date(2001,1,1)")] + public DateTime DateOfBirth { get; set; } + [AutoDefault(Eval = "utcNow")] + public DateTime? DateDied { get; set; } + [AutoUpdate(AutoUpdateStyle.NonDefaults), AutoDefault(Value = LivingStatus.Dead)] + public LivingStatus LivingStatus { get; set; } + } + + public class DeleteRockstar : IDeleteDb, IReturn + { + public int Id { get; set; } + } + + public class DeleteRockstarFilters : IDeleteDb, IReturn + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + } + + public class DeleteRockstarCountResponse + { + public int Count { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CreateNamedRockstar : RockstarBase, ICreateDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateNamedRockstar : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + } + + //[ConnectionInfo] on AutoCrudConnectionInfoServices + public class CreateConnectionInfoRockstar : RockstarBase, ICreateDb, IReturn + { + public int Id { get; set; } + } + + public class UpdateConnectionInfoRockstar : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + } + + public class DefaultValue + { + public int Id { get; set; } + public int Int { get; set; } + public int? NInt { get; set; } + public bool Bool { get; set; } + public bool? NBool { get; set; } + public string String { get; set; } + } + + public class CreateDefaultValues : ICreateDb, IReturn + { + public int Id { get; set; } + public int Int { get; set; } + public int? NInt { get; set; } + public bool Bool { get; set; } + public bool? NBool { get; set; } + public string String { get; set; } + } + + public class PatchDefaultValues : IPatchDb, IReturnVoid + { + public int Id { get; set; } + public int Int { get; set; } + public int? NInt { get; set; } + public bool Bool { get; set; } + public bool? NBool { get; set; } + public string String { get; set; } + public string[] Reset { get; set; } + } + + public class QueryRockstarsUnknownField : QueryDb + { + public int Id { get; set; } + public string Unknown { get; set; } + } + public class CreateRockstarUnknownField : RockstarBase, ICreateDb, IReturn + { + public string Unknown { get; set; } + } + public class UpdateRockstarUnknownField : RockstarBase, IUpdateDb, IReturn + { + public int Id { get; set; } + public string Unknown { get; set; } + } + public class PatchRockstarUnknownField : RockstarBase, IPatchDb, IReturn + { + public int Id { get; set; } + public string Unknown { get; set; } + } + public class DeleteRockstarUnknownField : IDeleteDb, IReturn + { + public int Id { get; set; } + public string Unknown { get; set; } + } + + [DataContract] + public class Booking : ServiceStack.AuditBase + { + [AutoIncrement] + [DataMember(Order = 1)] public int Id { get; set; } + [DataMember(Order = 2)] public RoomType RoomType { get; set; } + [CheckConstraint("RoomNumber < 500")] + [DataMember(Order = 3)] public int RoomNumber { get; set; } + [DataMember(Order = 4)] public DateTime BookingStartDate { get; set; } + [DataMember(Order = 5)] public DateTime? BookingEndDate { get; set; } + [DataMember(Order = 6)] public string Notes { get; set; } + [DataMember(Order = 7)] public bool? Cancelled { get; set; } + [DataMember(Order = 8)] public decimal Cost { get; set; } + } + + public enum RoomType + { + Single, + Double, + Queen, + Twin, + Suite, + } + + [DataContract] + [AutoApply(Behavior.AuditQuery)] + public class QueryBookings : QueryDb + { + [DataMember(Order = 1)] public int[] Ids { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoPopulate(nameof(CreatedBy), Eval = "userAuthName")] + [AutoApply(Behavior.AuditQuery)] + public class QueryUserBookings : QueryDb + { + [DataMember(Order = 1)] public string CreatedBy { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoPopulate(nameof(UserName), Eval = "userAuthName")] + [AutoApply(Behavior.AuditQuery)] + public class QueryUserMapBookings : QueryDb + { + [AutoMap(nameof(ServiceStack.AuditBase.CreatedBy))] + [DataMember(Order = 1)] public string UserName { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoFilter(QueryTerm.Ensure, nameof(ServiceStack.AuditBase.CreatedBy), Eval = "userAuthName")] + [AutoApply(Behavior.AuditQuery)] + public class QueryEnsureUserBookings : QueryDb {} + + [DataContract] + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditCreate)] + public class CreateBooking + : ICreateDb, IReturn + { + [ApiAllowableValues(typeof(RoomType))] + [DataMember(Order = 1)] public RoomType RoomType { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 2)] public int RoomNumber { get; set; } + [DataMember(Order = 3)] public DateTime BookingStartDate { get; set; } + [DataMember(Order = 4)] public DateTime? BookingEndDate { get; set; } + [DataMember(Order = 5)] public string Notes { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 6)] public decimal Cost { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditModify)] + public class UpdateBooking + : IPatchDb, IReturn + { + [DataMember(Order = 1)] public int Id { get; set; } + [ApiAllowableValues(typeof(RoomType))] + [DataMember(Order = 2)] public RoomType? RoomType { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 3)] public int? RoomNumber { get; set; } + [DataMember(Order = 4)] public DateTime? BookingStartDate { get; set; } + [DataMember(Order = 5)] public DateTime? BookingEndDate { get; set; } + [DataMember(Order = 6)] public string Notes { get; set; } + [DataMember(Order = 7)] public bool? Cancelled { get; set; } + [ValidateGreaterThan(0)] + [DataMember(Order = 8)] public decimal? Cost { get; set; } + } + + [DataContract] + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditSoftDelete)] + public class DeleteBooking : IDeleteDb, IReturnVoid + { + [DataMember(Order = 1)] public int Id { get; set; } + } + + + [ValidateIsAuthenticated] + [AutoApply(Behavior.AuditCreate)] + public class CustomCreateBooking + : ICreateDb, IReturn + { + [ApiAllowableValues(typeof(RoomType))] + public RoomType RoomType { get; set; } + [ValidateGreaterThan(0)] + public int RoomNumber { get; set; } + public DateTime BookingStartDate { get; set; } + public DateTime? BookingEndDate { get; set; } + public string Notes { get; set; } + [ValidateGreaterThan(0)] + public decimal Cost { get; set; } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.Validate.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.Validate.cs new file mode 100644 index 00000000000..d1db1670bd7 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.Validate.cs @@ -0,0 +1,721 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.Model; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class NoRockstarAlbumReferences : TypeValidator + { + public NoRockstarAlbumReferences() + : base("HasForeignKeyReferences", "Has RockstarAlbum References") {} + + public override async Task IsValidAsync(object dto, IRequest request) + { + //Example of using compiled accessor delegates to access `Id` property + //var id = TypeProperties.Get(dto.GetType()).GetPublicGetter("Id")(dto).ConvertTo(); + + var id = ((IHasId) dto).Id; + using var db = HostContext.AppHost.GetDbConnection(request); + return !await db.ExistsAsync(x => x.RockstarId == id); + } + } + + public class MyValidators : ScriptMethods + { + public ITypeValidator NoRockstarAlbumReferences() => new NoRockstarAlbumReferences(); + } + + public partial class AutoQueryCrudTests + { + private bool UseDbSource = true; + + partial void OnConfigure(AutoQueryAppHost host, Container container) + { + host.ScriptContext.ScriptMethods.AddRange(new ScriptMethods[] { + new DbScriptsAsync(), + new MyValidators(), + }); + + host.Plugins.Add(new ValidationFeature { + ConditionErrorCodes = { + [ValidationConditions.IsOdd] = "NotOdd", + }, + ErrorCodeMessages = { + ["NotOdd"] = "{PropertyName} must be odd", + ["RuleMessage"] = "ErrorCodeMessages for RuleMessage", + } + }); + + if (UseDbSource) + { + container.Register(c => + new OrmLiteValidationSource(c.Resolve(), host.GetMemoryCacheClient())); + } + else + { + container.Register(new MemoryValidationSource()); + } + + var validationSource = container.Resolve(); + validationSource.InitSchema(); + validationSource.SaveValidationRulesAsync(new List { + new ValidationRule { Type = nameof(DynamicValidationRules), Validator = "IsAuthenticated" }, + new ValidationRule { Type = nameof(DynamicValidationRules), Field = nameof(DynamicValidationRules.LastName), Validator = "NotNull" }, + new ValidationRule { Type = nameof(DynamicValidationRules), Field = nameof(DynamicValidationRules.Age), Validator = "InclusiveBetween(13,100)" }, + }); + } + + private static void AssertErrorResponse(WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'First Name' must not be empty.")); + var status = ex.ResponseStatus; + if (status.Errors.Count != 3) + status.PrintDump(); + Assert.That(status.Errors.Count, Is.EqualTo(3)); + + var fieldError = status.Errors.First(x => x.FieldName == nameof(RockstarBase.FirstName)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(fieldError.Message, Is.EqualTo("'First Name' must not be empty.")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(RockstarBase.Age)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(fieldError.Message, Is.EqualTo("'Age' must not be empty.")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(RockstarBase.LastName)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(fieldError.Message, Is.EqualTo("'Last Name' must not be empty.")); + } + + [Test] + public void Does_validate_when_no_Abstract_validator() + { + try + { + var response = client.Post(new NoAbstractValidator { + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + AssertErrorResponse(ex); + Console.WriteLine(ex); + } + + try + { + var response = client.Post(new NoAbstractValidator { + FirstName = "A", + LastName = "B", + Age = 12, + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'Age' must be between 13 and 100. You entered 12.")); + var status = ex.ResponseStatus; + Assert.That(status.Errors.Count, Is.EqualTo(1)); + } + + client.Post(new NoAbstractValidator { + FirstName = "A", + LastName = "B", + Age = 13, + DateOfBirth = new DateTime(2001,1,1), + }); + } + + [Test] + public void Does_validate_DynamicValidationRules_combined_with_IValidationSource_rules() + { + try + { + var anonClient = new JsonServiceClient(Config.ListeningOn); + var response = anonClient.Post(new DynamicValidationRules { + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int) HttpStatusCode.Unauthorized)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + + var authClient = CreateAuthClient(); + try + { + var response = authClient.Post(new DynamicValidationRules { + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + AssertErrorResponse(ex); + Console.WriteLine(ex); + } + + try + { + var response = authClient.Post(new DynamicValidationRules { + FirstName = "A", + LastName = "B", + Age = 12, + DateOfBirth = new DateTime(2001,1,1), + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'Age' must be between 13 and 100. You entered 12.")); + var status = ex.ResponseStatus; + Assert.That(status.Errors.Count, Is.EqualTo(1)); + } + + authClient.Post(new DynamicValidationRules { + FirstName = "A", + LastName = "B", + Age = 13, + DateOfBirth = new DateTime(2001,1,1), + }); + } + + [Test] + public void Does_validate_combined_declarative_and_AbstractValidator() + { + try + { + var response = client.Post(new ValidateCreateRockstar { + DateOfBirth = new DateTime(2000,1,1) + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + AssertErrorResponse(ex); + Console.WriteLine(ex); + } + } + + [Test] + public void Does_validate_all_NotEmpty_Fields() + { + try + { + var response = client.Post(new EmptyValidators()); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Errors.Count, + Is.EqualTo(typeof(EmptyValidators).GetPublicProperties().Length)); + Assert.That(ex.ResponseStatus.Errors.All(x => x.ErrorCode == "NotEmpty")); + Console.WriteLine(ex); + } + } + + [Test] + public void Does_Validate_TriggerAllValidators() + { + try + { + var response = client.Post(new TriggerAllValidators { + CreditCard = "NotCreditCard", + Email = "NotEmail", + Empty = "NotEmpty", + Equal = "NotEqual", + ExclusiveBetween = 1, + GreaterThan = 1, + GreaterThanOrEqual = 1, + InclusiveBetween = 1, + Length = "Length", + LessThan = 20, + LessThanOrEqual = 20, + NotEmpty = "", + NotEqual = "NotEqual", + Null = "NotNull", + RegularExpression = "FOO", + ScalePrecision = 123.456m + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.AssertTriggerValidators(); + Console.WriteLine(ex); + } + } + + [Test] + public void Does_use_CustomErrorMessages() + { + try + { + var response = client.Post(new CustomValidationErrors()); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Console.WriteLine(ex); + var status = ex.ResponseStatus; + Assert.That(ex.ErrorCode, Is.EqualTo("ZERROR")); + Assert.That(ex.ErrorMessage, Is.EqualTo("'Custom Error Code' must not be empty.")); + Assert.That(status.Errors.Count, Is.EqualTo(typeof(CustomValidationErrors).GetProperties().Length)); + + var fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.CustomErrorCode)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("ZERROR")); + Assert.That(fieldError.Message, Is.EqualTo("'Custom Error Code' must not be empty.")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.CustomErrorCodeAndMessage)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("ZERROR")); + Assert.That(fieldError.Message, Is.EqualTo("Custom Error Code And Message has to be between 1 and 2, you: 0")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.ErrorCodeRule)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("RuleMessage")); + Assert.That(fieldError.Message, Is.EqualTo("ErrorCodeMessages for RuleMessage")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.IsOddCondition)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("NotOdd")); + Assert.That(fieldError.Message, Is.EqualTo("Is Odd Condition must be odd")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.IsOddAndOverTwoDigitsCondition)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("RuleMessage")); + Assert.That(fieldError.Message, Is.EqualTo("ErrorCodeMessages for RuleMessage")); + + fieldError = status.Errors.First(x => x.FieldName == nameof(CustomValidationErrors.IsOddOrOverTwoDigitsCondition)); + Assert.That(fieldError.ErrorCode, Is.EqualTo("ScriptCondition")); + Assert.That(fieldError.Message, Is.EqualTo("The specified condition was not met for 'Is Odd Or Over Two Digits Condition'.")); + } + } + + [Test] + public void Can_satisfy_combined_conditions() + { + try + { + var response = client.Post(new CustomValidationErrors { + IsOddAndOverTwoDigitsCondition = 101 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Errors.Count, Is.EqualTo(typeof(CustomValidationErrors).GetProperties().Length - 1)); + Assert.That(ex.ResponseStatus.Errors.All(x => x.FieldName != nameof(CustomValidationErrors.IsOddAndOverTwoDigitsCondition))); + } + try + { + var response = client.Post(new CustomValidationErrors { + IsOddOrOverTwoDigitsCondition = 102 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Errors.Count, Is.EqualTo(typeof(CustomValidationErrors).GetProperties().Length - 1)); + Assert.That(ex.ResponseStatus.Errors.All(x => x.FieldName != nameof(CustomValidationErrors.IsOddOrOverTwoDigitsCondition))); + } + } + + [Test] + public void Does_OnlyValidatesRequest() + { + try + { + var response = client.Post(new OnlyValidatesRequest { + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.ErrorCode, Is.EqualTo("RuleMessage")); + Assert.That(ex.ErrorMessage, Is.EqualTo("ErrorCodeMessages for RuleMessage")); + Assert.That(ex.GetFieldErrors().Count, Is.EqualTo(0)); + } + + try + { + var response = client.Post(new OnlyValidatesRequest { + Test = 101 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(401)); + Assert.That(ex.ErrorCode, Is.EqualTo("AssertFailed2")); + Assert.That(ex.ErrorMessage, Is.EqualTo("2nd Assert Failed")); + Assert.That(ex.GetFieldErrors().Count, Is.EqualTo(0)); + } + + try + { + var response = client.Post(new OnlyValidatesRequest { + Test = 1001 + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.ErrorCode, Is.EqualTo("NotNull")); + Assert.That(ex.GetFieldErrors().Count, Is.EqualTo(1)); + } + } + + [Test] + public void Can_use_custom_Guid_Id_and_DateTimeOffset() + { + try + { + client.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var response = client.Post(new CreateBookmark { + Description = "Description", + Slug = "Slug", + Title = "Title", + Url = "Url", + }); + + Assert.That(response.Id, Is.Not.EqualTo(new Guid())); + Assert.That(response.Result.Id, Is.EqualTo(response.Id)); + Assert.That(response.Result.Description, Is.EqualTo("Description")); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + [Test] + public void Does_validate_TestAuthValidators() + { + try + { + var anonClient = new JsonServiceClient(Config.ListeningOn); + anonClient.Post(new TestAuthValidators()); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(401)); + Assert.That(e.ErrorCode, Is.EqualTo("Unauthorized")); + Assert.That(e.ErrorMessage, Is.EqualTo("Not Authenticated")); + } + + try + { + var employeeClient = new JsonServiceClient(Config.ListeningOn); + + employeeClient.Post(new Authenticate { + provider = "credentials", + UserName = "employee@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + employeeClient.Post(new TestAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(403)); + Assert.That(e.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(e.ErrorMessage, Is.EqualTo("Manager Role Required")); + } + + try + { + var managerClient = new JsonServiceClient(Config.ListeningOn); + + managerClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + managerClient.Post(new TestAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + + try + { + var adminClient = new JsonServiceClient(Config.ListeningOn); + + adminClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + adminClient.Post(new TestAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + } + + + [Test] + public void Does_validate_TestMultiAuthValidators() + { + try + { + var anonClient = new JsonServiceClient(Config.ListeningOn); + anonClient.Post(new TestMultiAuthValidators()); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(401)); + Assert.That(e.ErrorCode, Is.EqualTo("Unauthorized")); + Assert.That(e.ErrorMessage, Is.EqualTo("Not Authenticated")); + } + + try + { + var employeeClient = new JsonServiceClient(Config.ListeningOn); + + employeeClient.Post(new Authenticate { + provider = "credentials", + UserName = "employee@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + employeeClient.Post(new TestMultiAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(403)); + Assert.That(e.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(e.ErrorMessage, Is.EqualTo("Manager Role Required")); + } + + try + { + var managerClient = new JsonServiceClient(Config.ListeningOn); + + managerClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + managerClient.Post(new TestMultiAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + + try + { + var adminClient = new JsonServiceClient(Config.ListeningOn); + + adminClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + adminClient.Post(new TestMultiAuthValidators()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + } + + [Test] + public void Does_validate_TestIsAdmin() + { + var userNames = new[] { "employee@email.com", "manager" }; + foreach (var userName in userNames) + { + var userClient = new JsonServiceClient(Config.ListeningOn); + if (userName != null) + { + try + { + var managerClient = new JsonServiceClient(Config.ListeningOn); + + managerClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + managerClient.Post(new TestIsAdmin()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(403)); + Assert.That(e.ErrorCode, Is.EqualTo("Forbidden")); + Assert.That(e.ErrorMessage, Is.EqualTo("Admin Role Required")); + } + } + } + + try + { + var adminClient = new JsonServiceClient(Config.ListeningOn); + + adminClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + adminClient.Post(new TestIsAdmin()); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); + } + } + + [Test] + public void Does_validate_TestDbCondition() + { + using var db = appHost.Resolve().OpenDbConnection(); + db.DropAndCreateTable(); + + try + { + db.Insert(new RockstarAlbum { Id = 1, Name = "An Album", Genre = "Pop", RockstarId = 1 }); + var response = client.Post(new TestDbCondition { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("HasForeignKeyReferences")); + } + + try + { + db.Delete(x => x.RockstarId == 1); + var response = client.Post(new TestDbCondition { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); //success! + } + } + + [Test] + public void Does_validate_TestDbValidator() + { + using var db = appHost.Resolve().OpenDbConnection(); + db.DropAndCreateTable(); + + try + { + db.Insert(new RockstarAlbum { Id = 1, Name = "An Album", Genre = "Pop", RockstarId = 1 }); + var response = client.Post(new TestDbValidator { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("HasForeignKeyReferences")); + } + + try + { + db.Delete(x => x.RockstarId == 1); + var response = client.Post(new TestDbValidator { + Id = 1, + }); + } + catch (WebServiceException e) + { + Assert.That(e.StatusCode, Is.EqualTo(400)); + Assert.That(e.ErrorCode, Is.EqualTo("NotNull")); //success! + } + } + } + + public static class ValidationUtils + { + public static void AssertTriggerValidators(this WebServiceException ex) + { + var errors = ex.ResponseStatus.Errors; + Assert.That(errors.First(x => x.FieldName == "CreditCard").ErrorCode, Is.EqualTo("CreditCard")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Email").ErrorCode, Is.EqualTo("Email")); + Assert.That(errors.First(x => x.FieldName == "Empty").ErrorCode, Is.EqualTo("Empty")); + Assert.That(errors.First(x => x.FieldName == "Equal").ErrorCode, Is.EqualTo("Equal")); + Assert.That(errors.First(x => x.FieldName == "ExclusiveBetween").ErrorCode, Is.EqualTo("ExclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "GreaterThan").ErrorCode, Is.EqualTo("GreaterThan")); + Assert.That(errors.First(x => x.FieldName == "GreaterThanOrEqual").ErrorCode, Is.EqualTo("GreaterThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "InclusiveBetween").ErrorCode, Is.EqualTo("InclusiveBetween")); + Assert.That(errors.First(x => x.FieldName == "Length").ErrorCode, Is.EqualTo("Length")); + Assert.That(errors.First(x => x.FieldName == "LessThan").ErrorCode, Is.EqualTo("LessThan")); + Assert.That(errors.First(x => x.FieldName == "LessThanOrEqual").ErrorCode, Is.EqualTo("LessThanOrEqual")); + Assert.That(errors.First(x => x.FieldName == "NotEmpty").ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(errors.First(x => x.FieldName == "NotEqual").ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errors.First(x => x.FieldName == "Null").ErrorCode, Is.EqualTo("Null")); + Assert.That(errors.First(x => x.FieldName == "RegularExpression").ErrorCode, Is.EqualTo("RegularExpression")); + Assert.That(errors.First(x => x.FieldName == "ScalePrecision").ErrorCode, Is.EqualTo("ScalePrecision")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.ValidateModels.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.ValidateModels.cs new file mode 100644 index 00000000000..f95b5817f48 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.ValidateModels.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using ServiceStack.FluentValidation; +using ServiceStack.Model; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public static class ValidationConditions + { + public const string IsOdd = "it.isOdd()"; + public const string IsOver2Digits = "it.log10() > 2"; + } + + public class ValidateCreateRockstar + : ICreateDb, IReturn + { + [Validate(nameof(ValidateScripts.NotNull))] + // [Validate("NotNull")] + public string FirstName { get; set; } + + //Added by Fluent Validator + public string LastName { get; set; } + + // [Validate("[" + nameof(ValidateScripts.NotNull) + "," + nameof(ValidateScripts.Length) + "(13,100)]")] e.g. Typed + // [Validate("[NotNull,Length(13,100)]")] + [Validate("NotNull")] + [Validate("InclusiveBetween(13,100)")] + public int? Age { get; set; } + + [Validate("NotEmpty(default('DateTime'))")] + //[Validate("NotEmpty")] equivalent to above thanks to: Validators.AppendDefaultValueOnEmptyValidators + public DateTime DateOfBirth { get; set; } + + public DateTime? DateDied { get; set; } + + public LivingStatus LivingStatus { get; set; } + } + + public class ValidateCreateRockstarValidator : AbstractValidator + { + public ValidateCreateRockstarValidator() + { + RuleFor(x => x.LastName).NotNull(); + } + } + + [AutoPopulate(nameof(LivingStatus), Value = LivingStatus.Alive)] + public class NoAbstractValidator + : ICreateDb, IReturn + { + [Validate("NotNull")] + public string FirstName { get; set; } + + [Validate("NotNull")] + public string LastName { get; set; } + + [Validate("[NotNull,InclusiveBetween(13,100)]")] + public int? Age { get; set; } + + [Validate("NotEmpty")] + public DateTime DateOfBirth { get; set; } + + public LivingStatus LivingStatus { get; set; } + } + + public class EmptyValidators + : ICreateDb, IReturn + { + // [Validate("NotEmpty(0)")] + [Validate("NotEmpty")] + public int Int { get; set; } + [Validate("NotEmpty")] + public int? NInt { get; set; } + [Validate("NotEmpty")] + // [Validate("NotEmpty(default('System.TimeSpan'))")] + public TimeSpan TimeSpan { get; set; } + [Validate("NotEmpty")] + public TimeSpan? NTimeSpan { get; set; } + [Validate("NotEmpty")] + public string String { get; set; } + [Validate("NotEmpty")] + public int[] IntArray { get; set; } + [Validate("NotEmpty")] + public List StringList { get; set; } + } + + public class TriggerAllValidators + : ICreateDb, IReturn + { + [ValidateCreditCard] + public string CreditCard { get; set; } + [ValidateEmail] + public string Email { get; set; } + [ValidateEmpty] + public string Empty { get; set; } + [ValidateEqual("Equal")] + public string Equal { get; set; } + [ValidateExclusiveBetween(10, 20)] + public int ExclusiveBetween { get; set; } + [ValidateGreaterThanOrEqual(10)] + public int GreaterThanOrEqual { get; set; } + [ValidateGreaterThan(10)] + public int GreaterThan { get; set; } + [ValidateInclusiveBetween(10, 20)] + public int InclusiveBetween { get; set; } + [ValidateExactLength(10)] + public string Length { get; set; } + [ValidateLessThanOrEqual(10)] + public int LessThanOrEqual { get; set; } + [ValidateLessThan(10)] + public int LessThan { get; set; } + [ValidateNotEmpty] + public string NotEmpty { get; set; } + [ValidateNotEqual("NotEqual")] + public string NotEqual { get; set; } + [ValidateNull] + public string Null { get; set; } + [ValidateRegularExpression("^[a-z]*$")] + public string RegularExpression { get; set; } + [ValidateScalePrecision(1,1)] + public decimal ScalePrecision { get; set; } + } + + public class DynamicValidationRules + : ICreateDb, IReturn + { + [ValidateNotNull] + public string FirstName { get; set; } + + //[Validate("NotNull")] added in IValidationSource + public string LastName { get; set; } + + // [Validate("[NotNull,InclusiveBetween(13,100)]")] + [ValidateNotNull] + //[Validate("InclusiveBetween(13,100)")] added in IValidationSource + public int? Age { get; set; } + + [ValidateNotEmpty] + public DateTime DateOfBirth { get; set; } + + public LivingStatus LivingStatus { get; set; } + } + + public class CustomValidationErrors + : ICreateDb, IReturn + { + // Just overrides ErrorCode + [ValidateNotNull(ErrorCode = "ZERROR")] + public string CustomErrorCode { get; set; } + + // Overrides both ErrorCode & Message + [Validate("InclusiveBetween(1,2)", ErrorCode = "ZERROR", + Message = "{PropertyName} has to be between {From} and {To}, you: {PropertyValue}")] + public int CustomErrorCodeAndMessage { get; set; } + + // Overrides ErrorCode & uses Message from Validators + [ValidateNotNull(ErrorCode = "RuleMessage")] + public string ErrorCodeRule { get; set; } + + // Overrides ErrorCode & uses Message from Validators + [Validate(Condition = ValidationConditions.IsOdd)] + public int IsOddCondition { get; set; } + + // Combined typed conditions + Error code + [Validate(AllConditions = new[]{ ValidationConditions.IsOdd, ValidationConditions.IsOver2Digits }, ErrorCode = "RuleMessage")] + public int IsOddAndOverTwoDigitsCondition { get; set; } + + // Combined typed conditions + unknown error code + [Validate(AnyConditions = new[]{ ValidationConditions.IsOdd, ValidationConditions.IsOver2Digits })] + public int IsOddOrOverTwoDigitsCondition { get; set; } + } + + [ValidateHasRole("Manager")] + public class TestAuthValidators + : ICreateDb, IReturn + { + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest("[IsAuthenticated,HasRole('Manager')]")] + public class TestMultiAuthValidators + : ICreateDb, IReturn + { + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateIsAdmin] + public class TestIsAdmin + : ICreateDb, IReturn + { + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest(Condition = "!dbExistsSync('SELECT * FROM RockstarAlbum WHERE RockstarId = @Id', { dto.Id })", + ErrorCode = "HasForeignKeyReferences")] + public class TestDbCondition + : ICreateDb, IReturn + { + public int Id { get; set; } + + [ValidateNotNull] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest("NoRockstarAlbumReferences")] + public class TestDbValidator + : ICreateDb, IReturn, IHasId + { + public int Id { get; set; } + + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + [ValidateRequest(Conditions = new[]{ "it.Test.isOdd()", "it.Test.log10() > 2" }, ErrorCode = "RuleMessage")] + [ValidateRequest(Condition = "it.Test.log10() > 3", ErrorCode = "AssertFailed2", Message = "2nd Assert Failed", StatusCode = 401)] + public class OnlyValidatesRequest + : ICreateDb, IReturn + { + // Combined typed conditions + Error code + public int Test { get; set; } + + [Validate("NotNull")] //doesn't get validated if ValidateRequest is invalid + public string NotNull { get; set; } + } + + + public class DaoBase + { + public virtual Guid Id { get; set; } + public virtual DateTimeOffset CreateDate { get; set; } + public virtual string CreatedBy { get; set; } + public virtual DateTimeOffset ModifiedDate { get; set; } + public virtual string ModifiedBy { get; set; } + } + + public class Bookmark : DaoBase + { + public string Slug { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Url { get; set; } + } + + public class QueryBookmarks : QueryDb { } + + // custom script methods + [AutoPopulate(nameof(Bookmark.Id), Eval = "nguid")] + [AutoPopulate(nameof(Bookmark.CreatedBy), Eval = "userAuthId")] + [AutoPopulate(nameof(Bookmark.CreateDate), Eval = "utcNowOffset")] + [AutoPopulate(nameof(Bookmark.ModifiedBy), Eval = "userAuthId")] + [AutoPopulate(nameof(Bookmark.ModifiedDate), Eval = "utcNowOffset")] + public class CreateBookmark : ICreateDb, IReturn + { + public string Slug { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Url { get; set; } + } + + public class CreateBookmarkResponse + { + public Guid Id { get; set; } + public Bookmark Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.cs new file mode 100644 index 00000000000..c8c28f5d73d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryCrudTests.cs @@ -0,0 +1,1608 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.Host; +using ServiceStack.Messaging; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AutoCrudGatewayServices : Service + { + public async Task Any(CreateRockstarAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public async Task Any(UpdateRockstarAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public async Task Any(PatchRockstarAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public async Task Any(RealDeleteAuditTenantGateway request) + { + var gatewayRequest = request.ConvertTo(); + var sync = Gateway.Send(gatewayRequest); + var response = await Gateway.SendAsync(gatewayRequest); + return response; + } + + public void Any(CreateRockstarAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + Request.PopulateRequestDtoIfAuthenticated(mqRequest); + PublishMessage(mqRequest); + } + + public void Any(UpdateRockstarAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + Request.PopulateRequestDtoIfAuthenticated(mqRequest); + PublishMessage(mqRequest); + } + + public void Any(PatchRockstarAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + mqRequest.BearerToken = Request.GetJwtToken(); + PublishMessage(mqRequest); + } + + public void Any(RealDeleteAuditTenantMq request) + { + var mqRequest = request.ConvertTo(); + mqRequest.BearerToken = Request.GetJwtToken(); + PublishMessage(mqRequest); + } + } + + [ConnectionInfo(NamedConnection = AutoQueryAppHost.SqlServerNamedConnection)] + public class AutoCrudConnectionInfoServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + public Task Any(CreateConnectionInfoRockstar request) => + AutoQuery.CreateAsync(request, Request); + + public Task Any(UpdateConnectionInfoRockstar request) => + AutoQuery.UpdateAsync(request, Request); + } + + public class AutoCrudBatchServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + protected virtual async Task BatchCreateAsync(IEnumerable> requests) + { + using var db = AutoQuery.GetDb(Request); + using var dbTrans = db.OpenTransaction(); + + var results = new List(); + foreach (var request in requests) + { + var response = await AutoQuery.CreateAsync(request, Request, db); + results.Add(response); + } + + dbTrans.Commit(); + return results; + } + + public object Any(CustomCreateBooking[] requests) => BatchCreateAsync(requests); + } + + /* + public abstract class B + { + public virtual async Task BatchCreateAsync(IEnumerable> requests) => Task.FromResult("A"); + } + public class A : B + { + public object Any(CustomCreateBooking[] requests) => BatchCreateAsync(requests); + } + */ + + public partial class AutoQueryCrudTests + { + private readonly ServiceStackHost appHost; + public IServiceClient client; + + private static readonly int TotalRockstars = AutoQueryAppHost.SeedRockstars.Length; + private static readonly int TotalAlbums = AutoQueryAppHost.SeedAlbums.Length; + private const string TenantId = nameof(TenantId); + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + public static string JwtUserToken = null; + + partial void OnConfigure(AutoQueryAppHost host, Funq.Container container); + + public AutoQueryCrudTests() + { + appHost = new AutoQueryAppHost { + ConfigureFn = (host,container) => { + + container.AddSingleton(c => + new OrmLiteCrudEvents(c.Resolve()) { + NamedConnections = { AutoQueryAppHost.SqlServerNamedConnection } + }.Reset() //Drop and re-create AutoCrudEvent Table + ); + container.Resolve().InitSchema(); + + container.AddSingleton(c => + new InMemoryAuthRepository()); + host.Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(host.AppSettings), + new JwtAuthProvider(host.AppSettings) { + RequireSecureConnection = false, + AuthKey = AuthKey, + CreatePayloadFilter = (obj, session) => { + obj[nameof(AuthUserSession.City)] = ((AuthUserSession)session).City; + } + }, + })); + + var jwtProvider = host.GetPlugin().AuthProviders.OfType().First(); + JwtUserToken = jwtProvider.CreateJwtBearerToken(new AuthUserSession { + Id = SessionExtensions.CreateRandomSessionId(), + UserName = "jwtuser", + FirstName = "JWT", + LastName = "User", + DisplayName = "JWT User", + City = "Japan", + }); + + var authRepo = container.Resolve(); + authRepo.InitSchema(); + + authRepo.CreateUserAuth(new UserAuth { + Id = 1, + Email = "admin@email.com", + DisplayName = "Admin User", + City = "London", + Roles = new List { + RoleNames.Admin + } + }, "p@55wOrd"); + + authRepo.CreateUserAuth(new UserAuth { + Id = 2, + UserName = "manager", + DisplayName = "The Manager", + City = "Perth", + Roles = new List { + "Employee", + "Manager", + } + }, "p@55wOrd"); + + authRepo.CreateUserAuth(new UserAuth { + Id = 3, + Email = "employee@email.com", + DisplayName = "An Employee", + City = "Manhattan", + Roles = new List { + "Employee", + } + }, "p@55wOrd"); + + void AddTenantId(IRequest req, IResponse res, object dto) + { + var userSession = req.SessionAs(); + if (userSession.IsAuthenticated) + { + req.SetItem(TenantId, userSession.City switch { + "London" => 10, + "Perth" => 10, + _ => 20, + }); + } + } + + host.GlobalRequestFilters.Add(AddTenantId); + host.GlobalMessageRequestFilters.Add(AddTenantId); + + container.AddSingleton(c => new BackgroundMqService()); + var mqService = container.Resolve(); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + mqService.RegisterHandler(host.ExecuteMessage); + host.AfterInitCallbacks.Add(_ => mqService.Start()); + + OnConfigure(host, container); + } + } + .Init() + .Start(Config.ListeningOn); + + using var db = appHost.TryResolve().OpenDbConnection(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + db.CreateTable(); + + AutoMapping.RegisterPopulator((Dictionary target, CreateRockstarWithAutoGuid source) => { + if (source.FirstName == "Created") + { + target[nameof(source.LivingStatus)] = LivingStatus.Dead; + } + }); + + client = new JsonServiceClient(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost.Dispose(); + + public List Rockstars => AutoQueryAppHost.SeedRockstars.ToList(); + + public List PagingTests => AutoQueryAppHost.SeedPagingTest.ToList(); + + private static JsonServiceClient CreateAuthClient() + { + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + return authClient; + } + + [Test] + public void Can_CreateRockstar() + { + var request = new CreateRockstar { + FirstName = "Return", + LastName = "Empty", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.Single(x => x.LastName == "Empty"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Return")); + } + + [Test] + public void Can_CreateRockstarWithReturn() + { + var request = new CreateRockstarWithReturn { + FirstName = "Return", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,2,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + Assert.That(response.Id, Is.GreaterThan(0)); + var newRockstar = response.Result; + Assert.That(newRockstar.LastName, Is.EqualTo("Result")); + } + + [Test] + public void Can_CreateRockstarWithVoidReturn() + { + var request = new CreateRockstarWithVoidReturn { + FirstName = "Return", + LastName = "Void", + Age = 20, + DateOfBirth = new DateTime(2001,3,1), + LivingStatus = LivingStatus.Alive, + }; + + client.Post(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.Single(x => x.LastName == "Void"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Return")); + } + + [Test] + public void Can_CreateRockstarWithAutoGuid() + { + var request = new CreateRockstarWithAutoGuid { + FirstName = "Create", + LastName = "AutoId", + Age = 20, + DateOfBirth = new DateTime(2001,4,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + Assert.That(response.Id, Is.Not.Null); + var newRockstar = response.Result; + Assert.That(newRockstar.Id, Is.EqualTo(response.Id)); + Assert.That(newRockstar.LastName, Is.EqualTo("AutoId")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + } + + [Test] + public void Can_CreateRockstarWithAutoGuid_with_Custom_Mapping() + { + var request = new CreateRockstarWithAutoGuid { + FirstName = "Created", + LastName = "AutoId", + Age = 20, + DateOfBirth = new DateTime(2001,5,1), + LivingStatus = LivingStatus.Alive, + }; + + var response = client.Post(request); + + Assert.That(response.Id, Is.Not.Null); + var newRockstar = response.Result; + Assert.That(newRockstar.Id, Is.EqualTo(response.Id)); + Assert.That(newRockstar.LastName, Is.EqualTo("AutoId")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Dead)); //overridden by RegisterPopulator + } + + [Test] + public void Can_UpdateRockstar() + { + var createResponse = client.Post(new CreateRockstarWithReturn { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }); + + var request = new UpdateRockstar { + Id = createResponse.Id, + LastName = "UpdateResult", + }; + + var response = client.Put(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.FirstName, Is.Null); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateResult")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + } + + [Test] + public void Can_PatchRockstar() + { + var createRequest = new CreateRockstarWithReturn { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }; + var createResponse = client.Post(createRequest); + + var request = new PatchRockstar { + Id = createResponse.Id, + LastName = "UpdateResult", + }; + + var response = client.Patch(request); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateResult")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(newRockstar.Age, Is.EqualTo(createRequest.Age)); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + } + + [Test] + public void Can_UpdateRockstarAdhocNonDefaults() + { + var createRequest = new CreateRockstarWithReturn { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }; + var createResponse = client.Post(createRequest); + + var request = new UpdateRockstarAdhocNonDefaults { + Id = createResponse.Id, + LastName = "UpdateResult", + }; + + using (JsConfig.With(new Text.Config { AssumeUtc = true })) + { + var response = client.Put(request); + } + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateResult")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); //[AutoUpdate(AutoUpdateStyle.NonDefaults)] + Assert.That(newRockstar.Age, Is.EqualTo(21)); //[AutoDefault(Value = 21)] + //[AutoDefault(Eval = "date(2001,1,1)")] + Assert.That(newRockstar.DateOfBirth, Is.EqualTo(new DateTime(2001,1,1))); + Assert.That(newRockstar.DateDied.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + //[AutoUpdate(AutoUpdateStyle.NonDefaults), AutoDefault(Value = LivingStatus.Dead)] + Assert.That(newRockstar.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + } + + [Test] + public void Does_throw_when_no_rows_updated() + { + try + { + client.Put(new UpdateRockstar { + Id = 100, + LastName = "UpdateRockstar", + }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(OptimisticConcurrencyException))); + } + } + + [Test] + public void Can_Delete_CreateRockstarWithReturn() + { + var request = new CreateRockstarWithReturn { + FirstName = "Delete", + LastName = "Rockstar", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(request); + + using var db = appHost.GetDbConnection(); + + var newRockstar = db.Single(x => x.Id == createResponse.Id); + Assert.That(newRockstar, Is.Not.Null); + + var response = client.Delete(new DeleteRockstar { + Id = createResponse.Id + }); + + newRockstar = db.Single(x => x.Id == createResponse.Id); + Assert.That(newRockstar, Is.Null); + } + + [Test] + public void Does_throw_for_Delete_without_filters() + { + var request = new CreateRockstarWithReturn { + FirstName = "Delete", + LastName = "Rockstar", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(request); + + try + { + var response = client.Delete(new DeleteRockstar()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(NotSupportedException))); + } + } + + [Test] + public void Can_delete_with_multiple_non_PrimaryKey_filters() + { + var requests = 5.Times(i => new CreateRockstarWithReturn { + FirstName = "Delete", + LastName = "Filter" + i, + Age = 23, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }); + + requests.Each(x => client.Post(x)); + + try + { + client.Delete(new DeleteRockstarFilters()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(NotSupportedException))); + } + + using var db = appHost.GetDbConnection(); + + var response = client.Delete(new DeleteRockstarFilters { Age = 23, LastName = "Filter1" }); + Assert.That(response.Count, Is.EqualTo(1)); + var remaining = db.Select(x => x.Age == 23); + Assert.That(remaining.Count, Is.EqualTo(5 - 1)); + + response = client.Delete(new DeleteRockstarFilters { Age = 23 }); + Assert.That(response.Count, Is.EqualTo(4)); + remaining = db.Select(x => x.Age == 23); + Assert.That(remaining.Count, Is.EqualTo(0)); + } + + [Test] + public void Can_CreateRockstarAdhocNonDefaults() + { + var createRequest = new CreateRockstarAdhocNonDefaults { + FirstName = "Create", + LastName = "Defaults", + }; + + using var jsScope = JsConfig.With(new Text.Config { AssumeUtc = true }); + var createResponse = client.Post(createRequest); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("Defaults")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(newRockstar.Age, Is.EqualTo(21)); //[AutoDefault(Value = 21)] + //[AutoDefault(Eval = "date(2001,1,1)")] + Assert.That(newRockstar.DateOfBirth, Is.EqualTo(new DateTime(2001,1,1))); + Assert.That(newRockstar.DateDied.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + //[AutoDefault(Value = global::ServiceStack.WebHost.Endpoints.Tests.LivingStatus.Dead)] + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + } + + [Test] + public void Can_CreateRockstarAutoMap() + { + var createRequest = new CreateRockstarAutoMap { + MapFirstName = "Map", + MapLastName = "Defaults", + MapDateOfBirth = new DateTime(2002,2,2), + MapLivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(createRequest); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.LastName, Is.EqualTo("Defaults")); + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.MapFirstName)); + Assert.That(newRockstar.Age, Is.EqualTo(21)); //[AutoDefault(Value = 21)] + //[AutoDefault(Eval = "date(2001,1,1)")] + Assert.That(newRockstar.DateOfBirth.Date, Is.EqualTo(new DateTime(2002,2,2).Date)); + Assert.That(newRockstar.DateDied.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + //[AutoDefault(Value = LivingStatus.Alive)] + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + } + + [Test] + public void Can_CreateRockstarAudit() + { + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var createResponse = authClient.Post(new CreateRockstarAudit { + FirstName = "Create", + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.FirstName, Is.EqualTo("Create")); + Assert.That(newRockstar.LastName, Is.EqualTo("Audit")); + Assert.That(newRockstar.Age, Is.EqualTo(20)); + Assert.That(newRockstar.DateOfBirth.Date, Is.EqualTo(new DateTime(2002,2,2).Date)); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("Admin User (London)")); + + authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + authClient.Patch(new UpdateRockstarAudit { + Id = createResponse.Id, + FirstName = "Updated", + LivingStatus = LivingStatus.Alive, + }); + + newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.FirstName, Is.EqualTo("Updated")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("manager")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("The Manager (Perth)")); + + authClient.Delete(new DeleteRockstarAudit { + Id = createResponse.Id, + }); + + newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar, Is.Null); + } + + [Test] + public async Task Can_CreateRockstarAuditTenant_with_Events() + { + var dbEvents = (OrmLiteCrudEvents) appHost.Resolve(); + dbEvents.Clear(); + + var authClient = CreateAuthClient(); + var id = CreateAndSoftDeleteRockstarAuditTenant(authClient); + + using var db = appHost.GetDbConnection(); + + void assertState(RockstarAuditTenant result) + { + Assert.That(result.Id, Is.EqualTo(id)); + Assert.That(result.FirstName, Is.EqualTo("Updated & Patched")); + Assert.That(result.LastName, Is.EqualTo("Audit")); + Assert.That(result.Age, Is.EqualTo(20)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(new DateTime(2002, 2, 2).Date)); + Assert.That(result.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + + Assert.That(result.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(result.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(result.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.ModifiedBy, Is.EqualTo("manager")); + Assert.That(result.ModifiedInfo, Is.EqualTo("The Manager (Perth)")); + } + + var crudEvents = db.Select(); + // events.PrintDump(); + Assert.That(crudEvents.Count, Is.EqualTo(4)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(CreateRockstarAuditTenant)), Is.EqualTo(1)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(UpdateRockstarAuditTenant)), Is.EqualTo(1)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(PatchRockstarAuditTenant)), Is.EqualTo(1)); + Assert.That(crudEvents.Count(x => x.RequestType == nameof(SoftDeleteAuditTenant)), Is.EqualTo(1)); + + var newRockstar = db.SingleById(id); + assertState(newRockstar); + + db.DeleteById(id); + Assert.That(db.SingleById(id), Is.Null); + + // OrmLiteUtils.PrintSql(); + + var eventsPlayer = new CrudEventsExecutor(appHost); + foreach (var crudEvent in dbEvents.GetEvents(db)) + { + await eventsPlayer.ExecuteAsync(crudEvent); + } + + crudEvents = db.Select(); + Assert.That(crudEvents.Count, Is.EqualTo(4)); // Should not be any new events created by executor + + newRockstar = db.SingleById(id); //uses the same Id + assertState(newRockstar); // State should be the same + } + + [Test] + public void Can_CreateRockstarAuditTenant() + { + var authClient = CreateAuthClient(); + CreateAndSoftDeleteRockstarAuditTenant(authClient); + } + + private int CreateAndSoftDeleteRockstarAuditTenant(JsonServiceClient authClient) + { + using var db = appHost.GetDbConnection(); + db.DeleteAll(); + + var createRequest = new CreateRockstarAuditTenant { + FirstName = "Create", + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002, 2, 2), + LivingStatus = LivingStatus.Dead, + }; + var createResponse = authClient.Post(createRequest); + var id = createResponse.Id; + Assert.That(id, Is.GreaterThan(0)); + var result = createResponse.Result; + + Assert.That(result.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + + var newRockstar = db.SingleById(id); + Assert.That(newRockstar.TenantId, Is.EqualTo(10)); //admin.City London => 10 + Assert.That(newRockstar.FirstName, Is.EqualTo(createRequest.FirstName)); + Assert.That(newRockstar.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(newRockstar.Age, Is.EqualTo(createRequest.Age)); + Assert.That(newRockstar.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(createRequest.LivingStatus)); + + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("Admin User (London)")); + + Assert.That(authClient.Get(new QueryRockstarAudit {Id = id}).Results.Count, + Is.EqualTo(1)); + + authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + + var updateRequest = new UpdateRockstarAuditTenant { + Id = id, + FirstName = "Updated", + LivingStatus = LivingStatus.Alive, + }; + var updateResponse = authClient.Put(updateRequest); + + void assertUpdated(RockstarAuto result) + { + Assert.That(result.FirstName, Does.StartWith(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + } + + Assert.That(updateResponse.Id, Is.EqualTo(id)); + assertUpdated(updateResponse.Result); + + newRockstar = db.SingleById(id); + Assert.That(newRockstar.FirstName, Is.EqualTo("Updated")); + Assert.That(newRockstar.LivingStatus, Is.EqualTo(LivingStatus.Alive)); + + Assert.That(newRockstar.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.CreatedBy, Is.EqualTo("admin@email.com")); + Assert.That(newRockstar.CreatedInfo, Is.EqualTo("Admin User (London)")); + Assert.That(newRockstar.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.ModifiedBy, Is.EqualTo("manager")); + Assert.That(newRockstar.ModifiedInfo, Is.EqualTo("The Manager (Perth)")); + + Assert.That(authClient.Get(new QueryRockstarAuditSubOr { + FirstNameStartsWith = "Up", + AgeOlderThan = 18, + }).Results.Count, + Is.EqualTo(1)); + + var patchRequest = new PatchRockstarAuditTenant { + Id = id, + FirstName = updateRequest.FirstName + " & Patched" + }; + var patchResponse = authClient.Patch(patchRequest); + Assert.That(patchResponse.Result.FirstName, Is.EqualTo("Updated & Patched")); + assertUpdated(patchResponse.Result); + + var softDeleteResponse = authClient.Put(new SoftDeleteAuditTenant { + Id = id, + }); + + Assert.That(softDeleteResponse.Id, Is.EqualTo(id)); + assertUpdated(softDeleteResponse.Result); + + newRockstar = db.SingleById(id); + Assert.That(newRockstar.SoftDeletedDate.Value.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(newRockstar.SoftDeletedBy, Is.EqualTo("manager")); + Assert.That(newRockstar.SoftDeletedInfo, Is.EqualTo("The Manager (Perth)")); + + Assert.That(authClient.Get(new QueryRockstarAudit {Id = id}).Results.Count, + Is.EqualTo(0)); + + Assert.That(authClient.Get(new QueryRockstarAuditSubOr { + FirstNameStartsWith = "Up", + AgeOlderThan = 18, + }).Results.Count, + Is.EqualTo(0)); + + return id; + } + + [Test] + public void Can_CreateRockstarAuditTenant_with_RealDelete() + { + var authClient = CreateAuthClient(); + var id = CreateAndSoftDeleteRockstarAuditTenant(authClient); + + using var db = appHost.GetDbConnection(); + + var realDeleteResponse = authClient.Delete(new RealDeleteAuditTenant { + Id = id, + Age = 99 //non matching filter + }); + Assert.That(realDeleteResponse.Id, Is.EqualTo(id)); + Assert.That(realDeleteResponse.Count, Is.EqualTo(0)); + var newRockstar = db.SingleById(id); + Assert.That(newRockstar, Is.Not.Null); + + realDeleteResponse = authClient.Delete(new RealDeleteAuditTenant { + Id = id, + }); + Assert.That(realDeleteResponse.Id, Is.EqualTo(id)); + Assert.That(realDeleteResponse.Count, Is.EqualTo(1)); + newRockstar = db.SingleById(id); + Assert.That(newRockstar, Is.Null); + } + + [Test] + public void Can_CreateRockstarAuditTenantGateway_Gateway() + { + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var createRequest = new CreateRockstarAuditTenantGateway { + FirstName = "CreateGateway", + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + var createResponse = authClient.Post(createRequest); + Assert.That(createResponse.Id, Is.GreaterThan(0)); + var result = createResponse.Result; + + var updateRequest = new UpdateRockstarAuditTenantGateway { + Id = createResponse.Id, + FirstName = "UpdatedGateway", + LivingStatus = LivingStatus.Alive, + }; + var updateResponse = authClient.Put(updateRequest); + result = updateResponse.Result; + + Assert.That(updateResponse.Id, Is.EqualTo(createResponse.Id)); + Assert.That(result.FirstName, Is.EqualTo(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + + var patchRequest = new PatchRockstarAuditTenantGateway { + Id = createResponse.Id, + FirstName = "PatchedGateway", + LivingStatus = LivingStatus.Alive, + }; + var patchResponse = authClient.Patch(patchRequest); + result = patchResponse.Result; + + Assert.That(updateResponse.Id, Is.EqualTo(createResponse.Id)); + Assert.That(result.FirstName, Is.EqualTo(patchRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(patchRequest.LivingStatus)); + + var deleteRequest = authClient.Delete(new RealDeleteAuditTenantGateway { + Id = createResponse.Id, + }); + Assert.That(deleteRequest.Id, Is.EqualTo(createResponse.Id)); + } + + [Test] + public void Can_CreateRockstarAuditTenantMq() + { + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + Assert.That(authClient.GetTokenCookie(), Is.Not.Null); + + var createRequest = new CreateRockstarAuditTenantMq { + FirstName = nameof(CreateRockstarAuditTenantMq), + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + authClient.Post(createRequest); + + using var db = appHost.GetDbConnection(); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(CreateRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + var result = db.Single(x => x.FirstName == nameof(CreateRockstarAuditTenantMq)); + + var updateRequest = new UpdateRockstarAuditTenantMq { + Id = result.Id, + FirstName = nameof(UpdateRockstarAuditTenantMq), + LivingStatus = LivingStatus.Alive, + }; + authClient.Put(updateRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(UpdateRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(UpdateRockstarAuditTenantMq)); + + Assert.That(result.FirstName, Is.EqualTo(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + + var patchRequest = new PatchRockstarAuditTenantMq { + Id = result.Id, + FirstName = nameof(PatchRockstarAuditTenantMq), + LivingStatus = LivingStatus.Alive, + }; + authClient.Patch(patchRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)); + + Assert.That(result.FirstName, Is.EqualTo(patchRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(patchRequest.LivingStatus)); + + authClient.Delete(new RealDeleteAuditTenantMq { + Id = result.Id, + }); + + ExecUtils.RetryUntilTrue(() => + !db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + + Assert.That(db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), Is.False); + } + + [Test] + public void Can_CreateRockstarAuditTenant_OneWay() + { + var authClient = new JsonServiceClient(Config.ListeningOn); + var authResponse = authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var createRequest = new CreateRockstarAuditTenant { + FirstName = nameof(CreateRockstarAuditTenant), + LastName = "Audit", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + authClient.SendOneWay(createRequest); + + using var db = appHost.GetDbConnection(); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(CreateRockstarAuditTenant)), + TimeSpan.FromSeconds(2)); + var result = db.Single(x => x.FirstName == nameof(CreateRockstarAuditTenant)); + + var updateRequest = new UpdateRockstarAuditTenant { + Id = result.Id, + FirstName = nameof(UpdateRockstarAuditTenant), + LivingStatus = LivingStatus.Alive, + }; + authClient.SendOneWay(updateRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(UpdateRockstarAuditTenant)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(UpdateRockstarAuditTenant)); + + Assert.That(result.FirstName, Is.EqualTo(updateRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(updateRequest.LivingStatus)); + + var patchRequest = new PatchRockstarAuditTenant { + Id = result.Id, + FirstName = nameof(PatchRockstarAuditTenant), + LivingStatus = LivingStatus.Alive, + }; + authClient.SendOneWay(patchRequest); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenant)), + TimeSpan.FromSeconds(2)); + result = db.Single(x => x.FirstName == nameof(PatchRockstarAuditTenant)); + + Assert.That(result.FirstName, Is.EqualTo(patchRequest.FirstName)); + Assert.That(result.LastName, Is.EqualTo(createRequest.LastName)); + Assert.That(result.Age, Is.EqualTo(createRequest.Age)); + Assert.That(result.DateOfBirth.Date, Is.EqualTo(createRequest.DateOfBirth.Date)); + Assert.That(result.LivingStatus, Is.EqualTo(patchRequest.LivingStatus)); + + authClient.Delete(new RealDeleteAuditTenant { + Id = result.Id, + }); + + ExecUtils.RetryUntilTrue(() => + !db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), + TimeSpan.FromSeconds(2)); + + Assert.That(db.Exists(x => x.FirstName == nameof(PatchRockstarAuditTenantMq)), Is.False); + } + + [Test] + public void Can_CreateRockstarAuditMqToken_OneWay() + { + var createRequest = new CreateRockstarAuditMqToken { + BearerToken = JwtUserToken, + FirstName = nameof(CreateRockstarAuditMqToken), + LastName = "JWT", + Age = 20, + DateOfBirth = new DateTime(2002,2,2), + LivingStatus = LivingStatus.Dead, + }; + + client.SendOneWay(createRequest); + + using var db = appHost.GetDbConnection(); + + ExecUtils.RetryUntilTrue(() => + db.Exists(x => x.FirstName == nameof(CreateRockstarAuditMqToken)), + TimeSpan.FromSeconds(2)); + + var result = db.Single(x => x.FirstName == nameof(CreateRockstarAuditMqToken)); + Assert.That(result.Id, Is.GreaterThan(0)); + Assert.That(result.FirstName, Is.EqualTo(nameof(CreateRockstarAuditMqToken))); + Assert.That(result.LastName, Is.EqualTo("JWT")); + Assert.That(result.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + Assert.That(result.CreatedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.CreatedBy, Is.EqualTo("jwtuser")); + Assert.That(result.CreatedInfo, Is.EqualTo("JWT User (Japan)")); + Assert.That(result.ModifiedDate.Date, Is.EqualTo(DateTime.UtcNow.Date)); + Assert.That(result.ModifiedBy, Is.EqualTo("jwtuser")); + Assert.That(result.ModifiedInfo, Is.EqualTo("JWT User (Japan)")); + } + + [Test] + public void Can_UpdateRockstarVersion() + { + var createResponse = client.Post(new CreateRockstarVersion { + FirstName = "Create", + LastName = "Version", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + }); + + try + { + client.Patch(new UpdateRockstarVersion { + Id = createResponse.Id, + LastName = "UpdateVersion2", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(OptimisticConcurrencyException))); + } + + var response = client.Patch(new UpdateRockstarVersion { + Id = createResponse.Id, + LastName = "UpdateVersion3", + RowVersion = createResponse.RowVersion, + }); + + using var db = appHost.GetDbConnection(); + var newRockstar = db.SingleById(createResponse.Id); + Assert.That(newRockstar.RowVersion, Is.Not.EqualTo(default(uint))); + Assert.That(newRockstar.FirstName, Is.EqualTo("Create")); + Assert.That(newRockstar.LastName, Is.EqualTo("UpdateVersion3")); + + try + { + client.Patch(new UpdateRockstarVersion { + Id = createResponse.Id, + LastName = "UpdateVersion4", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(OptimisticConcurrencyException))); + } + } + + [Test] + public void Can_NamedConnection_AutoCrud_Services() + { + var createRequest = new CreateNamedRockstar { + Id = 10, + FirstName = "Named", + LastName = "SqlServer", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(createRequest); + Assert.That(createResponse.Id, Is.EqualTo(10)); + Assert.That(createResponse.Result, Is.Not.Null); + + using var db = appHost.Resolve() + .OpenDbConnection(AutoQueryAppHost.SqlServerNamedConnection); + + var newRockstar = db.Single(x => x.LastName == "SqlServer"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Named")); + + var updateRequest = new UpdateNamedRockstar { + Id = 10, + FirstName = "Updated", + Age = 21, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Dead, + }; + + var updateResponse = client.Put(updateRequest); + + Assert.That(updateResponse.Id, Is.EqualTo(10)); + Assert.That(updateResponse.Result.FirstName, Is.EqualTo("Updated")); + Assert.That(updateResponse.Result.Age, Is.EqualTo(21)); + Assert.That(updateResponse.Result.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + } + + [Test] + public void Can_ConnectionInfo_AutoCrud_Services() + { + var createRequest = new CreateConnectionInfoRockstar { + Id = 11, + FirstName = "Named", + LastName = "SqlServer", + Age = 20, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Alive, + }; + + var createResponse = client.Post(createRequest); + Assert.That(createResponse.Id, Is.EqualTo(11)); + Assert.That(createResponse.Result, Is.Not.Null); + + using var db = appHost.Resolve() + .OpenDbConnection(AutoQueryAppHost.SqlServerNamedConnection); + + var newRockstar = db.Single(x => x.LastName == "SqlServer"); + Assert.That(newRockstar.FirstName, Is.EqualTo("Named")); + + var updateRequest = new UpdateConnectionInfoRockstar { + Id = 11, + FirstName = "Updated", + Age = 21, + DateOfBirth = new DateTime(2001,1,1), + LivingStatus = LivingStatus.Dead, + }; + + var updateResponse = client.Put(updateRequest); + + Assert.That(updateResponse.Id, Is.EqualTo(11)); + Assert.That(updateResponse.Result.FirstName, Is.EqualTo("Updated")); + Assert.That(updateResponse.Result.Age, Is.EqualTo(21)); + Assert.That(updateResponse.Result.LivingStatus, Is.EqualTo(LivingStatus.Dead)); + } + + [Test] + public void Can_Patch_DefaultFields_to_default_values() + { + var createRequest = new CreateDefaultValues { + Id = 1, + Bool = true, + NBool = false, + Int = 2, + NInt = 3, + String = "A", + }; + var createResponse = client.Post(createRequest); + AssertCreateDefaultValues(createRequest); + + var request = new PatchDefaultValues { + Id = createRequest.Id, + Reset = new[] { + nameof(PatchDefaultValues.Bool), + nameof(PatchDefaultValues.NBool), + nameof(PatchDefaultValues.Int), + nameof(PatchDefaultValues.NInt), + nameof(PatchDefaultValues.String), + }, + }; + client.Patch(request); + + using var db = appHost.GetDbConnection(); + var row = db.SingleById(createRequest.Id); + Assert.That(row.Bool, Is.EqualTo(default(bool))); + Assert.That(row.NBool, Is.EqualTo(default(bool?))); + Assert.That(row.Int, Is.EqualTo(default(int))); + Assert.That(row.NInt, Is.EqualTo(default(int?))); + Assert.That(row.String, Is.EqualTo(default(string))); + + Assert.Throws(() => client.Post(new PatchDefaultValues { + Id = createRequest.Id, + Reset = new[] { nameof(PatchDefaultValues.Id) }, + })); + } + + private void AssertCreateDefaultValues(CreateDefaultValues createRequest) + { + using var db = appHost.GetDbConnection(); + var row = db.SingleById(createRequest.Id); + Assert.That(row.Id, Is.EqualTo(createRequest.Id)); + Assert.That(row.Bool, Is.EqualTo(createRequest.Bool)); + Assert.That(row.NBool, Is.EqualTo(createRequest.NBool)); + Assert.That(row.Int, Is.EqualTo(createRequest.Int)); + Assert.That(row.NInt, Is.EqualTo(createRequest.NInt)); + Assert.That(row.String, Is.EqualTo(createRequest.String)); + } + + [Test] + public void Does_ignore_unknown_properties_not_on_DataModel() + { + var createResponse = client.Post(new CreateRockstarUnknownField { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + Unknown = "Field", + }); + + var queryResponse = client.Get(new QueryRockstarsUnknownField { + Id = createResponse.Id, + Unknown = "Field", + }); + + Assert.That(queryResponse.Results.Count, Is.EqualTo(1)); + + var updateResponse = client.Put(new UpdateRockstarUnknownField { + Id = createResponse.Id, + LastName = "UpdateResult", + Unknown = "Field", + }); + + var patchResponse = client.Patch(new PatchRockstarUnknownField { + Id = createResponse.Id, + LastName = "PatchResult", + Unknown = "Field", + }); + + var deleteResponse = client.Delete(new DeleteRockstarUnknownField { + Id = createResponse.Id, + Unknown = "Field", + }); + } + + [Test] + public async Task Does_ignore_unknown_properties_not_on_DataModel_Async() + { + var createResponse = await client.PostAsync(new CreateRockstarUnknownField { + FirstName = "UpdateReturn", + LastName = "Result", + Age = 20, + DateOfBirth = new DateTime(2001,7,1), + LivingStatus = LivingStatus.Dead, + Unknown = "Field", + }); + + var queryResponse = await client.GetAsync(new QueryRockstarsUnknownField { + Id = createResponse.Id, + Unknown = "Field", + }); + + Assert.That(queryResponse.Results.Count, Is.EqualTo(1)); + + var updateResponse = await client.PutAsync(new UpdateRockstarUnknownField { + Id = createResponse.Id, + LastName = "UpdateResult", + Unknown = "Field", + }); + + var patchResponse = await client.PatchAsync(new PatchRockstarUnknownField { + Id = createResponse.Id, + LastName = "PatchResult", + Unknown = "Field", + }); + + var deleteResponse = await client.DeleteAsync(new DeleteRockstarUnknownField { + Id = createResponse.Id, + Unknown = "Field", + }); + } + + [Test] + public void Does_not_allow_inserting_with_default_primary_key() + { + try + { + var response = client.Post(new CreateRockstarWithId()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Errors[0].ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Errors[0].FieldName, Is.EqualTo(nameof(Rockstar.Id))); + } + } + + [Test] + public async Task Does_not_allow_inserting_with_default_primary_key_Async() + { + try + { + var response = await client.PostAsync(new CreateRockstarWithId()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Errors[0].ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Errors[0].FieldName, Is.EqualTo(nameof(Rockstar.Id))); + } + } + + [Test] + public void Does_apply_Audit_behavior() + { + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var booking1Id = authClient.Post(new CreateBooking { + RoomNumber = 1, + BookingStartDate = DateTime.Today.AddDays(1), + BookingEndDate = DateTime.Today.AddDays(5), + Cost = 100, + }).Id.ToInt(); + var booking2Id = authClient.Post(new CreateBooking { + RoomNumber = 2, + BookingStartDate = DateTime.Today.AddDays(2), + BookingEndDate = DateTime.Today.AddDays(6), + Cost = 200, + }).Id.ToInt(); + + var bookings = client.Get(new QueryBookings { + Ids = new []{ booking1Id, booking2Id } + }); + + // bookings.PrintDump(); + Assert.That(bookings.Results.Count, Is.EqualTo(2)); + + Assert.That(bookings.Results.All(x => x.CreatedBy != null)); + Assert.That(bookings.Results.All(x => x.CreatedDate >= DateTime.UtcNow.Date)); + Assert.That(bookings.Results.All(x => x.ModifiedBy != null)); + Assert.That(bookings.Results.All(x => x.ModifiedDate >= DateTime.UtcNow.Date)); + Assert.That(bookings.Results.All(x => x.ModifiedDate == x.CreatedDate)); + + authClient.Patch(new UpdateBooking { + Id = booking1Id, + Cancelled = true, + Notes = "Missed Flight", + }); + var booking1 = client.Get(new QueryBookings { + Ids = new[] { booking1Id } + }).Results[0]; + Assert.That(booking1.Cancelled, Is.True); + Assert.That(booking1.Notes, Is.EqualTo("Missed Flight")); + Assert.That(booking1.ModifiedDate, Is.Not.EqualTo(booking1.CreatedDate)); + + authClient.Delete(new DeleteBooking { + Id = booking2Id, + }); + var booking2 = client.Get(new QueryBookings { + Ids = new[] { booking2Id } + }).Results?.FirstOrDefault(); + Assert.That(booking2, Is.Null); + + using var db = appHost.Resolve().OpenDbConnection(); + booking2 = db.SingleById(booking2Id); + // booking2.PrintDump(); + Assert.That(booking2, Is.Not.Null); + Assert.That(booking2.DeletedBy, Is.Not.Null); + Assert.That(booking2.DeletedDate, Is.Not.Null); + + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "manager", + Password = "p@55wOrd", + RememberMe = true, + }); + var booking3Id = authClient.Post(new CreateBooking { + RoomNumber = 3, + BookingStartDate = DateTime.Today.AddDays(3), + BookingEndDate = DateTime.Today.AddDays(7), + Cost = 100, + }).Id.ToInt(); + + var managerBookings = authClient.Get(new QueryUserBookings()); + Assert.That(managerBookings.Results.Count, Is.EqualTo(1)); + Assert.That(managerBookings.Results[0].RoomNumber, Is.EqualTo(3)); + + managerBookings = authClient.Get(new QueryUserMapBookings()); + Assert.That(managerBookings.Results.Count, Is.EqualTo(1)); + Assert.That(managerBookings.Results[0].RoomNumber, Is.EqualTo(3)); + + managerBookings = authClient.Get(new QueryEnsureUserBookings()); + Assert.That(managerBookings.Results.Count, Is.EqualTo(1)); + Assert.That(managerBookings.Results[0].RoomNumber, Is.EqualTo(3)); + } + + [Test] + public void Can_override_custom_Batch_Crud_Operation() + { + using var db = appHost.TryResolve().OpenDbConnection(); + db.DropAndCreateTable(); + + var items = new CustomCreateBooking[] { + new() { RoomType = RoomType.Double, RoomNumber = 10, Cost = 100, BookingStartDate = new DateTime(2021,01,01) }, + new() { RoomType = RoomType.Queen, RoomNumber = 11, Cost = 200, BookingStartDate = new DateTime(2021,01,02) }, + new() { RoomType = RoomType.Single, RoomNumber = 12, Cost = 300, BookingStartDate = new DateTime(2021,01,03) }, + new() { RoomType = RoomType.Suite, RoomNumber = 13, Cost = 400, BookingStartDate = new DateTime(2021,01,04) }, + new() { RoomType = RoomType.Twin, RoomNumber = 14, Cost = 500, BookingStartDate = new DateTime(2021,01,05) }, + }; + + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var responses = authClient.SendAll(items); + var responseIds = responses.Map(x => x.Id.ToInt()); + var results = db.SelectByIds(responseIds); + Assert.That(results.Map(x => x.RoomNumber), Is.EquivalentTo(new[]{ 10, 11, 12, 13, 14 })); + + db.DropAndCreateTable(); + + items[2].RoomNumber = 0; //Validation Error + try + { + responses = authClient.SendAll(items); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.Message, Is.EqualTo("'Room Number' must be greater than '0'.")); + } + Assert.That(db.SelectByIds(responseIds).Count, Is.EqualTo(0)); + + items[2].RoomNumber = 500; //DB Check Constraint Error + try + { + responses = authClient.SendAll(items); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.Message, Does.Contain("CHECK constraint failed")); + } + Assert.That(db.SelectByIds(responseIds).Count, Is.EqualTo(0)); + } + + [Test] + public void Does_execute_AutoBatch_CRUD_Create_Operation() + { + using var db = appHost.TryResolve().OpenDbConnection(); + db.DropAndCreateTable(); + + var items = new CreateBooking[] { + new() { RoomType = RoomType.Double, RoomNumber = 10, Cost = 100, BookingStartDate = new DateTime(2021,01,01) }, + new() { RoomType = RoomType.Queen, RoomNumber = 11, Cost = 200, BookingStartDate = new DateTime(2021,01,02) }, + new() { RoomType = RoomType.Single, RoomNumber = 12, Cost = 300, BookingStartDate = new DateTime(2021,01,03) }, + new() { RoomType = RoomType.Suite, RoomNumber = 13, Cost = 400, BookingStartDate = new DateTime(2021,01,04) }, + new() { RoomType = RoomType.Twin, RoomNumber = 14, Cost = 500, BookingStartDate = new DateTime(2021,01,05) }, + }; + + var authClient = new JsonServiceClient(Config.ListeningOn); + authClient.Post(new Authenticate { + provider = "credentials", + UserName = "admin@email.com", + Password = "p@55wOrd", + RememberMe = true, + }); + + var responses = authClient.SendAll(items); + var responseIds = responses.Map(x => x.Id.ToInt()); + var results = db.SelectByIds(responseIds); + Assert.That(results.Map(x => x.RoomNumber), Is.EquivalentTo(new[]{ 10, 11, 12, 13, 14 })); + + db.DropAndCreateTable(); + + items[2].RoomNumber = 0; //Validation Error + try + { + responses = authClient.SendAll(items); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.Message, Is.EqualTo("'Room Number' must be greater than '0'.")); + } + Assert.That(db.SelectByIds(responseIds).Count, Is.EqualTo(0)); + + items[2].RoomNumber = 500; //DB Check Constraint Error + try + { + responses = authClient.SendAll(items); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + Assert.That(e.Message, Does.Contain("CHECK constraint failed")); + } + Assert.That(db.SelectByIds(responseIds).Count, Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataServiceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataServiceTests.cs new file mode 100644 index 00000000000..ccc02f3da83 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataServiceTests.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AutoQueryDataServiceTests : AutoQueryDataTests + { + static AutoQueryDataServiceTests() + { +#if NETFX + //https://githubengineering.com/crypto-removal-notice/ + ServicePointManager.Expect100Continue = true; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; +#endif + } + + public override ServiceStackHost CreateAppHost() + { + return new AutoQueryDataServiceAppHost(); + } + + [Test] + public void Can_call_overidden_AutoQueryData_Service_with_custom_MemorySource() + { + var response = client.Get(new GetAllRockstarGenresData { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(AutoQueryDataAppHost.SeedGenres.Length)); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryDataAppHost.SeedGenres.Length)); + + response = client.Get(new GetAllRockstarGenresData { Name = "Grunge" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].RockstarId, Is.EqualTo(3)); + } + + [Test] + public void Does_Cache_third_party_api_ServiceSource() + { + GetGithubRepos.ApiCalls = 0; + QueryResponse response; + + response = client.Get(new QueryGitHubRepos { Organization = "ServiceStack" }); + Assert.That(response.Results.Count, Is.GreaterThan(20)); + Assert.That(GetGithubRepos.ApiCalls, Is.EqualTo(1)); + + response = client.Get(new QueryGitHubRepos { Organization = "ServiceStack", + NameStartsWith = "ServiceStack", + Fields = "Name,Description,Homepage,Language,Watchers_Count", + OrderByDesc = "Watchers_Count" + }); + Assert.That(response.Results.Count, Is.LessThan(20)); + Assert.That(response.Results.All(x => x.Id == 0)); + Assert.That(response.Results.All(x => x.Name != null)); + Assert.That(response.Results[0].Watchers_Count, Is.GreaterThan(3000)); + Assert.That(GetGithubRepos.ApiCalls, Is.EqualTo(1)); + + response = client.Get(new QueryGitHubRepos { User = "mythz" }); + Assert.That(response.Results.Count, Is.GreaterThan(20)); + Assert.That(GetGithubRepos.ApiCalls, Is.EqualTo(2)); + + response = client.Get(new QueryGitHubRepos { User = "mythz", + DescriptionContains = "101 LINQ Samples", + Take = 4, + OrderBy = "Name", + }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + Assert.That(GetGithubRepos.ApiCalls, Is.EqualTo(2)); + } + + [Test] + public void Does_Cache_MemorySource() + { + QueryResponse response; + + response = client.Get(new QueryServiceStackContributors + { + Repo = "ServiceStack", + Take = 20, + Include = "Total" + }); + Assert.That(response.Total, Is.GreaterThan(20)); + Assert.That(response.Results.Count, Is.EqualTo(20)); + Assert.That(HostContext.LocalCache.Get>("aqd:" + typeof(GithubContributor).Name) != null); + + response = client.Get(new QueryServiceStackContributors + { + Repo = "ServiceStack", + ContributionsAbove = 10, + Fields = "Login,Contributions" + }); + Assert.That(response.Results.Count, Is.GreaterThan(10)); + Assert.That(response.Results.All(c => c.Contributions > 10)); + Assert.That(response.Results.All(c => c.Login != null)); + Assert.That(response.Results.All(c => c.Id == 0)); + Assert.That(response.Results.All(c => c.Type == null)); + } + } + + public class AutoQueryDataServiceAppHost : AutoQueryDataAppHost + { + public override void Configure(Container container) + { +#if NETFX + //https://githubengineering.com/crypto-removal-notice/ + ServicePointManager.Expect100Continue = true; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; +#endif + + base.Configure(container); + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + + using (var db = container.Resolve().Open()) + { + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.InsertAll(SeedRockstars); + db.InsertAll(SeedAlbums); + db.InsertAll(SeedAdhoc); + db.InsertAll(SeedMovies); + db.InsertAll(SeedAllFields); + db.InsertAll(SeedPagingTest); + db.InsertAll(SeedGenres); + } + + var feature = this.GetPlugin(); + feature.AddDataSource(ctx => ctx.ServiceSource(new GetAllRockstarData())); + feature.AddDataSource(ctx => ctx.ServiceSource(ctx.Dto.ConvertTo())); + feature.AddDataSource(ctx => ctx.ServiceSource(new GetAllAdhocData())); + feature.AddDataSource(ctx => ctx.ServiceSource(new GetAllMoviesData())); + feature.AddDataSource(ctx => ctx.ServiceSource(new GetAllFieldsData())); + feature.AddDataSource(ctx => ctx.ServiceSource(new GetAllPagingTestData())); + feature.AddDataSource(ctx => ctx.ServiceSource(new GetAllPagingTestData())); + feature.AddDataSource(ctx => ctx.ServiceSource(ctx.Dto.ConvertTo(), + HostContext.Cache, TimeSpan.FromMinutes(1))); + feature.AddDataSource(ctx => ctx.MemorySource( + () => "https://api.github.com/repos/ServiceStack/{0}/contributors" + .Fmt(ctx.Request.GetParam("repo")) + .GetJsonFromUrl(req => req.With(c => c.UserAgent = "AutoQuery")).FromJson>(), + HostContext.LocalCache, TimeSpan.FromMinutes(1))); + } + } + + //No IReturn -> List + public class GetAllRockstarData {} + + //IReturn -> List + public class GetAllRockstarAlbumsData : IReturn> + { + public int? Id { get; set; } + public int? RockstarId { get; set; } + public string Name { get; set; } + public string Genre { get; set; } + public int[] IdBetween { get; set; } + } + + //Response DTO + public class GetAllAdhocData : IReturn { } + public class GetAllAdhocDataResponse + { + public DateTime Created { get; set; } + public List Results { get; set; } + } + + //GET No IReturn Task Response + public class GetAllMoviesData {} + + //Response DTO Task Response + public class GetAllFieldsData : IReturn { } + public class GetAllFieldsDataResponse + { + public DateTime Created { get; set; } + public List Results { get; set; } + } + + //GET + public class GetAllPagingTestData { } + + public class QueryGitHubRepos : QueryData + { + public string User { get; set; } + public string Organization { get; set; } + + public string NameStartsWith { get; set; } + public string DescriptionContains { get; set; } + public int? Watchers_Count { get; set; } + } + + public class GetGithubRepos : IReturn> + { + public static int ApiCalls = 0; + + public string User { get; set; } + public string Organization { get; set; } + } + + public class QueryServiceStackContributors : QueryData + { + public string Repo { get; set; } + public int? ContributionsAbove { get; set; } + } + + public class DataQueryServices : Service + { + public object Any(GetAllRockstarData request) + { + return Db.Select().AsTaskResult(); + } + + public object Any(GetAllRockstarAlbumsData request) + { + var q = Db.From(); + + if (request.IdBetween != null) + q.Where(x => x.Id >= request.IdBetween[0] && x.Id <= request.IdBetween[1]); + + if (request.Name != null) + q.Where(x => x.Name == request.Name); + + var results = Db.Select(q); + return results; + } + + public object Any(GetAllAdhocData request) + { + return new GetAllAdhocDataResponse + { + Results = Db.Select() + }; + } + + public object Any(GetAllMoviesData request) + { + return Task.FromResult(Db.Select()); + } + + public Task Get(GetAllFieldsData request) + { + return Task.FromResult(new GetAllFieldsDataResponse + { + Created = DateTime.UtcNow, + Results = Db.Select(), + }); + } + + public Task> Get(GetAllPagingTestData request) + { + return Task.FromResult(Db.Select()); + } + + public object Get(GetGithubRepos request) + { + if (request.User == null && request.Organization == null) + throw new ArgumentNullException("User"); + + var url = request.User != null + ? "https://api.github.com/users/{0}/repos".Fmt(request.User) + : "https://api.github.com/orgs/{0}/repos".Fmt(request.Organization); + + Interlocked.Increment(ref GetGithubRepos.ApiCalls); + + return url.GetJsonFromUrl(requestFilter:req => req.With(c => c.UserAgent = GetType().Name)) + .FromJson>(); + } + } + + public class GetAllRockstarGenresData : QueryData + { + public string Name { get; set; } + } + + public class CustomDataQueryServices : Service + { + public IAutoQueryData AutoQuery { get; set; } + + public object Any(GetAllRockstarGenresData requestDto) + { + var memorySource = new MemoryDataSource(Db.Select(), requestDto, Request); + var q = AutoQuery.CreateQuery(requestDto, Request, memorySource); + return AutoQuery.Execute(requestDto, q, memorySource); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataTests.Dynamo.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataTests.Dynamo.cs new file mode 100644 index 00000000000..de2a7a02ecc --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataTests.Dynamo.cs @@ -0,0 +1,426 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.DataAnnotations; +using ServiceStack.Text; +using Amazon.DynamoDBv2; +using ServiceStack.Aws.DynamoDb; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AutoQueryDataDynamoTests : AutoQueryDataTests + { + public override ServiceStackHost CreateAppHost() + { + return new AutoQueryDataDynamoAppHost(); + } + + [Test] + public void Does_perform_QUERY_operation_when_querying_hash_key() + { + var response = client.Get(new QueryDataRockstarAlbums + { + RockstarId = 3, + Genre = "Grunge", + }); + + Assert.That(response.Results.Count, Is.EqualTo(4)); + Assert.That(response.Results.Map(x => x.RockstarId).Distinct(), + Is.EquivalentTo(new[] { 3 })); + } + + [Test] + public void Does_perform_SCAN_operation_when_not_querying_hash_key() + { + var response = client.Get(new QueryDataRockstarAlbums + { + Genre = "Grunge", + }); + + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Results.Map(x => x.RockstarId).Distinct(), + Is.EquivalentTo(new[] { 3, 5 })); + } + + [Test] + public void Can_query_on_ForeignKey_and_RockstarAlbumGenreIndex() + { + QueryResponse response; + response = client.Get(new QueryDataRockstarAlbumGenreIndex { Genre = "Grunge", Include = "Total" }); //Hash + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Total, Is.EqualTo(5)); + + response = client.Get(new QueryDataRockstarAlbumGenreIndex { Genre = "Grunge", Id = 3, Include = "Total" }); //Hash + Range + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Name, Is.EqualTo("Nevermind")); + + //Hash + Range BETWEEN + response = client.Get(new QueryDataRockstarAlbumGenreIndex + { + Genre = "Grunge", + IdBetween = new[] { 2, 3 }, + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(2)); + + //Hash + Range BETWEEN + Filter + response = client.Get(new QueryDataRockstarAlbumGenreIndex + { + Genre = "Grunge", + IdBetween = new[] { 2, 3 }, + Name = "Nevermind", + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Id, Is.EqualTo(3)); + + response.PrintDump(); + } + + [Test] + public void Can_query_on_ForeignKey_and_RockstarAlbumGenreIndex_Mapped() + { + QueryResponse response; + response = client.Get(new QueryDataRockstarAlbumGenreIndexMapped { Genre = "Grunge", Include = "Total" }); //Hash + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Total, Is.EqualTo(5)); + + response = client.Get(new QueryDataRockstarAlbumGenreIndexMapped { Genre = "Grunge", Id = 3, Include = "Total" }); //Hash + Range + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Name, Is.EqualTo("Nevermind")); + + //Hash + Range BETWEEN + response = client.Get(new QueryDataRockstarAlbumGenreIndexMapped + { + Genre = "Grunge", + IdBetween = new[] { 2, 3 }, + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(2)); + + //Hash + Range BETWEEN + Filter + response = client.Get(new QueryDataRockstarAlbumGenreIndexMapped + { + Genre = "Grunge", + IdBetween = new[] { 2, 3 }, + Name = "Nevermind", + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Id, Is.EqualTo(3)); + + response.PrintDump(); + } + + [Test] + public void Can_query_MovieTitleIndex_Ratings() + { + var response = client.Get(new QueryDataMovieTitleIndex { Ratings = new[] { "G", "PG-13" } }); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + var url = Config.ListeningOn + "moviesdataindex/search?ratings=G,PG-13"; + response = url.AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + response = client.Get(new QueryDataMovieTitleIndex + { + Ids = new[] { 1, 2 }, + ImdbIds = new[] { "tt0071562", "tt0060196" }, + Ratings = new[] { "G", "PG-13" } + }); + Assert.That(response.Results.Count, Is.EqualTo(9)); + + url = Config.ListeningOn + "moviesdataindex?ratings=G,PG-13&ids=1,2&imdbIds=tt0071562,tt0060196"; + response = url.AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(9)); + } + + [Test] + public void Does_implicitly_OrderBy_PrimaryKey_when_limits_is_specified_SearchDataMovieTitleIndex() + { + var movies = client.Get(new SearchDataMovieTitleIndex { Take = 100 }); + var ids = movies.Results.Map(x => x.Id); + var orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var rockstars = client.Get(new SearchDataMovieTitleIndex { Take = 100 }); + ids = rockstars.Results.Map(x => x.Id); + orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public void Can_OrderBy_queries_SearchDataMovieTitleIndex() + { + var movies = client.Get(new SearchDataMovieTitleIndex { Take = 100, OrderBy = "ImdbId" }); + var ids = movies.Results.Map(x => x.ImdbId); + var orderedIds = ids.OrderBy(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovieTitleIndex { Take = 100, OrderBy = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovieTitleIndex { Take = 100, OrderByDesc = "ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = ids.OrderByDescending(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovieTitleIndex { Take = 100, OrderByDesc = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovieTitleIndex { Take = 100, OrderBy = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovieTitleIndex { Take = 100, OrderByDesc = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var url = Config.ListeningOn + "moviesdata/search?take=100&orderBy=Rating,ImdbId"; + movies = url.AsJsonInto(); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + url = Config.ListeningOn + "moviesdata/search?take=100&orderByDesc=Rating,ImdbId"; + movies = url.AsJsonInto(); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public void Cached_DynamoQuery_does_cached_duplicate_requests_when_MaxAge() + { + var request = new QueryCacheMaxAgeDataRockstars(); + var client = new CachedServiceClient(new JsonServiceClient(Config.ListeningOn)); + + var response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count)); + + response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryCacheMaxAgeDataRockstars { Age = 27 }); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public void Cached_DynamoQuery_does_cached_duplicate_requests_when_MaxAge_Custom_Cached() + { + var request = new CustomQueryCacheMaxAgeDataRockstars(); + var client = new CachedServiceClient(new JsonServiceClient(Config.ListeningOn)); + + var response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count)); + + response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new CustomQueryCacheMaxAgeDataRockstars { Age = 27 }); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public void Cached_DynamoQuery_does_return_NotModified_when_MustRevalidate() + { + var request = new QueryCacheMustRevalidateDataRockstars(); + var client = new CachedServiceClient(new JsonServiceClient(Config.ListeningOn)); + + var response = client.Get(request); + Assert.That(client.NotModifiedHits, Is.EqualTo(0)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count)); + + response = client.Get(request); + Assert.That(client.NotModifiedHits, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryCacheMustRevalidateDataRockstars { Age = 27 }); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(client.NotModifiedHits, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public void Does_throw_on_SCAN_when_not_allowScans() + { + var results = client.Get(new QueryScannedTable { Id = 1 }); + + Assert.Throws(() => + client.Get(new QueryScannedTable { Name = "foo" }) + ); + } + } + + public class AutoQueryDataDynamoAppHost : AutoQueryDataAppHost + { + public override void Configure(Container container) + { + base.Configure(container); + + container.Register(c => new PocoDynamo( + new AmazonDynamoDBClient("keyId", "key", new AmazonDynamoDBConfig + { + ServiceURL = Tests.Config.DynamoDbServiceURL, + })) + .RegisterTable() + .RegisterTable() + .RegisterTable() + .RegisterTable() + .RegisterTable() + .RegisterTable() + .RegisterTable() + ); + + var dynamo = container.Resolve(); + //dynamo.DeleteAllTables(); + dynamo.InitSchema(); + dynamo.PutItems(SeedRockstars); + dynamo.PutItems(SeedAlbums); + dynamo.PutItems(SeedAdhoc); + dynamo.PutItems(SeedMovies); + dynamo.PutItems(SeedAllFields); + dynamo.PutItems(SeedPagingTest); + + var feature = this.GetPlugin(); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource()); + feature.AddDataSource(ctx => ctx.DynamoDbSource(allowScans: false)); + } + } + + public class ScannedTable + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class QueryScannedTable : QueryData + { + public int? Id { get; set; } + public string Name { get; set; } + } + + [Route("/moviesdataindex/search")] + [QueryData(QueryTerm.And)] //Default + public class SearchDataMovieTitleIndex : QueryData { } + + [Route("/moviesdataindex")] + [QueryData(QueryTerm.Or)] + public class QueryDataMovieTitleIndex : QueryData + { + public int[] Ids { get; set; } + public string[] ImdbIds { get; set; } + public string[] Ratings { get; set; } + } + + public class MovieTitleIndex : IGlobalIndex + { + [HashKey] + public string Title { get; set; } + + [RangeKey] + public decimal Score { get; set; } + + public int Id { get; set; } + public string ImdbId { get; set; } + public string Rating { get; set; } + public string Director { get; set; } + public DateTime ReleaseDate { get; set; } + public string TagLine { get; set; } + public List Genres { get; set; } + } + + [Route("/querydata/rockstaralbumindex")] + public class QueryDataRockstarAlbumGenreIndex : QueryData + { + public int? Id { get; set; } + public int? RockstarId { get; set; } + public string Name { get; set; } + public string Genre { get; set; } + public int[] IdBetween { get; set; } + } + + [Route("/querydata/rockstaralbumindex/mapped")] + public class QueryDataRockstarAlbumGenreIndexMapped : QueryData + { + public int? Id { get; set; } + public int? RockstarId { get; set; } + public string Name { get; set; } + public string Genre { get; set; } + public int[] IdBetween { get; set; } + } + + public class RockstarAlbumGenreGlobalIndex : IGlobalIndex + { + [HashKey] + public string Genre { get; set; } + + [RangeKey] + public int Id { get; set; } + + public string Name { get; set; } + public int RockstarId { get; set; } + } + + [CacheResponse(Duration = 10, MaxAge = 10)] + [Route("/querydata/cachemaxage/rockstars")] + public class QueryCacheMaxAgeDataRockstars : QueryData + { + public int? Age { get; set; } + } + + [CacheResponse(Duration = 10, MaxAge = 0, CacheControl = CacheControl.MustRevalidate)] + [Route("/querydata/cachemustrevalidate/rockstars")] + public class QueryCacheMustRevalidateDataRockstars : QueryData + { + public int? Age { get; set; } + } + + [Route("/custom/querydata/cachemaxage/rockstars")] + public class CustomQueryCacheMaxAgeDataRockstars : QueryData + { + public int? Age { get; set; } + } + + [CacheResponse(Duration = 10, MaxAge = 10)] + public class MyCachedAutoQueryServices : Service + { + public IAutoQueryData AutoQuery { get; set; } + + public object Any(CustomQueryCacheMaxAgeDataRockstars query) + { + return AutoQuery.Execute(query, AutoQuery.CreateQuery(query, Request), Request); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataTests.cs new file mode 100644 index 00000000000..03f0b2abe0e --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryDataTests.cs @@ -0,0 +1,1135 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.Extensions; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AutoQueryDataMemoryTests : AutoQueryDataTests + { + public override ServiceStackHost CreateAppHost() + { + return new AutoQueryDataAppHost(); + } + } + + public class AutoQueryDataAppHost : AppSelfHostBase + { + public AutoQueryDataAppHost() + : base("AutoQuerData", typeof(AutoQueryService).Assembly) + { } + + public override void Configure(Container container) + { + Plugins.Add(new AutoQueryDataFeature + { + MaxLimit = 100, + ResponseFilters = { + ctx => { + var executedCmds = new List(); + var supportedFns = new Dictionary>(StringComparer.OrdinalIgnoreCase) + { + {"ADD", (a,b) => a + b }, + {"MULTIPLY", (a,b) => a * b }, + {"DIVIDE", (a,b) => a / b }, + {"SUBTRACT", (a,b) => a - b }, + }; + foreach (var cmd in ctx.Commands) + { + if (!supportedFns.TryGetValue(cmd.Name, out var fn)) continue; + var label = !cmd.Suffix.IsNullOrWhiteSpace() ? cmd.Suffix.ToString().Trim() : cmd.ToString(); + ctx.Response.Meta[label] = fn(cmd.Args[0].ParseInt32(), cmd.Args[1].ParseInt32()).ToString(); + executedCmds.Add(cmd); + } + ctx.Commands.RemoveAll(executedCmds.Contains); + } + } + } + .AddDataSource(ctx => ctx.MemorySource(SeedRockstars)) + .AddDataSource(ctx => ctx.MemorySource(SeedAlbums)) + .AddDataSource(ctx => ctx.MemorySource(SeedGenres)) + .AddDataSource(ctx => ctx.MemorySource(SeedAdhoc)) + .AddDataSource(ctx => ctx.MemorySource(SeedMovies)) + .AddDataSource(ctx => ctx.MemorySource(SeedAllFields)) + .AddDataSource(ctx => ctx.MemorySource(SeedPagingTest)) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName, new EndsWithCondition(), "son") + ) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName, new EndsWithCondition(), "son") + ) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName, new EndsWithCondition(), "son") + ) + ); + } + + public static Rockstar[] SeedRockstars = new[] { + new Rockstar { Id = 1, FirstName = "Jimi", LastName = "Hendrix", LivingStatus = LivingStatus.Dead, Age = 27, DateOfBirth = new DateTime(1942, 11, 27), DateDied = new DateTime(1970, 09, 18), }, + new Rockstar { Id = 2, FirstName = "Jim", LastName = "Morrison", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1943, 12, 08), DateDied = new DateTime(1971, 07, 03), }, + new Rockstar { Id = 3, FirstName = "Kurt", LastName = "Cobain", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1967, 02, 20), DateDied = new DateTime(1994, 04, 05), }, + new Rockstar { Id = 4, FirstName = "Elvis", LastName = "Presley", Age = 42, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1935, 01, 08), DateDied = new DateTime(1977, 08, 16), }, + new Rockstar { Id = 5, FirstName = "David", LastName = "Grohl", Age = 44, LivingStatus = LivingStatus.Alive, DateOfBirth = new DateTime(1969, 01, 14), }, + new Rockstar { Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48, LivingStatus = LivingStatus.Alive, DateOfBirth = new DateTime(1964, 12, 23), }, + new Rockstar { Id = 7, FirstName = "Michael", LastName = "Jackson", Age = 50, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1958, 08, 29), DateDied = new DateTime(2009, 06, 05), }, + }; + + public static RockstarAlbum[] SeedAlbums = new[] { + new RockstarAlbum { Id = 1, RockstarId = 1, Name = "Electric Ladyland", Genre = "Funk" }, + new RockstarAlbum { Id = 2, RockstarId = 3, Name = "Bleach", Genre = "Grunge" }, + new RockstarAlbum { Id = 3, RockstarId = 3, Name = "Nevermind", Genre = "Grunge" }, + new RockstarAlbum { Id = 4, RockstarId = 3, Name = "In Utero", Genre = "Grunge" }, + new RockstarAlbum { Id = 5, RockstarId = 3, Name = "Incesticide", Genre = "Grunge" }, + new RockstarAlbum { Id = 6, RockstarId = 3, Name = "MTV Unplugged in New York", Genre = "Acoustic" }, + new RockstarAlbum { Id = 7, RockstarId = 5, Name = "Foo Fighters", Genre = "Grunge" }, + new RockstarAlbum { Id = 8, RockstarId = 6, Name = "Into the Wild", Genre = "Folk" }, + }; + + public static RockstarGenre[] SeedGenres = new[] { + new RockstarGenre { RockstarId = 1, Name = "Rock" }, + new RockstarGenre { RockstarId = 3, Name = "Grunge" }, + new RockstarGenre { RockstarId = 5, Name = "Alternative Rock" }, + new RockstarGenre { RockstarId = 6, Name = "Folk Rock" }, + }; + + public static Adhoc[] SeedAdhoc = SeedRockstars.Map(x => new Adhoc + { + Id = x.Id, + FirstName = x.FirstName, + LastName = x.LastName, + }).ToArray(); + + public static Movie[] SeedMovies = new[] { + new Movie { Id = 1, ImdbId = "tt0111161", Title = "The Shawshank Redemption", Score = 9.2m, Director = "Frank Darabont", ReleaseDate = new DateTime(1995,2,17), TagLine = "Fear can hold you prisoner. Hope can set you free.", Genres = new List{"Crime","Drama"}, Rating = "R", }, + new Movie { Id = 2, ImdbId = "tt0068646", Title = "The Godfather", Score = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List {"Crime","Drama", "Thriller"}, Rating = "R", }, + new Movie { Id = 3, ImdbId = "tt1375666", Title = "Inception", Score = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List{"Action", "Mystery", "Sci-Fi", "Thriller"}, Rating = "PG-13", }, + new Movie { Id = 4, ImdbId = "tt0071562", Title = "The Godfather: Part II", Score = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List {"Crime","Drama", "Thriller"}, Rating = "R", }, + new Movie { Id = 5, ImdbId = "tt0060196", Title = "The Good, the Bad and the Ugly", Score = 9.0m, Director = "Sergio Leone", ReleaseDate = new DateTime(1967,12,29), TagLine = "They formed an alliance of hate to steal a fortune in dead man's gold", Genres = new List{"Adventure","Western"}, Rating = "R", }, + new Movie { Id = 6, ImdbId = "tt0114709", Title = "Toy Story", Score = 8.3m, Director = "John Lasseter", ReleaseDate = new DateTime(1995,11,22), TagLine = "A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy's room.", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "G", }, + new Movie { Id = 7, ImdbId = "tt2294629", Title = "Frozen", Score = 7.8m, Director = "Chris Buck", ReleaseDate = new DateTime(2013,11,27), TagLine = "Fearless optimist Anna teams up with Kristoff in an epic journey, encountering Everest-like conditions, and a hilarious snowman named Olaf", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "PG", }, + new Movie { Id = 8, ImdbId = "tt1453405", Title = "Monsters University", Score = 7.4m, Director = "Dan Scanlon", ReleaseDate = new DateTime(2013,06,21), TagLine = "A look at the relationship between Mike and Sulley during their days at Monsters University -- when they weren't necessarily the best of friends.", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "G", }, + new Movie { Id = 9, ImdbId = "tt0468569", Title = "The Dark Knight", Score = 9.0m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2008,07,18), TagLine = "When Batman, Gordon and Harvey Dent launch an assault on the mob, they let the clown out of the box, the Joker, bent on turning Gotham on itself and bringing any heroes down to his level.", Genres = new List{"Action","Crime","Drama"}, Rating = "PG-13", }, + new Movie { Id = 10, ImdbId = "tt0109830", Title = "Forrest Gump", Score = 8.8m, Director = "Robert Zemeckis", ReleaseDate = new DateTime(1996,07,06), TagLine = "Forrest Gump, while not intelligent, has accidentally been present at many historic moments, but his true love, Jenny Curran, eludes him.", Genres = new List{"Drama","Romance"}, Rating = "PG-13", }, + }; + + public static AllFields[] SeedAllFields = new[] { + new AllFields + { + Id = 1, + NullableId = 2, + Byte = 3, + DateTime = new DateTime(2001, 01, 01), + NullableDateTime = new DateTime(2002, 02, 02), + Decimal = 4, + Double = 5.5, + Float = 6.6f, + Guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"), + NullableGuid = new Guid("7A2FDDD8-4BB0-4735-8230-A6AC79088489"), + Long = 7, + Short = 8, + String = "string", + TimeSpan = TimeSpan.FromHours(1), + NullableTimeSpan = TimeSpan.FromDays(1), + UInt = 9, + ULong = 10, + UShort = 11, + } + }; + + public static PagingTest[] SeedPagingTest = 250.Times(i => new PagingTest { Id = i, Name = "Name" + i, Value = i % 2 }).ToArray(); + } + + [Route("/querydata/rockstars")] + public class QueryDataRockstars : QueryData + { + public int? Age { get; set; } + } + + [Route("/querydata/rockstaralbums")] + public class QueryDataRockstarAlbums : QueryData + { + public int? Id { get; set; } + public int? RockstarId { get; set; } + public string Name { get; set; } + public string Genre { get; set; } + public int[] IdBetween { get; set; } + } + + [Route("/querydata/pagingtest")] + public class QueryDataPagingTest : QueryData + { + public int? Id { get; set; } + public string Name { get; set; } + public int? Value { get; set; } + } + + public class QueryDataRockstarsConventions : QueryData + { + public DateTime? DateOfBirthGreaterThan { get; set; } + public DateTime? DateDiedLessThan { get; set; } + public int[] Ids { get; set; } + public int? AgeOlderThan { get; set; } + public int? AgeGreaterThanOrEqualTo { get; set; } + public int? AgeGreaterThan { get; set; } + public int? GreaterThanAge { get; set; } + public string FirstNameStartsWith { get; set; } + public string LastNameEndsWith { get; set; } + public string LastNameContains { get; set; } + public string RockstarAlbumNameContains { get; set; } + public int? RockstarIdAfter { get; set; } + public int? RockstarIdOnOrAfter { get; set; } + } + + public class QueryDataCustomRockstars : QueryData + { + public int? Age { get; set; } + } + + public class QueryDataOverridedRockstars : QueryData + { + public int? Age { get; set; } + } + + public class QueryDataOverridedCustomRockstars : QueryData + { + public int? Age { get; set; } + } + + public class QueryDataFieldRockstars : QueryData + { + public string FirstName { get; set; } //default to 'AND FirstName = {Value}' + + public string[] FirstNames { get; set; } //Collections default to 'FirstName IN ({Values}) + + [QueryDataField(Condition = ">=")] + public int? Age { get; set; } + + [QueryDataField(Condition = "Like", Field = "FirstName")] + public string FirstNameCaseInsensitive { get; set; } + + [QueryDataField(Condition = "StartsWith", Field = "FirstName")] + public string FirstNameStartsWith { get; set; } + + [QueryDataField(Condition = "EndsWith", Field = "LastName")] + public string LastNameEndsWith { get; set; } + + [QueryDataField(Condition = "Between", Field = "FirstName")] + public string[] FirstNameBetween { get; set; } + + [QueryDataField(Term = QueryTerm.Or, Condition = "=", Field = "LastName")] + public string OrLastName { get; set; } + } + + public class QueryDataFieldRockstarsDynamic : QueryData + { + public int? Age { get; set; } + } + + public class QueryDataRockstarsFilter : QueryData + { + public int? Age { get; set; } + } + + public class QueryDataCustomRockstarsFilter : QueryData + { + public int? Age { get; set; } + } + + public class QueryDataRockstarsIFilter : QueryData, IFilterRockstars + { + public int? Age { get; set; } + } + + [QueryData(QueryTerm.Or)] + [Route("/OrDataRockstars")] + public class QueryDataOrRockstars : QueryData + { + public int? Age { get; set; } + public string FirstName { get; set; } + } + + [Route("/OrDataRockstarsFields")] + public class QueryDataOrRockstarsFields : QueryData + { + [QueryDataField(Term = QueryTerm.Or)] + public string FirstName { get; set; } + + [QueryDataField(Term = QueryTerm.Or)] + public string LastName { get; set; } + } + + [QueryData(QueryTerm.Or)] + public class QueryDataGetRockstars : QueryData + { + public int[] Ids { get; set; } + public List Ages { get; set; } + public List FirstNames { get; set; } + public int[] IdsBetween { get; set; } + } + + [QueryData(QueryTerm.Or)] + public class QueryDataGetRockstarsDynamic : QueryData { } + + [DataContract] + [Route("/adhocdata-rockstars")] + public class QueryDataAdhocRockstars : QueryData + { + [DataMember(Name = "first_name")] + public string FirstName { get; set; } + } + + [DataContract] + [Route("/adhocdata")] + public class QueryDataAdhoc : QueryData { } + + [Route("/moviesdata/search")] + [QueryData(QueryTerm.And)] //Default + public class SearchDataMovies : QueryData { } + + [Route("/moviesdata")] + [QueryData(QueryTerm.Or)] + public class QueryDataMovies : QueryData + { + public int[] Ids { get; set; } + public string[] ImdbIds { get; set; } + public string[] Ratings { get; set; } + } + + public class StreamDataMovies : QueryData + { + public string[] Ratings { get; set; } + } + + public class QueryDataUnknownRockstars : QueryData + { + public int UnknownInt { get; set; } + public string UnknownProperty { get; set; } + + } + + public class QueryDataAllFields : QueryData + { + public virtual Guid Guid { get; set; } + } + + public class AutoQueryDataService : Service + { + public IAutoQueryData AutoQuery { get; set; } + + //Override with custom impl + public object Any(QueryDataOverridedRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request); + q.Take(1); + return AutoQuery.Execute(dto, q, Request); + } + + public object Any(QueryDataOverridedCustomRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams(), Request); + q.Take(1); + return AutoQuery.Execute(dto, q, Request); + } + } + + [TestFixture] + public abstract class AutoQueryDataTests + { + public readonly ServiceStackHost appHost; + protected readonly IServiceClient client; + + private static readonly int TotalRockstars = AutoQueryAppHost.SeedRockstars.Length; + private static readonly int TotalAlbums = AutoQueryAppHost.SeedAlbums.Length; + + public abstract ServiceStackHost CreateAppHost(); + + public AutoQueryDataTests() + { + appHost = CreateAppHost() + .Init() + .Start(Config.ListeningOn); + + client = new JsonServiceClient(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public List Rockstars + { + get { return AutoQueryDataAppHost.SeedRockstars.ToList(); } + } + + public List PagingTests + { + get { return AutoQueryDataAppHost.SeedPagingTest.ToList(); } + } + + public bool IsDynamoDb + { + get + { + return appHost is AutoQueryDataDynamoAppHost; + } + } + + [Test] + public void Can_execute_basic_query() + { + var response = client.Get(new QueryDataRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public void Can_execute_overridden_basic_query() + { + var response = client.Get(new QueryDataOverridedRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_execute_AdhocRockstars_query() + { + var request = new QueryDataAdhocRockstars { FirstName = "Jimi", Include = "Total" }; + + Assert.That(request.ToGetUrl(), Is.EqualTo("/adhocdata-rockstars?first_name=Jimi&include=Total")); + + var response = client.Get(request); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo(request.FirstName)); + } + + [Test] + public void Can_execute_Adhoc_query_alias() + { + var response = Config.ListeningOn.CombineWith("adhocdata") + .AddQueryParam("first_name", "Jimi") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Jimi")); + } + + [Test] + public void Can_execute_Adhoc_query_convention() + { + var response = Config.ListeningOn.CombineWith("adhocdata") + .AddQueryParam("last_name", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Results.Count, Is.EqualTo(7)); + + JsConfig.Init(new Text.Config { TextCase = TextCase.SnakeCase }); + response = Config.ListeningOn.CombineWith("adhocdata") + .AddQueryParam("last_name", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + JsConfig.Reset(); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Jimi")); + } + + [Test] + public void Can_execute_explicit_equality_condition_on_overridden_CustomRockstar() + { + var response = client.Get(new QueryDataOverridedCustomRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_execute_basic_query_with_limits() + { + var response = client.Get(new QueryDataRockstars { Skip = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 2)); + + response = client.Get(new QueryDataRockstars { Take = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryDataRockstars { Skip = 2, Take = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_explicit_equality_condition() + { + var response = client.Get(new QueryDataRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_explicit_equality_condition_on_CustomRockstar() + { + var response = client.Get(new QueryDataCustomRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_implicit_equality_condition() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars") + .AddQueryParam("FirstName", "Jim") + .AddQueryParam("LivingStatus", "Dead") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("Morrison")); + } + + [Test] + public void Can_execute_multiple_conditions_with_same_param_name() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars") + .AddQueryParam("FirstName", "Jim") + .AddQueryParam("FirstName", "Jim") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("Morrison")); + + response = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars") + .AddQueryParam("FirstNameStartsWith", "Jim") + .AddQueryParam("FirstNameStartsWith", "Jimi") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("Hendrix")); + } + + [Test] + public void Can_execute_implicit_IsNull_condition() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars?DateDied=&Include=Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(2)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_custom_QueryFields() + { + QueryResponse response; + response = client.Get(new QueryDataFieldRockstars { FirstName = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryDataFieldRockstars { FirstNames = new[] { "Jim", "Kurt" } }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryDataFieldRockstars { FirstNameCaseInsensitive = "jim" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryDataFieldRockstars { FirstNameStartsWith = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryDataFieldRockstars { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryDataFieldRockstars { FirstNameBetween = new[] { "A", "F" } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + try + { + response = client.Get(new QueryDataFieldRockstars + { + LastNameEndsWith = "son", + OrLastName = "Hendrix" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + catch (Exception) + { + if (!IsDynamoDb) //DynamoDb doesn't support EndsWith + throw; + } + + response = client.Get(new QueryDataFieldRockstars + { + FirstNameStartsWith = "Jim", + OrLastName = "Presley" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryDataFieldRockstars { Age = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public void Can_execute_combination_of_QueryFields() + { + QueryResponse response; + + response = client.Get(new QueryDataFieldRockstars + { + FirstNameStartsWith = "Jim", + LastNameEndsWith = "son", + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryDataFieldRockstars + { + FirstNameStartsWith = "Jim", + OrLastName = "Cobain", + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Does_escape_values() + { + QueryResponse response; + + response = client.Get(new QueryDataFieldRockstars + { + FirstNameStartsWith = "Jim'\"", + }); + Assert.That(response.Results.Count, Is.EqualTo(0)); + } + + [Test] + public void Does_allow_adding_attributes_dynamically() + { + typeof(QueryDataFieldRockstarsDynamic) + .GetProperty("Age") + .AddAttributes(new QueryDataFieldAttribute { Condition = ">=" }); + + var response = client.Get(new QueryDataFieldRockstarsDynamic { Age = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public void Does_execute_typed_QueryFilters() + { + // QueryFilter appends additional: x => x.LastName.EndsWith("son") + var response = client.Get(new QueryDataRockstarsFilter { Age = 27 }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + var custom = client.Get(new QueryDataCustomRockstarsFilter { Age = 27 }); + Assert.That(custom.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryDataRockstarsIFilter { Age = 27 }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_execute_OR_QueryFilters() + { + var response = client.Get(new QueryDataOrRockstars { Age = 42, FirstName = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = Config.ListeningOn.CombineWith("OrDataRockstars") + .AddQueryParam("Age", "27") + .AddQueryParam("FirstName", "Kurt") + .AddQueryParam("LastName", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_OR_QueryFilters_Fields() + { + var response = client.Get(new QueryDataOrRockstarsFields + { + FirstName = "Jim", + LastName = "Vedder", + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = Config.ListeningOn.CombineWith("OrDataRockstarsFields") + .AddQueryParam("FirstName", "Kurt") + .AddQueryParam("LastName", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_implicit_conventions() + { + var baseUrl = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars"); + + var response = baseUrl.AddQueryParam("AgeOlderThan", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = baseUrl.AddQueryParam("AgeGreaterThanOrEqualTo", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam("AgeGreaterThan", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("GreaterThanAge", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("AgeNotEqualTo", 27).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam(">Age", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + response = baseUrl.AddQueryParam("Age>", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("Age<", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + response = baseUrl.AddQueryParam("Age!", "27").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam("FirstNameStartsWith", "Jim").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = baseUrl.AddQueryParam("LastNameEndsWith", "son").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = baseUrl.AddQueryParam("LastNameContains", "e").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_Explicit_conventions() + { + QueryResponse response; + response = client.Get(new QueryDataRockstarsConventions { Ids = new[] { 1, 2, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryDataRockstarsConventions { AgeOlderThan = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryDataRockstarsConventions { AgeGreaterThanOrEqualTo = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = client.Get(new QueryDataRockstarsConventions { AgeGreaterThan = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = client.Get(new QueryDataRockstarsConventions { GreaterThanAge = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryDataRockstarsConventions { FirstNameStartsWith = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = client.Get(new QueryDataRockstarsConventions { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = client.Get(new QueryDataRockstarsConventions { LastNameContains = "e" }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryDataRockstarsConventions { DateOfBirthGreaterThan = new DateTime(1960, 01, 01) }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = client.Get(new QueryDataRockstarsConventions { DateDiedLessThan = new DateTime(1980, 01, 01) }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_In_OR_Queries() + { + QueryResponse response; + response = client.Get(new QueryDataGetRockstars()); + Assert.That(response.Results.Count, Is.EqualTo(0)); + + response = client.Get(new QueryDataGetRockstars { Ids = new[] { 1, 2, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryDataGetRockstars { Ages = new[] { 42, 44 }.ToList() }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryDataGetRockstars { FirstNames = new[] { "Jim", "Kurt" }.ToList() }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryDataGetRockstars { IdsBetween = new[] { 1, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_In_OR_Queries_with_implicit_conventions() + { + var baseUrl = Config.ListeningOn.CombineWith("json/reply/QueryDataGetRockstarsDynamic"); + + QueryResponse response; + response = baseUrl.AddQueryParam("Ids", "1,2,3").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = baseUrl.AddQueryParam("Ages", "42, 44").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = baseUrl.AddQueryParam("FirstNames", "Jim,Kurt").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = baseUrl.AddQueryParam("IdsBetween", "1,3").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_query_Movie_Ratings() + { + var response = client.Get(new QueryDataMovies { Ratings = new[] { "G", "PG-13" } }); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + var url = Config.ListeningOn + "moviesdata?ratings=G,PG-13"; + response = url.AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + response = client.Get(new QueryDataMovies + { + Ids = new[] { 1, 2 }, + ImdbIds = new[] { "tt0071562", "tt0060196" }, + Ratings = new[] { "G", "PG-13" } + }); + Assert.That(response.Results.Count, Is.EqualTo(9)); + + url = Config.ListeningOn + "moviesdata?ratings=G,PG-13&ids=1,2&imdbIds=tt0071562,tt0060196"; + response = url.AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(9)); + } + + [Test] + public void Can_StreamMovies() + { + var results = client.GetLazy(new StreamDataMovies()).ToList(); + Assert.That(results.Count, Is.EqualTo(10)); + + results = client.GetLazy(new StreamDataMovies { Ratings = new[] { "G", "PG-13" } }).ToList(); + Assert.That(results.Count, Is.EqualTo(5)); + } + + [Test] + public void Does_implicitly_OrderBy_PrimaryKey_when_limits_is_specified() + { + var movies = client.Get(new SearchDataMovies { Take = 100 }); + var ids = movies.Results.Map(x => x.Id); + var orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var rockstars = client.Get(new SearchDataMovies { Take = 100 }); + ids = rockstars.Results.Map(x => x.Id); + orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public void Can_OrderBy_queries() + { + var movies = client.Get(new SearchDataMovies { Take = 100, OrderBy = "ImdbId" }); + var ids = movies.Results.Map(x => x.ImdbId); + var orderedIds = ids.OrderBy(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovies { Take = 100, OrderBy = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovies { Take = 100, OrderByDesc = "ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = ids.OrderByDescending(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovies { Take = 100, OrderByDesc = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovies { Take = 100, OrderBy = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchDataMovies { Take = 100, OrderByDesc = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var url = Config.ListeningOn + "moviesdata/search?take=100&orderBy=Rating,ImdbId"; + movies = url.AsJsonInto(); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + url = Config.ListeningOn + "moviesdata/search?take=100&orderByDesc=Rating,ImdbId"; + movies = url.AsJsonInto(); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public void Can_consume_as_CSV() + { + var url = Config.ListeningOn + "moviesdata/search.csv?ratings=G,PG-13"; + var csv = url.GetStringFromUrl(); + var headers = csv.SplitOnFirst('\n')[0].Trim(); + Assert.That(headers, Is.EqualTo("Id,ImdbId,Title,Rating,Score,Director,ReleaseDate,TagLine,Genres")); + csv.Print(); + + url = Config.ListeningOn + "querydata/rockstars.csv?Age=27"; + csv = url.GetStringFromUrl(); + headers = csv.SplitOnFirst('\n')[0].Trim(); + Assert.That(headers, Is.EqualTo("Id,FirstName,LastName,Age,DateOfBirth,DateDied,LivingStatus")); + csv.Print(); + } + + [Test] + public void Does_not_query_Ignored_properties() + { + var response = client.Get(new QueryDataUnknownRockstars + { + UnknownProperty = "Foo", + UnknownInt = 1, + Include = "Total" + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public void Can_Query_AllFields_Guid() + { + var guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"); + var response = client.Get(new QueryDataAllFields + { + Guid = guid + }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + + Assert.That(response.Results[0].Guid, Is.EqualTo(guid)); + } + + [Test] + public void Does_populate_Total() + { + var response = client.Get(new QueryDataRockstars { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta, Is.Null); + + response = client.Get(new QueryDataRockstars { Include = "COUNT" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryDataRockstars { Include = "COUNT(*)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryDataRockstars { Include = "COUNT(DISTINCT LivingStatus), Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryDataRockstars { Include = "Count(*), Min(Age), Max(Age), Sum(Id)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryDataRockstars { Age = 27, Include = "Count(*), Min(Age), Max(Age), Sum(Id)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public void Can_Include_Aggregates_in_AutoQuery() + { + QueryResponse response; + response = client.Get(new QueryDataRockstars { Include = "COUNT" }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = client.Get(new QueryDataRockstars { Include = "COUNT(*)" }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = client.Get(new QueryDataRockstars { Include = "COUNT(DISTINCT LivingStatus)" }); + Assert.That(response.Meta["COUNT(DISTINCT LivingStatus)"], Is.EqualTo("2")); + + response = client.Get(new QueryDataRockstars { Include = "MIN(Age)" }); + Assert.That(response.Meta["MIN(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = client.Get(new QueryDataRockstars { Include = "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age), First(Id), Last(Id)", OrderBy = "Id" }); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + Assert.That(response.Meta["Avg(Age)"], Is.EqualTo(Rockstars.Average(x => x.Age).ToString())); + Assert.That(response.Meta["First(Id)"], Is.EqualTo(Rockstars.First().Id.ToString())); + Assert.That(response.Meta["Last(Id)"], Is.EqualTo(Rockstars.Last().Id.ToString())); + + response = client.Get(new QueryDataRockstars { Age = 27, Include = "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age), First(Id), Last(Id)", OrderBy = "Id" }); + var rockstars27 = Rockstars.Where(x => x.Age == 27).ToList(); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(rockstars27.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(rockstars27.Map(x => x.Id).Sum().ToString())); + Assert.That(response.Meta["Avg(Age)"], Is.EqualTo(rockstars27.Average(x => x.Age).ToString())); + Assert.That(response.Meta["First(Id)"], Is.EqualTo(rockstars27.First().Id.ToString())); + Assert.That(response.Meta["Last(Id)"], Is.EqualTo(rockstars27.Last().Id.ToString())); + } + + [Test] + public void Does_ignore_unknown_aggregate_commands() + { + var response = client.Get(new QueryDataRockstars { Include = "FOO(1), Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta, Is.Null); + + response = client.Get(new QueryDataRockstars { Include = "FOO(1), Min(Age), Bar('a') alias, Count(*), Baz(1,'foo')" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + } + + [Test] + public void Can_Include_Aggregates_in_AutoQuery_with_Aliases() + { + var response = client.Get(new QueryDataRockstars { Include = "COUNT(*) Count" }); + Assert.That(response.Meta["Count"], Is.EqualTo(Rockstars.Count.ToString())); + + response = client.Get(new QueryDataRockstars { Include = "COUNT(DISTINCT LivingStatus) as UniqueStatus" }); + Assert.That(response.Meta["UniqueStatus"], Is.EqualTo("2")); + + response = client.Get(new QueryDataRockstars { Include = "MIN(Age) MinAge" }); + Assert.That(response.Meta["MinAge"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = client.Get(new QueryDataRockstars { Include = "Count(*) count, Min(Age) min, Max(Age) max, Sum(Id) sum" }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["min"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["max"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["sum"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + } + + [Test] + public void Can_execute_custom_aggregate_functions() + { + var response = client.Get(new QueryDataRockstars + { + Include = "ADD(6,2), Multiply(6,2) SixTimesTwo, Subtract(6,2), divide(6,2) TheDivide" + }); + Assert.That(response.Meta["ADD(6,2)"], Is.EqualTo("8")); + Assert.That(response.Meta["SixTimesTwo"], Is.EqualTo("12")); + Assert.That(response.Meta["Subtract(6,2)"], Is.EqualTo("4")); + Assert.That(response.Meta["TheDivide"], Is.EqualTo("3")); + } + + [Test] + public void Can_select_partial_list_of_fields() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars") + .AddQueryParam("Age", "27") + .AddQueryParam("Fields", "Id,FirstName,Age") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.FirstName != null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.Any(x => x.Age > 0)); + Assert.That(response.Results.All(x => x.DateDied == null)); + Assert.That(response.Results.All(x => x.DateOfBirth == default(DateTime).ToLocalTime())); + } + + [Test] + public void Can_select_partial_list_of_fields_case_insensitive() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryDataRockstars") + .AddQueryParam("Age", "27") + .AddQueryParam("Fields", "id,firstname,age") + .GetJsonFromUrl() + .FromJson>(); + + response.PrintDump(); + + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.FirstName != null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.Any(x => x.Age > 0)); + Assert.That(response.Results.All(x => x.DateDied == null)); + Assert.That(response.Results.All(x => x.DateOfBirth == default(DateTime).ToLocalTime())); + } + + [Test] + public void Does_return_MaxLimit_results() + { + QueryResponse response; + response = client.Get(new QueryDataPagingTest { Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = client.Get(new QueryDataPagingTest { Skip = 200, Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(PagingTests.Skip(200).Count())); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = client.Get(new QueryDataPagingTest { Value = 1, Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count(x => x.Value == 1))); + } + + [Test] + public void Can_query_on_ForeignKey_and_Index() + { + QueryResponse response; + response = client.Get(new QueryDataRockstarAlbums { RockstarId = 3, Include = "Total" }); //Hash + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Total, Is.EqualTo(5)); + + response = client.Get(new QueryDataRockstarAlbums { RockstarId = 3, Id = 3, Include = "Total" }); //Hash + Range + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Name, Is.EqualTo("Nevermind")); + + //Hash + Range BETWEEN + response = client.Get(new QueryDataRockstarAlbums + { + RockstarId = 3, + IdBetween = new[] { 2, 3 }, + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(2)); + + //Hash + Range BETWEEN + Filter + response = client.Get(new QueryDataRockstarAlbums + { + RockstarId = 3, + IdBetween = new[] { 2, 3 }, + Name = "Nevermind", + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Id, Is.EqualTo(3)); + + //Hash + LocalSecondaryIndex + response = client.Get(new QueryDataRockstarAlbums { RockstarId = 3, Genre = "Grunge", Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + Assert.That(response.Total, Is.EqualTo(4)); + + response.PrintDump(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryTests.cs new file mode 100644 index 00000000000..898be8a59ce --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/AutoQueryTests.cs @@ -0,0 +1,2150 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.Extensions; +using ServiceStack.Host; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Testing; +using ServiceStack.Text; +using TestsConfig = ServiceStack.WebHost.Endpoints.Tests.Config; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class AutoQueryAppHost : AppSelfHostBase + { + public AutoQueryAppHost() + : base("AutoQuery", typeof(AutoQueryService).Assembly) { } + + public static readonly string SqlServerConnString = TestsConfig.SqlServerConnString; + public const string SqlServerNamedConnection = "SqlServer"; + public const string SqlServerProvider = "SqlServer2012"; + + public static string SqliteFileConnString = "~/App_Data/autoquery.sqlite".MapProjectPath(); + + public Action ConfigureFn { get; set; } + + public override void Configure(Container container) + { + ScriptContext.ScriptMethods.AddRange(new ScriptMethods[] { + new DbScriptsAsync(), + new MyValidators(), + }); + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + + dbFactory.RegisterConnection(SqlServerNamedConnection, SqlServerConnString, SqlServer2012Dialect.Provider); + dbFactory.RegisterDialectProvider(SqlServerProvider, SqlServer2012Dialect.Provider); + + using (var db = dbFactory.OpenDbConnection(SqlServerNamedConnection)) + { + db.DropTable(); + db.DropAndCreateTable(); + + db.Insert(new NamedRockstar { + Id = 1, + FirstName = "Microsoft", + LastName = "SQL Server", + Age = 27, + DateOfBirth = new DateTime(1989,1,1), + LivingStatus = LivingStatus.Alive, + }); + } + + using (var db = dbFactory.OpenDbConnectionString(SqliteFileConnString)) + { + db.DropTable(); + db.DropAndCreateTable(); + db.Insert(new Rockstar { + Id = 1, + FirstName = "Sqlite", + LastName = "File DB", + Age = 16, + DateOfBirth = new DateTime(2000, 8, 1), + LivingStatus = LivingStatus.Alive, + }); + } + + RegisterTypedRequestFilter((req, res, dto) => + req.Items[Keywords.DbInfo] = dto.ConvertTo()); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Database=test;User Id=test;Password=test;", + // SqlServerDialect.Provider)); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Database=test;User Id=test;Password=test;", + // SqlServer2012Dialect.Provider)); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Database=test;UID=root;Password=test", + // MySqlDialect.Provider)); + + //container.Register( + // new OrmLiteConnectionFactory("Server=localhost;Port=5432;User Id=test;Password=test;Database=test;Pooling=true;MinPoolSize=0;MaxPoolSize=200", + // PostgreSqlDialect.Provider)); + + using (var db = container.Resolve().Open()) + { + db.DropTable(); + db.DropTable(); + db.CreateTable(); + db.CreateTable(); + + db.DropAndCreateTable(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + + db.InsertAll(SeedRockstars); + db.InsertAll(SeedAlbums); + db.InsertAll(SeedGenres); + db.InsertAll(SeedMovies); + db.InsertAll(SeedPagingTest); + + db.DropAndCreateTable(); + db.Insert(new AllFields + { + Id = 1, + NullableId = 2, + Byte = 3, + DateTime = new DateTime(2001, 01, 01), + NullableDateTime = new DateTime(2002, 02, 02), + Decimal = 4, + Double = 5.5, + Float = 6.6f, + Guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"), + NullableGuid = new Guid("7A2FDDD8-4BB0-4735-8230-A6AC79088489"), + Long = 7, + Short = 8, + String = "string", + TimeSpan = TimeSpan.FromHours(1), + NullableTimeSpan = TimeSpan.FromDays(1), + UInt = 9, + ULong = 10, + UShort = 11, + Enum = HttpStatusCode.MethodNotAllowed, + NullableEnum = HttpStatusCode.MethodNotAllowed, + }); + + db.DropAndCreateTable(); + db.InsertAll(SeedRockstars.Map(x => new Adhoc + { + Id = x.Id, + FirstName = x.FirstName, + LastName = x.LastName + })); + + db.CreateTable(); + + db.Insert(new TypeWithEnum { Id = 1, Name = "Value1", SomeEnum = SomeEnum.Value1, NSomeEnum = SomeEnum.Value1, SomeEnumAsInt = SomeEnumAsInt.Value1, NSomeEnumAsInt = SomeEnumAsInt.Value1 }); + db.Insert(new TypeWithEnum { Id = 2, Name = "Value2", SomeEnum = SomeEnum.Value2, NSomeEnum = SomeEnum.Value2, SomeEnumAsInt = SomeEnumAsInt.Value2, NSomeEnumAsInt = SomeEnumAsInt.Value2 }); + db.Insert(new TypeWithEnum { Id = 3, Name = "Value3", SomeEnum = SomeEnum.Value3, NSomeEnum = SomeEnum.Value3, SomeEnumAsInt = SomeEnumAsInt.Value3, NSomeEnumAsInt = SomeEnumAsInt.Value3 }); + } + + var autoQuery = new AutoQueryFeature + { + MaxLimit = 100, + // EnableAsync = false, + EnableRawSqlFilters = true, + ResponseFilters = { + ctx => { + var executedCmds = new List(); + var supportedFns = new Dictionary>(StringComparer.OrdinalIgnoreCase) + { + {"ADD", (a,b) => a + b }, + {"MULTIPLY", (a,b) => a * b }, + {"DIVIDE", (a,b) => a / b }, + {"SUBTRACT", (a,b) => a - b }, + }; + foreach (var cmd in ctx.Commands) + { + if (!supportedFns.TryGetValue(cmd.Name, out var fn)) continue; + var label = !cmd.Suffix.IsNullOrWhiteSpace() ? cmd.Suffix.ToString().Trim() : cmd.ToString(); + ctx.Response.Meta[label] = fn(cmd.Args[0].ParseInt32(), cmd.Args[1].ParseInt32()).ToString(); + executedCmds.Add(cmd); + } + ctx.Commands.RemoveAll(executedCmds.Contains); + } + } + } + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName.EndsWith("son")) + ) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName.EndsWith("son")) + ) + .RegisterQueryFilter((q, dto, req) => + q.And(x => x.LastName.EndsWith("son")) + ); + + Plugins.Add(autoQuery); + + ConfigureFn?.Invoke(this,container); + } + + public override void OnExceptionTypeFilter(Exception ex, ResponseStatus responseStatus) + { + base.OnExceptionTypeFilter(ex, responseStatus); + } + + public static Rockstar[] SeedRockstars = { + new() { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1942, 11, 27), DateDied = new DateTime(1970, 09, 18), }, + new() { Id = 2, FirstName = "Jim", LastName = "Morrison", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1943, 12, 08), DateDied = new DateTime(1971, 07, 03), }, + new() { Id = 3, FirstName = "Kurt", LastName = "Cobain", Age = 27, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1967, 02, 20), DateDied = new DateTime(1994, 04, 05), }, + new() { Id = 4, FirstName = "Elvis", LastName = "Presley", Age = 42, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1935, 01, 08), DateDied = new DateTime(1977, 08, 16), }, + new() { Id = 5, FirstName = "David", LastName = "Grohl", Age = 44, LivingStatus = LivingStatus.Alive, DateOfBirth = new DateTime(1969, 01, 14), }, + new() { Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48, LivingStatus = LivingStatus.Alive, DateOfBirth = new DateTime(1964, 12, 23), }, + new() { Id = 7, FirstName = "Michael", LastName = "Jackson", Age = 50, LivingStatus = LivingStatus.Dead, DateOfBirth = new DateTime(1958, 08, 29), DateDied = new DateTime(2009, 06, 05), }, + }; + + public static RockstarAlbum[] SeedAlbums = { + new() { Id = 1, RockstarId = 1, Name = "Electric Ladyland", Genre = "Funk" }, + new() { Id = 2, RockstarId = 3, Name = "Bleach", Genre = "Grunge" }, + new() { Id = 3, RockstarId = 3, Name = "Nevermind", Genre = "Grunge" }, + new() { Id = 4, RockstarId = 3, Name = "In Utero", Genre = "Grunge" }, + new() { Id = 5, RockstarId = 3, Name = "Incesticide", Genre = "Grunge" }, + new() { Id = 6, RockstarId = 3, Name = "MTV Unplugged in New York", Genre = "Acoustic" }, + new() { Id = 7, RockstarId = 5, Name = "Foo Fighters", Genre = "Grunge" }, + new() { Id = 8, RockstarId = 6, Name = "Into the Wild", Genre = "Folk" }, + }; + + public static RockstarGenre[] SeedGenres = { + new() { RockstarId = 1, Name = "Rock" }, + new() { RockstarId = 3, Name = "Grunge" }, + new() { RockstarId = 5, Name = "Alternative Rock" }, + new() { RockstarId = 6, Name = "Folk Rock" }, + }; + + public static Movie[] SeedMovies = { + new() { ImdbId = "tt0111161", Title = "The Shawshank Redemption", Score = 9.2m, Director = "Frank Darabont", ReleaseDate = new DateTime(1995,2,17), TagLine = "Fear can hold you prisoner. Hope can set you free.", Genres = new List{"Crime","Drama"}, Rating = "R", }, + new() { ImdbId = "tt0068646", Title = "The Godfather", Score = 9.2m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1972,3,24), TagLine = "An offer you can't refuse.", Genres = new List {"Crime","Drama", "Thriller"}, Rating = "R", }, + new() { ImdbId = "tt1375666", Title = "Inception", Score = 9.2m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2010,7,16), TagLine = "Your mind is the scene of the crime", Genres = new List{"Action", "Mystery", "Sci-Fi", "Thriller"}, Rating = "PG-13", }, + new() { ImdbId = "tt0071562", Title = "The Godfather: Part II", Score = 9.0m, Director = "Francis Ford Coppola", ReleaseDate = new DateTime(1974,12,20), Genres = new List {"Crime","Drama", "Thriller"}, Rating = "R", }, + new() { ImdbId = "tt0060196", Title = "The Good, the Bad and the Ugly", Score = 9.0m, Director = "Sergio Leone", ReleaseDate = new DateTime(1967,12,29), TagLine = "They formed an alliance of hate to steal a fortune in dead man's gold", Genres = new List{"Adventure","Western"}, Rating = "R", }, + new() { ImdbId = "tt0114709", Title = "Toy Story", Score = 8.3m, Director = "John Lasseter", ReleaseDate = new DateTime(1995,11,22), TagLine = "A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy's room.", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "G", }, + new() { ImdbId = "tt2294629", Title = "Frozen", Score = 7.8m, Director = "Chris Buck", ReleaseDate = new DateTime(2013,11,27), TagLine = "Fearless optimist Anna teams up with Kristoff in an epic journey, encountering Everest-like conditions, and a hilarious snowman named Olaf", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "PG", }, + new() { ImdbId = "tt1453405", Title = "Monsters University", Score = 7.4m, Director = "Dan Scanlon", ReleaseDate = new DateTime(2013,06,21), TagLine = "A look at the relationship between Mike and Sulley during their days at Monsters University -- when they weren't necessarily the best of friends.", Genres = new List{"Animation","Adventure","Comedy"}, Rating = "G", }, + new() { ImdbId = "tt0468569", Title = "The Dark Knight", Score = 9.0m, Director = "Christopher Nolan", ReleaseDate = new DateTime(2008,07,18), TagLine = "When Batman, Gordon and Harvey Dent launch an assault on the mob, they let the clown out of the box, the Joker, bent on turning Gotham on itself and bringing any heroes down to his level.", Genres = new List{"Action","Crime","Drama"}, Rating = "PG-13", }, + new() { ImdbId = "tt0109830", Title = "Forrest Gump", Score = 8.8m, Director = "Robert Zemeckis", ReleaseDate = new DateTime(1996,07,06), TagLine = "Forrest Gump, while not intelligent, has accidentally been present at many historic moments, but his true love, Jenny Curran, eludes him.", Genres = new List{"Drama","Romance"}, Rating = "PG-13", }, + }; + + public static PagingTest[] SeedPagingTest = 250.Times(i => new PagingTest { Id = i, Name = "Name" + i, Value = i % 2 }).ToArray(); + } + + [Alias("Rockstar")] + [NamedConnection("SqlServer")] + public class NamedRockstar : Rockstar { } + + [Route("/query/namedrockstars")] + public class QueryNamedRockstars : QueryDb + { + public int? Age { get; set; } + } + + [NamedConnection("SqlServer")] + [Route("/query/namedconnectionrockstars")] + public class QueryNamedConnectionRockstars : QueryDb + { + public int? Age { get; set; } + } + + [Route("/query/rockstars")] + public class QueryRockstars : QueryDb + { + public int? Age { get; set; } + //public LivingStatus? LivingStatus { get; set; } + } + + [Route("/query/rockstaralbums")] + public class QueryRockstarAlbums : QueryDb + { + public int? Id { get; set; } + public int? RockstarId { get; set; } + public string Name { get; set; } + public string Genre { get; set; } + public int[] IdBetween { get; set; } + } + + [Route("/query/pagingtest")] + public class QueryPagingTest : QueryDb + { + public int? Id { get; set; } + public string Name { get; set; } + public int? Value { get; set; } + } + + public class QueryRockstarsConventions : QueryDb + { + public DateTime? DateOfBirthGreaterThan { get; set; } + public DateTime? DateDiedLessThan { get; set; } + public int[] Ids { get; set; } + public int? AgeOlderThan { get; set; } + public int? AgeGreaterThanOrEqualTo { get; set; } + public int? AgeGreaterThan { get; set; } + public int? GreaterThanAge { get; set; } + public string FirstNameStartsWith { get; set; } + public string LastNameEndsWith { get; set; } + public string LastNameContains { get; set; } + public string RockstarAlbumNameContains { get; set; } + public int? RockstarIdAfter { get; set; } + public int? RockstarIdOnOrAfter { get; set; } + } + + public class QueryCustomRockstars : QueryDb + { + public int? Age { get; set; } + } + + [Route("/customrockstars")] + public class QueryJoinedRockstarAlbums : QueryDb, IJoin + { + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + } + + public class QueryRockstarAlbumsImplicit : QueryDb, IJoin + { + } + + public class QueryRockstarAlbumsLeftJoin : QueryDb, ILeftJoin + { + public int? Age { get; set; } + public string AlbumName { get; set; } + public int? IdNotEqualTo { get; set; } + } + + public class QueryRockstarAlbumsCustomLeftJoin : QueryDb + { + public int? Age { get; set; } + public string AlbumName { get; set; } + public int? IdNotEqualTo { get; set; } + } + + public class QueryMultiJoinRockstar : QueryDb, + IJoin, + IJoin + { + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + public string RockstarGenreName { get; set; } + } + + public class QueryOverridedRockstars : QueryDb + { + public int? Age { get; set; } + } + + public class QueryOverridedCustomRockstars : QueryDb + { + public int? Age { get; set; } + } + + public class QueryCaseInsensitiveOrderBy : QueryDb + { + public int? Age { get; set; } + } + + public class QueryFieldRockstars : QueryDb + { + public string FirstName { get; set; } //default to 'AND FirstName = {Value}' + + public string[] FirstNames { get; set; } //Collections default to 'FirstName IN ({Values}) + + [QueryDbField(Operand = ">=")] + public int? Age { get; set; } + + [QueryDbField(Template = "UPPER({Field}) LIKE UPPER({Value})", Field = "FirstName")] + public string FirstNameCaseInsensitive { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value}", Field = "FirstName", ValueFormat = "{0}%")] + public string FirstNameStartsWith { get; set; } + + [QueryDbField(Template = "{Field} LIKE {Value}", Field = "LastName", ValueFormat = "%{0}")] + public string LastNameEndsWith { get; set; } + + [QueryDbField(Template = "{Field} BETWEEN {Value1} AND {Value2}", Field = "FirstName")] + public string[] FirstNameBetween { get; set; } + + [QueryDbField(Term = QueryTerm.Or, Template = "UPPER({Field}) LIKE UPPER({Value})", Field = "LastName")] + public string OrLastName { get; set; } + } + + public class QueryRockstarAlias : QueryDb, + IJoin + { + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + } + + [DataContract] + public class RockstarAlias + { + [DataMember] + [Alias("Id")] + public int RockstarId { get; set; } + + [DataMember] + public string FirstName { get; set; } + + [DataMember] + [Alias("LastName")] + public string Surname { get; set; } + + [DataMember(Name = "album")] + public string RockstarAlbumName { get; set; } + } + + public class QueryFieldRockstarsDynamic : QueryDb + { + public int? Age { get; set; } + } + + public class QueryRockstarsFilter : QueryDb + { + public int? Age { get; set; } + } + + public class QueryCustomRockstarsFilter : QueryDb + { + public int? Age { get; set; } + } + + public interface IFilterRockstars { } + public class QueryRockstarsIFilter : QueryDb, IFilterRockstars + { + public int? Age { get; set; } + } + + [QueryDb(QueryTerm.Or)] + [Route("/OrRockstars")] + public class QueryOrRockstars : QueryDb + { + public int? Age { get; set; } + public string FirstName { get; set; } + } + + [Route("/OrRockstarsFields")] + public class QueryOrRockstarsFields : QueryDb + { + [QueryDbField(Term = QueryTerm.Or)] + public string FirstName { get; set; } + + [QueryDbField(Term = QueryTerm.Or)] + public string LastName { get; set; } + } + + public class QueryFieldsImplicitConventions : QueryDb + { + [QueryDbField(Term = QueryTerm.Or)] + public string FirstNameContains { get; set; } + + [QueryDbField(Term = QueryTerm.Or)] + public string LastNameEndsWith { get; set; } + } + + [QueryDb(QueryTerm.Or)] + public class QueryGetRockstars : QueryDb + { + public int[] Ids { get; set; } + public List Ages { get; set; } + public List FirstNames { get; set; } + public int[] IdsBetween { get; set; } + } + + public class QueryRockstarFilters : QueryDb + { + public int[] Ids { get; set; } + public List Ages { get; set; } + public HashSet FirstNames { get; set; } + public int[] IdsBetween { get; set; } + } + + [QueryDb(QueryTerm.Or)] + public class QueryGetRockstarsDynamic : QueryDb {} + + [References(typeof(RockstarAlbumGenreGlobalIndex))] + public class RockstarAlbum + { + [AutoIncrement] + public int Id { get; set; } + [References(typeof(Rockstar))] + public int RockstarId { get; set; } + public string Name { get; set; } + [Index] + public string Genre { get; set; } + } + + public class RockstarGenre + { + [AutoIncrement] + public int Id { get; set; } + public int RockstarId { get; set; } + public string Name { get; set; } + } + + public class CustomRockstar + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + public string RockstarGenreName { get; set; } + } + + public class QueryCustomRockstarsSchema : QueryDb + { + public int? Age { get; set; } + } + + [Schema("dbo")] + public class CustomRockstarSchema + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + public string RockstarGenreName { get; set; } + } + + [Route("/movies/search")] + [QueryDb(QueryTerm.And)] //Default + public class SearchMovies : QueryDb {} + + [Route("/movies")] + [QueryDb(QueryTerm.Or)] + public class QueryMovies : QueryDb + { + public int[] Ids { get; set; } + public string[] ImdbIds { get; set; } + public string[] Ratings { get; set; } + } + + [References(typeof(MovieTitleIndex))] + public class Movie + { + [AutoIncrement] + public int Id { get; set; } + public string ImdbId { get; set; } + public string Title { get; set; } + public string Rating { get; set; } + public decimal Score { get; set; } + public string Director { get; set; } + public DateTime ReleaseDate { get; set; } + public string TagLine { get; set; } + public List Genres { get; set; } + } + + public class StreamMovies : QueryDb + { + public string[] Ratings { get; set; } + } + + public class QueryUnknownRockstars : QueryDb + { + public int UnknownInt { get; set; } + public string UnknownProperty { get; set; } + + } + [Route("/query/rockstar-references")] + public class QueryRockstarsWithReferences : QueryDb + { + public int? Age { get; set; } + } + + public class QueryCustomRockstarsReferences : QueryDb + { + public int? Age { get; set; } + } + + [Alias("Rockstar")] + public class RockstarReference + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + + [Reference] + public List Albums { get; set; } + } + + [Route("/query/all-fields")] + public class QueryAllFields : QueryDb + { + public virtual Guid? Guid { get; set; } + } + + public class AllFields + { + public virtual int Id { get; set; } + public virtual int? NullableId { get; set; } + public virtual byte Byte { get; set; } + public virtual short Short { get; set; } + public virtual int Int { get; set; } + public virtual long Long { get; set; } + public virtual ushort UShort { get; set; } + public virtual uint UInt { get; set; } + public virtual ulong ULong { get; set; } + public virtual float Float { get; set; } + public virtual double Double { get; set; } + public virtual decimal Decimal { get; set; } + public virtual string String { get; set; } + public virtual DateTime DateTime { get; set; } + public virtual TimeSpan TimeSpan { get; set; } + public virtual Guid Guid { get; set; } + public virtual DateTime? NullableDateTime { get; set; } + public virtual TimeSpan? NullableTimeSpan { get; set; } + public virtual Guid? NullableGuid { get; set; } + public HttpStatusCode Enum { get; set; } + public HttpStatusCode? NullableEnum { get; set; } + } + + [EnumAsInt] + public enum SomeEnumAsInt + { + Value1 = 1, + Value2 = 2, + Value3 = 3, + } + + public enum SomeEnum + { + Value1 = 1, + Value2 = 2, + Value3 = 3 + } + + public class TypeWithEnum + { + public int Id { get; set; } + public string Name { get; set; } + public SomeEnum SomeEnum { get; set; } + public SomeEnumAsInt SomeEnumAsInt { get; set; } + public SomeEnum? NSomeEnum { get; set; } + public SomeEnumAsInt? NSomeEnumAsInt { get; set; } + } + + [Route("/query-enums")] + public class QueryTypeWithEnums : QueryDb {} + + [DataContract] + public class Adhoc + { + [DataMember] + public int Id { get; set; } + + [DataMember(Name = "first_name")] + public string FirstName { get; set; } + + [DataMember] + public string LastName { get; set; } + } + + [DataContract] + [Route("/adhoc-rockstars")] + public class QueryAdhocRockstars : QueryDb + { + [DataMember(Name = "first_name")] + public string FirstName { get; set; } + } + + [DataContract] + [Route("/adhoc")] + public class QueryAdhoc : QueryDb {} + + public class AutoQueryService : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + //Override with custom impl + public object Any(QueryOverridedRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams()); + q.Take(1); + return AutoQuery.Execute(dto, q); + } + + public object Any(QueryOverridedCustomRockstars dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams()); + q.Take(1); + return AutoQuery.Execute(dto, q); + } + + public object Any(QueryCaseInsensitiveOrderBy dto) + { + var q = AutoQuery.CreateQuery(dto, Request); + if (q.OrderByExpression != null) + q.OrderByExpression += " COLLATE NOCASE"; + + return AutoQuery.Execute(dto, q); + } + + public object Any(StreamMovies dto) + { + var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams()); + q.Take(2); + return AutoQuery.Execute(dto, q); + } + + public object Any(QueryCustomRockstarsReferences request) + { + var q = AutoQuery.CreateQuery(request, Request.GetRequestParams()); + var response = new QueryResponse + { + Offset = q.Offset.GetValueOrDefault(0), + Results = Db.LoadSelect(q, include:new string[0]), + Total = (int)Db.Count(q), + }; + return response; + } + + public object Any(QueryRockstarAlbumsCustomLeftJoin query) + { + var q = AutoQuery.CreateQuery(query, Request) + .LeftJoin((r, a) => r.Id == a.RockstarId); + return AutoQuery.Execute(query, q); + } + } + + public interface IChangeDb + { + string NamedConnection { get; set; } + string ConnectionString { get; set; } + string ProviderName { get; set; } + } + + [Route("/querychangedb")] + public class QueryChangeDb : QueryDb, IChangeDb + { + public string NamedConnection { get; set; } + public string ConnectionString { get; set; } + public string ProviderName { get; set; } + } + + [Route("/changedb")] + public class ChangeDb : IReturn, IChangeDb + { + public string NamedConnection { get; set; } + public string ConnectionString { get; set; } + public string ProviderName { get; set; } + } + + public class ChangeDbResponse + { + public List Results { get; set; } + } + + public class DynamicDbServices : Service + { + public object Any(ChangeDb request) + { + return new ChangeDbResponse { Results = Db.Select() }; + } + } + + public class ChangeConnectionInfo : IReturn { } + public class QueryChangeConnectionInfo : QueryDb { } + + [ConnectionInfo(NamedConnection = AutoQueryAppHost.SqlServerNamedConnection)] + public class NamedConnectionServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + public object Any(ChangeConnectionInfo request) + { + return new ChangeDbResponse { Results = Db.Select() }; + } + + public object Any(QueryChangeConnectionInfo query) + { + return AutoQuery.Execute(query, AutoQuery.CreateQuery(query, Request), Request); + } + } + + [Alias(nameof(Rockstar))] + public class CustomSelectRockstar + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + [CustomSelect("Age * 2")] + public int? Age { get; set; } + } + + public class QueryJoinedRockstarAlbumsCustomSelect : QueryDb, + IJoin + { + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + } + + public class CustomSelectRockstarResponse + { + public int Id { get; set; } + public string FirstName { get; set; } + public int? Age { get; set; } + } + + public class QueryJoinedRockstarAlbumsCustomSelectResponse : QueryDb, + IJoin + { + public int? Age { get; set; } + public string RockstarAlbumName { get; set; } + } + + public class AutoQueryUnitTests + { + private ServiceStackHost appHost; + + public AutoQueryUnitTests() + { + appHost = new BasicAppHost { + ConfigureAppHost = host => { + host.Plugins.Add(new AutoQueryFeature()); + }, + ConfigureContainer = container => { + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register(dbFactory); + using (var db = dbFactory.Open()) + { + db.DropAndCreateTable(); + db.InsertAll(AutoQueryAppHost.SeedMovies); + } + container.RegisterAutoWired(); + }, + }.Init(); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + public class MyQueryServices : Service + { + public IAutoQueryDb AutoQuery { get; set; } + + public async Task Any(QueryMovies query) + { + using var db = AutoQuery.GetDb(query, base.Request); + var q = AutoQuery.CreateQuery(query, base.Request, db); + return await AutoQuery.ExecuteAsync(query, q, base.Request, db); + } + } + + [Test] + public async Task Can_execute_AutoQueryService_in_UnitTest() + { + var service = appHost.Resolve(); + service.Request = new BasicRequest(); + + var response = (QueryResponse) await service.Any( + new QueryMovies { Ratings = new[] {"G", "PG-13"} }); + + Assert.That(response.Results.Count, Is.EqualTo(5)); + } + } + + [TestFixture] + public class AutoQueryTests + { + private readonly ServiceStackHost appHost; + public IServiceClient client; + + private static readonly int TotalRockstars = AutoQueryAppHost.SeedRockstars.Length; + private static readonly int TotalAlbums = AutoQueryAppHost.SeedAlbums.Length; + + public AutoQueryTests() + { + appHost = new AutoQueryAppHost() + .Init() + .Start(Config.ListeningOn); + + client = new JsonServiceClient(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public List Rockstars => AutoQueryAppHost.SeedRockstars.ToList(); + + public List PagingTests => AutoQueryAppHost.SeedPagingTest.ToList(); + + // [NUnit.Framework.Ignore("Debug Run"), Test] + public void RunFor10Mins() + { +#if NETFX + Process.Start(Config.ListeningOn); +#endif + Thread.Sleep(TimeSpan.FromMinutes(10)); + } + + [Test] + public void Can_execute_basic_query() + { + var response = client.Get(new QueryRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public void Can_execute_basic_QueryNamedRockstars() + { + var response = client.Get(new QueryNamedRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("SQL Server")); + } + + [Test] + public void Can_execute_basic_QueryNamedConnectionRockstars() + { + var response = client.Get(new QueryNamedConnectionRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("SQL Server")); + } + + [Test] + public void Can_execute_overridden_basic_query() + { + var response = client.Get(new QueryOverridedRockstars { Include = "Total" }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_execute_overridden_basic_query_with_case_insensitive_orderBy() + { + var response = client.Get(new QueryCaseInsensitiveOrderBy { Age = 27, OrderBy = "FirstName" }); + + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_query_IsNull() + { + var url = $"{Config.ListeningOn}query/rockstars?DateDiedIsNull"; + var response = url.GetJsonFromUrl().FromJson>(); + + response.PrintDump(); + Assert.That(response.Results.Count, Is.GreaterThan(0)); + Assert.That(response.Results.All(x => x.DateDied == null)); + } + + [Test] + public void Can_query_IsNotNull() + { + var url = $"{Config.ListeningOn}query/rockstars?DateDiedIsNotNull"; + var response = url.GetJsonFromUrl().FromJson>(); + + response.PrintDump(); + Assert.That(response.Results.Count, Is.GreaterThan(0)); + Assert.That(response.Results.All(x => x.DateDied != null)); + } + + [Test] + public void Can_execute_AdhocRockstars_query() + { + var request = new QueryAdhocRockstars { FirstName = "Jimi", Include = "Total" }; + + Assert.That(request.ToGetUrl(), Is.EqualTo("/adhoc-rockstars?first_name=Jimi&include=Total")); + + var response = client.Get(request); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo(request.FirstName)); + } + + [Test] + public void Can_execute_Adhoc_query_alias() + { + var response = Config.ListeningOn.CombineWith("adhoc") + .AddQueryParam("first_name", "Jimi") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Jimi")); + } + + [Test] + public void Can_execute_Adhoc_query_convention() + { + var response = Config.ListeningOn.CombineWith("adhoc") + .AddQueryParam("last_name", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Results.Count, Is.EqualTo(7)); + + JsConfig.Init(new Text.Config { TextCase = TextCase.SnakeCase }); + response = Config.ListeningOn.CombineWith("adhoc") + .AddQueryParam("last_name", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + JsConfig.Reset(); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Jimi")); + } + + [Test] + public void Can_execute_explicit_equality_condition_on_overridden_CustomRockstar() + { + var response = client.Get(new QueryOverridedCustomRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_execute_basic_query_with_limits() + { + var response = client.Get(new QueryRockstars { Skip = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 2)); + + response = client.Get(new QueryRockstars { Take = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryRockstars { Skip = 2, Take = 2, Include = "Total" }); + Assert.That(response.Offset, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_explicit_equality_condition() + { + var response = client.Get(new QueryRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_explicit_equality_condition_on_CustomRockstar() + { + var response = client.Get(new QueryCustomRockstars { Age = 27, Include = "Total" }); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_explicit_equality_condition_on_CustomRockstarSchema() + { + var response = client.Get(new QueryCustomRockstarsSchema { Age = 27, Include = "Total" }); + + response.PrintDump(); + + Assert.That(response.Total, Is.EqualTo(3)); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results[0].FirstName, Is.Not.Null); + Assert.That(response.Results[0].LastName, Is.Not.Null); + Assert.That(response.Results[0].Age, Is.EqualTo(27)); + } + + [Test] + public void Can_execute_implicit_equality_condition() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars") + .AddQueryParam("FirstName", "Jim") + .AddQueryParam("LivingStatus", "Dead") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("Morrison")); + } + + [Test] + public void Can_execute_multiple_conditions_with_same_param_name() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars") + .AddQueryParam("FirstName", "Jim") + .AddQueryParam("FirstName", "Jim") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("Morrison")); + + response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars") + .AddQueryParam("FirstNameStartsWith", "Jim") + .AddQueryParam("FirstNameStartsWith", "Jimi") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].LastName, Is.EqualTo("Hendrix")); + } + + [Test] + public void Can_execute_implicit_IsNull_condition() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars?DateDied=&Include=Total") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Total, Is.EqualTo(2)); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_query_with_JOIN_on_RockstarAlbums() + { + var response = client.Get(new QueryJoinedRockstarAlbums { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", "Foo Fighters", "Into the Wild", + })); + + response = client.Get(new QueryJoinedRockstarAlbums { Age = 27, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(6)); + Assert.That(response.Results.Count, Is.EqualTo(6)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", + })); + + response = client.Get(new QueryJoinedRockstarAlbums { RockstarAlbumName = "Nevermind", Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + } + + [Test] + public void Can_execute_query_with_JOIN_on_RockstarAlbums_and_CustomSelectRockstar() + { + var response = client.Get(new QueryJoinedRockstarAlbumsCustomSelect { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var ages = response.Results.Select(x => x.Age); + Assert.That(ages.Contains(27 * 2)); + + var customRes = client.Get(new QueryJoinedRockstarAlbumsCustomSelectResponse { Include = "Total" }); + Assert.That(customRes.Total, Is.EqualTo(TotalAlbums)); + Assert.That(customRes.Results.Count, Is.EqualTo(TotalAlbums)); + ages = customRes.Results.Select(x => x.Age); + Assert.That(ages.Contains(27 * 2)); + + response = client.Get(new QueryJoinedRockstarAlbumsCustomSelect { Age = 54, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(6)); + Assert.That(response.Results.Count, Is.EqualTo(6)); + ages = response.Results.Select(x => x.Age); + Assert.That(ages.All(x => x == 54)); + var lastNames = response.Results.Select(x => x.LastName); + Assert.That(lastNames, Is.EquivalentTo(new[] { + "Hendrix", "Cobain", "Cobain", "Cobain", "Cobain", "Cobain", + })); + } + + [Test] + public void Can_execute_query_with_multiple_JOINs_on_Rockstar_Albums_and_Genres() + { + var response = client.Get(new QueryMultiJoinRockstar { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalAlbums)); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York", "Foo Fighters", "Into the Wild", + })); + + var genreNames = response.Results.Select(x => x.RockstarGenreName).Distinct(); + Assert.That(genreNames, Is.EquivalentTo(new[] { + "Rock", "Grunge", "Alternative Rock", "Folk Rock" + })); + + response = client.Get(new QueryMultiJoinRockstar { RockstarAlbumName = "Nevermind", Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + + response = client.Get(new QueryMultiJoinRockstar { RockstarGenreName = "Folk Rock", Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarGenreName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Folk Rock" })); + } + + [Test] + public void Can_execute_IMPLICIT_query_with_JOIN_on_RockstarAlbums() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstarAlbumsImplicit") + .AddQueryParam("Age", "27") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Total, Is.EqualTo(6)); + Assert.That(response.Results.Count, Is.EqualTo(6)); + var albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Bleach", "Nevermind", "In Utero", "Incesticide", + "MTV Unplugged in New York" + })); + + response = Config.ListeningOn.CombineWith("json/reply/QueryRockstarAlbumsImplicit") + .AddQueryParam("RockstarAlbumName", "Nevermind") + .AddQueryParam("Include", "Total") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results.Count, Is.EqualTo(1)); + albumNames = response.Results.Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { "Nevermind" })); + } + + [Test] + public void Can_execute_query_with_LEFTJOIN_on_RockstarAlbums() + { + var response = client.Get(new QueryRockstarAlbumsLeftJoin { IdNotEqualTo = 3, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalRockstars - 1)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 1)); + var albumNames = response.Results.Where(x => x.RockstarAlbumName != null).Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Foo Fighters", "Into the Wild" + })); + } + + [Test] + public void Can_execute_query_with_custom_LEFTJOIN_on_RockstarAlbums() + { + var response = client.Get(new QueryRockstarAlbumsCustomLeftJoin { IdNotEqualTo = 3, Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(TotalRockstars - 1)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars - 1)); + var albumNames = response.Results.Where(x => x.RockstarAlbumName != null).Select(x => x.RockstarAlbumName); + Assert.That(albumNames, Is.EquivalentTo(new[] { + "Electric Ladyland", "Foo Fighters", "Into the Wild" + })); + } + + [Test] + public void Can_execute_custom_QueryFields() + { + QueryResponse response; + response = client.Get(new QueryFieldRockstars { FirstName = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryFieldRockstars { FirstNames = new[] { "Jim","Kurt" } }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryFieldRockstars { FirstNameCaseInsensitive = "jim" }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryFieldRockstars { FirstNameStartsWith = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryFieldRockstars { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryFieldRockstars { FirstNameBetween = new[] {"A","F"} }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryFieldRockstars + { + LastNameEndsWith = "son", + OrLastName = "Hendrix" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim", + OrLastName = "Presley" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryFieldRockstars { Age = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public void Can_execute_combination_of_QueryFields() + { + QueryResponse response; + + response = client.Get(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim", + LastNameEndsWith = "son", + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim", + OrLastName = "Cobain", + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Does_escape_values() + { + QueryResponse response; + + response = client.Get(new QueryFieldRockstars + { + FirstNameStartsWith = "Jim'\"", + }); + Assert.That(response.Results.Count, Is.EqualTo(0)); + } + + [Test] + public void Does_use_custom_model_to_select_columns() + { + var response = client.Get(new QueryRockstarAlias { RockstarAlbumName = "Nevermind" }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].RockstarId, Is.EqualTo(3)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Kurt")); + Assert.That(response.Results[0].RockstarAlbumName, Is.EqualTo("Nevermind")); + } + + [Test] + public void Does_allow_adding_attributes_dynamically() + { + typeof(QueryFieldRockstarsDynamic) + .GetProperty("Age") + .AddAttributes(new QueryDbFieldAttribute { Operand = ">=" }); + + var response = client.Get(new QueryFieldRockstarsDynamic { Age = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + } + + [Test] + public void Does_execute_typed_QueryFilters() + { + // QueryFilter appends additional: x => x.LastName.EndsWith("son") + var response = client.Get(new QueryRockstarsFilter { Age = 27 }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + + var custom = client.Get(new QueryCustomRockstarsFilter { Age = 27 }); + Assert.That(custom.Results.Count, Is.EqualTo(1)); + + response = client.Get(new QueryRockstarsIFilter { Age = 27 }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + } + + [Test] + public void Can_execute_OR_QueryFilters() + { + var response = client.Get(new QueryOrRockstars { Age = 42, FirstName = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = Config.ListeningOn.CombineWith("OrRockstars") + .AddQueryParam("Age", "27") + .AddQueryParam("FirstName", "Kurt") + .AddQueryParam("LastName", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Does_retain_implicit_convention_when_not_overriding_template_or_ValueFormat() + { + var response = client.Get(new QueryFieldsImplicitConventions { FirstNameContains = "im" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryFieldsImplicitConventions { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_OR_QueryFilters_Fields() + { + var response = client.Get(new QueryOrRockstarsFields + { + FirstName = "Jim", + LastName = "Vedder", + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = Config.ListeningOn.CombineWith("OrRockstarsFields") + .AddQueryParam("FirstName", "Kurt") + .AddQueryParam("LastName", "Hendrix") + .GetJsonFromUrl() + .FromJson>(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_implicit_conventions() + { + var baseUrl = Config.ListeningOn.CombineWith("json/reply/QueryRockstars"); + + var response = baseUrl.AddQueryParam("AgeOlderThan", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = baseUrl.AddQueryParam("AgeGreaterThanOrEqualTo", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam("AgeGreaterThan", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("GreaterThanAge", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("AgeNotEqualTo", 27).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam(">Age", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + response = baseUrl.AddQueryParam("Age>", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("Age<", 42).AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + response = baseUrl.AddQueryParam("Age!", "27").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam("FirstNameStartsWith", "jim").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = baseUrl.AddQueryParam("LastNameEndsWith", "son").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = baseUrl.AddQueryParam("LastNameContains", "e").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_implicit_conventions_on_JOIN() + { + var baseUrl = Config.ListeningOn.CombineWith("json/reply/QueryJoinedRockstarAlbums"); + + var response = baseUrl.AddQueryParam("RockstarAlbumNameContains", "n").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(6)); + + response = baseUrl.AddQueryParam(">RockstarId", "3").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(7)); + response = baseUrl.AddQueryParam("RockstarId>", "3").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + } + + [Test] + public void Can_execute_Explicit_conventions() + { + var response = client.Get(new QueryRockstarsConventions { Ids = new[] {1, 2, 3} }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryRockstarsConventions { AgeOlderThan = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryRockstarsConventions { AgeGreaterThanOrEqualTo = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = client.Get(new QueryRockstarsConventions { AgeGreaterThan = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = client.Get(new QueryRockstarsConventions { GreaterThanAge = 42 }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryRockstarsConventions { FirstNameStartsWith = "Jim" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = client.Get(new QueryRockstarsConventions { LastNameEndsWith = "son" }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = client.Get(new QueryRockstarsConventions { LastNameContains = "e" }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryRockstarsConventions { DateOfBirthGreaterThan = new DateTime(1960, 01, 01) }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = client.Get(new QueryRockstarsConventions { DateDiedLessThan = new DateTime(1980, 01, 01) }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_execute_where_SqlFilter() + { + var baseUrl = Config.ListeningOn.CombineWith("json/reply/QueryRockstars"); + + var response = baseUrl.AddQueryParam("_where", "Age > 42").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + response = baseUrl.AddQueryParam("_where", "Age >= 42").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(4)); + + response = baseUrl.AddQueryParam("_where", "FirstName".SqlColumn() + " LIKE 'Jim%'").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = baseUrl.AddQueryParam("_where", "LastName".SqlColumn() + " LIKE '%son'").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + response = baseUrl.AddQueryParam("_where", "LastName".SqlColumn() + " LIKE '%e%'").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = baseUrl + .AddQueryParam("_select", "r.*") + .AddQueryParam("_from", "{0} r INNER JOIN {1} a ON r.{2} = a.{3}".Fmt( + "Rockstar".SqlTable(), "RockstarAlbum".SqlTable(), + "Id".SqlColumn(), "RockstarId".SqlColumn())) + .AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(TotalAlbums)); + + response = baseUrl + .AddQueryParam("_select", "FirstName".SqlColumn()) + .AddQueryParam("_where", "LastName".SqlColumn() + " = 'Cobain'") + .AsJsonInto(); + var row = response.Results[0]; + Assert.That(row.Id, Is.EqualTo(default(int))); + Assert.That(row.FirstName, Is.EqualTo("Kurt")); + Assert.That(row.LastName, Is.Null); + Assert.That(row.Age, Is.Null); + } + + [Test] + public void Can_execute_In_OR_Queries() + { + QueryResponse response; + response = client.Get(new QueryGetRockstars()); + Assert.That(response.Results.Count, Is.EqualTo(0)); + + response = client.Get(new QueryGetRockstars { Ids = new[] { 1, 2, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = client.Get(new QueryGetRockstars { Ages = new[] { 42, 44 }.ToList() }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryGetRockstars { FirstNames = new[] { "Jim", "Kurt" }.ToList() }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = client.Get(new QueryGetRockstars { IdsBetween = new[] { 1, 3 } }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Does_ignore_empty_collection_filters_by_default() + { + QueryResponse response; + response = client.Get(new QueryRockstarFilters()); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryAppHost.SeedRockstars.Length)); + + response = client.Get(new QueryRockstarFilters + { + Ids = new int[] {}, + Ages = new List(), + FirstNames = new HashSet(), + IdsBetween = new int[] {}, + }); + Assert.That(response.Results.Count, Is.EqualTo(AutoQueryAppHost.SeedRockstars.Length)); + } + + [Test] + public void Can_execute_In_OR_Queries_with_implicit_conventions() + { + var baseUrl = Config.ListeningOn.CombineWith("json/reply/QueryGetRockstarsDynamic"); + + QueryResponse response; + response = baseUrl.AddQueryParam("Ids", "1,2,3").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + + response = baseUrl.AddQueryParam("Ages", "42, 44").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = baseUrl.AddQueryParam("FirstNames", "Jim,Kurt").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(2)); + + response = baseUrl.AddQueryParam("IdsBetween", "1,3").AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_query_Movie_Ratings() + { + var response = client.Get(new QueryMovies { Ratings = new[] {"G","PG-13"} }); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + var url = Config.ListeningOn + "movies?ratings=G,PG-13"; + response = url.AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(5)); + + response = client.Get(new QueryMovies { + Ids = new[] { 1, 2 }, + ImdbIds = new[] { "tt0071562", "tt0060196" }, + Ratings = new[] { "G", "PG-13" } + }); + Assert.That(response.Results.Count, Is.EqualTo(9)); + + url = Config.ListeningOn + "movies?ratings=G,PG-13&ids=1,2&imdbIds=tt0071562,tt0060196"; + response = url.AsJsonInto(); + Assert.That(response.Results.Count, Is.EqualTo(9)); + } + + [Test] + public void Can_StreamMovies() + { + var results = client.GetLazy(new StreamMovies()).ToList(); + Assert.That(results.Count, Is.EqualTo(10)); + + results = client.GetLazy(new StreamMovies { Ratings = new[]{"G","PG-13"} }).ToList(); + Assert.That(results.Count, Is.EqualTo(5)); + } + + [Test] + public void Does_implicitly_OrderBy_PrimaryKey_when_limits_is_specified() + { + var movies = client.Get(new SearchMovies { Take = 100 }); + var ids = movies.Results.Map(x => x.Id); + var orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var rockstars = client.Get(new SearchMovies { Take = 100 }); + ids = rockstars.Results.Map(x => x.Id); + orderedIds = ids.OrderBy(x => x); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public void Can_OrderBy_queries() + { + var movies = client.Get(new SearchMovies { Take = 100, OrderBy = "ImdbId" }); + var ids = movies.Results.Map(x => x.ImdbId); + var orderedIds = ids.OrderBy(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchMovies { Take = 100, OrderBy = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchMovies { Take = 100, OrderByDesc = "ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = ids.OrderByDescending(x => x).ToList(); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchMovies { Take = 100, OrderByDesc = "Rating,ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchMovies { Take = 100, OrderBy = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + movies = client.Get(new SearchMovies { Take = 100, OrderByDesc = "Rating,-ImdbId" }); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + var url = Config.ListeningOn + "movies/search?take=100&orderBy=Rating,ImdbId"; + movies = url.AsJsonInto(); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderBy(x => x.Rating).ThenBy(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + + url = Config.ListeningOn + "movies/search?take=100&orderByDesc=Rating,ImdbId"; + movies = url.AsJsonInto(); + ids = movies.Results.Map(x => x.ImdbId); + orderedIds = movies.Results.OrderByDescending(x => x.Rating) + .ThenByDescending(x => x.ImdbId).Map(x => x.ImdbId); + Assert.That(ids, Is.EqualTo(orderedIds)); + } + + [Test] + public void Can_consume_as_CSV() + { + var url = Config.ListeningOn + "movies/search.csv?ratings=G,PG-13"; + var csv = url.GetStringFromUrl(); + var headers = csv.SplitOnFirst('\n')[0].Trim(); + Assert.That(headers, Is.EqualTo("Id,ImdbId,Title,Rating,Score,Director,ReleaseDate,TagLine,Genres")); + csv.Print(); + + url = Config.ListeningOn + "query/rockstars.csv?Age=27"; + csv = url.GetStringFromUrl(); + headers = csv.SplitOnFirst('\n')[0].Trim(); + Assert.That(headers, Is.EqualTo("Id,FirstName,LastName,Age,DateOfBirth,DateDied,LivingStatus")); + csv.Print(); + + url = Config.ListeningOn + "customrockstars.csv"; + csv = url.GetStringFromUrl(); + headers = csv.SplitOnFirst('\n')[0].Trim(); + Assert.That(headers, Is.EqualTo("FirstName,LastName,Age,RockstarAlbumName,RockstarGenreName")); + csv.Print(); + } + + [Test] + public void Does_not_query_Ignored_properties() + { + var response = client.Get(new QueryUnknownRockstars { + UnknownProperty = "Foo", + UnknownInt = 1, + Include = "Total" + }); + + Assert.That(response.Offset, Is.EqualTo(0)); + Assert.That(response.Total, Is.EqualTo(TotalRockstars)); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public void Can_Query_Rockstars_with_References() + { + var response = client.Get(new QueryRockstarsWithReferences { + Age = 27 + }); + + Assert.That(response.Results.Count, Is.EqualTo(3)); + + var jimi = response.Results.First(x => x.FirstName == "Jimi"); + Assert.That(jimi.Albums.Count, Is.EqualTo(1)); + Assert.That(jimi.Albums[0].Name, Is.EqualTo("Electric Ladyland")); + + var jim = response.Results.First(x => x.FirstName == "Jim"); + Assert.That(jim.Albums, Is.Null); + + var kurt = response.Results.First(x => x.FirstName == "Kurt"); + Assert.That(kurt.Albums.Count, Is.EqualTo(5)); + + response = client.Get(new QueryRockstarsWithReferences + { + Age = 27, + Fields = "Id,FirstName,Age" + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.All(x => x.Albums == null)); + + response = client.Get(new QueryRockstarsWithReferences + { + Age = 27, + Fields = "Id,FirstName,Age,Albums" + }); + Assert.That(response.Results.Where(x => x.FirstName != "Jim").All(x => x.Albums != null)); + } + + [Test] + public void Can_Query_RockstarReference_without_References() + { + var response = client.Get(new QueryCustomRockstarsReferences + { + Age = 27 + }); + Assert.That(response.Results.Count, Is.EqualTo(3)); + Assert.That(response.Results.All(x => x.Albums == null)); + } + + [Test] + public void Can_Query_AllFields_Guid() + { + var guid = new Guid("3EE6865A-4149-4940-B7A2-F952E0FEFC5E"); + var response = client.Get(new QueryAllFields { + Guid = guid + }); + + Assert.That(response.Results.Count, Is.EqualTo(1)); + + Assert.That(response.Results[0].Guid, Is.EqualTo(guid)); + } + + [Test] + public void Does_populate_Total() + { + var response = client.Get(new QueryRockstars { Include = "Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta, Is.Null); + + response = client.Get(new QueryRockstars { Include = "COUNT" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryRockstars { Include = "COUNT(*)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryRockstars { Include = "COUNT(DISTINCT LivingStatus), Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryRockstars { Include = "Count(*), Min(Age), Max(Age), Sum(Id)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + + response = client.Get(new QueryRockstars { Age = 27, Include = "Count(*), Min(Age), Max(Age), Sum(Id)" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count(x => x.Age == 27))); + } + + [Test] + public void Can_Include_Aggregates_in_AutoQuery() + { + var response = client.Get(new QueryRockstars { Include = "COUNT" }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = client.Get(new QueryRockstars { Include = "COUNT(*)" }); + Assert.That(response.Meta["COUNT(*)"], Is.EqualTo(Rockstars.Count.ToString())); + + response = client.Get(new QueryRockstars { Include = "COUNT(DISTINCT LivingStatus)" }); + Assert.That(response.Meta["COUNT(DISTINCT LivingStatus)"], Is.EqualTo("2")); + + response = client.Get(new QueryRockstars { Include = "MIN(Age)" }); + Assert.That(response.Meta["MIN(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = client.Get(new QueryRockstars { Include = "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age)", OrderBy = "Id" }); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + Assert.That(double.Parse(response.Meta["Avg(Age)"]), Is.EqualTo(Rockstars.Average(x => x.Age)).Within(1d)); + //Not supported by Sqlite + //Assert.That(response.Meta["First(Id)"], Is.EqualTo(Rockstars.First().Id.ToString())); + //Assert.That(response.Meta["Last(Id)"], Is.EqualTo(Rockstars.Last().Id.ToString())); + + response = client.Get(new QueryRockstars { Age = 27, Include = "Count(*), Min(Age), Max(Age), Sum(Id), Avg(Age)", OrderBy = "Id" }); + var rockstars27 = Rockstars.Where(x => x.Age == 27).ToList(); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(rockstars27.Count.ToString())); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Max(Age)"], Is.EqualTo(rockstars27.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["Sum(Id)"], Is.EqualTo(rockstars27.Map(x => x.Id).Sum().ToString())); + Assert.That(double.Parse(response.Meta["Avg(Age)"]), Is.EqualTo(rockstars27.Average(x => x.Age)).Within(1d)); + //Not supported by Sqlite + //Assert.That(response.Meta["First(Id)"], Is.EqualTo(rockstars27.First().Id.ToString())); + //Assert.That(response.Meta["Last(Id)"], Is.EqualTo(rockstars27.Last().Id.ToString())); + } + + [Test] + public void Does_ignore_unknown_aggregate_commands() + { + var response = client.Get(new QueryRockstars { Include = "FOO(1), Total" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta, Is.Null); + + response = client.Get(new QueryRockstars { Include = "FOO(1), Min(Age), Bar('a') alias, Count(*), Baz(1,'foo')" }); + Assert.That(response.Total, Is.EqualTo(Rockstars.Count)); + Assert.That(response.Meta["Min(Age)"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["Count(*)"], Is.EqualTo(Rockstars.Count.ToString())); + } + + [Test] + public void Can_Include_Aggregates_in_AutoQuery_with_Aliases() + { + var response = client.Get(new QueryRockstars { Include = "COUNT(*) count" }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + + response = client.Get(new QueryRockstars { Include = "COUNT(DISTINCT LivingStatus) as uniquestatus" }); + Assert.That(response.Meta["uniquestatus"], Is.EqualTo("2")); + + response = client.Get(new QueryRockstars { Include = "MIN(Age) minage" }); + Assert.That(response.Meta["minage"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + + response = client.Get(new QueryRockstars { Include = "Count(*) count, Min(Age) min, Max(Age) max, Sum(Id) sum" }); + Assert.That(response.Meta["count"], Is.EqualTo(Rockstars.Count.ToString())); + Assert.That(response.Meta["min"], Is.EqualTo(Rockstars.Map(x => x.Age).Min().ToString())); + Assert.That(response.Meta["max"], Is.EqualTo(Rockstars.Map(x => x.Age).Max().ToString())); + Assert.That(response.Meta["sum"], Is.EqualTo(Rockstars.Map(x => x.Id).Sum().ToString())); + } + + [Test] + public void Can_execute_custom_aggregate_functions() + { + var response = client.Get(new QueryRockstars { + Include = "ADD(6,2), Multiply(6,2) SixTimesTwo, Subtract(6,2), divide(6,2) TheDivide" + }); + Assert.That(response.Meta["ADD(6,2)"], Is.EqualTo("8")); + Assert.That(response.Meta["SixTimesTwo"], Is.EqualTo("12")); + Assert.That(response.Meta["Subtract(6,2)"], Is.EqualTo("4")); + Assert.That(response.Meta["TheDivide"], Is.EqualTo("3")); + } + + [Test] + public void Sending_empty_ChangeDb_returns_default_info() + { + var response = client.Get(new ChangeDb()); + Assert.That(response.Results.Count, Is.EqualTo(TotalRockstars)); + + var aqResponse = client.Get(new QueryChangeDb()); + Assert.That(aqResponse.Results.Count, Is.EqualTo(TotalRockstars)); + } + + [Test] + public void Can_ChangeDb_with_Named_Connection() + { + var response = client.Get(new ChangeDb { NamedConnection = AutoQueryAppHost.SqlServerNamedConnection }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = client.Get(new QueryChangeDb { NamedConnection = AutoQueryAppHost.SqlServerNamedConnection }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public void Can_ChangeDb_with_ConnectionString() + { + var response = client.Get(new ChangeDb { ConnectionString = AutoQueryAppHost.SqliteFileConnString }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Sqlite")); + + var aqResponse = client.Get(new QueryChangeDb { ConnectionString = AutoQueryAppHost.SqliteFileConnString }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Sqlite")); + } + + [Test] + public void Can_ChangeDb_with_ConnectionString_and_Provider() + { + var response = client.Get(new ChangeDb + { + ConnectionString = AutoQueryAppHost.SqlServerConnString, + ProviderName = AutoQueryAppHost.SqlServerProvider, + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = client.Get(new QueryChangeDb + { + ConnectionString = AutoQueryAppHost.SqlServerConnString, + ProviderName = AutoQueryAppHost.SqlServerProvider, + }); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public void Can_Change_Named_Connection_with_ConnectionInfoAttribute() + { + var response = client.Get(new ChangeConnectionInfo()); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Results[0].FirstName, Is.EqualTo("Microsoft")); + + var aqResponse = client.Get(new QueryChangeConnectionInfo()); + Assert.That(aqResponse.Results.Count, Is.EqualTo(1)); + Assert.That(aqResponse.Results[0].FirstName, Is.EqualTo("Microsoft")); + } + + [Test] + public void Can_select_partial_list_of_fields() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars") + .AddQueryParam("Age", "27") + .AddQueryParam("Fields", "Id,FirstName,Age") + .GetJsonFromUrl() + .FromJson>(); + + response.PrintDump(); + + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.FirstName != null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.Any(x => x.Age > 0)); + Assert.That(response.Results.All(x => x.DateDied == null)); + Assert.That(response.Results.All(x => x.DateOfBirth == default(DateTime).ToLocalTime())); + } + + [Test] + public void Can_select_partial_list_of_fields_DISTINCT() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars") + .AddQueryParam("Fields", "DISTINCT Age") + .GetJsonFromUrl() + .FromJson>(); + + response.PrintDump(); + + Assert.That(response.Results.Any(x => x.Age > 0)); + Assert.That(response.Results.Count, Is.EqualTo(response.Results.Select(x => x.Age).ToSet().Count)); + Assert.That(response.Results.All(x => x.Id == 0)); + Assert.That(response.Results.All(x => x.FirstName == null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.All(x => x.DateDied == null)); + Assert.That(response.Results.All(x => x.DateOfBirth == default(DateTime).ToLocalTime())); + } + + [Test] + public void Can_select_partial_list_of_fields_case_insensitive() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryRockstars") + .AddQueryParam("Age", "27") + .AddQueryParam("Fields", "id,firstname,age") + .GetJsonFromUrl() + .FromJson>(); + + response.PrintDump(); + + Assert.That(response.Results.All(x => x.Id > 0)); + Assert.That(response.Results.All(x => x.FirstName != null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.Any(x => x.Age > 0)); + Assert.That(response.Results.All(x => x.DateDied == null)); + Assert.That(response.Results.All(x => x.DateOfBirth == default(DateTime).ToLocalTime())); + } + + [Test] + public void Can_select_partial_list_of_fields_from_joined_table() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryJoinedRockstarAlbums") + .AddQueryParam("Age", "27") + .AddQueryParam("fields", "FirstName,Age,RockstarAlbumName") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results.All(x => x.FirstName != null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.All(x => x.Age > 0)); + Assert.That(response.Results.All(x => x.RockstarAlbumName != null)); + } + + [Test] + public void Can_select_partial_list_of_fields_from_joined_table_case_insensitive() + { + var response = Config.ListeningOn.CombineWith("json/reply/QueryJoinedRockstarAlbums") + .AddQueryParam("Age", "27") + .AddQueryParam("fields", "firstname,age,rockstaralbumname") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results.All(x => x.FirstName != null)); + Assert.That(response.Results.All(x => x.LastName == null)); + Assert.That(response.Results.All(x => x.Age > 0)); + Assert.That(response.Results.All(x => x.RockstarAlbumName != null)); + } + + [Test] + public void Does_return_MaxLimit_results() + { + QueryResponse response; + response = client.Get(new QueryPagingTest { Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = client.Get(new QueryPagingTest { Skip = 200, Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(PagingTests.Skip(200).Count())); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count)); + + response = client.Get(new QueryPagingTest { Value = 1, Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(100)); + Assert.That(response.Total, Is.EqualTo(PagingTests.Count(x => x.Value == 1))); + } + + [Test] + public void Can_query_on_ForeignKey_and_Index() + { + QueryResponse response; + response = client.Get(new QueryRockstarAlbums { RockstarId = 3, Include = "Total" }); //Hash + Assert.That(response.Results.Count, Is.EqualTo(5)); + Assert.That(response.Total, Is.EqualTo(5)); + + response = client.Get(new QueryRockstarAlbums { RockstarId = 3, Id = 3, Include = "Total" }); //Hash + Range + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Name, Is.EqualTo("Nevermind")); + + //Hash + Range BETWEEN + response = client.Get(new QueryRockstarAlbums + { + RockstarId = 3, + IdBetween = new[] { 2, 3 }, + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(2)); + Assert.That(response.Total, Is.EqualTo(2)); + + //Hash + Range BETWEEN + Filter + response = client.Get(new QueryRockstarAlbums + { + RockstarId = 3, + IdBetween = new[] { 2, 3 }, + Name = "Nevermind", + Include = "Total" + }); + Assert.That(response.Results.Count, Is.EqualTo(1)); + Assert.That(response.Total, Is.EqualTo(1)); + Assert.That(response.Results[0].Id, Is.EqualTo(3)); + + //Hash + LocalSecondaryIndex + response = client.Get(new QueryRockstarAlbums { RockstarId = 3, Genre = "Grunge", Include = "Total" }); + Assert.That(response.Results.Count, Is.EqualTo(4)); + Assert.That(response.Total, Is.EqualTo(4)); + + response.PrintDump(); + } + + [Test] + public void Can_use_implicit_query_on_enums_on_all_fields() + { + var allFieldsResponse = Config.ListeningOn.CombineWith("query", "all-fields") + .AddQueryParam("EnumContains", "MethodNotAllowed") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(allFieldsResponse.Results[0].Enum, Is.EqualTo(HttpStatusCode.MethodNotAllowed)); + } + + [Test] + public void Can_use_implicit_query_to_query_equals_on_int_enums() + { + var response = Config.ListeningOn.CombineWith("query-enums") + .AddQueryParam("SomeEnumAsInt", "Value2") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results[0].SomeEnumAsInt, Is.EqualTo(SomeEnumAsInt.Value2)); + + response = Config.ListeningOn.CombineWith("query-enums") + .AddQueryParam("NSomeEnumAsInt", "Value2") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results[0].NSomeEnumAsInt, Is.EqualTo(SomeEnumAsInt.Value2)); + } + + [Test] + public void Can_use_implicit_query_to_query_contains_on_string_enums() + { + var response = Config.ListeningOn.CombineWith("query-enums") + .AddQueryParam("SomeEnumContains", "Value2") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results[0].SomeEnum, Is.EqualTo(SomeEnum.Value2)); + + response = Config.ListeningOn.CombineWith("query-enums") + .AddQueryParam("NSomeEnumContains", "Value2") + .GetJsonFromUrl() + .FromJson>(); + + Assert.That(response.Results[0].NSomeEnum, Is.EqualTo(SomeEnum.Value2)); + } + } + + public static class AutoQueryExtensions + { + public static QueryResponse AsJsonInto(this string url) + { + return url.GetJsonFromUrl() + .FromJson>(); + } + } +} + diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/BufferedRequestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/BufferedRequestTests.cs index d0c1456e2ab..807d92467df 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/BufferedRequestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/BufferedRequestTests.cs @@ -1,16 +1,14 @@ -using Funq; +using System; +using System.Collections.Generic; +using Funq; using NUnit.Framework; -using ServiceStack.ServiceInterface.Admin; using ServiceStack.Text; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; using System.Runtime.Serialization; -using ServiceStack.Service; -using ServiceStack.Messaging; -using System.ServiceModel.Channels; -using System; -using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -19,7 +17,7 @@ public class BufferedRequestTests { private BufferedRequestAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new BufferedRequestAppHost(); @@ -27,18 +25,17 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] - public void BufferredRequest_allows_rereading_of_Request_InputStream() + public void BufferedRequest_allows_rereading_of_Request_InputStream() { appHost.LastRequestBody = null; - appHost.UseBufferredStream = true; + appHost.UseBufferedStream = true; var client = new JsonServiceClient(Config.ServiceStackBaseUri); var request = new MyRequest { Data = "RequestData" }; @@ -49,37 +46,53 @@ public void BufferredRequest_allows_rereading_of_Request_InputStream() } [Test] - public void Cannot_reread_Request_InputStream_without_bufferring() + public void Cannot_reread_Request_InputStream_without_buffering() { appHost.LastRequestBody = null; - appHost.UseBufferredStream = false; + appHost.UseBufferedStream = false; var client = new JsonServiceClient(Config.ServiceStackBaseUri); var request = new MyRequest { Data = "RequestData" }; - var response = client.Post(request); - - Assert.That(appHost.LastRequestBody, Is.EqualTo(request.ToJson())); - Assert.That(response.Data, Is.Null); + try + { + var response = client.Post(request); + + Assert.That(appHost.LastRequestBody, Is.EqualTo(request.ToJson())); + Assert.That(response.Data, Is.Null); + } + catch (WebServiceException e) + { + //.NET 5 + Assert.That(e.Message, Does.StartWith("Could not deserialize 'application/json' request")); + } } [Test] - public void Cannot_see_RequestBody_in_RequestLogger_without_bufferring() + public void Cannot_see_RequestBody_in_RequestLogger_without_buffering() { appHost.LastRequestBody = null; - appHost.UseBufferredStream = false; + appHost.UseBufferedStream = false; var client = new JsonServiceClient(Config.ServiceStackBaseUri); var request = new MyRequest { Data = "RequestData" }; - var response = client.Post(request); - - Assert.That(appHost.LastRequestBody, Is.EqualTo(request.ToJson())); - Assert.That(response.Data, Is.Null); - - var requestLogger = appHost.TryResolve(); - var lastEntry = requestLogger.GetLatestLogs(1); - Assert.That(lastEntry[0].RequestBody, Is.Null); + try + { + var response = client.Post(request); + + Assert.That(appHost.LastRequestBody, Is.EqualTo(request.ToJson())); + Assert.That(response.Data, Is.Null); + + var requestLogger = appHost.TryResolve(); + var lastEntry = requestLogger.GetLatestLogs(1); + Assert.That(lastEntry[0].RequestBody, Is.Null); + } + catch (WebServiceException e) + { + //.NET 5 + Assert.That(e.Message, Does.StartWith("Could not deserialize 'application/json' request")); + } } } @@ -89,7 +102,7 @@ public class BufferedRequestLoggerTests private BufferedRequestAppHost appHost; MyRequest request = new MyRequest { Data = "RequestData" }; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new BufferedRequestAppHost { EnableRequestBodyTracking = true }; @@ -97,11 +110,10 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -112,6 +124,7 @@ public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking( Assert.That(logBody, Is.EqualTo(request.ToJson())); } +#if !NETCORE [Test] public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking_Soap12() { @@ -120,13 +133,12 @@ public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking_ var logBody = Run(new Soap12ServiceClient(Config.ServiceStackBaseUri)); - Assert.That(appHost.LastRequestBody, Is.StringStarting(soap12start)); - Assert.That(appHost.LastRequestBody, Is.StringEnding(soap12end)); - Assert.That(logBody, Is.StringStarting(soap12start)); - Assert.That(logBody, Is.StringEnding(soap12end)); + Assert.That(appHost.LastRequestBody, Does.StartWith(soap12start)); + Assert.That(appHost.LastRequestBody, Does.EndWith(soap12end)); + Assert.That(logBody, Does.StartWith(soap12start)); + Assert.That(logBody, Does.EndWith(soap12end)); } - [Test] public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking_Soap11() { @@ -136,13 +148,13 @@ public void Can_see_RequestBody_in_RequestLogger_when_EnableRequestBodyTracking_ Assert.That(appHost.LastRequestBody, Is.EqualTo(soap11)); Assert.That(logBody, Is.EqualTo(soap11)); } - +#endif string Run(IServiceClient client) { var requestLogger = appHost.TryResolve(); appHost.LastRequestBody = null; - appHost.UseBufferredStream = false; + appHost.UseBufferedStream = false; var response = client.Send(request); //Debug.WriteLine(appHost.LastRequestBody); @@ -157,17 +169,20 @@ string Run(IServiceClient client) public class BufferedRequestAppHost : AppHostHttpListenerBase { - public BufferedRequestAppHost() : base(typeof(BufferedRequestTests).Name, typeof(MyService).Assembly) { } + public BufferedRequestAppHost() : base(nameof(BufferedRequestTests), typeof(MyService).Assembly) { } public string LastRequestBody { get; set; } - public bool UseBufferredStream { get; set; } + public bool UseBufferedStream { get; set; } public bool EnableRequestBodyTracking { get; set; } public override void Configure(Container container) { +#if !NETCORE + Plugins.Add(new SoapFormat()); +#endif PreRequestFilters.Add((httpReq, httpRes) => { - if (UseBufferredStream) - httpReq.UseBufferedStream = UseBufferredStream; + if (UseBufferedStream) + httpReq.UseBufferedStream = UseBufferedStream; LastRequestBody = null; LastRequestBody = httpReq.GetRawBody(); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/BuiltinRouteTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/BuiltinRouteTests.cs new file mode 100644 index 00000000000..b80e8ef1082 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/BuiltinRouteTests.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics; +using System.Threading; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class BuiltinRouteServices : Service {} + + public class BuiltinRouteTests + { + public class BuiltinPathAppHost : AppSelfHostBase + { + public BuiltinPathAppHost() + : base(typeof(BuiltinPathAppHost).Name, typeof(BuiltinRouteServices).Assembly) {} + + public override void Configure(Container container) + { + PreRequestFilters.Add((req, res) => + { + req.UseBufferedStream = true; + res.UseBufferedStream = true; + }); + } + } + + readonly ServiceStackHost appHost; + public BuiltinRouteTests() + { + appHost = new BuiltinPathAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Ignore("Debug Run")] + [Test] + public void RunFor10Mins() + { + Process.Start(Config.AbsoluteBaseUri); + Thread.Sleep(TimeSpan.FromMinutes(10)); + } + + [Test] + public void Can_download_metadata_page() + { + var contents = "{0}/metadata".Fmt(Config.AbsoluteBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain("The following operations are supported.")); + } + + [Test] + public void Can_download_File_Template_OperationControl() + { + var contents = "{0}/json/metadata?op=Hello".Fmt(Config.AbsoluteBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain("/hello/{Name}")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CacheResponseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CacheResponseTests.cs new file mode 100644 index 00000000000..33d337637bf --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CacheResponseTests.cs @@ -0,0 +1,680 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/cache/serveronly/{Id}")] + public class ServerCacheOnly : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/serveronlyasync/{Id}")] + public class ServerCacheOnlyAsync : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/servershort/{Id}")] + public class ServerCacheShort : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/serversuser/{Id}")] + public class ServerCacheUser : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/serversroles/{Id}")] + public class ServerCacheRoles : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/clientmaxage/{Id}")] + public class ClientCacheMaxAge : IReturn, ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/clientmustrevalidate/{Id}")] + public class ClientCacheMustRevalidate : IReturn, ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/serverscustomkey/{Id}")] + public class ServerCustomCacheKey : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/alwaysthrows")] + public class CacheAlwaysThrows : IReturn + { + public string Message { get; set; } + } + + public interface ICacheDto + { + int Id { get; set; } + string Value { get; set; } + } + + public class HelloCache : IReturn + { + public string Name { get; set; } + } + + [Route("/cache/custom-json/{Id}")] + public class CacheCustomJson : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + [Route("/cache/stream-result/{Id}")] + public class CacheStream : ICacheDto + { + internal static int Count = 0; + + public int Id { get; set; } + public string Value { get; set; } + } + + public class CacheResponseServices : Service + { + [CacheResponse(Duration = 5000)] + public object Any(HelloCache request) + { + return new HelloResponse { Result = $"Hello, {request.Name}!"}; + } + + [CacheResponse(Duration = 10)] + public object Any(ServerCacheOnly request) + { + Interlocked.Increment(ref ServerCacheOnly.Count); + return request; + } + + [CacheResponse(Duration = 10)] + public async Task Any(ServerCacheOnlyAsync request) + { + await Task.Yield(); + Interlocked.Increment(ref ServerCacheOnlyAsync.Count); + return request; + } + + [CacheResponse(Duration = 1)] + public object Any(ServerCacheShort request) + { + Interlocked.Increment(ref ServerCacheShort.Count); + return request; + } + + [CacheResponse(Duration = 10, VaryByUser = true)] + public object Any(ServerCacheUser request) + { + Interlocked.Increment(ref ServerCacheUser.Count); + return request; + } + + [CacheResponse(Duration = 10, VaryByRoles = new[]{ "RoleA", "RoleB" })] + public object Any(ServerCacheRoles request) + { + Interlocked.Increment(ref ServerCacheRoles.Count); + return request; + } + + [CacheResponse(Duration = 10, MaxAge = 10)] + public object Any(ClientCacheMaxAge request) + { + Interlocked.Increment(ref ClientCacheMaxAge.Count); + return request; + } + + [CacheResponse(Duration = 10, MaxAge = 0, CacheControl = CacheControl.MustRevalidate)] + public object Any(ClientCacheMustRevalidate request) + { + Interlocked.Increment(ref ClientCacheMustRevalidate.Count); + return request; + } + + [CacheResponse(Duration = 10)] + public async Task Any(ServerCustomCacheKey request) + { + if (Request.GetItem(Keywords.CacheInfo) is CacheInfo cacheInfo) + { + cacheInfo.KeyBase += "::flag=" + (ServerCustomCacheKey.Count % 2 == 0); + if (await Request.HandleValidCache(cacheInfo)) + return null; + } + + Interlocked.Increment(ref ServerCustomCacheKey.Count); + return request; + } + + [CacheResponse(Duration = 5000)] + public object Any(CacheAlwaysThrows request) + { + throw new Exception(request.Message); + } + + [CacheResponse(Duration = 10)] + public object Any(CacheCustomJson request) + { + Interlocked.Increment(ref CacheCustomJson.Count); + return new HttpResult(request) + { + ResultScope = () => JsConfig.With(new Text.Config + { + TextCase = TextCase.CamelCase, + IncludeNullValues = true, + }) + }; + } + + [AddHeader(ContentType = MimeTypes.Jsv)] + [CacheResponse(Duration = 5000)] + public object Any(CacheStream request) + { + Interlocked.Increment(ref CacheStream.Count); + + var jsv = request.ToJsv(); + var bytes = jsv.ToUtf8Bytes(); + var ms = bytes.InMemoryStream(); + return ms; + } + } + + [TestFixture] + public class CacheResponseTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(CacheServerFeatureTests), typeof (CacheEtagServices).Assembly) {} + + public override void Configure(Container container) + { + PreRequestFilters.Add((req, res) => + { + var roleHeader = req.GetHeader("X-role"); + if (roleHeader == null) + return; + + req.Items[Keywords.Session] = new AuthUserSession + { + UserAuthId = "1", + UserAuthName = "test", + Roles = new List { roleHeader } + }; + }); + + ServiceExceptionHandlers.Add((req, dto, ex) => + { + return DtoUtils.CreateErrorResponse(dto, ex); + }); + } + } + + private readonly ServiceStackHost appHost; + public CacheResponseTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + private void AssertEquals(ICacheDto actual, ICacheDto expected) + { + Assert.That(actual.Id, Is.EqualTo(expected.Id)); + Assert.That(actual.Value, Is.EqualTo(expected.Value)); + } + + private static IJsonServiceClient CreateClient() + { +#if NET6_0_OR_GREATER + return new JsonApiClient(Config.ListeningOn); +#else + return new JsonServiceClient(Config.ListeningOn); +#endif + } + + [Test] + public void Does_cache_duplicate_requests() + { + ServerCacheOnly.Count = 0; + var request = new ServerCacheOnly { Id = 1, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(responseFilter: res => { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Json)); + Assert.That(res.GetHeader(HttpHeaders.CacheControl), Is.Null); + }) + .FromJson(); + + Assert.That(ServerCacheOnly.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Json)); + Assert.That(res.GetHeader(HttpHeaders.CacheControl), Is.Null); + }) + .FromJson(); + + Assert.That(ServerCacheOnly.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + var client = CreateClient(); + response = client.Get(request); + Assert.That(ServerCacheOnly.Count, Is.EqualTo(1)); + AssertEquals(response, request); + } + + [Test] + public async Task Does_cache_duplicate_requests_async() + { + ServerCacheOnlyAsync.Count = 0; + var request = new ServerCacheOnlyAsync { Id = 1, Value = "foo" }; + + var response = (await Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrlAsync(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Json)); + Assert.That(res.GetHeader(HttpHeaders.CacheControl), Is.Null); + })) + .FromJson(); + + Assert.That(ServerCacheOnlyAsync.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = (await Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrlAsync(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Json)); + Assert.That(res.GetHeader(HttpHeaders.CacheControl), Is.Null); + })) + .FromJson(); + + Assert.That(ServerCacheOnlyAsync.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + var client = CreateClient(); + response = await client.GetAsync(request); + Assert.That(ServerCacheOnlyAsync.Count, Is.EqualTo(1)); + AssertEquals(response, request); + } + + [Test] + public void Does_vary_cache_by_QueryString() + { + ServerCacheOnly.Count = 0; + var request = new ServerCacheOnly { Id = 2, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCacheOnly.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(new ServerCacheOnly { Id = 1 }.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCacheOnly.Count, Is.EqualTo(2)); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.Value, Is.Null); + } + + [Test] + public void Does_vary_cache_by_UserSession() + { + ServerCacheOnly.Count = 0; + var request = new ServerCacheUser { Id = 3, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(requestFilter: req => req.AddHeader("X-ss-id", "1")) + .FromJson(); + + Assert.That(ServerCacheUser.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(requestFilter: req => req.AddHeader("X-ss-id", "1")) + .FromJson(); + + Assert.That(ServerCacheUser.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(requestFilter: req => req.AddHeader("X-ss-id", "2")) + .FromJson(); + + Assert.That(ServerCacheUser.Count, Is.EqualTo(2)); + AssertEquals(response, request); + } + + [Test] + public void Does_vary_cache_by_Role() + { + ServerCacheRoles.Count = 0; + var request = new ServerCacheRoles { Id = 3, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(requestFilter: req => req.AddHeader("X-role", "RoleA")) + .FromJson(); + + Assert.That(ServerCacheRoles.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(requestFilter: req => req.AddHeader("X-role", "RoleA")) + .FromJson(); + + Assert.That(ServerCacheRoles.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl(requestFilter: req => req.AddHeader("X-role", "RoleB")) + .FromJson(); + + Assert.That(ServerCacheRoles.Count, Is.EqualTo(2)); + AssertEquals(response, request); + } + + [Test] + public void Does_cache_different_content_types_and_encoding() + { + ServerCacheOnly.Count = 0; + var request = new ServerCacheOnly { Id = 4, Value = "bar" }; + var url = Config.ListeningOn.CombineWith(request.ToGetUrl()); + + ServerCacheOnly response; + + //JSON + Deflate + response = url.GetJsonFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Json)); + }) + .FromJson(); + + Assert.That(ServerCacheOnly.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + //JSON + No Accept-Encoding + var webReq = WebRequest.CreateHttp(url); + webReq.Accept = MimeTypes.Json; +#if !NETCORE + webReq.AutomaticDecompression = DecompressionMethods.None; +#endif + var webRes = webReq.GetResponse(); + Assert.That(webRes.ContentType, Does.StartWith(MimeTypes.Json)); + response = webRes.GetResponseStream().ReadToEnd() + .FromJson(); + Assert.That(ServerCacheOnly.Count, Is.EqualTo(1)); //Uses plain json cache from #1 + AssertEquals(response, request); + + //JSON + GZip + webReq = WebRequest.CreateHttp(url); + webReq.Accept = MimeTypes.Json; + webReq.Headers[HttpHeaders.AcceptEncoding] = CompressionTypes.GZip; +#if !NETCORE + webReq.AutomaticDecompression = DecompressionMethods.GZip; +#endif + webRes = webReq.GetResponse(); + Assert.That(webRes.ContentType, Does.StartWith(MimeTypes.Json)); + var responseGzip = webRes.GetResponseStream().ReadFully(); +#if !NETCORE + response = responseGzip.FromUtf8Bytes().FromJson(); +#else + response = responseGzip.Decompress("gzip").FromJson(); +#endif + Assert.That(ServerCacheOnly.Count, Is.EqualTo(2)); //New encoding new cache + AssertEquals(response, request); + + //XML + Deflate + response = url.GetXmlFromUrl(responseFilter: res => { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Xml)); + }) + .FromXml(); + Assert.That(ServerCacheOnly.Count, Is.EqualTo(3)); + AssertEquals(response, request); + + //HTML + Deflate + var html = url.GetStringFromUrl(requestFilter:req => req.With(c => c.Accept = MimeTypes.Html)); + Assert.That(ServerCacheOnly.Count, Is.EqualTo(4)); + Assert.That(html, Does.StartWith("")); + html = url.GetStringFromUrl(requestFilter:req => req.With(c => c.Accept = MimeTypes.Html)); + Assert.That(ServerCacheOnly.Count, Is.EqualTo(4)); + Assert.That(html, Does.StartWith("")); + } + + [Test] + public void Can_execute_with_CompressionDisabled() + { + var client = new JsvServiceClient(Config.ListeningOn) + { + DisableAutoCompression = true, + }; + + var result = client.Get(new ServerCacheOnly { Value = "Hello" }); + Assert.That(result.Value, Is.EqualTo("Hello")); + + var response = client.Get(new HelloCache { Name = "World" }); + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Cache_does_Expire() + { + var request = new ServerCacheShort { Id = 5, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCacheShort.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + Thread.Sleep(1100); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCacheShort.Count, Is.EqualTo(2)); + AssertEquals(response, request); + } + + [Test] + public void Cached_client_does_return_local_cache_when_MaxAge() + { + ClientCacheMaxAge.Count = 0; + var request = new ClientCacheMaxAge { Id = 6, Value = "foo" }; + var client = new CachedServiceClient(new JsonServiceClient(Config.ListeningOn)); + + ClientCacheMaxAge response; + + response = client.Get(request); + Assert.That(ClientCacheMaxAge.Count, Is.EqualTo(1)); + Assert.That(client.CacheHits, Is.EqualTo(0)); + AssertEquals(response, request); + + response = client.Get(request); + Assert.That(ClientCacheMaxAge.Count, Is.EqualTo(1)); + Assert.That(client.CacheHits, Is.EqualTo(1)); + AssertEquals(response, request); + } + + [Test] + public void Cached_client_does_return_NotModified_when_MustRevalidate() + { + ClientCacheMaxAge.Count = 0; + var request = new ClientCacheMustRevalidate { Id = 7, Value = "foo" }; + var client = new CachedServiceClient(new JsonServiceClient(Config.ListeningOn)); + + ClientCacheMustRevalidate response; + + response = client.Get(request); + Assert.That(ClientCacheMustRevalidate.Count, Is.EqualTo(1)); + Assert.That(client.NotModifiedHits, Is.EqualTo(0)); + AssertEquals(response, request); + + response = client.Get(request); + Assert.That(ClientCacheMustRevalidate.Count, Is.EqualTo(1)); + Assert.That(client.NotModifiedHits, Is.EqualTo(1)); + AssertEquals(response, request); + } + + [Test] + public void Does_cache_by_custom_CacheKey() + { + ServerCustomCacheKey.Count = 0; + var request = new ServerCustomCacheKey { Id = 8, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCustomCacheKey.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCustomCacheKey.Count, Is.EqualTo(2)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetJsonFromUrl() + .FromJson(); + + Assert.That(ServerCustomCacheKey.Count, Is.EqualTo(2)); + AssertEquals(response, request); + } + + [Test] + public void Does_not_cache_Error_Responses() + { + var client = new JsonServiceClient(Config.ListeningOn); + + try + { + var response = client.Get(new CacheAlwaysThrows { Message = "foo" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorMessage, Is.EqualTo("foo")); + } + + try + { + var response = client.Get(new CacheAlwaysThrows { Message = "bar" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorMessage, Is.EqualTo("bar")); + } + } + + [Test] + public void Cache_does_use_custom_serialization() + { + var json = Config.ListeningOn.CombineWith("/cache/custom-json/1") + .GetJsonFromUrl(); + + Assert.That(json, Is.EqualTo("{\"id\":1,\"value\":null}")); + } + + [Test] + public void Does_cache_MemoryStream_HttpResult_Responses_preserving_ContentType() + { + CacheStream.Count = 0; + var request = new CacheStream { Id = 1, Value = "foo" }; + + var response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetStringFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Jsv)); + Assert.That(res.GetHeader(HttpHeaders.CacheControl), Is.Null); + }) + .FromJsv(); + + Assert.That(CacheStream.Count, Is.EqualTo(1)); + AssertEquals(response, request); + + response = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .GetStringFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Jsv)); + Assert.That(res.GetHeader(HttpHeaders.CacheControl), Is.Null); + }) + .FromJsv(); + + Assert.That(CacheStream.Count, Is.EqualTo(1)); + AssertEquals(response, request); + +#if NNETFX + var client = new JsvServiceClient(Config.ListeningOn); + response = client.Get(request); + Assert.That(CacheStream.Count, Is.EqualTo(1)); + AssertEquals(response, request); +#endif + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CacheServerFeatureTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CacheServerFeatureTests.cs new file mode 100644 index 00000000000..eca7ef2da3d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CacheServerFeatureTests.cs @@ -0,0 +1,446 @@ +using System; +using Funq; +using NUnit.Framework; +using ServiceStack.Caching; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class CacheServerFeatureTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(typeof(CacheServerFeatureTests).Name, typeof(CacheEtagServices).Assembly) + { } + + public override void Configure(Container container) { } + } + + private readonly ServiceStackHost appHost; + public CacheServerFeatureTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [TearDown] + public void TearDown() + { + //clear cache after each test + var cache = appHost.TryResolve(); + cache.FlushAll(); + } + + protected JsonServiceClient GetClient() + { + var client = new JsonServiceClient(Config.ListeningOn); +#if NETCORE + client.AddHeader(HttpHeaders.AcceptEncoding, "gzip,deflate"); +#endif + return client; + } + + [Test] + public void Does_set_Etag_and_Default_MaxAge() + { + var client = GetClient(); + client.ResponseFilter = res => + { + Assert.That(res.Headers[HttpHeaders.ETag], Is.EqualTo("etag".Quoted())); + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.EqualTo("max-age=600")); + }; + + var request = new SetCache { ETag = "etag" }; + var response = client.Get(request); + + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void Does_not_set_Etag_and_Default_MaxAge_on_POST() + { + var client = GetClient(); + client.ResponseFilter = res => + { + Assert.That(res.Headers[HttpHeaders.ETag], Is.Null); + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.Null); + }; + + var request = new SetCache { ETag = "etag" }; + var response = client.Post(request); + + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void Does_set_LastModified_and_Default_MaxAge() + { + var client = GetClient(); + var request = new SetCache { LastModified = new DateTime(2016, 1, 1, 0, 0, 0) }; + + client.ResponseFilter = res => + { + Assert.That(res.Headers[HttpHeaders.LastModified], Is.EqualTo(request.LastModified.Value.ToUniversalTime().ToString("r"))); + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.EqualTo("max-age=600")); + }; + + var response = client.Get(request); + + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void Does_set_Etag_MaxAge_and_CacheControl() + { + var client = GetClient(); + client.ResponseFilter = res => + { + Assert.That(res.Headers[HttpHeaders.Age], Is.EqualTo("864000")); + Assert.That(res.Headers[HttpHeaders.ETag], Is.EqualTo("etag".Quoted())); + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.EqualTo("max-age=86400, public, must-revalidate, no-store") + .Or.EqualTo("no-store, public, must-revalidate, max-age=86400")); + }; + + var request = new SetCache + { + ETag = "etag", + Age = TimeSpan.FromDays(10), + MaxAge = TimeSpan.FromDays(1), + CacheControl = CacheControl.Public | CacheControl.NoStore | CacheControl.MustRevalidate, + }; + var response = client.Get(request); + + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void Does_throw_304_when_etag_matches() + { + var client = GetClient(); + client.RequestFilter = req => + req.Headers[HttpHeaders.IfNoneMatch] = "etag".Quoted(); + + client.ResponseFilter = res => + Assert.That(res.ContentLength, Is.EqualTo(0)); + + try + { + var response = client.Get(new SetCache { ETag = "etag" }); + Assert.Fail("Should throw 304 NotModified"); + } + catch (Exception ex) + { + if (!ex.IsNotModified()) + throw; + } + } + + [Test] + public void Returns_response_when_etag_does_not_match() + { + var client = GetClient(); + client.RequestFilter = req => + req.Headers[HttpHeaders.IfNoneMatch] = "etag".Quoted(); + + client.ResponseFilter = res => + { + Assert.That(res.Headers[HttpHeaders.ETag], Is.EqualTo("etag-alt".Quoted())); + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.EqualTo("max-age=600")); + }; + + var request = new SetCache { ETag = "etag-alt" }; + var response = client.Get(request); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void Does_throw_304_when_not_ModifiedSince() + { + var client = GetClient(); + var request = new SetCache { LastModified = new DateTime(2016, 1, 1, 0, 0, 0) }; + + client.RequestFilter = req => + PclExportClient.Instance.SetIfModifiedSince(req, request.LastModified.Value); + + client.ResponseFilter = res => + { + Assert.That(res.ContentLength, Is.EqualTo(0)); + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.EqualTo("max-age=3600")); + }; + + try + { + var response = client.Get(request); + Assert.Fail("Should throw 304 NotModified"); + } + catch (Exception ex) + { + if (!ex.IsNotModified()) + throw; + } + } + + [Test] + public void Returns_response_when_ModifiedSince_LastModified() + { + var client = GetClient(); + var request = new SetCache { LastModified = new DateTime(2016, 1, 1, 0, 0, 0) }; + + client.RequestFilter = req => + PclExportClient.Instance.SetIfModifiedSince(req, request.LastModified.Value + TimeSpan.FromSeconds(-1)); + + client.ResponseFilter = res => + Assert.That(res.Headers[HttpHeaders.CacheControl], Is.EqualTo("max-age=600")); + + var response = client.Get(request); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void Can_short_circuit_Service_implementation_when_ETag_matches() + { + var client = GetClient(); + client.RequestFilter = req => + req.Headers[HttpHeaders.IfNoneMatch] = "etag".Quoted(); + + client.ResponseFilter = res => + { + Assert.That(res.ContentLength, Is.EqualTo(0)); + Assert.That(res.Headers[HttpHeaders.Age], Is.Null); //short-circuit + }; + + try + { + var response = client.Get(new ShortCircuitImpl { ETag = "etag", Age = TimeSpan.FromDays(1) }); + Assert.Fail("Should throw 304 NotModified"); + } + catch (Exception ex) + { + if (!ex.IsNotModified()) + throw; + } + } + + [Test] + public void Does_bypass_short_circuit_Service_implementation_when_ETag_not_matches() + { + var client = GetClient(); + client.RequestFilter = req => + req.Headers[HttpHeaders.IfNoneMatch] = "etag".Quoted(); + + client.ResponseFilter = res => + Assert.That(res.Headers[HttpHeaders.Age], Is.EqualTo("86400")); + + var request = new ShortCircuitImpl + { + ETag = "etag-alt", + Age = TimeSpan.FromDays(1) + }; + var response = client.Get(request); + + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void ToOptimizedResult_does_populate_LastModified() + { + var client = GetClient(); + + client.ResponseFilter = res => + Assert.That(DateTime.Parse(res.Headers[HttpHeaders.LastModified]).ToUniversalTime(), + Is.EqualTo(DateTime.UtcNow).Within(TimeSpan.FromMinutes(1))); + + var request = new CachedRequest { ETag = "etag" }; + var response = client.Get(request); + Assert.That(response, Is.EqualTo(request)); + + response = client.Get(request); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void ToOptimizedResult_throws_304_when_not_ModifiedSince() + { + var client = GetClient(); + + DateTime? lastModified = null; + + client.ResponseFilter = res => + lastModified = DateTime.Parse(res.Headers[HttpHeaders.LastModified]); + + var request = new CachedRequest { Age = TimeSpan.FromHours(1) }; + var response = client.Get(request); + Assert.That(response, Is.EqualTo(request)); + + try + { + client.RequestFilter = req => + PclExportClient.Instance.SetIfModifiedSince(req, lastModified.Value); + + response = client.Get(request); + Assert.Fail("Should throw 304 NotModified"); + } + catch (Exception ex) + { + if (!ex.IsNotModified()) + throw; + } + } + + [Test] + public void CachedServiceClient_does_return_cached_ETag_Requests() + { + var client = new CachedServiceClient(GetClient()); + + var request = new SetCache { ETag = "etag" }; + + var response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + } + + public abstract class CacheRequestBase + { + public string ETag { get; set; } + public TimeSpan? Age { get; set; } + public TimeSpan? MaxAge { get; set; } + public DateTime? Expires { get; set; } + public DateTime? LastModified { get; set; } + public CacheControl? CacheControl { get; set; } + + public bool Equals(CacheRequestBase other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(ETag, other.ETag) + && MaxAge.Equals(other.MaxAge) + && Expires.Equals(other.Expires) + && LastModified.Equals(other.LastModified) + && CacheControl == other.CacheControl; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((SetCache)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (ETag != null ? ETag.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ MaxAge.GetHashCode(); + hashCode = (hashCode * 397) ^ Expires.GetHashCode(); + hashCode = (hashCode * 397) ^ LastModified.GetHashCode(); + hashCode = (hashCode * 397) ^ CacheControl.GetHashCode(); + return hashCode; + } + } + } + + [Route("/set-cache")] + public class SetCache : CacheRequestBase, IReturn, IEquatable + { + public bool Equals(SetCache other) + { + return base.Equals(other); + } + } + + public class ShortCircuitImpl : CacheRequestBase, IReturn, IEquatable + { + public bool Equals(ShortCircuitImpl other) + { + return base.Equals(other); + } + } + + public class CachedRequest : CacheRequestBase, IReturn, IEquatable + { + public bool Equals(CachedRequest other) + { + return base.Equals(other); + } + } + + public class FailsAfterOnce : CacheRequestBase, IReturn, IEquatable + { + internal static int Count = 0; + + public bool Equals(FailsAfterOnce other) + { + return base.Equals(other); + } + } + + public class CacheEtagServices : Service + { + public object Any(SetCache request) + { + return new HttpResult(request) + { + Age = request.Age, + ETag = request.ETag, + MaxAge = request.MaxAge, + Expires = request.Expires, + LastModified = request.LastModified, + CacheControl = request.CacheControl.GetValueOrDefault(CacheControl.None), + }; + } + + public object Any(ShortCircuitImpl request) + { + if (Request.HasValidCache(request.ETag, request.LastModified)) + return HttpResult.NotModified(); + + return new HttpResult(request) + { + Age = request.Age, + ETag = request.ETag, + MaxAge = request.MaxAge, + Expires = request.Expires, + LastModified = request.LastModified, + CacheControl = request.CacheControl.GetValueOrDefault(CacheControl.None), + }; + } + + public object Any(CachedRequest request) + { + var cacheKey = Request.QueryString.ToString(); + + return Request.ToOptimizedResultUsingCache(Cache, cacheKey, () => request); + } + + public object Any(FailsAfterOnce request) + { + if (FailsAfterOnce.Count++ > 0) + throw new Exception("Can only be called once"); + + return new HttpResult(request) + { + Age = request.Age, + ETag = request.ETag, + MaxAge = request.MaxAge, + Expires = request.Expires, + LastModified = request.LastModified, + CacheControl = request.CacheControl.GetValueOrDefault(CacheControl.None), + }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceClientTests.cs new file mode 100644 index 00000000000..7245b2384c8 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceClientTests.cs @@ -0,0 +1,243 @@ +using System; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class CachedJsonServiceClientTests : CachedServiceClientTests + { + protected override ICachedServiceClient GetCachedServiceClient() + { + var client = new JsonServiceClient(Config.ListeningOn); +#if NETCORE + client.AddHeader(HttpHeaders.AcceptEncoding, "gzip,deflate"); +#endif + return new CachedServiceClient(client); + } + } + + public class CachedJsonHttpClientTests : CachedServiceClientTests + { + protected override ICachedServiceClient GetCachedServiceClient() + { + return new CachedHttpClient(new JsonHttpClient(Config.ListeningOn)); + } + } + + [TestFixture] + public abstract class CachedServiceClientTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(typeof(CacheServerFeatureTests).Name, typeof(CacheEtagServices).Assembly) + { } + + public override void Configure(Container container) { } + } + + private readonly ServiceStackHost appHost; + protected CachedServiceClientTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [TearDown] + public void TearDown() + { + //clear cache after each test + var cache = Service.GlobalResolver.TryResolve(); + cache.FlushAll(); + } + + protected abstract ICachedServiceClient GetCachedServiceClient(); + + [Test] + public void CachedServiceClient_does_return_cached_ETag_Requests_when_MustRevalidate() + { + var client = GetCachedServiceClient(); + + var request = new SetCache { ETag = "etag", CacheControl = CacheControl.MustRevalidate }; + + var response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public async Task CachedServiceClient_does_return_cached_ETag_Requests_Async() + { + var client = GetCachedServiceClient(); + + var request = new SetCache { ETag = "etag", CacheControl = CacheControl.MustRevalidate }; + + var response = await client.GetAsync(request); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = await client.GetAsync(request); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void CachedServiceClient_does_return_cached_ETag_Requests_using_URL() + { + var client = GetCachedServiceClient(); + + var requestUrl = Config.ListeningOn.CombineWith("set-cache?etag=etag"); + + var response = client.Get(requestUrl); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response.ETag, Is.EqualTo("etag")); + + response = client.Get(requestUrl); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.ETag, Is.EqualTo("etag")); + } + + [Test] + public void CachedServiceClient_does_return_cached_LastModified_Requests() + { + var client = GetCachedServiceClient(); + + var request = new SetCache { LastModified = new DateTime(2016, 1, 1, 0, 0, 0) }; + + var response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = client.Get(request); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void CachedServiceClient_does_return_cached_LastModified_Requests_using_URL() + { + var client = GetCachedServiceClient(); + + var requestUrl = Config.ListeningOn.CombineWith("set-cache?lastModified=2016-01-01"); + + var response = client.Get(requestUrl); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response.LastModified, Is.EqualTo(new DateTime(2016, 1, 1, 0, 0, 0))); + + response = client.Get(requestUrl); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.LastModified, Is.EqualTo(new DateTime(2016, 1, 1, 0, 0, 0))); + } + + [Test] + public async Task CachedServiceClient_does_return_cached_LastModified_Requests_using_URL_Async() + { + var client = GetCachedServiceClient(); + + var requestUrl = Config.ListeningOn.CombineWith("set-cache?lastModified=2016-01-01"); + + var response = await client.GetAsync(requestUrl); + Assert.That(client.CacheHits, Is.EqualTo(0)); + Assert.That(response.LastModified, Is.EqualTo(new DateTime(2016, 1, 1, 0, 0, 0))); + + response = await client.GetAsync(requestUrl); + Assert.That(client.CacheHits, Is.EqualTo(1)); + Assert.That(response.LastModified, Is.EqualTo(new DateTime(2016, 1, 1, 0, 0, 0))); + } + + [Test] + public void CachedServiceClient_does_return_cached_ToOptimizedResults() + { + var client = GetCachedServiceClient(); + + var request = new CachedRequest { Age = TimeSpan.FromHours(1) }; + var response = client.Get(request); + Assert.That(client.NotModifiedHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = client.Get(request); + Assert.That(client.NotModifiedHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public async Task CachedServiceClient_does_return_cached_ToOptimizedResults_Async() + { + var client = GetCachedServiceClient(); + + var request = new CachedRequest { Age = TimeSpan.FromHours(1) }; + var response = await client.GetAsync(request); + Assert.That(client.NotModifiedHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = await client.GetAsync(request); + Assert.That(client.NotModifiedHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void CachedServiceClient_does_return_cached_after_FailedResponse() + { + var client = GetCachedServiceClient(); + FailsAfterOnce.Count = 0; + + var request = new FailsAfterOnce { ETag = "etag", MaxAge = TimeSpan.FromSeconds(0) }; + var response = client.Get(request); + Assert.That(client.ErrorFallbackHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = client.Get(request); + Assert.That(client.ErrorFallbackHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public async Task CachedServiceClient_does_return_cached_after_FailedResponse_Async() + { + var client = GetCachedServiceClient(); + FailsAfterOnce.Count = 0; + + var request = new FailsAfterOnce { ETag = "etag", MaxAge = TimeSpan.FromSeconds(0) }; + var response = await client.GetAsync(request); + Assert.That(client.ErrorFallbackHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + response = await client.GetAsync(request); + Assert.That(client.ErrorFallbackHits, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo(request)); + } + + [Test] + public void CachedServiceClient_does_not_return_NoCache_after_FailedResponse() + { + var client = GetCachedServiceClient(); + FailsAfterOnce.Count = 0; + + var request = new FailsAfterOnce { ETag = "etag", CacheControl = CacheControl.NoCache }; + var response = client.Get(request); + Assert.That(client.ErrorFallbackHits, Is.EqualTo(0)); + Assert.That(response, Is.EqualTo(request)); + + try + { + client.Get(request); + Assert.Fail("Should throw"); + } + catch (Exception) {} + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceTests.cs index 20c51b2140d..438378b59dd 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CachedServiceTests.cs @@ -1,10 +1,6 @@ using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; +using ServiceStack.ProtoBuf; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -13,7 +9,7 @@ public class CachedServiceTests { ExampleAppHostHttpListener appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { appHost = new ExampleAppHostHttpListener(); @@ -21,7 +17,7 @@ public void OnTestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); @@ -37,6 +33,36 @@ public void Can_call_Cached_WebService_with_JSON() Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); } + [Test] + public void Can_call_Cached_WebService_with_JSON_string() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get("/cached-string/TEXT"); + + Assert.That(response, Is.EqualTo("TEXT")); + } + + [Test] + public void Can_call_CachedWithTimeout_WebService_with_JSON() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get("/cached-timeout/movies"); + + Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + } + + [Test] + public void Can_call_CachedWithTimeout_and_Redis_WebService_with_JSON() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get("/cached-timeout-redis/movies"); + + Assert.That(response.Movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + } + [Test] public void Can_call_Cached_WebService_with_ProtoBuf() { @@ -48,11 +74,11 @@ public void Can_call_Cached_WebService_with_ProtoBuf() } [Test] - public void Can_call_Cached_WebService_with_JSONP() - { - var url = Config.ServiceStackBaseUri.CombineWith("/cached/movies?callback=cb"); - var jsonp = url.GetJsonFromUrl(); - Assert.That(jsonp.StartsWith("cb(")); - } - } + public void Can_call_Cached_WebService_with_JSONP() + { + var url = Config.ServiceStackBaseUri.CombineWith("/cached/movies?callback=cb"); + var jsonp = url.GetJsonFromUrl(); + Assert.That(jsonp.StartsWith("cb(")); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CancellableRequestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CancellableRequestTests.cs new file mode 100644 index 00000000000..127cbbacacf --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CancellableRequestTests.cs @@ -0,0 +1,93 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class CancellableRequestAppHost : AppSelfHostBase + { + public CancellableRequestAppHost() + : base("CancellableRequests", typeof(CancellableRequestTestService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new CancellableRequestsFeature()); + } + } + + public class TestCancelRequest : IReturn + { + public string Tag { get; set; } + } + + public class TestCancelRequestResponse + { + public ResponseStatus ResponseStatus { get; set; } + } + + public class CancellableRequestTestService : Service + { + public object Any(TestCancelRequest req) + { + using (var cancellableRequest = base.Request.CreateCancellableRequest()) + { + while (true) + { + cancellableRequest.Token.ThrowIfCancellationRequested(); + Thread.Sleep(100); + } + } + } + } + + public class CancellableRequestTests + { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new CancellableRequestAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public async Task Can_Cancel_long_running_request() + { + var tag = Guid.NewGuid().ToString(); + var client = new JsonServiceClient(Config.AbsoluteBaseUri) { + RequestFilter = req => req.Headers[HttpHeaders.XTag] = tag + }; + + var responseTask = client.PostAsync(new TestCancelRequest + { + Tag = tag + }); + + await Task.Delay(1000); + + var cancelResponse = client.Post(new CancelRequest { Tag = tag }); + Assert.That(cancelResponse.Tag, Is.EqualTo(tag)); + + try + { + var response = await responseTask; + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(OperationCanceledException).Name)); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CompressResponseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CompressResponseTests.cs new file mode 100644 index 00000000000..9fc1b97f459 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CompressResponseTests.cs @@ -0,0 +1,357 @@ +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Text; +using ServiceStack.VirtualPath; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class CompressData : IReturn + { + public string String { get; set; } + public byte[] Bytes { get; set; } + } + + public class CompressString : IReturn + { + public string String { get; set; } + } + + public class CompressBytes : IReturn + { + public byte[] Bytes { get; set; } + } + + [Route("/compress/{Path*}")] + public class CompressFile + { + public string Path { get; set; } + } + + public class CompressError : IReturn { } + + [Route("/compress/dto-result/{Name}")] + public class CompressDtoResult : IReturn + { + public string Name { get; set; } + } + + [CompressResponse] + public class CompressedServices : Service + { + public object Any(CompressData request) => request; + public object Any(CompressString request) => request.String; + public object Any(CompressBytes request) => request.Bytes; + + public object Any(CompressFile request) + { + var file = VirtualFileSources.GetFile(request.Path); + if (file == null) + throw HttpError.NotFound($"{request.Path} does not exist"); + + return new HttpResult(file); + } + + public object Any(CompressDtoResult request) => new HttpResult(request, MimeTypes.Xml); + + public object Any(CompressError request) + { + throw HttpError.NotFound("Always NotFound"); + } + } + + public class CompressResponseTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(CompressResponseTests), typeof(CompressedServices).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + CompressFilesWithExtensions = { "html", "css" } + }); + } + + public override List GetVirtualFileSources() + { + var existingProviders = base.GetVirtualFileSources(); + var memFs = new MemoryVirtualFiles(); + + memFs.WriteFile("/file.js", "console.log('foo')"); + memFs.WriteFile("/file.css", ".foo{}"); + memFs.WriteFile("/file.txt", "foo"); + memFs.WriteFile("/default.html", "foo"); + + //Give new Memory FS highest priority + existingProviders.Insert(0, memFs); + return existingProviders; + } + } + + private ServiceStackHost appHost; + + public CompressResponseTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_compress_RequestDto_responses() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Post(new CompressData + { + String = "Hello", + Bytes = "World".ToUtf8Bytes() + }); + + Assert.That(response.String, Is.EqualTo("Hello")); + Assert.That(response.Bytes, Is.EqualTo("World".ToUtf8Bytes())); + } + + [Test] + public async Task Does_compress_RequestDto_responses_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn); + var response = await client.PostAsync(new CompressData + { + String = "Hello", + Bytes = "World".ToUtf8Bytes() + }); + + Assert.That(response.String, Is.EqualTo("Hello")); + Assert.That(response.Bytes, Is.EqualTo("World".ToUtf8Bytes())); + } + + [Test] + public void Does_compress_raw_String_responses() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Post(new CompressString + { + String = "foo", + }); + + Assert.That(response, Is.EqualTo("foo")); + } + + [Test] + public async Task Does_compress_raw_String_responses_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn); + var response = await client.PostAsync(new CompressString + { + String = "foo", + }); + + Assert.That(response, Is.EqualTo("foo")); + } + + [Test] + public void Does_compress_raw_Bytes_responses() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Post(new CompressBytes + { + Bytes = "foo".ToUtf8Bytes(), + }); + + Assert.That(response, Is.EquivalentTo("foo".ToUtf8Bytes())); + } + + [Test] + public async Task Does_compress_raw_Bytes_responses_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn); + var response = await client.PostAsync(new CompressBytes + { + Bytes = "foo".ToUtf8Bytes(), + }); + + Assert.That(response, Is.EquivalentTo("foo".ToUtf8Bytes())); + } + + [Test] + public void Does_not_compress_error_responses() + { + var client = new JsonServiceClient(Config.ListeningOn); + + try + { + client.Post(new CompressError()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(404)); + Assert.That(ex.ErrorCode, Is.EqualTo("NotFound")); + Assert.That(ex.ErrorMessage, Is.EqualTo("Always NotFound")); + } + } + + [Test] + public async Task Does_not_compress_error_responses_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn); + + try + { + await client.PostAsync(new CompressError()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(404)); + Assert.That(ex.ErrorCode, Is.EqualTo("NotFound")); + Assert.That(ex.ErrorMessage, Is.EqualTo("Always NotFound")); + } + } + + [Test] + public void Does_compress_using_ContenType_in_HttpResult() + { + var url = Config.ListeningOn.CombineWith(new CompressDtoResult { Name = "foo" }.ToGetUrl()); + + var xml = url.GetJsonFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Xml)); + }); + + Assert.That(xml, Does.StartWith(" + { + Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.Xml)); + }); + + Assert.That(xml, Does.StartWith(" + { + req.AutomaticDecompression = DecompressionMethods.None; + req.Headers[HttpRequestHeader.AcceptEncoding] = "deflate"; + }, responseFilter: res => + { + Assert.That(res.Headers[HttpResponseHeader.ContentEncoding], Is.EqualTo("deflate")); + }); + + var bytes = zipBytes.DecompressBytes("deflate"); + Assert.That(bytes.FromUtf8Bytes(), Is.EqualTo("console.log('foo')")); + } + + [Test] + public async Task Does_compress_file_returned_in_HttpResult_Async() + { + var url = Config.ListeningOn.CombineWith("/compress/file.js"); + var zipBytes = await url.GetBytesFromUrlAsync( + requestFilter: req => + { + req.AutomaticDecompression = DecompressionMethods.None; + req.Headers[HttpRequestHeader.AcceptEncoding] = "deflate"; + }, responseFilter: res => + { + Assert.That(res.Headers[HttpResponseHeader.ContentEncoding], Is.EqualTo("deflate")); + }); + + var bytes = zipBytes.DecompressBytes("deflate"); + Assert.That(bytes.FromUtf8Bytes(), Is.EqualTo("console.log('foo')")); + } + + [Test] + public void Does_compress_static_file_in_CompressFilesWithExtensions() + { + var url = Config.ListeningOn.CombineWith("/file.css"); + var zipBytes = url.GetBytesFromUrl( + requestFilter: req => + { + req.AutomaticDecompression = DecompressionMethods.None; + req.Headers[HttpRequestHeader.AcceptEncoding] = "deflate"; + }, responseFilter: res => + { + Assert.That(res.Headers[HttpResponseHeader.ContentEncoding], Is.EqualTo("deflate")); + }); + + var bytes = zipBytes.DecompressBytes("deflate"); + Assert.That(bytes.FromUtf8Bytes(), Is.EqualTo(".foo{}")); + } + + [Test] + public async Task Does_compress_static_file_in_CompressFilesWithExtensions_Async() + { + var url = Config.ListeningOn.CombineWith("/file.css"); + var zipBytes = await url.GetBytesFromUrlAsync( + requestFilter: req => + { + req.AutomaticDecompression = DecompressionMethods.None; + req.Headers[HttpRequestHeader.AcceptEncoding] = "deflate"; + }, responseFilter: res => + { + Assert.That(res.Headers[HttpResponseHeader.ContentEncoding], Is.EqualTo("deflate")); + }); + + var bytes = zipBytes.DecompressBytes("deflate"); + Assert.That(bytes.FromUtf8Bytes(), Is.EqualTo(".foo{}")); + } + + [Test] + public void Does_compress_default_page_in_CompressFilesWithExtensions() + { + var url = Config.ListeningOn.CombineWith("/default.html"); + var zipBytes = url.GetBytesFromUrl( + requestFilter: req => + { + req.AutomaticDecompression = DecompressionMethods.None; + req.Headers[HttpRequestHeader.AcceptEncoding] = "deflate"; + }, responseFilter: res => + { + Assert.That(res.Headers[HttpResponseHeader.ContentEncoding], Is.EqualTo("deflate")); + }); + + var bytes = zipBytes.DecompressBytes("deflate"); + Assert.That(bytes.FromUtf8Bytes(), Is.EqualTo("foo")); + } + + [Test] + public async Task Does_compress_default_page_in_CompressFilesWithExtensions_Async() + { + var url = Config.ListeningOn.CombineWith("/default.html"); + var zipBytes = await url.GetBytesFromUrlAsync( + requestFilter: req => + { + req.AutomaticDecompression = DecompressionMethods.None; + req.Headers[HttpRequestHeader.AcceptEncoding] = "deflate"; + }, responseFilter: res => + { + Assert.That(res.Headers[HttpResponseHeader.ContentEncoding], Is.EqualTo("deflate")); + }); + + var bytes = zipBytes.DecompressBytes("deflate"); + Assert.That(bytes.FromUtf8Bytes(), Is.EqualTo("foo")); + } +#endif + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CompressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CompressionTests.cs index e9dc8e87039..944fe983d3b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CompressionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CompressionTests.cs @@ -1,18 +1,14 @@ using System; using System.Runtime.Serialization; using Funq; -using Moq; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; +using ServiceStack.Host; using ServiceStack.Logging; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.ServiceModel.Serialization; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Tests.Mocks; -using DataContractSerializer = ServiceStack.ServiceModel.Serialization.DataContractSerializer; +using ServiceStack.Serialization; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; +using DataContractSerializer = ServiceStack.Serialization.DataContractSerializer; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -42,12 +38,18 @@ public class CompressionTests { private static readonly ILog Log = LogManager.GetLogger(typeof(CompressionTests)); + [OneTimeSetUp] + public void Init() + { + LogManager.LogFactory = null; + } + [Test] public void Can_compress_and_decompress_SimpleDto() { var simpleDto = new TestCompress(1, "name"); - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); var simpleDtoZip = simpleDtoXml.Deflate(); @@ -57,7 +59,7 @@ public void Can_compress_and_decompress_SimpleDto() Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( deserializedSimpleDtoXml); Assert.That(deserializedSimpleDto, Is.Not.Null); @@ -70,47 +72,43 @@ public void Can_compress_and_decompress_SimpleDto() [Test] public void Test_response_with_CompressedResult() { - EndpointHost.Config = new EndpointHostConfig( - "ServiceName", - new ServiceManager(GetType().Assembly)); - - var assembly = typeof (CompressionTests).Assembly; - EndpointHost.ConfigureHost( - new TestAppHost(new Container(), assembly), "Name", new ServiceManager(assembly)); + using (new BasicAppHost(typeof(CompressionTests).Assembly).Init()) + { + var mockResponse = new MockHttpResponse(); - var mockResponse = new HttpResponseMock(); + var simpleDto = new TestCompress(1, "name"); - var simpleDto = new TestCompress(1, "name"); - - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); - const string expectedXml = "1name"; + const string expectedXml = "1name"; + const string expectedXmlNetCore = "1name"; - Assert.That(simpleDtoXml, Is.EqualTo(expectedXml)); + Assert.That(simpleDtoXml, Is.EqualTo(expectedXml).Or.EqualTo(expectedXmlNetCore)); - var simpleDtoZip = simpleDtoXml.Deflate(); + var simpleDtoZip = simpleDtoXml.Deflate(); - Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); + Assert.That(simpleDtoZip.Length, Is.GreaterThan(0)); - var compressedResult = new CompressedResult(simpleDtoZip); + var compressedResult = new CompressedResult(simpleDtoZip); - var reponseWasAutoHandled = mockResponse.WriteToResponse( - compressedResult, CompressionTypes.Deflate); + var reponseWasAutoHandled = mockResponse.WriteToResponse( + compressedResult, CompressionTypes.Deflate); - Assert.That(reponseWasAutoHandled, Is.True); + Assert.That(reponseWasAutoHandled.Result, Is.True); - //var bytesToWriteToResponseStream = new byte[simpleDtoZip.Length - 4]; - //Array.Copy(simpleDtoZip, CompressedResult.Adler32ChecksumLength, bytesToWriteToResponseStream, 0, bytesToWriteToResponseStream.Length); + //var bytesToWriteToResponseStream = new byte[simpleDtoZip.Length - 4]; + //Array.Copy(simpleDtoZip, CompressedResult.Adler32ChecksumLength, bytesToWriteToResponseStream, 0, bytesToWriteToResponseStream.Length); - var bytesToWriteToResponseStream = simpleDtoZip; + var bytesToWriteToResponseStream = simpleDtoZip; - var writtenBytes = mockResponse.GetOutputStreamAsBytes(); - Assert.That(writtenBytes, Is.EqualTo(bytesToWriteToResponseStream)); - Assert.That(mockResponse.ContentType, Is.EqualTo(MimeTypes.Xml)); - Assert.That(mockResponse.Headers[HttpHeaders.ContentEncoding], Is.EqualTo(CompressionTypes.Deflate)); + var writtenBytes = mockResponse.ReadAsBytes(); + Assert.That(writtenBytes, Is.EqualTo(bytesToWriteToResponseStream)); + Assert.That(mockResponse.ContentType, Is.EqualTo(MimeTypes.Xml)); + Assert.That(mockResponse.Headers[HttpHeaders.ContentEncoding], Is.EqualTo(CompressionTypes.Deflate)); - Log.Debug("Content-length: " + writtenBytes.Length); - Log.Debug(BitConverter.ToString(writtenBytes)); + Log.Debug("Content-length: " + writtenBytes.Length); + Log.Debug(BitConverter.ToString(writtenBytes)); + } } [Test] @@ -118,7 +116,7 @@ public void Can_gzip_and_gunzip_SimpleDto() { var simpleDto = new TestCompress(1, "name"); - var simpleDtoXml = DataContractSerializer.Instance.Parse(simpleDto); + var simpleDtoXml = DataContractSerializer.Instance.SerializeToString(simpleDto); var simpleDtoZip = simpleDtoXml.GZip(); @@ -128,7 +126,7 @@ public void Can_gzip_and_gunzip_SimpleDto() Assert.That(deserializedSimpleDtoXml, Is.Not.Empty); - var deserializedSimpleDto = DataContractDeserializer.Instance.Parse( + var deserializedSimpleDto = DataContractSerializer.Instance.DeserializeFromString( deserializedSimpleDtoXml); Assert.That(deserializedSimpleDto, Is.Not.Null); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ConcurrencyTest.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ConcurrencyTest.cs new file mode 100644 index 00000000000..d4c2a60bd86 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ConcurrencyTest.cs @@ -0,0 +1,117 @@ +using System; +using System.Diagnostics; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class SleepTest : IReturn + { + public string Name { get; set; } + public int WaitingSecs { get; set; } + } + + public class SleepTestResponse + { + public string Message { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class TestConcurrencyService : Service + { + public object Any(SleepTest request) + { + var sw = Stopwatch.StartNew(); + + Thread.Sleep(TimeSpan.FromSeconds(request.WaitingSecs)); + + return new SleepTestResponse + { + Message = $"{request.Name} took {sw.Elapsed.TotalSeconds} secs", + }; + } + } + + [Ignore("Comment out to run load test")] + public class ConcurrencyTest + { + private static ILog log; + private readonly ServiceStackHost appHost; + + public ConcurrencyTest() + { + LogManager.LogFactory = new ConsoleLogFactory(); + log = LogManager.GetLogger(typeof(ConcurrencyTest)); + + appHost = new AppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + public class AppHost : AppHostHttpListenerPoolBase + { + public AppHost() : base("Server", 500, typeof(TestConcurrencyService).Assembly) {} + + public override void Configure(Container container) + { + } + } + + [Test] + public void Does_handle_concurrent_requests() + { + var rand = new Random(); + var client = new JsonHttpClient(Config.AbsoluteBaseUri); + client.GetHttpClient().Timeout = TimeSpan.FromMinutes(5); + long responsesReceived = 0; + long totalSecondsWaited = 0; + var sw = Stopwatch.StartNew(); + const int ConcurrentRequests = 50; + + ConcurrentRequests.Times(i => + { + Interlocked.Increment(ref responsesReceived); + + ThreadPool.QueueUserWorkItem(async _ => + { + var request = new SleepTest + { + Name = $"Request {i+1}", + WaitingSecs = rand.Next(30, 60), + }; + Interlocked.Add(ref totalSecondsWaited, request.WaitingSecs); + + log.Info($"[{DateTime.Now.TimeOfDay}] Sending {request.Name} to sleep for {request.WaitingSecs} seconds..."); + + try + { + var response = await client.GetAsync(request); + + log.Info($"[{DateTime.Now.TimeOfDay}] Received {request.Name}: {response.Message}"); + } + catch (Exception ex) + { + log.Error($"[{DateTime.Now.TimeOfDay}] Error Response: {ex.UnwrapIfSingleException().Message}", ex); + } + finally + { + Interlocked.Decrement(ref responsesReceived); + } + }); + }); + + while (Interlocked.Read(ref responsesReceived) > 0) + { + Thread.Sleep(10); + } + + log.Info($"Took {sw.Elapsed.TotalSeconds} to execute {ConcurrentRequests} Concurrent Requests waiting a total of {totalSecondsWaited} seconds."); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Config.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Config.cs new file mode 100644 index 00000000000..ec4ed4fe2aa --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Config.cs @@ -0,0 +1,22 @@ +using System; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class Config + { + public static readonly string ServiceStackBaseUri = Environment.GetEnvironmentVariable("CI_BASEURI") ?? "http://localhost:20000"; + public static readonly string AbsoluteBaseUri = ServiceStackBaseUri + "/"; + + public static readonly string HostNameBaseUrl = "http://DESKTOP-BCS76J0:20000/"; //Allow fiddler + public static readonly string AnyHostBaseUrl = "http://*:20000/"; //Allow capturing by fiddler + + public static readonly string ListeningOn = ServiceStackBaseUri + "/"; + public static readonly string RabbitMQConnString = Environment.GetEnvironmentVariable("CI_RABBITMQ") ?? "localhost"; + public static readonly string SqlServerConnString = Environment.GetEnvironmentVariable("MSSQL_CONNECTION") ?? "Server=localhost;Database=test;User Id=test;Password=test;"; + public static readonly string PostgreSqlConnString = Environment.GetEnvironmentVariable("PGSQL_CONNECTION") ?? "Server=localhost;Port=5432;User Id=test;Password=test;Database=test;Pooling=true;MinPoolSize=0;MaxPoolSize=200"; + public static readonly string DynamoDbServiceURL = Environment.GetEnvironmentVariable("CI_DYNAMODB") ?? "http://localhost:8000"; + + public const string AspNetBaseUri = "http://localhost:50000/"; + public const string AspNetServiceStackBaseUri = AspNetBaseUri + "api"; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ContainerTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ContainerTests.cs new file mode 100644 index 00000000000..1b038e949c4 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ContainerTests.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + class SimpleContainerTests : ContainerTests + { + protected override IContainer CreateContainer() + { + return new SimpleContainer(); + } + } + + class FunqContainerTests : ContainerTests + { + protected override IContainer CreateContainer() + { + return new Funq.Container(); + } + + [Test] + public void Does_use_native_Exists_method() + { + var container = new Funq.Container(); + + container.AddTransient(() => new Foo()); + + Assert.That(container.Exists(typeof(IFoo))); + Assert.That(container.Exists()); + + Assert.That(!container.Exists(typeof(Foo))); + Assert.That(!container.Exists()); + } + } + + public abstract class ContainerTests + { + protected abstract IContainer CreateContainer(); + + public class Foo : IFoo + { + } + + public class Foo2 : IFoo + { + } + + public interface IFoo + { + } + + public class Bar : IBar + { + } + + public class Bar2 : IBar + { + } + + public interface IBar + { + } + + public class Test + { + public IFoo Foo { get; set; } + public IBar Bar { get; set; } + public Foo2 Foo2 { get; set; } + public IEnumerable Names { get; set; } + public int Age { get; set; } + public string Name { get; set; } + + public Test() + { + this.Age = 27; + this.Name = "foo"; + this.Names = new List { "bar" }; + } + } + + public class TestCtor + { + public IFoo Foo; + public Foo2 Foo2; + public IBar Bar { get; set; } + + public TestCtor(IFoo foo, Foo2 foo2) + { + Foo = foo; + Foo2 = foo2; + } + } + + [Test] + public void Does_not_throw_when_registering_null_dependency() + { + var container = new Funq.Container(); + container.Register((IFoo) new Foo()); + Assert.That(container.TryResolve() != null); + container.Register((IFoo) null); + Assert.That(container.TryResolve() == null); + } + + [Test] + public void Can_register_transient() + { + var container = CreateContainer(); + + container.AddTransient(() => new Test()); + + var instance = container.Resolve(typeof(Test)); + Assert.That(instance, Is.Not.Null); + Assert.That(container.Resolve(typeof(Test)), Is.Not.EqualTo(instance)); + + container.AddTransient(() => new Foo()); + var foo = container.Resolve(); + Assert.That(foo, Is.Not.Null); + Assert.That(container.Resolve(), Is.Not.EqualTo(foo)); + + container.AddTransient(() => new Foo()); + var ifoo = container.Resolve(); + Assert.That(ifoo, Is.Not.Null); + Assert.That(container.Resolve(), Is.Not.EqualTo(ifoo)); + } + + [Test] + public void Can_register_singleton() + { + var container = CreateContainer(); + + container.AddSingleton(() => new Test()); + + var instance = container.Resolve(typeof(Test)); + Assert.That(instance, Is.Not.Null); + Assert.That(container.Resolve(typeof(Test)), Is.EqualTo(instance)); + + container.AddSingleton(() => new Foo()); + var foo = container.Resolve(); + Assert.That(foo, Is.Not.Null); + Assert.That(container.Resolve(), Is.EqualTo(foo)); + + container.AddSingleton(() => new Foo()); + var ifoo = container.Resolve(); + Assert.That(ifoo, Is.Not.Null); + Assert.That(container.Resolve(), Is.EqualTo(ifoo)); + } + + [Test] + public void Can_register_Autowired_Transient() + { + var container = CreateContainer(); + + container.AddTransient(() => new Foo()); + container.AddTransient(() => new Bar()); + container.AddTransient(() => new Foo2()); + + //Should not be autowired + container.AddTransient(() => "Replaced String"); + container.AddTransient(() => 99); + + container.AddTransient(); + + var instance1 = container.Resolve(); + var instance2 = container.Resolve(); + + Assert.That(instance1, Is.Not.Null); + Assert.That(instance1.Foo, Is.Not.Null); + Assert.That(instance1.Bar, Is.Not.Null); + Assert.That(instance1.Foo2, Is.Not.Null); + Assert.That(instance1.Age, Is.EqualTo(27)); + Assert.That(instance1.Name, Is.EqualTo("foo")); + Assert.That(instance1.Names, Is.Null); //overridden + + Assert.That(instance1, Is.Not.EqualTo(instance2)); + Assert.That(instance1.Foo, Is.Not.EqualTo(instance2.Foo)); + Assert.That(instance1.Bar, Is.Not.EqualTo(instance2.Bar)); + Assert.That(instance1.Foo2, Is.Not.EqualTo(instance2.Foo2)); + } + + [Test] + public void Can_register_Autowired_Singleton() + { + var container = CreateContainer(); + + container.AddSingleton(() => new Foo()); + container.AddSingleton(() => new Bar()); + container.AddSingleton(() => new Foo2()); + + //Should not be autowired + container.AddSingleton(() => "Replaced String"); + container.AddSingleton(() => 99); + + container.AddSingleton(); + + var instance1 = container.Resolve(); + var instance2 = container.Resolve(); + + Assert.That(instance1, Is.Not.Null); + Assert.That(instance1.Foo, Is.Not.Null); + Assert.That(instance1.Bar, Is.Not.Null); + Assert.That(instance1.Foo2, Is.Not.Null); + Assert.That(instance1.Age, Is.EqualTo(27)); + Assert.That(instance1.Name, Is.EqualTo("foo")); + Assert.That(instance1.Names, Is.Null); //overridden + + Assert.That(instance1, Is.EqualTo(instance2)); + Assert.That(instance1.Foo, Is.EqualTo(instance2.Foo)); + Assert.That(instance1.Bar, Is.EqualTo(instance2.Bar)); + Assert.That(instance1.Foo2, Is.EqualTo(instance2.Foo2)); + } + + [Test] + public void Resolve_does_use_ctor_and_property_injection() + { + var container = CreateContainer(); + + container.AddTransient(() => new Foo()); + container.AddTransient(() => new Bar()); + container.AddTransient(() => new Foo2()); + + container.AddTransient(); + + var instance = container.Resolve(); + + Assert.That(instance.Foo, Is.Not.Null); + Assert.That(instance.Foo2, Is.Not.Null); + Assert.That(instance.Bar, Is.Not.Null); + } + + [Test] + public void Missing_ctor_dependency_should_throw() + { + var container = CreateContainer(); + + container.AddTransient(() => new Foo()); + container.AddTransient(() => new Bar()); + + container.AddTransient(); + + try + { + var instance = container.Resolve(); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + e.ToString().Print(); + } + + try + { + var instance = container.Resolve(typeof(TestCtor)); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + e.ToString().Print(); + } + } + + [Test] + public void Can_use_exists() + { + var container = CreateContainer(); + + container.AddTransient(() => new Foo()); + + Assert.That(container.Exists(typeof(IFoo))); + Assert.That(container.Exists()); + + Assert.That(!container.Exists(typeof(Foo))); + Assert.That(!container.Exists()); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeDisabledTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeDisabledTests.cs new file mode 100644 index 00000000000..67577a3ddb0 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeDisabledTests.cs @@ -0,0 +1,84 @@ +using System; +using System.Net; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ContentTypeDisabledTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ContentTypeDisabledTests), typeof(TestContentTypeService).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + EnableFeatures = Feature.All.Remove(Feature.Xml | Feature.Csv | Feature.Jsv | Feature.Soap), + DefaultContentType = MimeTypes.Json, + }); + } + } + + private readonly ServiceStackHost appHost; + + public ContentTypeDisabledTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Disabling_XML_ContentType_fallbacks_to_DefaultContentType() + { + var json = Config.ListeningOn.AppendPath("testcontenttype") + .GetStringFromUrl( + requestFilter: req => req.With(c => c.Accept = "text/xml,*/*"), + responseFilter: res => { + Assert.That(res.GetHeader(HttpHeaders.ContentType).MatchesContentType(MimeTypes.Json)); + }); + } + + [Test] + public void Requesting_only_disabled_ContentType_returns_Forbidden_response() + { + try + { + Config.ListeningOn.AppendPath("testcontenttype") + .GetStringFromUrl(requestFilter: req => req.With(c => c.Accept = "text/xml")); + } + catch (WebException ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(403)); + } + } + + [Test] + public void Disabling_XML_ContentType_prevents_posting_XML() + { + var client = new XmlServiceClient(Config.ListeningOn); + + try + { + client.Post(new TestContentType { Id = 1 }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(403)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(HttpStatusCode.Forbidden))); + } + } + + [Test] + public void Can_use_JSON_when_other_default_ContentTypes_are_removed() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Post(new TestContentType { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeRouteTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeRouteTests.cs new file mode 100644 index 00000000000..a7b06af2dda --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeRouteTests.cs @@ -0,0 +1,105 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.DataAnnotations; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [ExcludeMetadata] + [Route("/content/{Id}")] + public class ContentRoute + { + public int Id { get; set; } + } + + public class ContentRouteService : Service + { + public object Any(ContentRoute request) + { + return request; + } + + public object GetJson(ContentRoute request) + { + request.Id++; + return request; + } + + public object AnyHtml(ContentRoute request) + { + return $@" + + +

      AnyHtml {request.Id}

      + +"; + } + + public object GetHtml(ContentRoute request) + { + return $@" + + +

      GetHtml {request.Id}

      + +"; + } + } + + public class ContentTypeRouteTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ContentTypeRouteTests), typeof(ContentRouteService).Assembly) { } + + public override void Configure(Container container) {} + } + + private readonly ServiceStackHost appHost; + public ContentTypeRouteTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void GET_Html_Request_calls_GetHtml() + { + var html = Config.ListeningOn.CombineWith("/content/1") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(html, Does.Contain("

      GetHtml 1

      ")); + } + + [Test] + public void POST_Html_Request_calls_AnyHtml() + { + var html = Config.ListeningOn.CombineWith("/content/1") + .PostStringToUrl(accept: MimeTypes.Html, requestBody: ""); + + Assert.That(html, Does.Contain("

      AnyHtml 1

      ")); + } + + [Test] + public void GET_JSON_Request_calls_GetJson() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var response = client.Get(new ContentRoute { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1 + 1)); + } + + [Test] + public void POST_JSON_Request_calls_Any() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var response = client.Post(new ContentRoute { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeTests.cs new file mode 100644 index 00000000000..5bb928711d6 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ContentTypeTests.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/testcontenttype")] + public class TestContentType : IReturn + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class TestContentTypeService : Service + { + public object Any(TestContentType request) + { + return request; + } + } + + [TestFixture] + public class ContentTypeTests + { + private const string ListeningOn = "http://localhost:1337/"; + + ExampleAppHostHttpListener appHost; + readonly JsonServiceClient client = new(ListeningOn); + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_return_JSON() + { + var json = ListeningOn.AppendPath("testcontenttype") + .AddQueryParam("id", 1) + .GetStringFromUrl(accept: MimeTypes.Json, + responseFilter: res => + Assert.That(res.MatchesContentType(MimeTypes.Json))); + + var dto = json.FromJson(); + Assert.That(dto.Id, Is.EqualTo(1)); + } + + [Test] + public void Does_return_JSON_UpperCase() + { + var json = ListeningOn.AppendPath("testcontenttype") + .AddQueryParam("id", 1) + .GetStringFromUrl(accept: MimeTypes.Json.ToUpper(), + responseFilter: res => + Assert.That(res.MatchesContentType(MimeTypes.Json))); + + var dto = json.FromJson(); + Assert.That(dto.Id, Is.EqualTo(1)); + } + + [Test] + public void Does_return_JSON_extension() + { + var json = ListeningOn.AppendPath("testcontenttype.json") + .AddQueryParam("id", 1) + .GetStringFromUrl(responseFilter: res => + Assert.That(res.MatchesContentType(MimeTypes.Json))); + + var dto = json.FromJson(); + Assert.That(dto.Id, Is.EqualTo(1)); + } + + [Test] + public void Does_return_JSON_format() + { + var json = ListeningOn.AppendPath("testcontenttype") + .AddQueryParam("id", 1) + .AddQueryParam("format", "json") + .GetStringFromUrl(responseFilter: res => + Assert.That(res.MatchesContentType(MimeTypes.Json))); + + var dto = json.FromJson(); + Assert.That(dto.Id, Is.EqualTo(1)); + } + + [Test] + public void Can_call_JSON_Service_with_UTF8_BOM() + { + var dto = new TestContentType { Id = 1, Name = "Foo" }; + var json = dto.ToJson(); + var jsonBytes = json.ToUtf8Bytes(); + + var bytes = new List(new byte[] { 0xEF, 0xBB, 0xBF }); + bytes.AddRange(jsonBytes); + + var mergedBytes = bytes.ToArray(); + + var responseBytes = ListeningOn.AppendPath("testcontenttype") + .PostBytesToUrl(mergedBytes, contentType: MimeTypes.Json); + + var responseJson = responseBytes.FromUtf8Bytes(); + var fromJson = responseJson.FromJson(); + + Assert.That(fromJson.Id, Is.EqualTo(dto.Id)); + Assert.That(fromJson.Name, Is.EqualTo(dto.Name)); + } + + [Test] + public void Can_get_custom_json_format() + { + var json = ListeningOn.AppendPath("testcontenttype") + .AddQueryParam("format", "x-custom+json") + .GetStringFromUrl(responseFilter: res => + Assert.That(res.MatchesContentType("application/x-custom+json"))); + + Assert.That(json, Is.EqualTo("{\"custom\":\"json\"}")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeaturePluginTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeaturePluginTests.cs new file mode 100644 index 00000000000..eae8334e9bb --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeaturePluginTests.cs @@ -0,0 +1,74 @@ +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/corsplugin", "GET")] + public class CorsFeaturePlugin { } + + public class CorsFeaturePluginResponse + { + public bool IsSuccess { get; set; } + } + + public class CorsFeaturePluginService : IService + { + public object Any(CorsFeaturePlugin request) + { + return new CorsFeaturePluginResponse { IsSuccess = true }; + } + } + + [TestFixture] + public class CorsFeaturePluginTests + { + public class CorsFeaturePluginAppHostHttpListener + : AppHostHttpListenerBase + { + public CorsFeaturePluginAppHostHttpListener() + : base("Cors Feature Tests", typeof(CorsFeatureService).Assembly) { } + + public override void Configure(Funq.Container container) + { + Plugins.Add(new CorsFeature { AutoHandleOptionsRequests = true }); + } + } + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new CorsFeaturePluginAppHostHttpListener() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_Get_CORS_Headers_with_non_matching_OPTIONS_Request() + { + "{0}/corsplugin".Fmt(Config.ServiceStackBaseUri).OptionsFromUrl(responseFilter: r => + { + Assert.That(r.GetHeader(HttpHeaders.AllowOrigin), Is.EqualTo(CorsFeature.DefaultOrigin)); + Assert.That(r.GetHeader(HttpHeaders.AllowMethods), Is.EqualTo(CorsFeature.DefaultMethods)); + Assert.That(r.GetHeader(HttpHeaders.AllowHeaders), Is.EqualTo(CorsFeature.DefaultHeaders)); + }); + } + + [Test] + public void Can_Get_CORS_Headers_with_not_found_OPTIONS_Request() + { + "{0}/notfound".Fmt(Config.ServiceStackBaseUri).OptionsFromUrl(responseFilter: r => + { + Assert.That(r.GetHeader(HttpHeaders.AllowOrigin), Is.EqualTo(CorsFeature.DefaultOrigin)); + Assert.That(r.GetHeader(HttpHeaders.AllowMethods), Is.EqualTo(CorsFeature.DefaultMethods)); + Assert.That(r.GetHeader(HttpHeaders.AllowHeaders), Is.EqualTo(CorsFeature.DefaultHeaders)); + }); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeatureTest.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeatureTest.cs index e99943b6f03..45d8fa176ef 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeatureTest.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CorsFeatureTest.cs @@ -1,36 +1,21 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Service; -using ServiceStack.ServiceInterface; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.ServiceInterface.Cors; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Utils; namespace ServiceStack.WebHost.Endpoints.Tests { [Route("/corsmethod")] - public class CorsFeatureRequest - { - } + [EnableCors("http://localhost http://localhost2", "POST, GET", "Type1, Type2", true)] + public class CorsFeatureRequest { } - [CorsSupport("http://localhost http://localhost2", "POST, GET", "Type1, Type2", true)] public class CorsFeatureResponse { public bool IsSuccess { get; set; } } - public class CorsFeatureService : IService + public class CorsFeatureService : IService { - public object Execute(CorsFeatureRequest request) + public object Any(CorsFeatureRequest request) { return new CorsFeatureResponse { IsSuccess = true }; } @@ -46,9 +31,9 @@ public class GlobalCorsFeatureResponse public bool IsSuccess { get; set; } } - public class GlobalCorsFeatureService : IService + public class GlobalCorsFeatureService : IService { - public object Execute(GlobalCorsFeatureRequest request) + public object Any(GlobalCorsFeatureRequest request) { return new GlobalCorsFeatureResponse { IsSuccess = true }; } @@ -57,32 +42,26 @@ public object Execute(GlobalCorsFeatureRequest request) [TestFixture] public class CorsFeatureServiceTest { - private const string ListeningOn = "http://localhost:8022/"; - private const string ServiceClientBaseUri = "http://localhost:8022/"; - public class CorsFeatureAppHostHttpListener : AppHostHttpListenerBase { - public CorsFeatureAppHostHttpListener() : base("Cors Feature Tests", typeof(CorsFeatureService).Assembly) { } - public override void Configure(Funq.Container container) - { - } + public override void Configure(Funq.Container container) {} } - CorsFeatureAppHostHttpListener appHost; + ServiceStackHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { - appHost = new CorsFeatureAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); + appHost = new CorsFeatureAppHostHttpListener() + .Init() + .Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); @@ -90,12 +69,12 @@ public void OnTestFixtureTearDown() static IRestClient[] RestClients = { - new JsonServiceClient(ServiceClientBaseUri), - new XmlServiceClient(ServiceClientBaseUri), - new JsvServiceClient(ServiceClientBaseUri) + new JsonServiceClient(Config.AbsoluteBaseUri), + new XmlServiceClient(Config.AbsoluteBaseUri), + new JsvServiceClient(Config.AbsoluteBaseUri) }; - [Test, Explicit] + [Ignore("Debug Only")] public void RunFor5Mins() { Thread.Sleep(TimeSpan.FromMinutes(5)); @@ -106,24 +85,23 @@ public void CorsMethodHasAccessControlHeaders(IRestClient client) { appHost.Config.GlobalResponseHeaders.Clear(); - var response = RequestContextTests.GetResponseHeaders(ListeningOn + "/corsmethod"); + var response = RequestContextTests.GetResponseHeaders(Config.ServiceStackBaseUri + "/corsmethod"); Assert.That(response[HttpHeaders.AllowOrigin], Is.EqualTo("http://localhost http://localhost2")); Assert.That(response[HttpHeaders.AllowMethods], Is.EqualTo("POST, GET")); Assert.That(response[HttpHeaders.AllowHeaders], Is.EqualTo("Type1, Type2")); Assert.That(response[HttpHeaders.AllowCredentials], Is.EqualTo("true")); } - [Test, TestCaseSource("RestClients")] - public void GlobalCorsHasAccessControlHeaders(IRestClient client) + [Test] + public void GlobalCorsHasAccessControlHeaders() { - appHost.LoadPlugin(new CorsFeature()); + appHost.LoadPlugin(new CorsFeature { AutoHandleOptionsRequests = false }); - var response = RequestContextTests.GetResponseHeaders(ListeningOn + "/globalcorsfeature"); - Assert.That(response[HttpHeaders.AllowOrigin], Is.EqualTo("*")); - Assert.That(response[HttpHeaders.AllowMethods], Is.EqualTo("GET, POST, PUT, DELETE, OPTIONS")); + var response = RequestContextTests.GetResponseHeaders(Config.ServiceStackBaseUri + "/globalcorsfeature"); + Assert.That(response[HttpHeaders.AllowOrigin], Is.EqualTo(CorsFeature.DefaultOrigin)); + Assert.That(response[HttpHeaders.AllowMethods], Is.EqualTo(CorsFeature.DefaultMethods)); Assert.False(response.ContainsKey(HttpHeaders.AllowCredentials)); - Assert.That(response[HttpHeaders.AllowHeaders], Is.EqualTo("Content-Type")); + Assert.That(response[HttpHeaders.AllowHeaders], Is.EqualTo(CorsFeature.DefaultHeaders)); } - } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs index 36bd319540a..38eda422bb0 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CsvContentTypeFilterTests.cs @@ -3,171 +3,162 @@ using System.Linq; using System.Net; using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; +using ServiceStack.Common; using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class CsvContentTypeFilterTests - { - const int HeaderRowCount = 1; - private const string ListeningOn = "http://localhost:1182/"; - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - [Test] - [Explicit("Helps debugging when you need to find out WTF is going on")] - public void Run_for_30secs() - { - Thread.Sleep(30000); - } - - private static void FailOnAsyncError(T response, Exception ex) - { - Assert.Fail(ex.Message); - } - - [Test] - public void Can_Serialize_Movies_Dto() - { - var csv = CsvSerializer.SerializeToString(ResetMoviesService.Top5Movies); - var csvRows = csv.Split('\n').Where(x => !x.IsNullOrEmpty()).ToArray(); - Assert.That(csvRows.Length, Is.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); - } - - [Test] - public void Can_Serialize_MovieResponse_Dto() - { - var request = new MovieResponse { Movie = ResetMoviesService.Top5Movies[0] }; - var csv = CsvSerializer.SerializeToString(request); - var csvRows = csv.Split('\n').Where(x => !x.IsNullOrEmpty()).ToArray(); - Assert.That(csvRows.Length, Is.EqualTo(HeaderRowCount + 1)); - } - - [Test] - public void Can_Serialize_MoviesResponse_Dto() - { - var request = new MoviesResponse { Movies = ResetMoviesService.Top5Movies }; - var csv = CsvSerializer.SerializeToString(request); - var csvRows = csv.Split('\n').Where(x => !x.IsNullOrEmpty()).ToArray(); - Assert.That(csvRows.Length, Is.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); - } - - [Test][Ignore("Fails because CSV Deserializer is not implemented")] - public void Can_download_movies_in_Csv() - { - var asyncClient = new AsyncServiceClient - { - ContentType = ContentType.Csv, - StreamSerializer = (r,o,s) => CsvSerializer.SerializeToStream(o,s), - StreamDeserializer = CsvSerializer.DeserializeFromStream, - }; - - MoviesResponse response = null; - asyncClient.SendAsync(HttpMethods.Get, ListeningOn + "movies", null, - r => response = r, FailOnAsyncError); - - Thread.Sleep(1000); - - Assert.That(response, Is.Not.Null, "No response received"); - } - - [Test] - public void Can_download_CSV_movies_using_csv_syncreply_endpoint() - { - var req = (HttpWebRequest)WebRequest.Create(ListeningOn + "csv/syncreply/Movies"); - - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Console.WriteLine(res.Headers); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); - - var csvRows = new StreamReader(res.GetResponseStream()).ReadLines().ToList(); - - const int headerRowCount = 1; - Assert.That(csvRows, Has.Count.EqualTo(headerRowCount + ResetMoviesService.Top5Movies.Count)); - //Console.WriteLine(csvRows.Join("\n")); - } - - [Test] - public void Can_download_CSV_movies_using_csv_Accept_and_RestPath() - { - var req = (HttpWebRequest)WebRequest.Create(ListeningOn + "movies"); - req.Accept = ContentType.Csv; - - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); - - var csvRows = new StreamReader(res.GetResponseStream()).ReadLines().ToList(); - - Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); - //Console.WriteLine(csvRows.Join("\n")); - } - - [Test] - public void Can_download_CSV_Hello_using_csv_syncreply_endpoint() - { - var req = (HttpWebRequest)WebRequest.Create(ListeningOn + "csv/syncreply/Hello?Name=World!"); - - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Hello.csv")); - - var csv = new StreamReader(res.GetResponseStream()).ReadToEnd(); - Assert.That(csv, Is.EqualTo("Result\r\n\"Hello, World!\"\r\n")); - - Console.WriteLine(csv); - } - - [Test] - public void Can_download_CSV_Hello_using_csv_Accept_and_RestPath() - { - var req = (HttpWebRequest)WebRequest.Create(ListeningOn + "hello/World!"); - req.Accept = ContentType.Csv; - - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Hello.csv")); - - var csv = new StreamReader(res.GetResponseStream()).ReadToEnd(); - Assert.That(csv, Is.EqualTo("Result\r\n\"Hello, World!\"\r\n")); - - Console.WriteLine(csv); - } - - [Test] - public void Can_download_CSV_movies_using_csv_SyncReply_Path() - { - var req = (HttpWebRequest)WebRequest.Create(ListeningOn + "csv/syncreply/Movies"); - req.Accept = "application/xml"; - - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); - - var csvRows = new StreamReader(res.GetResponseStream()).ReadLines().ToList(); - - Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); - } - } -} \ No newline at end of file + [TestFixture] + public class CsvContentTypeFilterTests + { + const int HeaderRowCount = 1; + private const string ListeningOn = "http://localhost:1182/"; + + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + [Ignore("Helps debugging when you need to find out WTF is going on")] + public void Run_for_30secs() + { + Thread.Sleep(30000); + } + + private static void FailOnAsyncError(T response, Exception ex) + { + Assert.Fail(ex.Message); + } + + [Test] + public void Can_Serialize_Movies_Dto() + { + var csv = CsvSerializer.SerializeToString(ResetMoviesService.Top5Movies); + var csvRows = csv.Split('\n').Where(x => !x.IsNullOrEmpty()).ToArray(); + Assert.That(csvRows.Length, Is.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); + } + + [Test] + public void Can_Serialize_MovieResponse_Dto() + { + var request = new MovieResponse { Movie = ResetMoviesService.Top5Movies[0] }; + var csv = CsvSerializer.SerializeToString(request); + var csvRows = csv.Split('\n').Where(x => !x.IsNullOrEmpty()).ToArray(); + Assert.That(csvRows.Length, Is.EqualTo(HeaderRowCount + 1)); + } + + [Test] + public void Can_Serialize_MoviesResponse_Dto() + { + var request = new MoviesResponse { Movies = ResetMoviesService.Top5Movies }; + var csv = CsvSerializer.SerializeToString(request); + var csvRows = csv.Split('\n').Where(x => !x.IsNullOrEmpty()).ToArray(); + Assert.That(csvRows.Length, Is.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); + } + + [Test] + public async Task Can_download_movies_in_Csv() + { + var client = new CsvServiceClient(ListeningOn); + + var response = await client.GetAsync(new Movies()); + + Assert.That(response, Is.Not.Null, "No response received"); + } + + [Test] + public void Can_download_CSV_movies_using_csv_reply_endpoint() + { + var req = WebRequest.CreateHttp(ListeningOn + "csv/reply/Movies"); + + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Console.WriteLine(res.Headers); + Assert.That(res.Headers[HttpHeaders.ContentDisposition].Replace("; ", ";"), Is.EqualTo("attachment;filename=\"Movies.csv\"")); + + var csvRows = res.ReadLines().ToList(); + + const int headerRowCount = 1; + Assert.That(csvRows, Has.Count.EqualTo(headerRowCount + ResetMoviesService.Top5Movies.Count)); + //Console.WriteLine(csvRows.Join("\n")); + } + + [Test] + public void Can_download_CSV_movies_using_csv_Accept_and_RestPath() + { + var req = WebRequest.CreateHttp(ListeningOn + "all-movies"); + req.Accept = MimeTypes.Csv; + + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition].Replace("; ", ";"), Is.EqualTo("attachment;filename=\"Movies.csv\"")); + + var csvRows = res.ReadLines().ToList(); + + Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); + //Console.WriteLine(csvRows.Join("\n")); + } + + [Test] + public void Can_download_CSV_Hello_using_csv_reply_endpoint() + { + var req = WebRequest.CreateHttp(ListeningOn + "csv/reply/Hello?Name=World!"); + + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition].Replace("; ", ";"), Is.EqualTo("attachment;filename=\"Hello.csv\"")); + + var csv = res.ReadToEnd(); + Assert.That(csv, Is.EqualTo("Result\r\n\"Hello, World!\"\r\n")); + + Console.WriteLine(csv); + } + + [Test] + public void Can_download_CSV_Hello_using_csv_Accept_and_RestPath() + { + var req = WebRequest.CreateHttp(ListeningOn + "hello/World!"); + req.Accept = MimeTypes.Csv; + + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition].Replace("; ", ";"), Is.EqualTo("attachment;filename=\"Hello.csv\"")); + + var csv = res.ReadToEnd(); + Assert.That(csv, Is.EqualTo("Result\r\n\"Hello, World!\"\r\n")); + + Console.WriteLine(csv); + } + + [Test] + public void Can_download_CSV_movies_using_csv_reply_Path() + { + var req = WebRequest.CreateHttp(ListeningOn + "csv/reply/Movies"); + req.Accept = "application/xml"; + + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition].Replace("; ", ";"), Is.EqualTo("attachment;filename=\"Movies.csv\"")); + + var csvRows = res.ReadLines().ToList(); + + Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CsvServiceClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CsvServiceClientTests.cs new file mode 100644 index 00000000000..85db0a522c4 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CsvServiceClientTests.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public partial class CsvItem : IReturn + { + public int Id { get; set; } + public string Name { get; set; } + public List Ints { get; set; } + public List Strings { get; set; } + public List CsvPocos { get; set; } + public Dictionary CsvPocoMap { get; set; } + } + + public partial class CsvPoco + { + public int Id { get; set; } + public string Name { get; set; } + } + + + [Route("/csvlist")] + public class CsvList : List, IReturn + { + public CsvList() {} + public CsvList(IEnumerable collection) : base(collection) {} + } + + [Route("/csvfirst")] + [Csv(CsvBehavior.FirstEnumerable)] + public class CsvFirstEnumerable : IReturn + { + public int Id { get; set; } + public string Name { get; set; } + public List Items { get; set; } + } + + [Route("/csvdto")] + [DataContract] + public class CsvDtoEnumerable : IReturn + { + [DataMember] + public int Id { get; set; } + + [DataMember] + public string Name { get; set; } + + [DataMember] + public List Items { get; set; } + } + + public class CsvServices : Service + { + public object Any(CsvItem request) + { + return request; + } + + public object Any(CsvList request) + { + return request; + } + + public object Any(CsvFirstEnumerable request) + { + return request; + } + + public object Any(CsvDtoEnumerable request) + { + return request; + } + } + + [TestFixture] + public class CsvServiceClientTests + { + private readonly ServiceStackHost appHost; + class AppHost : AppSelfHostBase + { + public AppHost() : base(typeof(CsvServiceClientTests).Name, typeof(CsvServices).Assembly) {} + + public override void Configure(Container container) {} + } + + public CsvServiceClientTests() + { + appHost = new AppHost().Init().Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + CsvItem CreateCsvItem(int i) + { + return new CsvItem + { + Id = i, + Name = "Name" + i, + Ints = i.Times(x => x), + Strings = i.Times(x => "Name" + x), + CsvPocos = new List + { + new CsvPoco { Id = 10 + i, Name = "CsvPoco" + i }, + }, + CsvPocoMap = new Dictionary + { + { "Key" + i, new CsvPoco { Id = 10 + i, Name = "CsvPoco" + i } } + } + }; + } + + [Test] + public void Can_SendAll_CsvItem() + { + var client = new CsvServiceClient(Config.ListeningOn); + + var dtos = 3.Times(x => CreateCsvItem(x)); + + var response = client.SendAll(dtos); + Assert.That(response, Is.EquivalentTo(dtos)); + + response = Config.ListeningOn.CombineWith("csv/reply/CsvItem[]") + .PostCsvToUrl(dtos) + .FromCsv>(); + Assert.That(response, Is.EquivalentTo(dtos)); + } + + [Test] + public void Can_POST_CsvList() + { + var client = new CsvServiceClient(Config.ListeningOn); + + var dtos = 3.Times(x => CreateCsvItem(x)); + + var response = client.Post(new CsvList(dtos)); + Assert.That(response, Is.EquivalentTo(dtos)); + + response = Config.ListeningOn.CombineWith("csvlist") + .PostCsvToUrl(dtos) + .FromCsv(); + Assert.That(response, Is.EquivalentTo(dtos)); + + var csv = dtos.ToCsv(); + response = Config.ListeningOn.CombineWith("csvlist") + .PostCsvToUrl(csv) + .FromCsv(); + Assert.That(response, Is.EquivalentTo(dtos)); + } + + [Test] + public void Can_POST_CsvFirstEnumerable() + { + var client = new CsvServiceClient(Config.ListeningOn); + + var dto = new CsvFirstEnumerable + { + Id = 1, + Name = "Name", + Items = 3.Times(x => CreateCsvItem(x)) + }; + + var response = client.Post(dto); + Assert.That(response.Id, Is.EqualTo(0)); + Assert.That(response.Name, Is.Null); + Assert.That(response.Items, Is.EquivalentTo(dto.Items)); + + response = Config.ListeningOn.CombineWith("csvfirst") + .PostCsvToUrl(dto) + .FromCsv(); + Assert.That(response.Id, Is.EqualTo(0)); + Assert.That(response.Name, Is.Null); + Assert.That(response.Items, Is.EquivalentTo(dto.Items)); + } + + [Test] + public void Can_POST_CsvDto() + { + var client = new CsvServiceClient(Config.ListeningOn); + + var dto = new CsvDtoEnumerable + { + Id = 1, + Name = "Name", + Items = 3.Times(x => CreateCsvItem(x)) + }; + + var response = client.Post(dto); + Assert.That(response.Id, Is.EqualTo(0)); + Assert.That(response.Name, Is.Null); + Assert.That(response.Items, Is.EquivalentTo(dto.Items)); + + response = Config.ListeningOn.CombineWith("csvdto") + .PostCsvToUrl(dto) + .FromCsv(); + Assert.That(response.Id, Is.EqualTo(0)); + Assert.That(response.Name, Is.Null); + Assert.That(response.Items, Is.EquivalentTo(dto.Items)); + } + } + + public partial class CsvItem : IEquatable + { + public bool Equals(CsvItem other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id == other.Id + && string.Equals(Name, other.Name) + && Ints.EquivalentTo(other.Ints) + && Strings.EquivalentTo(other.Strings) + && CsvPocos.EquivalentTo(other.CsvPocos) + && CsvPocoMap.EquivalentTo(other.CsvPocoMap); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((CsvItem)obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Id; + hashCode = (hashCode * 397) ^ (Name != null ? Name.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (Ints != null ? Ints.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (Strings != null ? Strings.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (CsvPocos != null ? CsvPocos.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (CsvPocoMap != null ? CsvPocoMap.GetHashCode() : 0); + return hashCode; + } + } + } + + public partial class CsvPoco : IEquatable + { + public bool Equals(CsvPoco other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id == other.Id && string.Equals(Name, other.Name); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((CsvPoco)obj); + } + + public override int GetHashCode() + { + unchecked + { + return (Id * 397) ^ (Name != null ? Name.GetHashCode() : 0); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomFormatTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomFormatTests.cs new file mode 100644 index 00000000000..a755b1a1a0f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomFormatTests.cs @@ -0,0 +1,73 @@ +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/hellojson/{Name}")] + public class HelloJson + { + public string Name { get; set; } + } + + public class HelloJsonResponse + { + public string Name { get; set; } + } + + public class Services : Service + { + public object Any(HelloJson request) + { + return new HelloJsonResponse + { + Name = "Hello, {0}!".Fmt(request.Name ?? "World") + }; + } + } + + public class CustomFormatTests + { + public class AppHost : AppHostHttpListenerBase + { + public AppHost() + : base(typeof(CustomFormatTests).Name, typeof(CustomFormatTests).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DefaultContentType = MimeTypes.Json, + EnableFeatures = Feature.All.Remove(Feature.Html) + }); + } + } + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_get_service_with_default_content_type() + { + var json = Config.AbsoluteBaseUri.CombineWith("hellojson", "World") + .GetStringFromUrl(accept: "text/html,*/*;q=0.9"); + + Assert.That(json, Is.EqualTo("{\"Name\":\"Hello, World!\"}") + .Or.EqualTo("{\"name\":\"Hello, World!\"}")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomHttpMethodTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomHttpMethodTests.cs new file mode 100644 index 00000000000..b103fa5a1b4 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomHttpMethodTests.cs @@ -0,0 +1,97 @@ +using System.Reflection; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/custom-method/result")] + public class CustomMethodResult : IReturn + { + public int Id { get; set; } + } + + [Route("/custom-method/headers")] + public class CustomMethodHeaders : IReturn + { + public int Id { get; set; } + } + + public class CustomMethodService : Service + { + public object Head(CustomMethodResult request) + { + return new HttpResult { + Headers = { + {"X-Method", "HEAD"}, + {"X-Id", request.Id.ToString()}, + {"Content-Length", "100"}, + {"Content-Type", "video/mp4"}, + } + }; + } + + public object Any(CustomMethodResult request) => request; + + public void Head(CustomMethodHeaders request) + { + Response.AddHeader("X-Method", "HEAD"); + Response.AddHeader("X-Id", request.Id.ToString()); + Response.AddHeader("Content-Type", "video/mp4"); + Response.SetContentLength(100); + } + + public object Any(CustomMethodHeaders request) => request; + } + + public class CustomHttpMethodTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(CustomHttpMethodTests), typeof(CustomMethodService).Assembly) { } + + public override void Configure(Container container) { } + } + + private ServiceStackHost appHost; + + public CustomHttpMethodTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_execute_HEAD_Request_returning_custom_HttpResult() + { + var response = Config.ListeningOn.AppendPath("custom-method","result").AddQueryParam("id", 1) + .SendStringToUrl(method: "HEAD", + responseFilter: res => { + Assert.That(res.GetHeader("X-Method"), Is.EqualTo("HEAD")); + Assert.That(res.GetHeader("X-Id"), Is.EqualTo("1")); + Assert.That(res.MatchesContentType("video/mp4")); + Assert.That(res.GetContentLength(), Is.EqualTo(100)); + }); + + Assert.That(response, Is.Empty); + } + + [Test] + public void Does_execute_HEAD_Request_writing_custom_headers() + { + var response = Config.ListeningOn.AppendPath("custom-method","headers").AddQueryParam("id", 1) + .SendStringToUrl(method: "HEAD", + responseFilter: res => { + Assert.That(res.GetHeader("X-Method"), Is.EqualTo("HEAD")); + Assert.That(res.GetHeader("X-Id"), Is.EqualTo("1")); + Assert.That(res.MatchesContentType("video/mp4")); + Assert.That(res.GetContentLength(), Is.EqualTo(100)); + }); + + Assert.That(response, Is.Empty); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomOrmLiteAuthRepositoryTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomOrmLiteAuthRepositoryTests.cs new file mode 100644 index 00000000000..47c2a2f7c66 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomOrmLiteAuthRepositoryTests.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.FluentValidation; +using ServiceStack.OrmLite; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class CustomUserAuth : IUserAuth + { + [AutoIncrement] + public int Id { get; set; } + public string UserName { get; set; } + public string DisplayName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Company { get; set; } + public string Email { get; set; } + public string PhoneNumber { get; set; } + public DateTime? BirthDate { get; set; } + public string BirthDateRaw { get; set; } + public string Address { get; set; } + public string Address2 { get; set; } + public string City { get; set; } + public string State { get; set; } + public string Country { get; set; } + public string Culture { get; set; } + public string FullName { get; set; } + public string Gender { get; set; } + public string Language { get; set; } + public string MailAddress { get; set; } + public string Nickname { get; set; } + public string PostalCode { get; set; } + public string TimeZone { get; set; } + public Dictionary Meta { get; set; } + public string PrimaryEmail { get; set; } + public string Salt { get; set; } + public string PasswordHash { get; set; } + public string DigestHa1Hash { get; set; } + public List Roles { get; set; } + public List Permissions { get; set; } + public int? RefId { get; set; } + public string RefIdStr { get; set; } + public int InvalidLoginAttempts { get; set; } + public DateTime? LastLoginAttempt { get; set; } + public DateTime? LockedDate { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } + } + + public class CustomUserAuthDetails : IUserAuthDetails + { + public string UserName { get; set; } + public string DisplayName { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Company { get; set; } + public string Email { get; set; } + public string PhoneNumber { get; set; } + public DateTime? BirthDate { get; set; } + public string BirthDateRaw { get; set; } + public string Address { get; set; } + public string Address2 { get; set; } + public string City { get; set; } + public string State { get; set; } + public string Country { get; set; } + public string Culture { get; set; } + public string FullName { get; set; } + public string Gender { get; set; } + public string Language { get; set; } + public string MailAddress { get; set; } + public string Nickname { get; set; } + public string PostalCode { get; set; } + public string TimeZone { get; set; } + public string Provider { get; set; } + public string UserId { get; set; } + public string AccessToken { get; set; } + public string AccessTokenSecret { get; set; } + public string RefreshToken { get; set; } + public DateTime? RefreshTokenExpiry { get; set; } + public string RequestToken { get; set; } + public string RequestTokenSecret { get; set; } + public Dictionary Items { get; set; } + public Dictionary Meta { get; set; } + public int Id { get; set; } + public int UserAuthId { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime ModifiedDate { get; set; } + public int? RefId { get; set; } + public string RefIdStr { get; set; } + } + + [DataContract] + public class CustomAuthUserSession : AuthUserSession + { + [DataMember] + public string CustomField { get; set; } + } + + public class CustomOrmLiteAuthRepositoryTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(CustomOrmLiteAuthRepositoryTests), typeof(CustomOrmLiteAuthRepositoryTests).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DebugMode = true, + }); + + Plugins.Add(new AuthFeature(() => new CustomAuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(AppSettings), + }) { + IncludeRegistrationService = true + }); + + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + + container.Resolve().InitSchema(); + + container.RegisterAs>(); + + var authRepo = container.Resolve(); + var userAuth = authRepo.CreateUserAuth(new CustomUserAuth + { + UserName = "admin", + Email = "admin@if.com", + DisplayName = "Admin User", + FirstName = "Admin", + LastName = "User", + Roles = new List { RoleNames.Admin } + }, "p@55w0rd"); + + userAuth = authRepo.GetUserAuth(userAuth.Id.ToString()); + Assert.That(userAuth, Is.Not.Null); + Assert.That(userAuth.UserName, Is.EqualTo("admin")); + } + } + + private readonly ServiceStackHost appHost; + + public CustomOrmLiteAuthRepositoryTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_register_user_using_Custom_UserAuth_and_UserAuthDetails() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var response = client.Post(new Register + { + UserName = "user", + Password = "pass", + Email = "as@if.com", + DisplayName = "DisplayName", + FirstName = "FirstName", + LastName = "LastName", + }); + + Assert.That(response.UserId, Is.Not.Null); + } + + [Test] + public void Can_assign_roles_to_Custom_UserAuth() + { + var client = new JsonServiceClient(Config.ListeningOn); + + client.Post(new Register + { + UserName = "user2", + Password = "pass2", + Email = "as2@if.com", + DisplayName = "DisplayName2", + FirstName = "FirstName2", + LastName = "LastName2", + }); + + client.Post(new Authenticate + { + provider = "credentials", + UserName = "admin", + Password = "p@55w0rd", + RememberMe = true + }); + + var response = client.Post(new AssignRoles + { + UserName = "user2", + Roles = new List { "role1", "role2" }, + Permissions = new List { "perm1", "perm2" }, + }); + + Assert.That(response.AllRoles, Is.EquivalentTo(new[] { "role1", "role2" })); + Assert.That(response.AllPermissions, Is.EquivalentTo(new[] { "perm1", "perm2" })); + + var currentRoles = client.Post(new UnAssignRoles + { + UserName = "user2", + Roles = new List { "role1" }, + Permissions = new List { "perm2" }, + }); + + Assert.That(currentRoles.AllRoles, Is.EquivalentTo(new[] { "role2" })); + Assert.That(currentRoles.AllPermissions, Is.EquivalentTo(new[] { "perm1" })); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRegisterServiceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRegisterServiceTests.cs new file mode 100644 index 00000000000..d00299d7780 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRegisterServiceTests.cs @@ -0,0 +1,158 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.FluentValidation; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class RegisterUser : Register + { + public string NetworkName { get; set; } + } + + public class MyUser : UserAuth + { + public string NetworkName { get; set; } + } + + public class RegisterUserService : RegisterUserAuthServiceBase + { + public async Task PostAsync(RegisterUser request) + { + if (string.IsNullOrEmpty(request.NetworkName)) + throw new ArgumentNullException(nameof(request.NetworkName)); + + var session = await GetSessionAsync(); + if (await UserExistsAsync(session)) + throw new NotSupportedException("You're already registered"); + + var newUser = (MyUser)ToUser(request); + newUser.NetworkName = request.NetworkName; + + await ValidateAndThrowAsync(request); + var user = await AuthRepositoryAsync.CreateUserAuthAsync(newUser, request.Password); + await RegisterNewUserAsync(session, user); + + var response = await CreateRegisterResponse(session, + request.UserName ?? request.Email, request.Password, request.AutoLogin); + return response; + } + } + + public class CustomRegisterServiceTests + { + private ServiceStackHost appHost; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(CustomRegisterServiceTests), typeof(RegisterUserService).Assembly) { } + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider) { + AutoDisposeConnection = false, + }); + + container.Register(c => + new OrmLiteAuthRepository(c.Resolve())); + container.Resolve().InitSchema(); + + Plugins.Add(new AuthFeature(new CredentialsAuthProvider(AppSettings))); + // Plugins.Add(new ValidationFeature()); + } + } + + [OneTimeSetUp] + public void TestFixtureSetUp() => appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + const string Password = "p@55wOrd"; + + [Test] + public void Can_register_Custom_User_and_Register_Service() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Send(new RegisterUser { + Email = "user@gmail.com", + DisplayName = "Test User", + FirstName = "Test", + LastName = "User", + NetworkName = nameof(RegisterUser), + Password = Password, + ConfirmPassword = Password, + }); + + var authRepo = appHost.TryResolve(); + var newUser = (MyUser)authRepo.GetUserAuth(response.UserId); + + Assert.That(newUser.Email, Is.EqualTo("user@gmail.com")); + Assert.That(newUser.NetworkName, Is.EqualTo(nameof(RegisterUser))); + + var authResponse = client.Send(new Authenticate { + provider = "credentials", + UserName = newUser.Email, + Password = Password, + RememberMe = true, + }); + Assert.That(authResponse.DisplayName, Is.EqualTo("Test User")); + } + + [Test] + public void Does_apply_custom_validation() + { + var client = new JsonServiceClient(Config.ListeningOn); + try + { + var response = client.Send(new RegisterUser { + Email = "user@gmail.com", + DisplayName = "Test User", + FirstName = "Test", + LastName = "User", + Password = Password, + ConfirmPassword = Password, + }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.GetResponseStatus(); + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ArgumentNullException))); + Assert.That(status.Message, Does.StartWith("Value cannot be null.")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo(nameof(MyUser.NetworkName))); + } + } + + [Test] + public void Does_apply_existing_Register_validation() + { + var client = new JsonServiceClient(Config.ListeningOn); + try + { + var response = client.Send(new RegisterUser { + NetworkName = nameof(RegisterUser), + }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.GetResponseStatus(); + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ValidationException))); + Assert.That(status.Errors.First(x => x.FieldName == nameof(Register.Password)).ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors.First(x => x.FieldName == nameof(Register.UserName)).ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors.First(x => x.FieldName == nameof(Register.Email)).ErrorCode, Is.EqualTo("NotEmpty")); + } + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRequestDataTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRequestDataTests.cs index 20220664662..549dad51c3c 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRequestDataTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomRequestDataTests.cs @@ -4,9 +4,8 @@ using System.Web; using NUnit.Framework; using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; @@ -15,14 +14,14 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class CustomRequestDataTests { - private const string ListeningOn = "http://localhost:82/"; + private const string ListeningOn = "http://localhost:1337/"; ExampleAppHostHttpListener appHost; readonly JsonServiceClient client = new JsonServiceClient(ListeningOn); private string customUrl = ListeningOn.CombineWith("customrequestbinder"); - private string predefinedUrl = ListeningOn.CombineWith("json/syncreply/customrequestbinder"); + private string predefinedUrl = ListeningOn.CombineWith("json/reply/customrequestbinder"); - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { appHost = new ExampleAppHostHttpListener(); @@ -30,7 +29,7 @@ public void OnTestFixtureSetUp() appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); @@ -42,24 +41,29 @@ public void OnTestFixtureTearDown() [Test] public void Can_parse_custom_form_data() { - var webReq = (HttpWebRequest)WebRequest.Create("http://localhost:82/customformdata?format=json"); + var webReq = WebRequest.CreateHttp("http://localhost:1337/customformdata?format=json"); webReq.Method = HttpMethods.Post; - webReq.ContentType = ContentType.FormUrlEncoded; + webReq.ContentType = MimeTypes.FormUrlEncoded; try { - using (var sw = new StreamWriter(webReq.GetRequestStream())) + using (var sw = new StreamWriter(PclExport.Instance.GetRequestStream(webReq))) { - sw.Write("&first-name=tom&item-0=blah&item-1-delete=1"); +#if !NETCORE + sw.Write("&"); +#endif + sw.Write("first-name=tom&item-0=blah&item-1-delete=1"); } - var response = new StreamReader(webReq.GetResponse().GetResponseStream()).ReadToEnd(); + var response = webReq.GetResponse().GetResponseStream().ReadToEnd(); - Assert.That(response, Is.EqualTo("{\"FirstName\":\"tom\",\"Item0\":\"blah\",\"Item1Delete\":\"1\"}")); + Assert.That(response, Is.EqualTo("{\"FirstName\":\"tom\",\"Item0\":\"blah\",\"Item1Delete\":\"1\"}") + .Or.EqualTo("{\"firstName\":\"tom\",\"item0\":\"blah\",\"item1Delete\":\"1\"}") + ); } catch (WebException webEx) { var errorWebResponse = ((HttpWebResponse)webEx.Response); - var errorResponse = new StreamReader(errorWebResponse.GetResponseStream()).ReadToEnd(); + var errorResponse = errorWebResponse.GetResponseStream().ReadToEnd(); Assert.Fail(errorResponse); } @@ -101,14 +105,14 @@ public void Does_use_request_binder_for_Send() [Test] public void Does_use_request_binder_for_POST() { - var response = client.Post("/customrequestbinder", new CustomRequestBinder()); + var response = client.Post("/customrequestbinder", new CustomRequestBinder()); Assert.That(response.FromBinder); } [Test] public void Does_use_request_binder_for_POST_FormData() { - var responseStr = customUrl.PostToUrl("IsFromBinder=false", acceptContentType:ContentType.Json); + var responseStr = customUrl.PostToUrl("IsFromBinder=false", accept: MimeTypes.Json); Console.WriteLine(responseStr); var response = responseStr.FromJson(); Assert.That(response.FromBinder); @@ -127,7 +131,7 @@ public void Does_use_request_binder_for_POST_FormData_without_ContentType() public void Does_use_request_binder_for_POST_FormData_without_ContentType_with_QueryString() { string customUrlWithQueryString = customUrl + "?IsFromBinder=false"; - var responseStr = customUrlWithQueryString.PostToUrl("k=v", acceptContentType: ContentType.Json); + var responseStr = customUrlWithQueryString.PostToUrl("k=v", accept: MimeTypes.Json); var response = responseStr.FromJson(); Assert.That(response.FromBinder); } @@ -144,16 +148,19 @@ public void Does_use_request_binder_for_predefined_POST() [Test] public void Does_use_request_binder_for_predefined_POST_FormData() { - var responseStr = predefinedUrl.PostToUrl("k=v", acceptContentType: ContentType.Json); + var responseStr = predefinedUrl.PostToUrl("k=v", accept: MimeTypes.Json); Console.WriteLine(responseStr); var response = responseStr.FromJson(); Assert.That(response.FromBinder); } [Test] +#if NETCORE + [Ignore("HttpClient does not support `Expect: 100-Continue`. Should be fixed in .NET Core 1.1")] +#endif public void Does_use_request_binder_for_PUT() { - var response = client.Put("/customrequestbinder", new CustomRequestBinder()); + var response = client.Put("/customrequestbinder", new CustomRequestBinder()); Assert.That(response.FromBinder); } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomServiceRunnerTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomServiceRunnerTests.cs new file mode 100644 index 00000000000..cb0d2502b86 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomServiceRunnerTests.cs @@ -0,0 +1,89 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class CustomServiceRunnerTests + { + string ListeningOn = Config.AbsoluteBaseUri; + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new CustomServiceRunnerAppHost() + .Init() + .Start(ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public class CustomServiceRunnerAppHost : AppHostHttpListenerBase + { + public CustomServiceRunnerAppHost() + : base("CustomServiceRunner", typeof(CustomServiceRunnerAppHost).Assembly) { } + + public override void Configure(Container container) {} + + public override Web.IServiceRunner CreateServiceRunner(ActionContext actionContext) + { + return new CustomServiceRunner(this, actionContext); + } + } + + public class CustomServiceRunner : ServiceRunner + { + public CustomServiceRunner(IAppHost appHost, ActionContext actionContext) + : base(appHost, actionContext) { + } + + public override object OnAfterExecute(Web.IRequest req, object response, object service) + { + if (response is CustomRunnerResponse dto) + { + dto.ServiceName = base.ActionContext.ServiceType.Name; + dto.RequestName = base.ActionContext.RequestType.Name; + } + return base.OnAfterExecute(req, response, service); + } + } + + public class CustomRunner : IReturn + { + public int Id { get; set; } + } + + public class CustomRunnerResponse + { + public int Id { get; set; } + public string RequestName { get; set; } + public string ServiceName { get; set; } + } + + public class CustomRunnerService : Service + { + public object Get(CustomRunner request) + { + return new CustomRunnerResponse { Id = 1 }; + } + } + + [Test] + public void ServiceRunner_has_Request_and_ServiceType() + { + var client = new JsonServiceClient(ListeningOn); + + var response = client.Get(new CustomRunner { Id = 1 }); + + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.ServiceName, Is.EqualTo(typeof(CustomRunnerService).Name)); + Assert.That(response.RequestName, Is.EqualTo(typeof(CustomRunner).Name)); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomValidationErrorTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomValidationErrorTests.cs index 2097a6618c3..ad1bb1c75d7 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomValidationErrorTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomValidationErrorTests.cs @@ -1,29 +1,29 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; +using System.Runtime.Serialization; using Funq; using NUnit.Framework; -using ServiceStack.Common.Web; using ServiceStack.FluentValidation; using ServiceStack.FluentValidation.Results; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Validation; using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { - public class CustomValidationAppHost : AppHostHttpListenerBase + public class CustomValidationAppHost : AppSelfHostBase { - public CustomValidationAppHost() : base("Custom Error", typeof(CustomValidationAppHost).Assembly) {} + public CustomValidationAppHost() : base("Custom Error", typeof(CustomValidationAppHost).Assembly) { } public override void Configure(Container container) { Plugins.Add(new ValidationFeature { ErrorResponseFilter = CustomValidationError }); - container.RegisterValidators(typeof(MyValidator).Assembly); + container.RegisterValidators(typeof(MyValidator).Assembly); } - public static object CustomValidationError(ValidationResult validationResult, object errorDto) + public static object CustomValidationError(IRequest req, ValidationResult validationResult, object errorDto) { var firstError = validationResult.Errors[0]; var dto = new MyCustomErrorDto { code = firstError.ErrorCode, error = firstError.ErrorMessage }; @@ -53,12 +53,69 @@ public MyValidator() } } - public class CustomValidationService : ServiceInterface.Service + [Route("/customrequesterror/{Name}")] + public class CustomRequestError + { + public string Name { get; set; } + + public List Items { get; set; } + } + + public class CustomRequestItem + { + public string Name { get; set; } + } + + public class MyRequestValidator : AbstractValidator + { + public MyRequestValidator() + { + RuleSet(ApplyTo.Post | ApplyTo.Put | ApplyTo.Get, () => + { + var req = base.Request; + RuleFor(c => c.Name) + .Must(x => !base.Request.PathInfo.ContainsAny("-", ".", " ")); + + RuleForEach(x => x.Items).SetValidator(new MyRequestItemValidator()); + }); + } + } + + public class MyRequestItemValidator : AbstractValidator + { + public MyRequestItemValidator() + { + RuleFor(x => x.Name) + .Must(x => !base.Request.QueryString["Items"].ContainsAny("-", ".", " ")); + } + } + + public class CustomValidationErrorService : Service { public object Get(CustomError request) { return request; } + + public object Any(CustomRequestError request) + { + return request; + } + } + + [Route("/errorrequestbinding")] + public class ErrorRequestBinding : IReturn + { + public int Int { get; set; } + public decimal Decimal { get; set; } + } + + public class TestRequestBindingService : Service + { + public object Any(ErrorRequestBinding errorRequest) + { + return errorRequest; + } } [TestFixture] @@ -66,7 +123,7 @@ public class CustomValidationErrorTests { private CustomValidationAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new CustomValidationAppHost(); @@ -74,11 +131,10 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -91,24 +147,160 @@ public void Can_create_custom_validation_error() } catch (Exception ex) { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.BadRequest)); +#if NETFX var body = ex.GetResponseBody(); Assert.That(body, Is.EqualTo("{\"code\":\"GreaterThan\",\"error\":\"'Age' must be greater than '0'.\"}")); +#endif + } + } + + [Test] + public void Can_access_Request_in_Validator() + { + try + { + var response = "{0}/customrequesterror/the.name".Fmt(Config.ServiceStackBaseUri) + .GetJsonFromUrl(); + Assert.Fail("Should throw HTTP Error"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.BadRequest)); +#if NETFX + var body = ex.GetResponseBody(); + Assert.That(body, Is.EquivalentTo("{\"code\":\"Predicate\",\"error\":\"The specified condition was not met for 'Name'.\"}")); +#endif + } + } + + [Test] + public void Can_access_Request_in_item_collection_Validator() + { + try + { + var response = (Config.ServiceStackBaseUri + "/customrequesterror/thename?items=[{name:item.name}]") + .GetJsonFromUrl(); + Assert.Fail("Should throw HTTP Error"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.BadRequest)); +#if NETFX + var body = ex.GetResponseBody(); + /** + * Need to add `Request = Request,` in all ValidationContext.Clone* APIs starting from L177 + GetFromNonGenericContext() L96 + */ + // body.Print(); + Assert.That(body, Is.EqualTo("{\"code\":\"Predicate\",\"error\":\"The specified condition was not met for 'Name'.\"}")); +#endif + } + } + + [Test] + public void RequestBindingException_QueryString_returns_populated_FieldError() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + try + { + var response = client.Get("/errorrequestbinding?Int=string&Decimal=string"); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.Message, + Is.EqualTo("Unable to bind to request 'ErrorRequestBinding'")); + + var intFieldError = ex.GetFieldErrors()[0]; + Assert.That(intFieldError.FieldName, Is.EqualTo("Int")); + Assert.That(intFieldError.ErrorCode, Is.EqualTo(typeof(SerializationException).Name)); + Assert.That(intFieldError.Message, Is.EqualTo("'string' is an Invalid value for 'Int'")); + + var decimalFieldError = ex.GetFieldErrors()[1]; + Assert.That(decimalFieldError.FieldName, Is.EqualTo("Decimal")); + Assert.That(decimalFieldError.ErrorCode, Is.EqualTo(typeof(SerializationException).Name)); + Assert.That(decimalFieldError.Message, Is.EqualTo("'string' is an Invalid value for 'Decimal'")); + } + } + + [Test] + public void RequestBindingException_QueryString_predefined_route_returns_populated_FieldError() + { + try + { + var response = Config.ServiceStackBaseUri.CombineWith("/json/reply/ErrorRequestBinding?Int=string&Decimal=string") + .GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + AssertErrorRequestBindingResponse(ex); + } + } + + [Test] + public void RequestBindingException_FormData_returns_populated_FieldError() + { + try + { + var response = Config.ServiceStackBaseUri.CombineWith("errorrequestbinding") + .PostStringToUrl("Int=string&Decimal=string", contentType: MimeTypes.FormUrlEncoded, accept: MimeTypes.Json); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + AssertErrorRequestBindingResponse(ex); + } + } + + [Test] + public void RequestBindingException_FormData_predefined_route_returns_populated_FieldError() + { + try + { + var response = Config.ServiceStackBaseUri.CombineWith("/json/reply/ErrorRequestBinding") + .PostStringToUrl("Int=string&Decimal=string", contentType: MimeTypes.FormUrlEncoded, accept: MimeTypes.Json); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + AssertErrorRequestBindingResponse(ex); } } + + private static void AssertErrorRequestBindingResponse(Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.BadRequest)); + +#if NETFX + var responseBody = ex.GetResponseBody(); + var status = responseBody.FromJson().ResponseStatus; + + Assert.That(status.Message, + Is.EqualTo("Unable to bind to request 'ErrorRequestBinding'")); + + var fieldError = status.Errors[0]; + Assert.That(fieldError.FieldName, Is.EqualTo("Int")); + Assert.That(fieldError.ErrorCode, Is.EqualTo(typeof(SerializationException).Name)); + Assert.That(fieldError.Message, Is.EqualTo("'string' is an Invalid value for 'Int'")); + + var fieldError2 = status.Errors[1]; + Assert.That(fieldError2.FieldName, Is.EqualTo("Decimal")); + Assert.That(fieldError2.ErrorCode, Is.EqualTo(typeof(SerializationException).Name)); + Assert.That(fieldError2.Message, Is.EqualTo("'string' is an Invalid value for 'Decimal'")); +#endif + } } public static class WebRequestUtils { public static string GetResponseBody(this Exception ex) { - var webEx = ex as WebException; - if (webEx == null || webEx.Status != WebExceptionStatus.ProtocolError) return null; + if (!(ex is WebException webEx) || webEx.Status != WebExceptionStatus.ProtocolError) + return null; var errorResponse = ((HttpWebResponse)webEx.Response); - using (var reader = new StreamReader(errorResponse.GetResponseStream())) - { - return reader.ReadToEnd(); - } + return errorResponse.GetResponseStream().ReadToEnd(); } } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerRestExample.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerRestExample.cs new file mode 100644 index 00000000000..7010c596784 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerRestExample.cs @@ -0,0 +1,158 @@ +using System.Collections.Generic; +using Funq; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; + +namespace NewApi.Customers +{ + public class AppHost : AppSelfHostBase + { + public AppHost() : base("Customer REST Example", typeof(CustomerService).Assembly) {} + + public override void Configure(Container container) + { + container.Register(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + using var db = container.Resolve().Open(); + db.CreateTableIfNotExists(); + } + } + + [Route("/customers", "GET")] + public class GetCustomers : IReturn {} + + public class GetCustomersResponse + { + public List Results { get; set; } + } + + [Route("/customers/{Id}", "GET")] + public class GetCustomer : IReturn + { + public int Id { get; set; } + } + + [Route("/customers", "POST")] + public class CreateCustomer : IReturn + { + public string Name { get; set; } + } + + [Route("/customers/{Id}", "PUT")] + public class UpdateCustomer : IReturn + { + public int Id { get; set; } + + public string Name { get; set; } + } + + [Route("/customers/{Id}", "DELETE")] + public class DeleteCustomer : IReturnVoid + { + public int Id { get; set; } + } + + public class Customer + { + [AutoIncrement] + public int Id { get; set; } + + public string Name { get; set; } + } + + public class CustomerService : Service + { + public object Get(GetCustomers request) + { + return new GetCustomersResponse { Results = Db.Select() }; + } + + public object Get(GetCustomer request) + { + return Db.SingleById(request.Id); + } + + public object Post(CreateCustomer request) + { + var customer = new Customer { Name = request.Name }; + Db.Save(customer); + return customer; + } + + public object Put(UpdateCustomer request) + { + var customer = Db.SingleById(request.Id); + if (customer == null) + throw HttpError.NotFound("Customer '{0}' does not exist".Fmt(request.Id)); + + customer.Name = request.Name; + Db.Update(customer); + + return customer; + } + + public void Delete(DeleteCustomer request) + { + Db.DeleteById(request.Id); + } + } + + + [TestFixture] + public class CustomerRestExample + { + const string BaseUri = "http://localhost:1337/"; + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost() + .Init() + .Start(BaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Run_Customer_REST_Example() + { + var client = new JsonServiceClient(BaseUri); + + //GET /customers + var all = client.Get(new GetCustomers()); + Assert.That(all.Results.Count, Is.EqualTo(0)); + + //POST /customers + var customer = client.Post(new CreateCustomer { Name = "Foo" }); + Assert.That(customer.Id, Is.EqualTo(1)); + //GET /customer/1 + customer = client.Get(new GetCustomer { Id = customer.Id }); + Assert.That(customer.Name, Is.EqualTo("Foo")); + + //GET /customers + all = client.Get(new GetCustomers()); + Assert.That(all.Results.Count, Is.EqualTo(1)); + + //PUT /customers/1 + customer = client.Put(new UpdateCustomer { Id = customer.Id, Name = "Bar" }); + Assert.That(customer.Name, Is.EqualTo("Bar")); + + //DELETE /customers/1 + client.Delete(new DeleteCustomer { Id = customer.Id }); + //GET /customers + all = client.Get(new GetCustomers()); + Assert.That(all.Results.Count, Is.EqualTo(0)); + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerServiceValidationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerServiceValidationTests.cs index 92b0cd5b4cc..4f2117e5ab6 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerServiceValidationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/CustomerServiceValidationTests.cs @@ -3,165 +3,209 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using System.Runtime.Serialization; using System.Text.RegularExpressions; using Funq; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; using ServiceStack.FluentValidation; -using ServiceStack.Service; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.ServiceInterface.Validation; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Support; -using ServiceStack.WebHost.Endpoints.Tests; +using ServiceStack.Validation; using ServiceStack.WebHost.Endpoints.Tests.Support; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.IntegrationTests.Services { - [Route("/customers")] - [Route("/customers/{Id}")] - public class Customers - { - public int Id { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public string Company { get; set; } - public decimal Discount { get; set; } - public string Address { get; set; } - public string Postcode { get; set; } - public bool HasDiscount { get; set; } - } - - public interface IAddressValidator - { - bool ValidAddress(string address); - } - - public class AddressValidator : IAddressValidator - { - public bool ValidAddress(string address) - { - return address != null - && address.Length >= 20 - && address.Length <= 250; - } - } - - public class CustomersValidator : AbstractValidator - { - public IAddressValidator AddressValidator { get; set; } - - public CustomersValidator() - { - RuleFor(x => x.Id).NotEqual(default(int)); - - RuleSet(ApplyTo.Post | ApplyTo.Put, () => { - RuleFor(x => x.LastName).NotEmpty().WithErrorCode("ShouldNotBeEmpty"); - RuleFor(x => x.FirstName).NotEmpty().WithMessage("Please specify a first name"); - RuleFor(x => x.Company).NotNull(); - RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount); - RuleFor(x => x.Address).Must(x => AddressValidator.ValidAddress(x)); - RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode"); - }); - } - - static readonly Regex UsPostCodeRegEx = new Regex(@"^\d{5}(-\d{4})?$", RegexOptions.Compiled); - - private bool BeAValidPostcode(string postcode) - { - return !string.IsNullOrEmpty(postcode) && UsPostCodeRegEx.IsMatch(postcode); - } - } - - public class CustomersResponse - { - public Customers Result { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - [DefaultRequest(typeof(Customers))] - public class CustomerService : ServiceInterface.Service - { - public object Get(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public object Post(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public object Put(Customers request) - { - return new CustomersResponse { Result = request }; - } - - public object Delete(Customers request) - { - return new CustomersResponse { Result = request }; - } - } - - [TestFixture] - public class CustomerServiceValidationTests - { - private const string ListeningOn = "http://localhost:82/"; - - public class ValidationAppHostHttpListener - : AppHostHttpListenerBase - { - public ValidationAppHostHttpListener() - : base("Validation Tests", typeof(CustomerService).Assembly) { } - - public override void Configure(Container container) - { - Plugins.Add(new ValidationFeature()); - container.Register(new AddressValidator()); - container.RegisterValidators(typeof(CustomersValidator).Assembly); - } - } - - ValidationAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new ValidationAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - EndpointHandlerBase.ServiceManager = null; - } - - private static List GetValidationFieldErrors(string httpMethod, Customers request) - { - var validator = (IValidator)new CustomersValidator { - AddressValidator = new AddressValidator() - }; - - var validationResult = validator.Validate( - new ValidationContext(request, null, new MultiRuleSetValidatorSelector(httpMethod))); + [Route("/validcustomers")] + [Route("/validcustomers/{Id}")] + public class ValidCustomers + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Company { get; set; } + public decimal Discount { get; set; } + public string Address { get; set; } + public string Postcode { get; set; } + public bool HasDiscount { get; set; } + public string[] NickNames { get; set; } + } + + public interface IAddressValidator + { + bool ValidAddress(string address); + } + + public class AddressValidator : IAddressValidator + { + public bool ValidAddress(string address) + { + return address != null + && address.Length >= 20 + && address.Length <= 250; + } + } + + public class CustomersValidator : AbstractValidator + { + public IAddressValidator AddressValidator { get; set; } + + public CustomersValidator() + { + RuleFor(x => x.Id).NotEqual(default(int)); + + RuleSet(ApplyTo.Post | ApplyTo.Put, () => + { + RuleFor(x => x.LastName).NotEmpty().WithErrorCode("ShouldNotBeEmpty"); + RuleFor(x => x.FirstName).NotEmpty().WithMessage("Please specify a first name"); + RuleFor(x => x.Company).NotNull(); + RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount); + RuleFor(x => x.Address).Must(x => AddressValidator.ValidAddress(x)); + RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode"); + RuleForEach(x => x.NickNames).NotNull(); + }); + } + + static readonly Regex UsPostCodeRegEx = new Regex(@"^\d{5}(-\d{4})?$", RegexOptions.Compiled); + + private bool BeAValidPostcode(string postcode) + { + return !string.IsNullOrEmpty(postcode) && UsPostCodeRegEx.IsMatch(postcode); + } + } + + public class ValidCustomersResponse + { + public ValidCustomers Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + [DefaultRequest(typeof(ValidCustomers))] + public class CustomerService : Service + { + public object Get(ValidCustomers request) + { + return new ValidCustomersResponse { Result = request }; + } + + public object Post(ValidCustomers request) + { + return new ValidCustomersResponse { Result = request }; + } + + public object Put(ValidCustomers request) + { + return new ValidCustomersResponse { Result = request }; + } + + public object Delete(ValidCustomers request) + { + return new ValidCustomersResponse { Result = request }; + } + } + + public class SaveUser : IReturn + { + public int Id { get; set; } + + public User User { get; set; } + } + + public class User + { + public string Name { get; set; } + } + + public class UserValidator : AbstractValidator + { + public UserValidator() + { + this.CascadeMode = CascadeMode.StopOnFirstFailure; + + RuleFor(x => x.Name).NotEmpty(); + } + } + + public class SaveUserValidator : AbstractValidator + { + public SaveUserValidator() + { + this.CascadeMode = CascadeMode.StopOnFirstFailure; + + RuleFor(x => x.Id) + .Must(ThrowException); + + RuleFor(x => x.User) + .NotEmpty() + .SetValidator(new UserValidator()); + } + + private bool ThrowException(int arg) + { + if (arg < 0) + throw new ApplicationException("Validator Exception"); + return true; + } + } + + public class UserService : Service + { + public object Post(SaveUser request) + { + return new HttpResult(new SaveUser { Id = -100, User = new User { Name = "bad name" } }, HttpStatusCode.Created); + } + } + + [TestFixture] + public class CustomerServiceValidationTests + { + private const string ListeningOn = "http://localhost:1337/"; + + public class ValidationAppHostHttpListener + : AppHostHttpListenerBase + { + public ValidationAppHostHttpListener() + : base("Validation Tests", typeof(CustomerService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + container.Register(new AddressValidator()); + container.RegisterValidators(typeof(CustomersValidator).Assembly); + } + } + + static ValidationAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ValidationAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + private static List GetValidationFieldErrors(string httpMethod, ValidCustomers request) + { + var validator = (IValidator)new CustomersValidator + { + AddressValidator = new AddressValidator() + }; + + var validationResult = validator.Validate( + new ValidationContext(request, null, new MultiRuleSetValidatorSelector(httpMethod))); var responseStatus = validationResult.ToErrorResult().ToResponseStatus(); - var errorFields = responseStatus.Errors; - return errorFields ?? new List(); - } + var errorFields = responseStatus.Errors; + return errorFields ?? new List(); + } - private string[] ExpectedPostErrorFields = new[] { + private string[] ExpectedPostErrorFields = new[] { "Id", "LastName", "FirstName", @@ -170,189 +214,249 @@ private static List GetValidationFieldErrors(string httpMethod, C "Postcode", }; - private string[] ExpectedPostErrorCodes = new[] { - "NotEqual", - "ShouldNotBeEmpty", - "NotEmpty", - "NotNull", - "Predicate", - "Predicate", - }; + private string[] ExpectedPostErrorCodes = new[] { + "NotEqual", + "ShouldNotBeEmpty", + "NotEmpty", + "NotNull", + "Predicate", + "Predicate", + }; + + ValidCustomers validRequest; - Customers validRequest; - - [SetUp] - public void SetUp() - { - validRequest = new Customers { - Id = 1, - FirstName = "FirstName", - LastName = "LastName", - Address = "12345 Address St, New York", - Company = "Company", - Discount = 10, - HasDiscount = true, - Postcode = "11215", - }; - } + [SetUp] + public void SetUp() + { + validRequest = CreateValidCustomers(); + } + + private ValidCustomers CreateValidCustomers() + { + return new ValidCustomers + { + Id = 1, + FirstName = "FirstName", + LastName = "LastName", + Address = "12345 Address St, New York", + Company = "Company", + Discount = 10, + HasDiscount = true, + Postcode = "11215", + }; + } + + [Test] + public void Does_validate_using_registered_UserValidator() + { + var client = new JsonServiceClient(ListeningOn); + + try + { + var response = client.Post(new SaveUser()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.ResponseStatus; + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'User' must not be empty.")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("User")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'User' must not be empty.")); + } + } + + [Test] + public void Does_handle_Exception_thrown_in_validator() + { + var client = new JsonServiceClient(ListeningOn); + + try + { + var response = client.Post(new SaveUser { Id = -1 }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.ResponseStatus; + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ApplicationException))); + Assert.That(status.Message, Is.EqualTo("Validator Exception")); + } + } [Test] public void ValidationFeature_add_request_filter_once() { - var old = appHost.RequestFilters.Count; + var old = appHost.GlobalRequestFilters.Count; appHost.LoadPlugin(new ValidationFeature()); - Assert.That(old, Is.EqualTo(appHost.RequestFilters.Count)); - } - - [Test] - public void Validates_ValidRequest_request_on_Post() - { - var errorFields = GetValidationFieldErrors(HttpMethods.Post, validRequest); - Assert.That(errorFields.Count, Is.EqualTo(0)); - } - - [Test] - public void Validates_ValidRequest_request_on_Get() - { - var errorFields = GetValidationFieldErrors(HttpMethods.Get, validRequest); - Assert.That(errorFields.Count, Is.EqualTo(0)); - } - - [Test] - public void Validates_Conditional_Request_request_on_Post() - { - validRequest.Discount = 0; - validRequest.HasDiscount = true; - - var errorFields = GetValidationFieldErrors(HttpMethods.Post, validRequest); - Assert.That(errorFields.Count, Is.EqualTo(1)); - Assert.That(errorFields[0].FieldName, Is.EqualTo("Discount")); - } - - [Test] - public void Validates_empty_request_on_Post() - { - var request = new Customers(); - var errorFields = GetValidationFieldErrors(HttpMethods.Post, request); - - var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); - var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); - - Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); - Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); - Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); - } - - [Test] - public void Validates_empty_request_on_Put() - { - var request = new Customers(); - var errorFields = GetValidationFieldErrors(HttpMethods.Put, request); - - var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); - var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); - - Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); - Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); - Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); - } - - [Test] - public void Validates_empty_request_on_Get() - { - var request = new Customers(); - var errorFields = GetValidationFieldErrors(HttpMethods.Get, request); - - Assert.That(errorFields.Count, Is.EqualTo(1)); - Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); - Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); - } - - [Test] - public void Validates_empty_request_on_Delete() - { - var request = new Customers(); - var errorFields = GetValidationFieldErrors(HttpMethods.Delete, request); - - Assert.That(errorFields.Count, Is.EqualTo(1)); - Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); - Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); - } - - protected static IServiceClient UnitTestServiceClient() - { - EndpointHandlerBase.ServiceManager = new ServiceManager(typeof(SecureService).Assembly).Init(); - return new DirectServiceClient(EndpointHandlerBase.ServiceManager); - } - - public static IEnumerable ServiceClients - { - get - { - //Seriously retarded workaround for some devs idea who thought this should - //be run for all test fixtures, not just this one. - - return new Func[] { + Assert.That(old, Is.EqualTo(appHost.GlobalRequestFilters.Count)); + } + + [Test] + public void Validates_ValidRequest_request_on_Post() + { + var errorFields = GetValidationFieldErrors(HttpMethods.Post, validRequest); + Assert.That(errorFields.Count, Is.EqualTo(0)); + } + + [Test] + public void Validates_ValidRequest_request_on_Get() + { + var errorFields = GetValidationFieldErrors(HttpMethods.Get, validRequest); + Assert.That(errorFields.Count, Is.EqualTo(0)); + } + + [Test] + public void Validates_Conditional_Request_request_on_Post() + { + validRequest.Discount = 0; + validRequest.HasDiscount = true; + + var errorFields = GetValidationFieldErrors(HttpMethods.Post, validRequest); + Assert.That(errorFields.Count, Is.EqualTo(1)); + Assert.That(errorFields[0].FieldName, Is.EqualTo("Discount")); + } + + [Test] + public void Validates_empty_request_on_Post() + { + var request = new ValidCustomers(); + var errorFields = GetValidationFieldErrors(HttpMethods.Post, request); + + var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); + var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); + + Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); + Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); + Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); + } + + [Test] + public void Validates_empty_request_on_Put() + { + var request = new ValidCustomers(); + var errorFields = GetValidationFieldErrors(HttpMethods.Put, request); + + var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); + var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); + + Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); + Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); + Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); + } + + [Test] + public void Validates_empty_request_on_Get() + { + var request = new ValidCustomers(); + var errorFields = GetValidationFieldErrors(HttpMethods.Get, request); + + Assert.That(errorFields.Count, Is.EqualTo(1)); + Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); + } + + [Test] + public void Validates_empty_request_on_Delete() + { + var request = new ValidCustomers(); + var errorFields = GetValidationFieldErrors(HttpMethods.Delete, request); + + Assert.That(errorFields.Count, Is.EqualTo(1)); + Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); + } + + [Test] + public void Validates_collection_with_null_request_on_Post() + { + var invalidCollection = CreateValidCustomers(); + invalidCollection.NickNames = new[] { null, "foo", null }; + var errorFields = GetValidationFieldErrors(HttpMethods.Post, invalidCollection); + + Assert.That(errorFields.Count, Is.EqualTo(2)); + Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotNull")); + Assert.That(errorFields[0].FieldName, Is.EqualTo("NickNames[0]")); + Assert.That(errorFields[1].ErrorCode, Is.EqualTo("NotNull")); + Assert.That(errorFields[1].FieldName, Is.EqualTo("NickNames[2]")); + } + + protected static IServiceClient UnitTestServiceClient() + { + return new DirectServiceClient(appHost.ServiceController); + } + + public static IEnumerable ServiceClients + { + get + { + //Seriously retarded workaround for some devs idea who thought this should + //be run for all test fixtures, not just this one. + + return new Func[] { () => UnitTestServiceClient(), () => new JsonServiceClient(ListeningOn), () => new JsvServiceClient(ListeningOn), () => new XmlServiceClient(ListeningOn), }; - } - } - - [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] - public void Post_empty_request_throws_validation_exception(Func factory) - { - try - { - var client = factory(); - var response = client.Send(new Customers()); - Assert.Fail("Should throw Validation Exception"); - } - catch (WebServiceException ex) - { - var response = (CustomersResponse)ex.ResponseDto; - - var errorFields = response.ResponseStatus.Errors; - var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); - var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); - - Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); - Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); - Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); - Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); - } - } - - [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] - public void Get_empty_request_throws_validation_exception(Func factory) - { - try - { - var client = (IRestClient)factory(); - var response = client.Get("Customers"); - Assert.Fail("Should throw Validation Exception"); - } - catch (WebServiceException ex) - { - var response = (CustomersResponse)ex.ResponseDto; - - var errorFields = response.ResponseStatus.Errors; - Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); - Assert.That(errorFields.Count, Is.EqualTo(1)); - Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); - Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); - } - } - - [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] - public void Post_ValidRequest_succeeds(Func factory) - { - var client = factory(); - var response = client.Send(validRequest); - Assert.That(response.ResponseStatus, Is.Null); - } - - } -} \ No newline at end of file + } + } + + [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] + public void Post_empty_request_throws_validation_exception(Func factory) + { + try + { + var client = factory(); + var response = client.Send(new ValidCustomers()); + Assert.Fail("Should throw Validation Exception"); + } + catch (WebServiceException ex) + { + var response = (ValidCustomersResponse)ex.ResponseDto; + + var errorFields = response.ResponseStatus.Errors; + var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); + var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); + + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); + Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); + Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); + Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); + } + } + + [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] + public void Get_empty_request_throws_validation_exception(Func factory) + { + try + { + var client = (IRestClient)factory(); + var response = client.Get("ValidCustomers"); + Assert.Fail("Should throw Validation Exception"); + } + catch (WebServiceException ex) + { + var response = (ValidCustomersResponse)ex.ResponseDto; + + var errorFields = response.ResponseStatus.Errors; + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); + Assert.That(ex.StatusDescription, Is.EqualTo("NotEqual")); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("'Id' must not be equal to '0'.")); + Assert.That(errorFields.Count, Is.EqualTo(1)); + Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); + Assert.That(errorFields[0].Message, Is.EqualTo("'Id' must not be equal to '0'.")); + } + } + + [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] + public void Post_ValidRequest_succeeds(Func factory) + { + var client = factory(); + var response = client.Send(validRequest); + Assert.That(response.ResponseStatus, Is.Null); + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/DeclarativeValidationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/DeclarativeValidationTests.cs new file mode 100644 index 00000000000..130e2e02fc1 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/DeclarativeValidationTests.cs @@ -0,0 +1,264 @@ +using Funq; +using NUnit.Framework; +using System.Collections.Generic; +using ServiceStack.FluentValidation; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class DeclarativeChildValidation + { + public string Name { get; set; } + [ValidateMaximumLength(20)] + public string Value { get; set; } + } + + public class FluentChildValidation + { + public string Name { get; set; } + public string Value { get; set; } + } + + public class DeclarativeCollectiveValidationTest : IReturn + { + [ValidateNotEmpty] + [ValidateMaximumLength(20)] + public string Site { get; set; } + public List DeclarativeValidations { get; set; } + public List FluentValidations { get; set; } + public List NoValidators { get; set; } + } + + public class DeclarativeSingleValidation + { + public string Name { get; set; } + [ValidateMaximumLength(20)] + public string Value { get; set; } + } + + public class FluentSingleValidation + { + public string Name { get; set; } + public string Value { get; set; } + } + + public class DeclarativeSingleValidationTest : IReturn + { + [ValidateNotEmpty] + [ValidateMaximumLength(20)] + public string Site { get; set; } + public DeclarativeSingleValidation DeclarativeSingleValidation { get; set; } + public FluentSingleValidation FluentSingleValidation { get; set; } + public NoValidators NoValidators { get; set; } + } + + public class NoValidators + { + public string Name { get; set; } + public string Value { get; set; } + } + + // Declarative Collection Validation equivalent to: + // public class DeclarativeValidationTestValidator : AbstractValidator + // { + // public DeclarativeValidationTestValidator() + // { + // RuleForEach(x => x.FluentValidations).SetValidator(new CustomChildValidator()); + // } + // } + public class FluentChildValidationValidator : AbstractValidator + { + public FluentChildValidationValidator() + { + RuleFor(x => x.Value).MaximumLength(20); + } + } + + // public class DeclarativeSingleValidationTestValidator : AbstractValidator + // { + // public DeclarativeSingleValidationTestValidator() + // { + // RuleFor(x => x.FluentSingleValidation).SetValidator(new FluentSingleValidationValidator()); + // } + // } + public class FluentSingleValidationValidator : AbstractValidator + { + public FluentSingleValidationValidator() + { + RuleFor(x => x.Value).MaximumLength(20); + } + } + + public class DeclarativeValidationTestUpdate : DeclarativeCollectiveValidationTest, IReturn { } + + public class DeclarativeValidationServices : Service + { + public object Any(DeclarativeCollectiveValidationTest request) + { + return new EmptyResponse(); + } + public object Any(DeclarativeSingleValidationTest request) + { + return new EmptyResponse(); + } + } + + public class DeclarativeValidationTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(DeclarativeValidationTests), typeof(DeclarativeValidationServices)) {} + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + + container.RegisterValidator(typeof(FluentChildValidationValidator)); + container.RegisterValidator(typeof(FluentSingleValidationValidator)); + } + } + + private readonly ServiceStackHost appHost; + public DeclarativeValidationTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + IServiceClient CreateClient() => new JsonServiceClient(Config.ListeningOn); + + [Test] + public void Does_execute_declarative_collection_validation_for_declarative_collections() + { + var client = CreateClient(); + + try + { + var invalidRequest = new DeclarativeCollectiveValidationTest { + Site = "Location 1", + DeclarativeValidations = new List { + new() { Name = "Location 1", Value = "Very long description > 20 chars" } + } + }; + var response = client.Post(invalidRequest); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + var status = ex.GetResponseStatus(); + + var errorMsg = "The length of 'Value' must be 20 characters or fewer. You entered 32 characters."; + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(status.Message, Is.EqualTo(errorMsg)); + var errors = status.Errors; + Assert.That(errors.Count, Is.EqualTo(1)); + Assert.That(errors[0].ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(errors[0].Message, Is.EqualTo(errorMsg)); + Assert.That(errors[0].FieldName, Is.EqualTo("DeclarativeValidations[0].Value")); + } + } + + [Test] + public void Does_execute_declarative_collection_validation_for_FluentValidation_collections() + { + var client = CreateClient(); + + try + { + var invalidRequest = new DeclarativeCollectiveValidationTest { + Site = "Location 1", + FluentValidations = new List { + new() {Name = "Location 1", Value = "Very long description > 20 chars"} + } + }; + var response = client.Post(invalidRequest); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + var status = ex.GetResponseStatus(); + + var errorMsg = "The length of 'Value' must be 20 characters or fewer. You entered 32 characters."; + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(status.Message, Is.EqualTo(errorMsg)); + var errors = status.Errors; + Assert.That(errors.Count, Is.EqualTo(1)); + Assert.That(errors[0].ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(errors[0].Message, Is.EqualTo(errorMsg)); + Assert.That(errors[0].FieldName, Is.EqualTo("FluentValidations[0].Value")); + } + } + + [Test] + public void Does_execute_declarative_single_validation_for_DeclarativeSingleValidation() + { + var client = CreateClient(); + + try + { + var invalidRequest = new DeclarativeSingleValidationTest { + Site = "Location 1", + DeclarativeSingleValidation = new() { Name = "Location 1", Value = "Very long description > 20 chars" }, + }; + var response = client.Post(invalidRequest); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + var status = ex.GetResponseStatus(); + status.PrintDump(); + + var errorMsg = "The length of 'Value' must be 20 characters or fewer. You entered 32 characters."; + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(status.Message, Is.EqualTo(errorMsg)); + var errors = status.Errors; + Assert.That(errors.Count, Is.EqualTo(1)); + Assert.That(errors[0].ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(errors[0].Message, Is.EqualTo(errorMsg)); + Assert.That(errors[0].FieldName, Is.EqualTo("DeclarativeSingleValidation.Value")); + } + } + + [Test] + public void Does_execute_declarative_single_validation_for_FluentSingleValidation() + { + var client = CreateClient(); + + try + { + var invalidRequest = new DeclarativeSingleValidationTest { + Site = "Location 1", + FluentSingleValidation = new() { Name = "Location 1", Value = "Very long description > 20 chars" }, + }; + var response = client.Post(invalidRequest); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + var status = ex.GetResponseStatus(); + status.PrintDump(); + + var errorMsg = "The length of 'Value' must be 20 characters or fewer. You entered 32 characters."; + Assert.That(status.ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(status.Message, Is.EqualTo(errorMsg)); + var errors = status.Errors; + Assert.That(errors.Count, Is.EqualTo(1)); + Assert.That(errors[0].ErrorCode, Is.EqualTo(nameof(ValidateScripts.MaximumLength))); + Assert.That(errors[0].Message, Is.EqualTo(errorMsg)); + Assert.That(errors[0].FieldName, Is.EqualTo("FluentSingleValidation.Value")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/EncodingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/EncodingTests.cs index 9784d5178ab..bda196b9891 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/EncodingTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/EncodingTests.cs @@ -1,15 +1,11 @@ -using System; -using System.Text; +using System.Text; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; namespace ServiceStack.WebHost.Endpoints.Tests { //[Route("/HelloWorld/Greeting/{FirstName}/{LastName}", "GET")] [Route("/HelloWorld/Greeting/{FirstName}", "GET")] - [Restrict(EndpointAttributes.InternalNetworkAccess)] + [Restrict(RequestAttributes.InternalNetworkAccess)] public class HelloWorldName : IReturn { public string FirstName { get; set; } @@ -21,7 +17,7 @@ public class HelloWorldGreeting public string Greeting { get; set; } } - public class HelloWorldService : ServiceInterface.Service + public class HelloWorldService : Service { public HelloWorldGreeting Get(HelloWorldName request) { @@ -44,7 +40,7 @@ public class EncodingTests { private EncodingTestsAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new EncodingTestsAppHost(); @@ -52,11 +48,10 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } private HelloWorldGreeting PerformRequest(string firstName, string lastName) diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/EndpointRestrictionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/EndpointRestrictionTests.cs index b68e521ab3d..74fed787ca7 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/EndpointRestrictionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/EndpointRestrictionTests.cs @@ -2,226 +2,295 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceHost; +using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class EndpointRestrictionTests - : ServiceHostTestBase - { - - //Localhost and LocalSubnet is always included with the Internal flag - private const int EndpointAttributeCount = 17; - private static readonly List AllAttributes = (EndpointAttributeCount).Times().ConvertAll(x => (EndpointAttributes)(1 << (int)x)); - - TestAppHost appHost; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - appHost = CreateAppHost(); - } - - public void ShouldAllowAccessWhen(EndpointAttributes withScenario) - where TRequestDto : new() - { - ShouldNotThrow(() => appHost.ExecuteService(new TRequestDto(), withScenario)); - } - - public void ShouldDenyAccessWhen(EndpointAttributes withScenario) - where TRequestDto : new() - { - ShouldThrow(() => appHost.ExecuteService(new TRequestDto(), withScenario)); - } - - public void ShouldDenyAccessForAllOtherScenarios(params EndpointAttributes[] notIncluding) - where TRequestDto : new() - { - ShouldDenyAccessForOtherScenarios(AllAttributes.Where(x => !notIncluding.Contains(x)).ToList()); - } - - public void ShouldDenyAccessForOtherNetworkAccessScenarios(params EndpointAttributes[] notIncluding) - where TRequestDto : new() - { - var scenarios = new List { EndpointAttributes.Localhost, EndpointAttributes.LocalSubnet, EndpointAttributes.External }; - ShouldDenyAccessForOtherScenarios(scenarios.Where(x => !notIncluding.Contains(x)).ToList()); - } - - public void ShouldDenyAccessForOtherHttpRequestTypesScenarios(params EndpointAttributes[] notIncluding) - where TRequestDto : new() - { - var scenarios = new List { EndpointAttributes.HttpHead, EndpointAttributes.HttpGet, - EndpointAttributes.HttpPost, EndpointAttributes.HttpPut, EndpointAttributes.HttpDelete }; - ShouldDenyAccessForOtherScenarios(scenarios.Where(x => !notIncluding.Contains(x)).ToList()); - } - - private void ShouldDenyAccessForOtherScenarios(IEnumerable otherScenarios) - where TRequestDto : new() - { - var requestDto = new TRequestDto(); - foreach (var otherScenario in otherScenarios) - { - try - { - ShouldThrow(() => appHost.ExecuteService(requestDto, otherScenario)); - } - catch (Exception ex) - { - throw new Exception("Failed to throw on: " + otherScenario, ex); - } - } - } - - - [Test] - public void InternalRestriction_allows_calls_from_Localhost_or_LocalSubnet() - { - ShouldAllowAccessWhen(EndpointAttributes.Localhost); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet); - ShouldDenyAccessForOtherNetworkAccessScenarios(EndpointAttributes.Localhost, EndpointAttributes.LocalSubnet); - } - - [Test] - public void LocalhostRestriction_allows_calls_from_localhost() - { - ShouldAllowAccessWhen(EndpointAttributes.Localhost); - ShouldDenyAccessForOtherNetworkAccessScenarios(EndpointAttributes.Localhost); - } - - [Test] - public void LocalSubnetRestriction_allows_calls_from_LocalSubnet() - { - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet); - ShouldDenyAccessForOtherNetworkAccessScenarios(EndpointAttributes.LocalSubnet); - } - - [Test] - public void LocalSubnetRestriction_does_not_allow_calls_from_Localhost() - { - ShouldDenyAccessWhen(EndpointAttributes.Localhost); - ShouldDenyAccessWhen(EndpointAttributes.External); - } - - [Test] - public void InternalRestriction_allows_calls_from_Localhost_and_LocalSubnet() - { - ShouldAllowAccessWhen(EndpointAttributes.Localhost); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet); - ShouldDenyAccessWhen(EndpointAttributes.External); - } - - [Test] - public void SecureLocalSubnetRestriction_does_not_allow_partial_success() - { - ShouldDenyAccessWhen(EndpointAttributes.Localhost); - ShouldDenyAccessWhen(EndpointAttributes.InSecure | EndpointAttributes.LocalSubnet); - ShouldDenyAccessWhen(EndpointAttributes.InSecure); - ShouldDenyAccessWhen(EndpointAttributes.Secure | EndpointAttributes.Localhost); - ShouldAllowAccessWhen(EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - - ShouldDenyAccessWhen(EndpointAttributes.Secure | EndpointAttributes.InternalNetworkAccess); - ShouldDenyAccessForOtherNetworkAccessScenarios(EndpointAttributes.LocalSubnet); - } - - [Test] - public void HttpPostXmlAndSecureLocalSubnetRestriction_does_not_allow_partial_success() - { - ShouldDenyAccessForOtherNetworkAccessScenarios(EndpointAttributes.LocalSubnet); - ShouldDenyAccessForOtherHttpRequestTypesScenarios(EndpointAttributes.HttpPost); - - ShouldDenyAccessWhen(EndpointAttributes.Localhost); - ShouldDenyAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Json | EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - ShouldDenyAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml | EndpointAttributes.Secure | EndpointAttributes.Localhost); - - ShouldDenyAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpHead); - ShouldDenyAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml | EndpointAttributes.InSecure ); - - ShouldDenyAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Json | EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - ShouldDenyAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml | EndpointAttributes.Secure | EndpointAttributes.Localhost); - - ShouldAllowAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml | EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - } - - [Test] - public void HttpPostXmlOrSecureLocalSubnetRestriction_does_allow_partial_success() - { - ShouldDenyAccessForOtherNetworkAccessScenarios(EndpointAttributes.LocalSubnet); - - ShouldDenyAccessWhen(EndpointAttributes.Localhost | EndpointAttributes.HttpPut); - ShouldAllowAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - ShouldDenyAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Json | EndpointAttributes.Secure | EndpointAttributes.Localhost); - - ShouldAllowAccessWhen(EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - ShouldAllowAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml); - - ShouldAllowAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Json | EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - ShouldAllowAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml | EndpointAttributes.Secure | EndpointAttributes.Localhost); - - ShouldAllowAccessWhen(EndpointAttributes.HttpPost | EndpointAttributes.Xml | EndpointAttributes.Secure | EndpointAttributes.LocalSubnet); - } - - [Test] - public void Can_access_from_insecure_dev_environment() - { - ShouldAllowAccessWhen(EndpointAttributes.Localhost | EndpointAttributes.InSecure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.InSecure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.Reply); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.OneWay); - } - - [Test] - public void Can_access_from_secure_dev_environment() - { - ShouldAllowAccessWhen(EndpointAttributes.Localhost | EndpointAttributes.Secure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.Reply); - ShouldAllowAccessWhen(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.OneWay); - } - - [Test] - public void Can_access_from_insecure_live_environment() - { - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.Reply); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.OneWay); - } - - [Test] - public void Can_access_from_secure_live_environment() - { - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.Reply); - ShouldAllowAccessWhen(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.OneWay); - } - - - [Ignore] - [Test] - public void Print_enum_results() - { - PrintEnumResult(EndpointAttributes.InternalNetworkAccess, EndpointAttributes.Secure); - PrintEnumResult(EndpointAttributes.InternalNetworkAccess, EndpointAttributes.Secure | EndpointAttributes.External); - PrintEnumResult(EndpointAttributes.InternalNetworkAccess, EndpointAttributes.Secure | EndpointAttributes.Localhost); - PrintEnumResult(EndpointAttributes.InternalNetworkAccess, EndpointAttributes.Localhost); - - PrintEnumResult(EndpointAttributes.Localhost, EndpointAttributes.Secure | EndpointAttributes.External); - PrintEnumResult(EndpointAttributes.Localhost, EndpointAttributes.Secure | EndpointAttributes.InternalNetworkAccess); - PrintEnumResult(EndpointAttributes.Localhost, EndpointAttributes.LocalSubnet); - PrintEnumResult(EndpointAttributes.Localhost, EndpointAttributes.Secure); - } - - public void PrintEnumResult(EndpointAttributes actual, EndpointAttributes required) - { - Console.WriteLine(string.Format("({0} | {1}): {2}", actual, required, (actual | required))); - Console.WriteLine(string.Format("({0} & {1}): {2}", actual, required, (actual & required))); - Console.WriteLine(string.Format("({0} ^ {1}): {2}", actual, required, (actual ^ required))); - Console.WriteLine(); - } - - } + [TestFixture] + public class EndpointRestrictionTests + : ServiceHostTestBase + { + //Localhost and LocalSubnet is always included with the Internal flag + private const int EndpointAttributeCount = 17; + private static readonly List AllAttributes = (EndpointAttributeCount).Times().Map(x => (RequestAttributes)(1 << (int)x)); + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new TestAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public void ShouldAllowAccessWhen(RequestAttributes withScenario) + { + ShouldNotThrow(() => appHost.ExecuteService(typeof(TRequestDto).New(), withScenario)); + } + + public void ShouldDenyAccessWhen(RequestAttributes withScenario) + { + ShouldThrow(() => + appHost.ExecuteService(typeof(TRequestDto).New(), withScenario)); + } + + public void ShouldDenyAccessForAllOtherScenarios(params RequestAttributes[] notIncluding) + { + ShouldDenyAccessForOtherScenarios(AllAttributes.Where(x => !notIncluding.Contains(x)).ToList()); + } + + public void ShouldDenyAccessForOtherNetworkAccessScenarios(params RequestAttributes[] notIncluding) + { + var scenarios = new List { RequestAttributes.Localhost, RequestAttributes.LocalSubnet, RequestAttributes.External }; + ShouldDenyAccessForOtherScenarios(scenarios.Where(x => !notIncluding.Contains(x)).ToList()); + } + + public void ShouldDenyAccessForOtherHttpRequestTypesScenarios(params RequestAttributes[] notIncluding) + { + var scenarios = new List + { + RequestAttributes.HttpHead, + RequestAttributes.HttpGet, + RequestAttributes.HttpPost, + RequestAttributes.HttpPut, + RequestAttributes.HttpDelete, + RequestAttributes.HttpPatch, + RequestAttributes.HttpOptions, + RequestAttributes.HttpOther + }; + ShouldDenyAccessForOtherScenarios(scenarios.Where(x => !notIncluding.Contains(x)).ToList()); + } + + private void ShouldDenyAccessForOtherScenarios(IEnumerable otherScenarios) + { + var requestDto = typeof(TRequestDto).New(); + foreach (var otherScenario in otherScenarios) + { + try + { + ShouldThrow(() => appHost.ExecuteService(requestDto, otherScenario)); + } + catch (Exception ex) + { + throw new Exception("Failed to throw on: " + otherScenario, ex); + } + } + } + + + [Test] + public void InternalRestriction_allows_calls_from_Localhost_or_LocalSubnet() + { + ShouldAllowAccessWhen(RequestAttributes.Localhost); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet); + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.Localhost, RequestAttributes.LocalSubnet); + } + + [Test] + public void LocalhostRestriction_allows_calls_from_localhost() + { + ShouldAllowAccessWhen(RequestAttributes.Localhost); + ShouldAllowAccessWhen(RequestAttributes.Localhost); + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.Localhost); + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.Localhost); + } + + [Test] + public void LocalSubnetRestriction_allows_calls_from_LocalSubnet() + { + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet); + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.LocalSubnet); + } + + [Test] + public void LocalSubnetRestriction_does_not_allow_calls_from_Localhost() + { + ShouldDenyAccessWhen(RequestAttributes.Localhost); + ShouldDenyAccessWhen(RequestAttributes.External); + } + + [Test] + public void InternalRestriction_allows_calls_from_Localhost_and_LocalSubnet() + { + ShouldAllowAccessWhen(RequestAttributes.InProcess); + ShouldAllowAccessWhen(RequestAttributes.Localhost); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.External); + } + + [Test] + public void InProcessRestriction_does_not_allow_any_other_NetworkAccess() + { + ShouldAllowAccessWhen(RequestAttributes.InProcess); + ShouldDenyAccessWhen(RequestAttributes.Localhost); + ShouldDenyAccessWhen(RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.External); + } + + [Test] + public void AccessToNoneRestriction_does_not_allow_any_access() + { + ShouldDenyAccessWhen(RequestAttributes.InProcess); + ShouldDenyAccessWhen(RequestAttributes.Localhost); + ShouldDenyAccessWhen(RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.External); + } + + [Test] + public void SecureLocalSubnetRestriction_does_not_allow_partial_success() + { + ShouldDenyAccessWhen(RequestAttributes.Localhost); + ShouldDenyAccessWhen(RequestAttributes.InSecure | RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.InSecure); + ShouldDenyAccessWhen(RequestAttributes.Secure | RequestAttributes.Localhost); + ShouldAllowAccessWhen(RequestAttributes.Secure | RequestAttributes.LocalSubnet); + + ShouldDenyAccessWhen(RequestAttributes.Secure | RequestAttributes.External); + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.LocalSubnet); + } + + [Test] + public void HttpPostXmlAndSecureLocalSubnetRestriction_does_not_allow_partial_success() + { + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.LocalSubnet); + ShouldDenyAccessForOtherHttpRequestTypesScenarios(RequestAttributes.HttpPost); + + ShouldDenyAccessWhen(RequestAttributes.Localhost); + ShouldDenyAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Json | RequestAttributes.Secure | RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml | RequestAttributes.Secure | RequestAttributes.Localhost); + + ShouldDenyAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.Secure | RequestAttributes.HttpHead); + ShouldDenyAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml | RequestAttributes.InSecure); + + ShouldDenyAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Json | RequestAttributes.Secure | RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml | RequestAttributes.Secure | RequestAttributes.Localhost); + + ShouldAllowAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml | RequestAttributes.Secure | RequestAttributes.LocalSubnet); + } + + [Test] + public void HttpPostXmlOrSecureLocalSubnetRestriction_does_allow_partial_success() + { + ShouldDenyAccessForOtherNetworkAccessScenarios(RequestAttributes.LocalSubnet); + + ShouldDenyAccessWhen(RequestAttributes.Localhost | RequestAttributes.HttpPut); + ShouldAllowAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Secure | RequestAttributes.LocalSubnet); + ShouldDenyAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Json | RequestAttributes.Secure | RequestAttributes.Localhost); + + ShouldAllowAccessWhen(RequestAttributes.Secure | RequestAttributes.LocalSubnet); + ShouldAllowAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml); + + ShouldAllowAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Json | RequestAttributes.Secure | RequestAttributes.LocalSubnet); + ShouldAllowAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml | RequestAttributes.Secure | RequestAttributes.Localhost); + + ShouldAllowAccessWhen(RequestAttributes.HttpPost | RequestAttributes.Xml | RequestAttributes.Secure | RequestAttributes.LocalSubnet); + } + + [Test] + public void Can_access_from_insecure_dev_environment() + { + ShouldAllowAccessWhen(RequestAttributes.Localhost | RequestAttributes.InSecure | RequestAttributes.HttpPost); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.InSecure | RequestAttributes.HttpPost); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.InSecure | RequestAttributes.HttpPost | RequestAttributes.Reply); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.InSecure | RequestAttributes.HttpPost | RequestAttributes.OneWay); + } + + [Test] + public void Can_access_from_secure_dev_environment() + { + ShouldAllowAccessWhen(RequestAttributes.Localhost | RequestAttributes.Secure | RequestAttributes.HttpPost); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.Secure | RequestAttributes.HttpPost); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.Reply); + ShouldAllowAccessWhen(RequestAttributes.LocalSubnet | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.OneWay); + } + + [Test] + public void Can_access_from_insecure_live_environment() + { + ShouldAllowAccessWhen(RequestAttributes.External | RequestAttributes.InSecure | RequestAttributes.HttpPost); + ShouldAllowAccessWhen(RequestAttributes.External | RequestAttributes.InSecure | RequestAttributes.HttpPost | RequestAttributes.Reply); + ShouldAllowAccessWhen(RequestAttributes.External | RequestAttributes.InSecure | RequestAttributes.HttpPost | RequestAttributes.OneWay); + } + + [Test] + public void Can_access_from_secure_live_environment() + { + ShouldAllowAccessWhen(RequestAttributes.External | RequestAttributes.Secure | RequestAttributes.HttpPost); + ShouldAllowAccessWhen(RequestAttributes.External | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.Reply); + ShouldAllowAccessWhen(RequestAttributes.External | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.OneWay); + } + + [Test] + public void Can_access_MessageQueueRestriction_from_MQ() + { + ShouldAllowAccessWhen(RequestAttributes.Localhost | RequestAttributes.MessageQueue | RequestAttributes.HttpPost); + } + + [Test] + public void Can_not_access_MessageQueueRestriction_from_HTTP() + { + ShouldDenyAccessWhen(RequestAttributes.Localhost | RequestAttributes.Http | RequestAttributes.HttpPost); + } + + [Ignore("TODO: Ignore reason")] + [Test] + public void Print_enum_results() + { + PrintEnumResult(RequestAttributes.InternalNetworkAccess, RequestAttributes.Secure); + PrintEnumResult(RequestAttributes.InternalNetworkAccess, RequestAttributes.Secure | RequestAttributes.External); + PrintEnumResult(RequestAttributes.InternalNetworkAccess, RequestAttributes.Secure | RequestAttributes.Localhost); + PrintEnumResult(RequestAttributes.InternalNetworkAccess, RequestAttributes.Localhost); + + PrintEnumResult(RequestAttributes.Localhost, RequestAttributes.Secure | RequestAttributes.External); + PrintEnumResult(RequestAttributes.Localhost, RequestAttributes.Secure | RequestAttributes.InternalNetworkAccess); + PrintEnumResult(RequestAttributes.Localhost, RequestAttributes.LocalSubnet); + PrintEnumResult(RequestAttributes.Localhost, RequestAttributes.Secure); + } + + public void PrintEnumResult(RequestAttributes actual, RequestAttributes required) + { + $"({actual} | {required}): {actual | required}".Print(); + $"({actual} & {required}): {actual & required}".Print(); + $"({actual} ^ {required}): {actual ^ required}".Print(); + "".Print(); + } + + [Test] + public void Enum_masks_are_correct() + { + const RequestAttributes network = RequestAttributes.Localhost | RequestAttributes.LocalSubnet | RequestAttributes.External; + Assert.That((network.ToAllowedFlagsSet() & network) == network); + + const RequestAttributes security = RequestAttributes.Secure | RequestAttributes.InSecure; + Assert.That((security.ToAllowedFlagsSet() & security) == security); + + const RequestAttributes method = + RequestAttributes.HttpHead | RequestAttributes.HttpGet | RequestAttributes.HttpPost | + RequestAttributes.HttpPut | RequestAttributes.HttpDelete | RequestAttributes.HttpPatch | + RequestAttributes.HttpOptions | RequestAttributes.HttpOther; + Assert.That((method.ToAllowedFlagsSet() & method) == method); + + const RequestAttributes call = RequestAttributes.OneWay | RequestAttributes.Reply; + Assert.That((call.ToAllowedFlagsSet() & call) == call); + + const RequestAttributes format = + RequestAttributes.Soap11 | RequestAttributes.Soap12 | RequestAttributes.Xml | RequestAttributes.Json | + RequestAttributes.Jsv | RequestAttributes.ProtoBuf | RequestAttributes.Csv | RequestAttributes.Html | + RequestAttributes.Wire | RequestAttributes.MsgPack | RequestAttributes.FormatOther; + Assert.That((format.ToAllowedFlagsSet() & format) == format); + + const RequestAttributes endpoint = + RequestAttributes.Http | RequestAttributes.MessageQueue | RequestAttributes.Tcp | + RequestAttributes.EndpointOther; + Assert.That((endpoint.ToAllowedFlagsSet() & endpoint) == endpoint); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandling2Tests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandling2Tests.cs index 47990b3ae3c..3d6119901ea 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandling2Tests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandling2Tests.cs @@ -3,15 +3,15 @@ using System.Runtime.Serialization; using NUnit.Framework; using ProtoBuf; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Text; +using ServiceStack.ProtoBuf; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif +using ServiceStack.Logging; namespace ServiceStack.WebHost.Endpoints.Tests { - [Route("/reqstars")] [DataContract] public class Reqstar //: IReturn> @@ -98,8 +98,8 @@ public object Any(SearchReqstars request) Total = 2, Aged = 10, Results = new List { - new Reqstar { Id = 1, FirstName = "Max", LastName = "Meier", Age = 10 }, - new Reqstar { Id = 2, FirstName = "Susan", LastName = "Stark", Age = 10 } + new Reqstar {Id = 1, FirstName = "Max", LastName = "Meier", Age = 10}, + new Reqstar {Id = 2, FirstName = "Susan", LastName = "Stark", Age = 10} } }; @@ -118,21 +118,19 @@ public object Any(SearchReqstars2 request) Total = 2, Aged = 10, Results = new List { - new Reqstar { Id = 1, FirstName = "Max", LastName = "Meier", Age = 10 }, - new Reqstar { Id = 2, FirstName = "Susan", LastName = "Stark", Age = 10 } + new Reqstar {Id = 1, FirstName = "Max", LastName = "Meier", Age = 10}, + new Reqstar {Id = 2, FirstName = "Susan", LastName = "Stark", Age = 10} } }; return response; } } - + public class AppHost : AppHostHttpListenerBase { public AppHost() - : base("Test ErrorHandling", typeof(ReqstarsService).Assembly) - { - } + : base("Test ErrorHandling", typeof(ReqstarsService).Assembly) { } public override void Configure(Funq.Container container) { @@ -143,40 +141,40 @@ public override void Configure(Funq.Container container) [TestFixture] public class ExceptionHandling2Tests { - private static string testUri = "http://localhost:1337/"; + private static string testUri = Config.ListeningOn; AppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void Init() { try { + LogManager.LogFactory = null; appHost = new AppHost(); appHost.Init(); - EndpointHost.Config.DebugMode = true; - appHost.Start("http://*:1337/"); + appHost.Start(Config.ListeningOn); + appHost.Config.DebugMode = true; } catch (Exception ex) { - Console.WriteLine(ex.ToString()); + ex.ToString().Print(); } } - [TestFixtureTearDown] + [OneTimeTearDown] public void TearDown() { appHost.Dispose(); - appHost = null; } - static IRestClient[] ServiceClients = - { - new JsonServiceClient(testUri), - new XmlServiceClient(testUri), - new JsvServiceClient(testUri), - new ProtoBufServiceClient(testUri) - }; + static IRestClient[] ServiceClients = { + new JsonServiceClient(testUri), + new JsonHttpClient(testUri), + new XmlServiceClient(testUri), + new JsvServiceClient(testUri), + new ProtoBufServiceClient(testUri) + }; /// @@ -186,7 +184,7 @@ public void TearDown() [Category("OldNamingConvention")] public void OldNamingConv_Get_ExpectingResults(IRestClient client) { - var response = client.Get(new SearchReqstars { Age = 10 }); + var response = client.Get(new SearchReqstars {Age = 10}); Assert.AreEqual(2, response.Total); } @@ -200,7 +198,7 @@ public void OldNamingConv_Get_ArgumentException_InvalidAge(IRestClient client) { try { - client.Get(new SearchReqstars { Age = -1 }); + client.Get(new SearchReqstars {Age = -1}); } catch (WebServiceException ex) { @@ -216,7 +214,7 @@ public void OldNamingConv_Get_ArgumentException_InvalidAge(IRestClient client) [Category("OldNamingConvention")] public void OldNamingConv_Post_ExpectingResults(IRestClient client) { - var response = client.Post(new SearchReqstars { Age = 10 }); + var response = client.Post(new SearchReqstars {Age = 10}); Assert.AreEqual(2, response.Total); } @@ -230,7 +228,7 @@ public void OldNamingConv_Post_ArgumentException_InvalidAge(IRestClient client) { try { - client.Post(new SearchReqstars { Age = -1 }); + client.Post(new SearchReqstars {Age = -1}); } catch (WebServiceException ex) { @@ -247,7 +245,7 @@ public void OldNamingConv_Post_ArgumentException_InvalidAge(IRestClient client) [Category("NoNamingConvention")] public void NoNamingConv_Get_ExpectingResults(IRestClient client) { - var response = client.Get(new SearchReqstars2 { Age = 10 }); + var response = client.Get(new SearchReqstars2 {Age = 10}); Assert.AreEqual(2, response.Total); } @@ -261,7 +259,7 @@ public void NoNamingConv_Get_ArgumentException_InvalidAge(IRestClient client) { try { - client.Get(new SearchReqstars2 { Age = -1 }); + client.Get(new SearchReqstars2 {Age = -1}); } catch (WebServiceException ex) { @@ -277,7 +275,7 @@ public void NoNamingConv_Get_ArgumentException_InvalidAge(IRestClient client) [Category("NoNamingConvention")] public void NoNamingConv_Post_ExpectingResults(IRestClient client) { - var response = client.Post(new SearchReqstars2 { Age = 10 }); + var response = client.Post(new SearchReqstars2 {Age = 10}); Assert.AreEqual(2, response.Total); } @@ -291,7 +289,7 @@ public void NoNamingConv_Post_ArgumentException_InvalidAge(IRestClient client) { try { - client.Post(new SearchReqstars2 { Age = -1 }); + client.Post(new SearchReqstars2 {Age = -1}); } catch (WebServiceException ex) { @@ -299,8 +297,5 @@ public void NoNamingConv_Post_ArgumentException_InvalidAge(IRestClient client) Assert.AreEqual("Invalid Age", ex.ErrorMessage, "Wrong message"); } } - - } - -} +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTests.cs index ce32fa5e075..92afa20e290 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTests.cs @@ -1,24 +1,38 @@ using System; +using System.IO; using System.Net; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using System.Runtime.Serialization; +using System.Threading.Tasks; using NUnit.Framework; using Funq; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; +using ServiceStack.ProtoBuf; using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { [Route("/users")] - public class User { } + [DataContract] + public class User {} + + [DataContract] public class UserResponse : IHasResponseStatus { - public ResponseStatus ResponseStatus { get; set; } + [DataMember(Order = 1)] public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/usersvoid")] + public class UserVoid {} + + [DataContract] + public class UserVoidResponse : IHasResponseStatus + { + [DataMember(Order = 1)] public ResponseStatus ResponseStatus { get; set; } } - public class UserService : ServiceInterface.Service + public class UserReturnVoid : IReturnVoid {} + + public class UserService : Service { public object Get(User request) { @@ -39,19 +53,33 @@ public object Put(User request) { throw new ArgumentException(); } + + public void Delete(UserVoid request) + { + throw new HttpError(HttpStatusCode.Forbidden, "CanNotExecute", "Failed to execute!"); + } + + public void Delete(UserReturnVoid request) + { + throw new HttpError(HttpStatusCode.Forbidden, "CanNotExecute", "Failed to execute!"); + } } public class CustomException : ArgumentException { - public CustomException() : base("User Defined Error") { } + public CustomException() : base("User Defined Error") + { + } } - public class ExceptionWithResponseStatus { } + public class ExceptionWithResponseStatus {} + public class ExceptionWithResponseStatusResponse { public ResponseStatus ResponseStatus { get; set; } } - public class ExceptionWithResponseStatusService : ServiceInterface.Service + + public class ExceptionWithResponseStatusService : Service { public object Any(ExceptionWithResponseStatus request) { @@ -59,9 +87,11 @@ public object Any(ExceptionWithResponseStatus request) } } - public class ExceptionNoResponseStatus { } - public class ExceptionNoResponseStatusResponse { } - public class ExceptionNoResponseStatusService : ServiceInterface.Service + public class ExceptionNoResponseStatus {} + + public class ExceptionNoResponseStatusResponse {} + + public class ExceptionNoResponseStatusService : Service { public object Any(ExceptionNoResponseStatus request) { @@ -69,8 +99,9 @@ public object Any(ExceptionNoResponseStatus request) } } - public class ExceptionNoResponseDto { } - public class ExceptionNoResponseDtoService : ServiceInterface.Service + public class ExceptionNoResponseDto {} + + public class ExceptionNoResponseDtoService : Service { public object Any(ExceptionNoResponseDto request) { @@ -78,9 +109,38 @@ public object Any(ExceptionNoResponseDto request) } } - public class UncatchedException { } - public class UncatchedExceptionResponse { } - public class UncatchedExceptionService : ServiceInterface.Service + public class ExceptionReturnVoid : IReturnVoid {} + + public class ExceptionReturnVoidService : Service + { + public void Any(ExceptionReturnVoid request) + { + throw new CustomException(); + } + } + + public class CaughtException {} + public class CaughtExceptionAsync {} + + public class CaughtExceptionService : Service + { + public object Any(CaughtException request) + { + throw new ArgumentException(); + } + + public async Task Any(CaughtExceptionAsync request) + { + await Task.Yield(); + throw new ArgumentException(); + } + } + + public class UncatchedException {} + public class UncatchedExceptionAsync {} + public class UncatchedExceptionResponse {} + + public class UncatchedExceptionService : Service { public object Any(UncatchedException request) { @@ -88,70 +148,206 @@ public object Any(UncatchedException request) //so the global exception handling strategy is invoked throw new ArgumentException(); } + + public async Task Any(UncatchedExceptionAsync request) + { + await Task.Yield(); + throw new ArgumentException(); + } } + [Route("/binding-error/{Id}")] + public class ExceptionWithRequestBinding + { + public int Id { get; set; } + } - [TestFixture] - public class ExceptionHandlingTests + public class ExceptionWithRequestBindingService : Service + { + public object Any(ExceptionWithRequestBinding request) + { + return request; + } + } + + public class CustomHttpError { - private const string ListeningOn = "http://localhost:82/"; + public int StatusCode { get; set; } + public string StatusDescription { get; set; } + } - public class ExceptionHandlingAppHostHttpListener - : AppHostHttpListenerBase + public class CustomHttpErrorResponse + { + public string Custom { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomHttpErrorService : Service + { + public object Any(CustomHttpError request) { + throw new HttpError(request.StatusCode, request.StatusDescription); + } + } - public ExceptionHandlingAppHostHttpListener() - : base("Exception handling tests", typeof(UserService).Assembly) { } + + [Route("/alwaysthrowsjsscope")] + [DataContract] + public class AlwaysThrowsJsScope + { + [DataMember] public string TheValue { get; set; } + } + + public class CustomFieldHttpError {} + + public class CustomFieldHttpErrorResponse + { + public string Custom { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomFieldHttpErrorService : Service + { + public object Any(CustomFieldHttpError request) + { + throw new HttpError(new CustomFieldHttpErrorResponse + { + Custom = "Ignored", + ResponseStatus = new ResponseStatus("StatusErrorCode", "StatusErrorMessage") + }, + 500, + "HeaderErrorCode"); + } + + public object Any(AlwaysThrowsJsScope request) => + throw new HttpError(HttpStatusCode.BadRequest) + { + ResultScope = () => JsConfig.With(new Text.Config + { + TextCase = TextCase.SnakeCase, + }) + }; + } + + + public class DirectHttpError {} + + public class DirectResponseService : Service + { + public object Any(DirectHttpError request) + { + base.Response.StatusCode = 500; + base.Response.StatusDescription = "HeaderErrorCode"; + + return new CustomFieldHttpErrorResponse + { + Custom = "Not Ignored", + ResponseStatus = new ResponseStatus("StatusErrorCode", "StatusErrorMessage") + }; + } + } + + public class ErrorStream {} + + public class ErrorStreamService : Service + { + [AddHeader(ContentType = "application/pdf")] + public Stream Any(ErrorStream request) + { + throw new NotImplementedException("Exception in Stream Response"); + } + } + + [TestFixture] + public class ExceptionHandlingTests + { + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ExceptionHandlingTests), typeof(UserService).Assembly) + { + } public override void Configure(Container container) { - JsConfig.EmitCamelCaseNames = true; + JsConfig.Init(new Text.Config + { + TextCase = TextCase.CamelCase, + }); + + SetConfig(new HostConfig + { + DebugMode = false, + }); + + Plugins.Add(new ProtoBufFormat()); - SetConfig(new EndpointHostConfig { DebugMode = false }); + GlobalRequestFilters.Add((req, res, dto) => { + if (dto is UncatchedException || dto is UncatchedExceptionAsync) + throw new ArgumentException(); + }); //Custom global uncaught exception handling strategy - this.ExceptionHandler = (req, res, operationName, ex) => + this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) => { - res.Write(string.Format("Exception {0}", ex.GetType().Name)); - res.EndRequest(skipHeaders: true); - }; + res.WriteAsync($"UncaughtException {ex.GetType().Name}") + .ContinueWith(t => res.EndRequest(skipHeaders: true)); + }); - this.ServiceExceptionHandler = (request, exception) => + this.ServiceExceptionHandlers.Add((httpReq, request, ex) => { - if (request is UncatchedException) - throw exception; + if (request is UncatchedException || request is UncatchedExceptionAsync) + throw ex; + + if (request is CaughtException || request is CaughtExceptionAsync) + return DtoUtils.CreateErrorResponse(request, new ArgumentException("ExceptionCaught")); return null; - }; + }); + } + + public override void OnExceptionTypeFilter(Exception ex, ResponseStatus responseStatus) + { + "In OnExceptionTypeFilter...".Print(); + base.OnExceptionTypeFilter(ex, responseStatus); + } + + public override Task OnUncaughtException(IRequest httpReq, IResponse httpRes, string operationName, + Exception ex) + { + "In OnUncaughtException...".Print(); + return base.OnUncaughtException(httpReq, httpRes, operationName, ex); } } - ExceptionHandlingAppHostHttpListener appHost; + AppHost appHost; - [TestFixtureSetUp] - public void OnTestFixtureSetUp() + public ExceptionHandlingTests() { - appHost = new ExceptionHandlingAppHostHttpListener(); + appHost = new AppHost(); appHost.Init(); - appHost.Start(ListeningOn); + appHost.Start(Config.ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); - EndpointHost.ExceptionHandler = null; + appHost.UncaughtExceptionHandlers = null; + JsConfig.Reset(); } - static IRestClient[] ServiceClients = - { - new JsonServiceClient(ListeningOn), - new XmlServiceClient(ListeningOn), - new JsvServiceClient(ListeningOn) - //SOAP not supported in HttpListener - //new Soap11ServiceClient(ServiceClientBaseUri), - //new Soap12ServiceClient(ServiceClientBaseUri) - }; + static IRestClient[] ServiceClients = + { + new JsonServiceClient(Config.ListeningOn), + new JsonHttpClient(Config.ListeningOn), + new XmlServiceClient(Config.ListeningOn), + new JsvServiceClient(Config.ListeningOn), + new ProtoBufServiceClient(Config.ListeningOn), + //SOAP not supported in HttpListener + //new Soap11ServiceClient(ServiceClientBaseUri), + //new Soap12ServiceClient(ServiceClientBaseUri) + }; [Test, TestCaseSource("ServiceClients")] @@ -164,9 +360,9 @@ public void Handles_Returned_Http_Error(IRestClient client) } catch (WebServiceException ex) { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.BadRequest)); Assert.That(ex.ErrorCode, Is.EqualTo("CanNotExecute")); - Assert.That(ex.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.BadRequest)); - Assert.That(ex.Message, Is.EqualTo("CanNotExecute")); + Assert.That(ex.Message, Is.EqualTo("Failed to execute!")); } } @@ -180,9 +376,9 @@ public void Handles_Thrown_Http_Error(IRestClient client) } catch (WebServiceException ex) { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.BadRequest)); Assert.That(ex.ErrorCode, Is.EqualTo("CanNotExecute")); - Assert.That(ex.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.BadRequest)); - Assert.That(ex.Message, Is.EqualTo("CanNotExecute")); + Assert.That(ex.Message, Is.EqualTo("Failed to execute!")); } } @@ -196,9 +392,41 @@ public void Handles_Thrown_Http_Error_With_Forbidden_status_code(IRestClient cli } catch (WebServiceException ex) { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.Forbidden)); + Assert.That(ex.ErrorCode, Is.EqualTo("CanNotExecute")); + Assert.That(ex.Message, Is.EqualTo("Failed to execute!")); + } + } + + [Test, TestCaseSource("ServiceClients")] + public void Handles_Thrown_Http_Error_With_Forbidden_status_code_in_void_method(IRestClient client) + { + try + { + client.Delete("/usersvoid"); + Assert.Fail(); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.Forbidden)); + Assert.That(ex.ErrorCode, Is.EqualTo("CanNotExecute")); + Assert.That(ex.Message, Is.EqualTo("Failed to execute!")); + } + } + + [Test, TestCaseSource("ServiceClients")] + public void Handles_Thrown_Http_Error_With_Forbidden_status_code_using_IReturnVoid(IRestClient client) + { + try + { + client.Delete(new UserReturnVoid()); + Assert.Fail(); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.Forbidden)); Assert.That(ex.ErrorCode, Is.EqualTo("CanNotExecute")); - Assert.That(ex.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.Forbidden)); - Assert.That(ex.Message, Is.EqualTo("CanNotExecute")); + Assert.That(ex.Message, Is.EqualTo("Failed to execute!")); } } @@ -212,14 +440,33 @@ public void Handles_Normal_Exception(IRestClient client) } catch (WebServiceException ex) { + Assert.That(ex.IsAny400()); + Assert.That(!ex.IsAny500()); Assert.That(ex.ErrorCode, Is.EqualTo("ArgumentException")); - Assert.That(ex.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.BadRequest)); + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.BadRequest)); + } + } + + [Test, TestCaseSource("ServiceClients")] + public void Handles_Exception_in_Stream_Response(IRestClient client) + { + try + { + var response = client.Get(new ErrorStream()); + Assert.Fail(); + } + catch (WebServiceException ex) + { + Assert.That(ex.IsAny400()); + Assert.That(!ex.IsAny500()); + Assert.That(ex.ErrorCode, Is.EqualTo("NotImplementedException")); + Assert.That(ex.StatusCode, Is.EqualTo((int) System.Net.HttpStatusCode.MethodNotAllowed)); } } public string PredefinedJsonUrl() { - return ListeningOn + "json/reply/" + typeof(T).Name; + return Config.ListeningOn + "json/reply/" + typeof(T).Name; } [Test] @@ -230,12 +477,19 @@ public void Returns_populated_dto_when_has_ResponseStatus() var json = PredefinedJsonUrl().GetJsonFromUrl(); Assert.Fail("Should throw"); } - catch (WebException webEx) + catch (Exception ex) { - var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.EqualTo( - "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\",\"errors\":[]}}")); + Assert.That(ex.IsAny400()); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + Assert.That(webEx.IsAny400()); + Assert.That(!webEx.IsAny500()); + var body = errorResponse.GetResponseStream().ReadToEnd(); + Assert.That(body, Is.EqualTo( + "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\",\"errors\":[]}}")); + } } } @@ -247,11 +501,16 @@ public void Returns_empty_dto_when_NoResponseStatus() var json = PredefinedJsonUrl().GetJsonFromUrl(); Assert.Fail("Should throw"); } - catch (WebException webEx) + catch (Exception ex) { - var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.EqualTo("{}")); + Assert.That(ex.IsAny400()); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + var body = errorResponse.GetResponseStream().ReadToEnd(); + Assert.That(body, Is.EqualTo("{}")); + } } } @@ -263,20 +522,225 @@ public void Returns_no_body_when_NoResponseDto() var json = PredefinedJsonUrl().GetJsonFromUrl(); Assert.Fail("Should throw"); } - catch (WebException webEx) + catch (Exception ex) + { + Assert.That(ex.IsAny400()); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + var body = errorResponse.GetResponseStream().ReadToEnd(); + Assert.That(body, + Does.StartWith( + "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); + } + } + } + + [Test] + public void Returns_exception_when_ReturnVoid() + { + try + { + var json = PredefinedJsonUrl().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) { - var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.StringStarting("{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.BadRequest)); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + var body = errorResponse.GetResponseStream().ReadToEnd(); + Assert.That(body, + Does.StartWith( + "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); + } + } + + try + { + var client = new JsonServiceClient(Config.ListeningOn); + client.Get(new ExceptionReturnVoid()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.IsAny400()); + Assert.That(ex.StatusDescription, Is.EqualTo(typeof(CustomException).Name)); + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(CustomException).Name)); + Assert.That(ex.ErrorMessage, Is.EqualTo("User Defined Error")); + Assert.That(ex.ResponseBody, + Does.StartWith( + "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); + } + } + + [Test] + public void Returns_custom_ResponseStatus_with_CustomFieldHttpError() + { + try + { + var json = PredefinedJsonUrl().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.InternalServerError)); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + Assert.That((int) errorResponse.StatusCode, Is.EqualTo(500)); + Assert.That(webEx.IsAny500()); + Assert.That(errorResponse.StatusDescription, Is.EqualTo("HeaderErrorCode")); + + var body = errorResponse.GetResponseStream().ReadToEnd(); + var customResponse = body.FromJson(); + var errorStatus = customResponse.ResponseStatus; + Assert.That(errorStatus.ErrorCode, Is.EqualTo("StatusErrorCode")); + Assert.That(errorStatus.Message, Is.EqualTo("StatusErrorMessage")); + Assert.That(customResponse.Custom, Is.Null); + } + } + } + + [Test] + public void Returns_custom_Status_and_Description_with_CustomHttpError() + { + try + { + var json = PredefinedJsonUrl() + .AddQueryParam("StatusCode", 406) + .AddQueryParam("StatusDescription", "CustomDescription") + .GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.NotAcceptable)); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + Assert.That((int) errorResponse.StatusCode, Is.EqualTo(406)); + Assert.That(webEx.IsAny400()); + Assert.That(errorResponse.StatusDescription, Is.EqualTo("CustomDescription")); + } + } + } + + [Test] + public void Returns_custom_ResponseStatus_with_DirectHttpError() + { + try + { + var json = PredefinedJsonUrl().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.InternalServerError)); + + if (ex is WebException webEx) + { + var errorResponse = ((HttpWebResponse) webEx.Response); + Assert.That((int) errorResponse.StatusCode, Is.EqualTo(500)); + Assert.That(webEx.IsAny500()); + Assert.That(errorResponse.StatusDescription, Is.EqualTo("HeaderErrorCode")); + + var body = errorResponse.GetResponseStream().ReadToEnd(); + var customResponse = body.FromJson(); + var errorStatus = customResponse.ResponseStatus; + Assert.That(errorStatus.ErrorCode, Is.EqualTo("StatusErrorCode")); + Assert.That(errorStatus.Message, Is.EqualTo("StatusErrorMessage")); + Assert.That(customResponse.Custom, Is.EqualTo("Not Ignored")); + } } } [Test] public void Can_override_global_exception_handling() { - var req = (HttpWebRequest)WebRequest.Create(PredefinedJsonUrl()); - var res = req.GetResponse().DownloadText(); - Assert.AreEqual("Exception ArgumentException", res); + var req = (HttpWebRequest) WebRequest.Create(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.AreEqual("UncaughtException ArgumentException", res); + } + + [Test] + public void Can_override_global_exception_handling_async() + { + var req = (HttpWebRequest) WebRequest.Create(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.AreEqual("UncaughtException ArgumentException", res); + } + + [Test] + public void Can_override_caught_exception() + { + try + { + var req = (HttpWebRequest) WebRequest.Create(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.Fail("Should Throw"); + } + catch (WebException ex) + { + Assert.That(ex.IsAny400()); + var json = ex.GetResponseBody(); + var response = json.FromJson(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("ExceptionCaught")); + } + } + + [Test] + public void Can_override_caught_exception_async() + { + try + { + var req = (HttpWebRequest) WebRequest.Create(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.Fail("Should Throw"); + } + catch (WebException ex) + { + Assert.That(ex.IsAny400()); +#if NETFX + var json = ex.GetResponseBody(); + var response = json.FromJson(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("ExceptionCaught")); +#endif + } + } + + [Test] + public void Request_binding_error_raises_UncaughtException() + { + var response = PredefinedJsonUrl() + .AddQueryParam("Id", "NaN") + .GetStringFromUrl(); + + Assert.That(response, Is.EqualTo("UncaughtException SerializationException")); + } + + [Test] + public void Does_serialize_HttpError_with_CustomScope() + { + try + { + var json = Config.ListeningOn.AppendPath("/alwaysthrowsjsscope").GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + Assert.That(e.IsAny400()); +#if NETFX + var json = e.GetResponseBody(); + Assert.That(json, Does.Contain("response_status")); +#endif + } } } -} +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTestsAsync.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTestsAsync.cs new file mode 100644 index 00000000000..21911c6359f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ExceptionHandlingTestsAsync.cs @@ -0,0 +1,148 @@ +using System; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class ExceptionHandlingTestsAsync + { + readonly AppHost appHost; + public ExceptionHandlingTestsAsync() + { + appHost = new AppHost(); + appHost.Init(); + appHost.Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + appHost.UncaughtExceptionHandlers = null; + } + + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ExceptionHandlingTestsAsync), typeof(UserService).Assembly) { } + + public static int OnEndRequestCallbacksCount; + + public override void Configure(Container container) + { + SetConfig(new HostConfig { DebugMode = false }); + + OnEndRequestCallbacks.Add(req => { + Interlocked.Increment(ref OnEndRequestCallbacksCount); + }); + + GlobalRequestFilters.Add((req, res, dto) => { + if (dto is UncatchedException || dto is UncatchedExceptionAsync) + throw new ArgumentException(); + }); + + //Custom global uncaught exception handling strategy + this.UncaughtExceptionHandlersAsync.Add(async (req, res, operationName, ex) => + { + await res.WriteAsync($"UncaughtException {ex.GetType().Name}"); + res.EndRequest(skipHeaders: true); + }); + + this.ServiceExceptionHandlersAsync.Add(async (httpReq, request, ex) => + { + await Task.Yield(); + + if (request is UncatchedException || request is UncatchedExceptionAsync) + throw ex; + + if (request is CaughtException || request is CaughtExceptionAsync) + return DtoUtils.CreateErrorResponse(request, new ArgumentException("ExceptionCaught")); + + return null; + }); + } + + public override Task OnUncaughtException(IRequest httpReq, IResponse httpRes, string operationName, Exception ex) + { + "In OnUncaughtException...".Print(); + return base.OnUncaughtException(httpReq, httpRes, operationName, ex); + } + } + + public string PredefinedJsonUrl() + { + return Config.ListeningOn + "json/reply/" + typeof(T).Name; + } + + [Test] + public void Can_override_global_exception_handling() + { + var req = WebRequest.CreateHttp(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.AreEqual("UncaughtException ArgumentException", res); + } + + [Test] + public void Can_override_global_exception_handling_async() + { + var req = WebRequest.CreateHttp(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.AreEqual("UncaughtException ArgumentException", res); + } + + [Test] + public void Can_override_caught_exception() + { + try + { + var req = WebRequest.CreateHttp(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.Fail("Should Throw"); + } + catch (WebException ex) + { + Assert.That(ex.IsAny400()); + var json = ex.GetResponseBody(); + var response = json.FromJson(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("ExceptionCaught")); + } + } + + [Test] + public void Can_override_caught_exception_async() + { + try + { + var req = WebRequest.CreateHttp(PredefinedJsonUrl()); + var res = req.GetResponse().ReadToEnd(); + Assert.Fail("Should Throw"); + } + catch (WebException ex) + { + Assert.That(ex.IsAny400()); + var json = ex.GetResponseBody(); + var response = json.FromJson(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("ExceptionCaught")); + } + } + + [Test] + public void Request_binding_error_raises_UncaughtException() + { + Interlocked.Exchange(ref AppHost.OnEndRequestCallbacksCount, 0); + + var response = PredefinedJsonUrl() + .AddQueryParam("Id", "NaN") + .GetStringFromUrl(); + + Assert.That(AppHost.OnEndRequestCallbacksCount, Is.EqualTo(1)); + Assert.That(response, Is.EqualTo("UncaughtException SerializationException")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/FileUploadTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/FileUploadTests.cs index 50ce4c3c36b..dd04f4ddf9e 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/FileUploadTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/FileUploadTests.cs @@ -2,161 +2,265 @@ using System.IO; using System.Net; using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class FileUploadTests - { - public const string ListeningOn = "http://localhost:8082/"; - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void TextFixtureSetUp() - { - try - { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - catch (Exception ex) - { - throw ex; - } - } - - [Test] - [Explicit("Helps debugging when you need to find out WTF is going on")] - public void Run_for_30secs() - { - Thread.Sleep(30000); - } - - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - if (appHost != null) appHost.Dispose(); - appHost = null; - } - - public void AssertResponse(HttpWebResponse response, Action customAssert) - { - var contentType = response.ContentType; - - AssertResponse(response, contentType); - - var contents = new StreamReader(response.GetResponseStream()).ReadToEnd(); - var result = DeserializeResult(response, contents, contentType); - - customAssert(result); - } - - private static T DeserializeResult(WebResponse response, string contents, string contentType) - { - T result; - switch (contentType) - { - case ContentType.Xml: - result = XmlSerializer.DeserializeFromString(contents); - break; - - case ContentType.Json: - case ContentType.Json + ContentType.Utf8Suffix: - result = JsonSerializer.DeserializeFromString(contents); - break; - - case ContentType.Jsv: - result = TypeSerializer.DeserializeFromString(contents); - break; - - default: - throw new NotSupportedException(response.ContentType); - } - return result; - } - - public void AssertResponse(HttpWebResponse response, string contentType) - { - var statusCode = (int)response.StatusCode; - Assert.That(statusCode, Is.LessThan(400)); - Assert.That(response.ContentType.StartsWith(contentType)); - } - - [Test] - public void Can_POST_upload_file() - { - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - - var webRequest = (HttpWebRequest)WebRequest.Create(ListeningOn + "/fileuploads"); - webRequest.Accept = ContentType.Json; - var webResponse = webRequest.UploadFile(uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); - - AssertResponse((HttpWebResponse)webResponse, r => - { - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); - Assert.That(r.FileName, Is.EqualTo(uploadFile.Name)); - Assert.That(r.ContentLength, Is.EqualTo(uploadFile.Length)); - Assert.That(r.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadFile.Name))); - Assert.That(r.Contents, Is.EqualTo(expectedContents)); - }); - } - - [Test] - public void Can_POST_upload_file_using_ServiceClient() - { - IServiceClient client = new JsonServiceClient(ListeningOn); - - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - - - var response = client.PostFile( - ListeningOn + "/fileuploads", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); - - - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); - Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); - Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); - Assert.That(response.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadFile.Name))); - Assert.That(response.Contents, Is.EqualTo(expectedContents)); - } + [TestFixture] + public class FileUploadTests + { + string ListeningOn = Config.ListeningOn; + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void TextFixtureSetUp() + { + try + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + catch (Exception ex) + { + throw ex; + } + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + [Ignore("Helps debugging when you need to find out WTF is going on")] + public void Run_for_30secs() + { + Thread.Sleep(30000); + } + + public void AssertResponse(HttpWebResponse response, Action customAssert) + { + var contentType = response.ContentType; + + AssertResponse(response, contentType); + + var contents = response.GetResponseStream().ReadToEnd(); + var result = DeserializeResult(response, contents, contentType); + + customAssert(result); + } + + private static T DeserializeResult(WebResponse response, string contents, string contentType) + { + T result; + switch (contentType) + { + case MimeTypes.Xml: + result = XmlSerializer.DeserializeFromString(contents); + break; + + case MimeTypes.Json: + case MimeTypes.Json + ContentFormat.Utf8Suffix: + result = JsonSerializer.DeserializeFromString(contents); + break; + + case MimeTypes.Jsv: + result = TypeSerializer.DeserializeFromString(contents); + break; + + default: + throw new NotSupportedException(response.ContentType); + } + return result; + } + + public void AssertResponse(HttpWebResponse response, string contentType) + { + var statusCode = (int)response.StatusCode; + Assert.That(statusCode, Is.LessThan(400)); + Assert.That(response.ContentType.StartsWith(contentType)); + } + +#if !NETCORE + [Test] + public void Can_POST_upload_file() + { + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + var webRequest = WebRequest.CreateHttp(ListeningOn + "/fileuploads"); + webRequest.Accept = MimeTypes.Json; + var webResponse = webRequest.UploadFile(uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); + + AssertResponse((HttpWebResponse)webResponse, r => + { + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(r.Name, Is.EqualTo("file")); + Assert.That(r.FileName, Is.EqualTo(uploadFile.Name)); + Assert.That(r.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(r.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadFile.Name))); + Assert.That(r.Contents, Is.EqualTo(expectedContents)); + }); + } +#endif + + [Test] + public void Can_POST_upload_file_using_ServiceClient() + { + IServiceClient client = new JsonServiceClient(ListeningOn); + + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + + var response = client.PostFile( + ListeningOn + "/fileuploads", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); + + + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(response.Name, Is.EqualTo("file")); + Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); + Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(response.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadFile.Name))); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + } [Test] public void Can_POST_upload_file_using_ServiceClient_with_request() { IServiceClient client = new JsonServiceClient(ListeningOn); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); - var request = new FileUpload{CustomerId = 123, CustomerName = "Foo"}; - var response = client.PostFileWithRequest(ListeningOn + "/fileuploads", uploadFile, request); + var request = new FileUpload { CustomerId = 123, CustomerName = "Foo,Bar" }; + var response = client.PostFileWithRequest( + ListeningOn + "/fileuploads", + uploadFile, + request); + + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(response.Name, Is.EqualTo("upload")); + Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); + Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + Assert.That(response.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(response.CustomerId, Is.EqualTo(123)); + } + + [Test] + public void Can_POST_upload_file_using_ServiceClient_with_request_and_QueryString() + { + IServiceClient client = new JsonServiceClient(ListeningOn); + + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + var request = new FileUpload(); + var response = client.PostFileWithRequest( + ListeningOn + "/fileuploads?CustomerId=123&CustomerName=Foo,Bar", + uploadFile, request); - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(response.Name, Is.EqualTo("upload")); Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); Assert.That(response.Contents, Is.EqualTo(expectedContents)); - Assert.That(response.CustomerName, Is.EqualTo("Foo")); + Assert.That(response.CustomerName, Is.EqualTo("Foo,Bar")); Assert.That(response.CustomerId, Is.EqualTo(123)); } + [Test] + public void Can_POST_upload_multiple_files_using_ServiceClient_with_request_and_QueryString() + { + IServiceClient client = new JsonServiceClient(ListeningOn); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + using (var stream1 = uploadFile.OpenRead()) + using (var stream2 = uploadFile.OpenRead()) + { + var response = client.PostFilesWithRequest( + ListeningOn + "/multi-fileuploads?CustomerId=123", + new MultipleFileUpload { CustomerName = "Foo,Bar" }, + new[] { + new UploadFile("upload1.html", stream1), + new UploadFile("upload2.html", stream2), + }); + + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + + Assert.That(response.Results.Count, Is.EqualTo(2)); + + var file1 = response.Results[0]; + Assert.That(file1.Name, Is.EqualTo("upload0")); + Assert.That(file1.FileName, Is.EqualTo("upload1.html")); + Assert.That(file1.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(file1.Contents, Is.EqualTo(expectedContents)); + Assert.That(file1.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(file1.CustomerId, Is.EqualTo(123)); + + var file2 = response.Results[1]; + Assert.That(file2.Name, Is.EqualTo("upload1")); + Assert.That(file2.FileName, Is.EqualTo("upload2.html")); + Assert.That(file2.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(file2.Contents, Is.EqualTo(expectedContents)); + Assert.That(file2.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(file2.CustomerId, Is.EqualTo(123)); + } + } + + [Test] + public async Task Can_POST_upload_multiple_files_using_ServiceClient_with_request_and_QueryString_JsonHttpClient() + { + var client = new JsonHttpClient(ListeningOn); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + using (var stream1 = uploadFile.OpenRead()) + using (var stream2 = uploadFile.OpenRead()) + { + var response = await client.PostFilesWithRequestAsync( + new MultipleFileUpload { CustomerId = 123, CustomerName = "Foo,Bar" }, + new[] { + new UploadFile("upload1.html", stream1), + new UploadFile("upload2.html", stream2), + }); + + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + + Assert.That(response.Results.Count, Is.EqualTo(2)); + + var file1 = response.Results[0]; + Assert.That(file1.Name, Is.EqualTo("upload0")); + Assert.That(file1.FileName, Is.EqualTo("upload1.html")); + Assert.That(file1.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(file1.Contents, Is.EqualTo(expectedContents)); + Assert.That(file1.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(file1.CustomerId, Is.EqualTo(123)); + + var file2 = response.Results[1]; + Assert.That(file2.Name, Is.EqualTo("upload1")); + Assert.That(file2.FileName, Is.EqualTo("upload2.html")); + Assert.That(file2.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(file2.Contents, Is.EqualTo(expectedContents)); + Assert.That(file2.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(file2.CustomerId, Is.EqualTo(123)); + } + } + [Test] public void Can_POST_upload_file_using_ServiceClient_with_request_containing_utf8_chars() { var client = new JsonServiceClient(ListeningOn); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); var request = new FileUpload { CustomerId = 123, CustomerName = "Föяšč" }; var response = client.PostFileWithRequest(ListeningOn + "/fileuploads", uploadFile, request); - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(response.Name, Is.EqualTo("upload")); Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); Assert.That(response.Contents, Is.EqualTo(expectedContents)); @@ -164,43 +268,43 @@ public void Can_POST_upload_file_using_ServiceClient_with_request_containing_utf Assert.That(response.CustomerId, Is.EqualTo(123)); } - [Test] - public void Can_handle_error_on_POST_upload_file_using_ServiceClient() - { - IServiceClient client = new JsonServiceClient(ListeningOn); - - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - - try - { - client.PostFile( - ListeningOn + "/fileuploads/ThrowError", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); - - Assert.Fail("Upload Service should've thrown an error"); - } - catch (Exception ex) - { - var webEx = ex as WebServiceException; - var response = (FileUploadResponse)webEx.ResponseDto; - Assert.That(response.ResponseStatus.ErrorCode, - Is.EqualTo(typeof(NotSupportedException).Name)); - Assert.That(response.ResponseStatus.Message, Is.EqualTo("ThrowError")); - } - } - - [Test] - public void Can_GET_upload_file() - { - var uploadedFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - var webRequest = (HttpWebRequest)WebRequest.Create(ListeningOn + "/fileuploads/TestExistingDir/upload.html"); - var expectedContents = new StreamReader(uploadedFile.OpenRead()).ReadToEnd(); - - var webResponse = webRequest.GetResponse(); - var actualContents = new StreamReader(webResponse.GetResponseStream()).ReadToEnd(); - - Assert.That(webResponse.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadedFile.Name))); - Assert.That(actualContents, Is.EqualTo(expectedContents)); - } + [Test] + public void Can_handle_error_on_POST_upload_file_using_ServiceClient() + { + IServiceClient client = new JsonServiceClient(ListeningOn); + + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + + try + { + client.PostFile( + ListeningOn + "/fileuploads/ThrowError", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); + + Assert.Fail("Upload Service should've thrown an error"); + } + catch (Exception ex) + { + var webEx = ex as WebServiceException; + var response = (FileUploadResponse)webEx.ResponseDto; + Assert.That(response.ResponseStatus.ErrorCode, + Is.EqualTo(typeof(NotSupportedException).Name)); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("ThrowError")); + } + } + + [Test] + public void Can_GET_upload_file() + { + var uploadedFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + var webRequest = WebRequest.CreateHttp(ListeningOn + "/fileuploads/TestExistingDir/upload.html"); + var expectedContents = uploadedFile.OpenRead().ReadToEnd(); + + var webResponse = webRequest.GetResponse(); + var actualContents = webResponse.GetResponseStream().ReadToEnd(); + + Assert.That(webResponse.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadedFile.Name))); + Assert.That(actualContents, Is.EqualTo(expectedContents)); + } [Test] public void Can_POST_upload_file_and_apply_filter_using_ServiceClient() @@ -209,16 +313,17 @@ public void Can_POST_upload_file_and_apply_filter_using_ServiceClient() { var client = new JsonServiceClient(ListeningOn); - var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); bool isFilterCalled = false; - ServiceClientBase.HttpWebRequestFilter = request => { isFilterCalled = true; }; + ServiceClientBase.GlobalRequestFilter = request => { isFilterCalled = true; }; var response = client.PostFile( ListeningOn + "/fileuploads", uploadFile, MimeTypes.GetMimeType(uploadFile.Name)); - var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd(); + var expectedContents = uploadFile.OpenRead().ReadToEnd(); Assert.That(isFilterCalled); + Assert.That(response.Name, Is.EqualTo("file")); Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); Assert.That(response.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadFile.Name))); @@ -226,7 +331,7 @@ public void Can_POST_upload_file_and_apply_filter_using_ServiceClient() } finally { - ServiceClientBase.HttpWebRequestFilter = null; //reset this to not cause side-effects + ServiceClientBase.GlobalRequestFilter = null; //reset this to not cause side-effects } } @@ -237,23 +342,59 @@ public void Can_POST_upload_stream_using_ServiceClient() { var client = new JsonServiceClient(ListeningOn); - using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()).OpenRead()) + using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()).OpenRead()) { var fileName = "upload.html"; bool isFilterCalled = false; - ServiceClientBase.HttpWebRequestFilter = request => + ServiceClientBase.GlobalRequestFilter = request => { isFilterCalled = true; + }; + var response = client.PostFile( + "/fileuploads", fileStream, fileName, MimeTypes.GetMimeType(fileName)); + + fileStream.Position = 0; + var expectedContents = fileStream.ReadToEnd(); + Assert.That(isFilterCalled); + Assert.That(response.Name, Is.EqualTo("file")); + Assert.That(response.FileName, Is.EqualTo(fileName)); + Assert.That(response.ContentLength, Is.EqualTo(fileStream.Length)); + Assert.That(response.ContentType, Is.EqualTo(MimeTypes.GetMimeType(fileName))); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + } + } + finally + { + ServiceClientBase.GlobalRequestFilter = null; //reset this to not cause side-effects + } + } + + [Test] + public void Can_POST_upload_stream_using_JsonHttpClient() + { + try + { + var client = new JsonHttpClient(ListeningOn); + + using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()).OpenRead()) + { + var fileName = "upload.html"; + + bool isFilterCalled = false; + JsonHttpClient.GlobalRequestFilter = request => + { + isFilterCalled = true; }; var response = client.PostFile( - ListeningOn + "/fileuploads", fileStream, fileName, MimeTypes.GetMimeType(fileName)); + "/fileuploads", fileStream, fileName, MimeTypes.GetMimeType(fileName)); fileStream.Position = 0; - var expectedContents = new StreamReader(fileStream).ReadToEnd(); + var expectedContents = fileStream.ReadToEnd(); Assert.That(isFilterCalled); + Assert.That(response.Name, Is.EqualTo("file")); Assert.That(response.FileName, Is.EqualTo(fileName)); Assert.That(response.ContentLength, Is.EqualTo(fileStream.Length)); Assert.That(response.ContentType, Is.EqualTo(MimeTypes.GetMimeType(fileName))); @@ -262,9 +403,59 @@ public void Can_POST_upload_stream_using_ServiceClient() } finally { - ServiceClientBase.HttpWebRequestFilter = null; //reset this to not cause side-effects + JsonHttpClient.GlobalRequestFilter = null; //reset this to not cause side-effects + } + } + + [Test] + public void PostFileWithRequest_returns_the_same_date_as_normal_Put_with_ServiceClient() + { + var client = new JsonServiceClient(ListeningOn); + + using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()).OpenRead()) + { + var request = new FileUpload { + CreatedDate = new DateTime(2014, 1, 1, 1, 0, 0) + }; + + var response = client.PostFileWithRequest( + "/fileuploads", + fileStream, + "upload.html", + request); + + Assert.That(response.CreatedDate, Is.EqualTo(request.CreatedDate).Within(TimeSpan.FromHours(1))); + + response = client.Put(request); + + Assert.That(response.CreatedDate, Is.EqualTo(request.CreatedDate).Within(TimeSpan.FromHours(1))); } } - } + [Test] + public void PostFileWithRequest_returns_the_same_date_as_normal_Put_with_JsonHttpClient() + { + var client = new JsonHttpClient(ListeningOn); + + using (var fileStream = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()).OpenRead()) + { + var request = new FileUpload + { + CreatedDate = new DateTime(2014, 1, 1, 1, 0, 0) + }; + + var response = client.PostFileWithRequest( + "/fileuploads", + fileStream, + "upload.html", + request); + + Assert.That(response.CreatedDate, Is.EqualTo(request.CreatedDate).Within(TimeSpan.FromHours(1))); + + response = client.Put(request); + + Assert.That(response.CreatedDate, Is.EqualTo(request.CreatedDate).Within(TimeSpan.FromHours(1))); + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/GetEncodingFromContentTypeTest.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/GetEncodingFromContentTypeTest.cs new file mode 100644 index 00000000000..f6db8f9c507 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/GetEncodingFromContentTypeTest.cs @@ -0,0 +1,51 @@ +#if !NETCORE +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using ServiceStack.Host.HttpListener; + +namespace ServiceStack.WebHost.Endpoints.Tests.TestExistingDir +{ + [TestFixture] + public class GetEncodingFromContentTypeTest + { + + [Test] + public void Can_Get_Correct_Encoding() + { + var ct = "Content-Type: text/plain; charset=KOI8-R"; + + var encoding = ListenerRequest.GetEncoding(ct); + + Assert.AreEqual("koi8-r", encoding.BodyName); + + } + + [Test] + public void Return_Null_When_No_Encoding() + { + var ct = "Content-Type: text/plain"; + + var encoding = ListenerRequest.GetEncoding(ct); + + Assert.IsNull(encoding); + + } + + [Test] + public void Return_Null_When_Wrong_Encoding() + { + var ct = "Content-Type: text/plain; charset=ASDFG"; + + var encoding = ListenerRequest.GetEncoding(ct); + + Assert.IsNull(encoding); + + } + + + } +} +#endif diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/GithubGatewayTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/GithubGatewayTests.cs new file mode 100644 index 00000000000..93f2eeae98a --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/GithubGatewayTests.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Ignore("Integration Tests")] + public class GithubGatewayTests + { + public static readonly string GistId = "67bc8f75273a29a1ba0609675b8ed1ae"; + public static readonly string AccessToken = Environment.GetEnvironmentVariable("GITHUB_GIST_TOKEN"); + + [Test] + public void Can_create_gist() + { + var gateway = new GitHubGateway(AccessToken); + + var gist = gateway.CreateGithubGist( + description: "Hello World Examples", + isPublic: true, + textFiles: new Dictionary { + ["hello_world_ruby.txt"] = "Run `ruby hello_world.rb` to print Hello World", + ["hello_world_python.txt"] = "Run `python hello_world.py` to print Hello World", + }); + + gist.PrintDump(); + + Assert.That(gist.Owner.Login, Is.EqualTo("gistlyn")); + Assert.That(gist.Owner.Url, Is.EqualTo("https://api.github.com/users/gistlyn")); + Assert.That(gist.Owner.Html_Url, Is.EqualTo("https://github.com/gistlyn")); + + var file = gist.Files["hello_world_ruby.txt"]; + Assert.That(file.Filename, Is.EqualTo("hello_world_ruby.txt")); + Assert.That(file.Type, Is.EqualTo("text/plain")); + Assert.That(file.Language, Is.EqualTo("Text")); + Assert.That(file.Raw_Url, Does.EndWith("/hello_world_ruby.txt")); + Assert.That(file.Size, Is.GreaterThan(0)); + Assert.That(file.Content, Does.Contain("Run `ruby hello_world.rb` to print Hello World")); + + file = gist.Files["hello_world_python.txt"]; + Assert.That(file.Filename, Is.EqualTo("hello_world_python.txt")); + Assert.That(file.Type, Is.EqualTo("text/plain")); + Assert.That(file.Language, Is.EqualTo("Text")); + Assert.That(file.Raw_Url, Does.EndWith("/hello_world_python.txt")); + Assert.That(file.Size, Is.GreaterThan(0)); + Assert.That(file.Content, Does.Contain("Run `python hello_world.py` to print Hello World")); + } + + [Test] + public void Can_download_public_gist() + { + var gateway = new GitHubGateway(); + var result = gateway.GetGist(GistId); + var gist = (GithubGist)result; + Assert.That(gist.Owner.Login, Is.EqualTo("gistlyn")); + Assert.That(gist.Owner.Url, Is.EqualTo("https://api.github.com/users/gistlyn")); + Assert.That(gist.Owner.Html_Url, Is.EqualTo("https://github.com/gistlyn")); + + var file = gist.Files["main.cs"]; + Assert.That(file.Filename, Is.EqualTo("main.cs")); + Assert.That(file.Type, Is.EqualTo("text/plain")); + Assert.That(file.Language, Is.EqualTo("C#")); + Assert.That(file.Raw_Url, Does.EndWith("/main.cs")); + Assert.That(file.Size, Is.GreaterThan(0)); + Assert.That(file.Content, Does.Contain("Hello, {name}!")); + } + + [Test] + public async Task Can_download_public_gist_Async() + { + var gateway = new GitHubGateway(); + var result = await gateway.GetGistAsync(GistId); + var gist = (GithubGist)result; + Assert.That(gist.Owner.Login, Is.EqualTo("gistlyn")); + Assert.That(gist.Owner.Url, Is.EqualTo("https://api.github.com/users/gistlyn")); + Assert.That(gist.Owner.Html_Url, Is.EqualTo("https://github.com/gistlyn")); + + var file = gist.Files["main.cs"]; + Assert.That(file.Filename, Is.EqualTo("main.cs")); + Assert.That(file.Type, Is.EqualTo("text/plain")); + Assert.That(file.Language, Is.EqualTo("C#")); + Assert.That(file.Raw_Url, Does.EndWith("/main.cs")); + Assert.That(file.Size, Is.GreaterThan(0)); + Assert.That(file.Content, Does.Contain("Hello, {name}!")); + } + + [Test] + public void Can_add_and_delete_gist_file() + { + var gateway = new GitHubGateway(AccessToken); + + var newFile = "new.txt"; + gateway.WriteGistFile(GistId, newFile, "this is a new file"); + + var gist = gateway.GetGist(GistId); + var file = gist.Files[newFile]; + Assert.That(file.Filename, Is.EqualTo(newFile)); + Assert.That(file.Type, Is.EqualTo("text/plain")); + Assert.That(file.Content, Is.EqualTo("this is a new file")); + + gateway.DeleteGistFiles(GistId, newFile); + + gist = gateway.GetGist(GistId); + Assert.That(gist.Files.TryGetValue(newFile, out file), Is.False); + } + + [Test] + public async Task Does_FetchAllTruncatedFilesAsync() + { + var gistWithTruncatedFiles = "6f3484ef287c85b118ee6ca3262c1534"; + var vfs = new GistVirtualFiles(gistWithTruncatedFiles); + var gist = await vfs.GetGistAsync(); + Assert.That(gist.Files.Values.Any(x => x.Truncated && string.IsNullOrEmpty(x.Content))); + + await vfs.LoadAllTruncatedFilesAsync(); + + Assert.That(!gist.Files.Values.Any(x => x.Truncated && string.IsNullOrEmpty(x.Content))); + } + + [Test] + public void Can_GetSourceTagZipUrl() + { + var user = "NetCoreTemplates"; + var repo = "web"; + var tag = "v28"; + + var gateway = new GitHubGateway(AccessToken); + + var zipUrlForTag = gateway.GetSourceZipUrl(user, repo, tag); + + Assert.That(zipUrlForTag, Is.EqualTo("https://github.com/NetCoreTemplates/web/archive/refs/tags/v28.zip")); + } + + [Test] + public void Can_GetSourceTagZipUrl_InvalidTag() + { + var user = "NetCoreTemplates"; + var repo = "web"; + var tag = "invalid-tag"; + + var gateway = new GitHubGateway(AccessToken); + + var exception = Assert.Throws(() => + { + var zipBytes = gateway.GetSourceZipUrl(user, repo, tag).GetBytesFromUrl(); + }); + + Assert.That(exception, Is.Not.Null); + Assert.That(exception.Message, Does.Contain("(404) Not Found")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HtmlResultTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HtmlResultTests.cs index d4fdc5bac2c..fdf13941d36 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/HtmlResultTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HtmlResultTests.cs @@ -1,12 +1,8 @@ -using System; -using System.Text; -using Moq; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Tests.Mocks; -using ServiceStack.WebHost.Endpoints.Tests.Support; +using ServiceStack.Common.Tests; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -23,7 +19,8 @@ public static HttpResult RedirectTo(string url) "", url); - return new HttpResult(html, ContentType.Html) { + return new HttpResult(html, MimeTypes.Html) + { Headers = { { "Location", url } }, }; } @@ -32,19 +29,19 @@ public static HttpResult RedirectTo(string url) [Test] public void Test_response_with_html_result() { - var mockResponse = new HttpResponseMock(); + var mockResponse = new MockHttpResponse(); const string url = "http://www.servicestack.net"; var htmlResult = Html.RedirectTo(url); var reponseWasAutoHandled = mockResponse.WriteToResponse(htmlResult, "text/xml"); - Assert.That(reponseWasAutoHandled, Is.True); + Assert.That(reponseWasAutoHandled.Result, Is.True); var expectedOutput = string.Format( "", url); - var writtenString = mockResponse.GetOutputStreamAsString(); + var writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo(expectedOutput)); Assert.That(mockResponse.Headers["Location"], Is.EqualTo(url)); } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorAsyncTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorAsyncTests.cs new file mode 100644 index 00000000000..ac52652ebdf --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorAsyncTests.cs @@ -0,0 +1,165 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class HttpErrorAsyncJsonServiceClientTests : HttpErrorAsyncTests + { + public override IHttpRestClientAsync CreateRestClient(string baseUri = null) + { + return baseUri != null + ? new JsonServiceClient(baseUri) + : new JsonServiceClient(); + } + } + + public class HttpErrorAsyncJsonHttpClientTests : HttpErrorAsyncTests + { + public override IHttpRestClientAsync CreateRestClient(string baseUri = null) + { + return baseUri != null + ? new JsonHttpClient(baseUri) + : new JsonHttpClient(); + } + } + + + public abstract class HttpErrorAsyncTests + { + private const string ListeningOn = "http://localhost:1337/"; + + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + public abstract IHttpRestClientAsync CreateRestClient(string baseUri = null); + + [Test] + public async Task GET_returns_ArgumentNullException() + { + var restClient = CreateRestClient(); + try + { + var response = await restClient.GetAsync(ListeningOn + "errors"); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(400)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentNullException))); + } + } + + [Test] + public async Task GET_returns_custom_Exception_and_StatusCode() + { + var restClient = CreateRestClient(); + try + { + var response = await restClient.GetAsync( + ListeningOn + "errors/FileNotFoundException/404"); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(nameof(FileNotFoundException))); + } + } + + [Test] + public async Task GET_returns_custom_Exception_Message_and_StatusCode() + { + var restClient = CreateRestClient(); + + try + { + var response = await restClient.GetAsync( + ListeningOn + "errors/FileNotFoundException/404/ClientErrorMessage"); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(nameof(FileNotFoundException))); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("ClientErrorMessage")); + } + } + + [Test] + public async Task PUT_returning_custom_403_Exception() + { + var restClient = CreateRestClient(ListeningOn); + var counter = HttpErrorService.DisposeCounter; + + try + { + var response = await restClient.PutAsync(new ThrowHttpError + { + StatusCode = 403, + Type = nameof(Exception), + Message = "ForbiddenErrorMessage", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(403)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(nameof(Exception))); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("ForbiddenErrorMessage")); + Assert.That(HttpErrorService.DisposeCounter, Is.EqualTo(counter + 1)); + } + } + + [Test] + public async Task Can_catch_async_error_to_non_existing_host() + { + var client = CreateRestClient("https://blahblahblah/"); + try + { + var response = await client.GetAsync("/not-here"); + Assert.Fail("Should throw"); + } + catch (WebException ex) //JsonServiceClient + { + Assert.That(ex.Status, Is.EqualTo(WebExceptionStatus.NameResolutionFailure)); + } + catch (Exception ex) //JsonHttpClient + { + var innerEx = ex.UnwrapIfSingleException().InnerException; +#if !NETCORE + Assert.That(((WebException)innerEx).Status, Is.EqualTo(WebExceptionStatus.NameResolutionFailure)); +#else + Assert.That(innerEx.Message, Is.EqualTo("Couldn't resolve host name") + .Or.EqualTo("No such host is known.") // .NET Core 3.1 + .Or.EqualTo("The server name or address could not be resolved")); // .NET Core 2.0 +#endif + } + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorSyncTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorSyncTests.cs new file mode 100644 index 00000000000..d939deaf20a --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorSyncTests.cs @@ -0,0 +1,274 @@ +using System; +using System.Net; +using NUnit.Framework; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; +using ServiceStack.Logging; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class HttpErrorSyncJsonServiceClientTests : HttpErrorSyncTests + { + public override IRestClient CreateClient(string baseUri = null) + { + return baseUri != null + ? new JsonServiceClient(baseUri) + : new JsonServiceClient(); + } + } + + public class HttpErrorSyncJsonHttpClientTests : HttpErrorSyncTests + { + public override IRestClient CreateClient(string baseUri = null) + { + return baseUri != null + ? new JsonHttpClient(baseUri) + : new JsonHttpClient(); + } + } + + [TestFixture] + public abstract class HttpErrorSyncTests + { + private const string ListeningOn = "http://localhost:1337/"; + + private ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + LogManager.LogFactory = null; + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + public abstract IRestClient CreateClient(string baseUri = null); + + [Test] + public void PUT_returning_custom_403_Exception() + { + var client = CreateClient(ListeningOn); + var counter = HttpErrorService.DisposeCounter; + + try + { + var response = client.Put(new ThrowHttpError + { + StatusCode = 403, + Type = nameof(Exception), + Message = "ForbiddenErrorMessage", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(403)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(nameof(Exception))); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("ForbiddenErrorMessage")); + Assert.That(HttpErrorService.DisposeCounter, Is.EqualTo(counter + 1)); + } + } + + [Test] + public void PUT_throwing_custom_403_Exception() + { + var client = CreateClient(ListeningOn); + + try + { + client.Put(new ThrowHttpErrorNoReturn + { + StatusCode = 403, + Type = nameof(Exception), + Message = "ForbiddenErrorMessage", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(403)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(nameof(Exception))); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("ForbiddenErrorMessage")); + } + } + + [Test] + public void Throw404_does_return_404() + { + var client = CreateClient(ListeningOn); + + try + { + var response = client.Get(new Throw404()); + } + catch (WebServiceException webEx) + { + webEx.StatusDescription.Print(); + Assert404(webEx); + } + } + + [Test] + public void Throw404Description_does_return_404_with_Custom_StatusDescription() + { + var client = CreateClient(ListeningOn); + + try + { + var response = client.Get(new Throw404Description()); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + Assert.That(webEx.StatusDescription, Is.EqualTo("Custom Status Description")); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(HttpStatusCode.NotFound.ToString())); + } + } + + [Test] + public void Return404_does_return_404() + { + var client = CreateClient(ListeningOn); + + try + { + var response = client.Get(new Return404()); + } + catch (WebServiceException webEx) + { + Assert404(webEx); + } + } + + [Test] + public void Return404Result_does_return_404_with_Empty_Response_Body() + { + var client = CreateClient(ListeningOn); + + try + { + var response = client.Get(new Return404Result()); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + Assert.That(webEx.StatusDescription, Is.EqualTo("Custom Status Description")); + Assert.That(webEx.ResponseStatus, Is.Null); + Assert.That(webEx.ResponseBody, Is.Null.Or.Empty); + } + } + + private static void Assert404(WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(HttpStatusCode.NotFound.ToString())); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("Custom Status Description")); + } + + [Test] + public void ThrowCustom404_does_return_404() + { + var client = CreateClient(ListeningOn); + + try + { + var response = client.Get(new ThrowCustom404()); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(typeof(Custom404Exception).Name)); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo("Custom Status Description")); + Assert.That(webEx.ResponseStatus.Errors[0].ErrorCode, Is.EqualTo("FieldErrorCode")); + Assert.That(webEx.ResponseStatus.Errors[0].Message, Is.EqualTo("FieldMessage")); + Assert.That(webEx.ResponseStatus.Errors[0].FieldName, Is.EqualTo("FieldName")); + } + } + + [Test] + public void Does_preserve_WebServiceException() + { + var client = CreateClient(ListeningOn); + + var request = new ThrowWebServiceException + { + StatusCode = 400, + StatusDescription = "Original Message", + ResponseStatus = new ResponseStatus + { + ErrorCode = "ResponseStatus.ErrorCode", + Message = "ResponseStatus.Message" + } + }; + + try + { + var response = client.Get(request); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(request.StatusCode.Value)); + Assert.That(webEx.Message, Is.EqualTo(request.ResponseStatus.Message)); + Assert.That(webEx.StatusDescription, Is.EqualTo(request.StatusDescription)); + Assert.That(webEx.ResponseStatus.ErrorCode, Is.EqualTo(request.ResponseStatus.ErrorCode)); + Assert.That(webEx.ResponseStatus.Message, Is.EqualTo(request.ResponseStatus.Message)); + } + } + } + + public class Custom400Exception : Exception { } + + public class Custom400SubException : Custom400Exception { } + + public class Custom401Exception : Exception, IHasStatusCode + { + public int StatusCode => 401; + } + + public class CustomErrorCodeException : Exception, IHasErrorCode + { + public string ErrorCode { get; set; } + } + + [TestFixture] + public class ErrorStatusTests + { + [Test] + public void Does_map_Exception_to_StatusCode() + { + using (new BasicAppHost + { + ConfigFilter = c => + { + c.MapExceptionToStatusCode[typeof(Custom400Exception)] = 400; + } + }.Init()) + { + Assert.That(new Custom400Exception().ToStatusCode(), Is.EqualTo(400)); + Assert.That(new Custom400SubException().ToStatusCode(), Is.EqualTo(400)); + Assert.That(new Custom401Exception().ToStatusCode(), Is.EqualTo(401)); + } + } + + [Test] + public void Does_map_Exception_to_ErrorCode() + { + using (new BasicAppHost().Init()) + { + Assert.That(new CustomErrorCodeException().ToErrorCode(), Is.EqualTo("CustomErrorCodeException")); + Assert.That(new CustomErrorCodeException { ErrorCode = "ERR401" }.ToErrorCode(), Is.EqualTo("ERR401")); + } + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorTests.cs deleted file mode 100644 index a8790289a98..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpErrorTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; -using ServiceStack.WebHost.Endpoints.Tests.Support.Services; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [TestFixture] - public class HttpErrorTests - { - private const string ListeningOn = "http://localhost:82/"; - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - private static void FailOnAsyncError(T response, Exception ex) - { - Assert.Fail(ex.Message); - } - - public IRestClientAsync CreateRestClient() - { - return new JsonRestClientAsync(); - } - - [Test] - public void GET_returns_ArgumentNullException() - { - var restClient = CreateRestClient(); - - WebServiceException webEx = null; - HttpErrorResponse response = null; - restClient.GetAsync(ListeningOn + "errors", - r => response = r, - (r, ex) => { - response = r; - webEx = (WebServiceException)ex; - }); - - Thread.Sleep(1000); - - Assert.That(webEx.StatusCode, Is.EqualTo(400)); - Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(typeof(ArgumentNullException).Name)); - } - - [Test] - public void GET_returns_custom_Exception_and_StatusCode() - { - var restClient = CreateRestClient(); - - WebServiceException webEx = null; - HttpErrorResponse response = null; - restClient.GetAsync(ListeningOn + "errors/FileNotFoundException/404", - r => response = r, - (r, ex) => - { - response = r; - webEx = (WebServiceException)ex; - }); - - Thread.Sleep(1000); - - Assert.That(webEx.StatusCode, Is.EqualTo(404)); - Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(typeof(FileNotFoundException).Name)); - } - - [Test] - public void GET_returns_custom_Exception_Message_and_StatusCode() - { - var restClient = CreateRestClient(); - - WebServiceException webEx = null; - HttpErrorResponse response = null; - restClient.GetAsync(ListeningOn + "errors/FileNotFoundException/404/ClientErrorMessage", - r => response = r, - (r, ex) => - { - response = r; - webEx = (WebServiceException)ex; - }); - - Thread.Sleep(1000); - - Assert.That(webEx.StatusCode, Is.EqualTo(404)); - Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(typeof(FileNotFoundException).Name)); - Assert.That(response.ResponseStatus.Message, Is.EqualTo("ClientErrorMessage")); - } - - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpHandlerTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpHandlerTests.cs new file mode 100644 index 00000000000..7e5437f449c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpHandlerTests.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/customresult")] + public class CustomResult { } + + public class CustomXmlResult : IStreamWriterAsync, IHasOptions + { + public IDictionary Options { get; set; } + + public CustomXmlResult() + { + Options = new Dictionary + { + { "Content-Type", "application/xml" }, + { "Content-Disposition", "attachement; filename=\"file.xml\"" }, + }; + } + + public async Task WriteToAsync(Stream responseStream, CancellationToken token = new CancellationToken()) + { + await responseStream.WriteAsync("quz", token); + } + } + + + + public class CustomService : Service + { + public object Any(CustomResult request) + { + return new CustomXmlResult(); + } + } + + + public class HttpHandlerTests + { + private readonly ServiceStackHost appHost; + + public HttpHandlerTests() + { + appHost = new HttpHandlerAppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public static int BeginRequestCount = 0; + public static int EndRequestCount = 0; + + public class HttpHandlerAppHost : AppSelfHostBase + { + public HttpHandlerAppHost() : base("HttpHandlerAppHost", typeof(PerfServices).Assembly) { } + + public override void Configure(Container container) + { + } + +#if !NETCORE + protected override void OnBeginRequest(HttpListenerContext context) + { + Interlocked.Increment(ref BeginRequestCount); + base.OnBeginRequest(context); + } +#endif + + public override void OnEndRequest(IRequest request = null) + { + Interlocked.Increment(ref EndRequestCount); + base.OnEndRequest(request); + } + } + + [SetUp] + public void SetUp() + { + BeginRequestCount = EndRequestCount = 0; + } + + [Test] +#if NETCORE + [Ignore("NotFoundHttpHandler is not used in .NET Core and is skipped in AppSelfHostBase.ProcessRequest")] +#endif + public void Does_call_begin_and_end_on_Raw_HttpHandler_requests() + { + try + { + var response = Config.ListeningOn.CombineWith("/non-existing-request") + .GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (WebException ex) + { + Assert.That(ex.Message, Does.Contain("(404) Not Found")); + + Assert.That(BeginRequestCount, Is.EqualTo(1)); + Thread.Sleep(1); + Assert.That(EndRequestCount, Is.EqualTo(1)); + } + } + + [Test] + public void Can_set_Headers_with_Custom_Result() + { + var xml = Config.ListeningOn.CombineWith("customresult") + .GetStringFromUrl(responseFilter: res => { + Assert.That(res.MatchesContentType(MimeTypes.Xml)); + Assert.That(res.GetHeader(HttpHeaders.ContentDisposition), Is.EqualTo("attachement; filename=\"file.xml\"")); + }); + + Assert.That(xml, Is.EqualTo("quz")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultContentTypeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultContentTypeTests.cs index 67709ac1101..72e0cdbeed2 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultContentTypeTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultContentTypeTests.cs @@ -1,26 +1,23 @@ using System; using System.IO; using System.Net; -using System.Threading; using NUnit.Framework; -using ServiceStack.Common.Web; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; -using System.Collections.Specialized; -using System.Linq; +using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { [TestFixture] - public class HttpResultContentTypeTests { - #region setup for example plaintext service - public class SimpleAppHostHttpListener : AppHostHttpListenerBase { + public class HttpResultContentTypeTests + { + public class SimpleAppHostHttpListener : AppHostHttpListenerBase + { //Tell Service Stack the name of your application and where to find your web services public SimpleAppHostHttpListener() - : base("Test Services", typeof(SimpleAppHostHttpListener).Assembly) { + : base("Test Services", typeof(SimpleAppHostHttpListener).Assembly) + { LogManager.LogFactory = new TestLogFactory(); } @@ -28,73 +25,108 @@ public SimpleAppHostHttpListener() /// AppHostHttpListenerBase method. /// /// SS's funq container - public override void Configure(Funq.Container container) { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); + public override void Configure(Funq.Container container) + { + HostContext.Config.GlobalResponseHeaders.Clear(); + + PreRequestFilters.Add((req,res) => req.UseBufferedStream = res.UseBufferedStream = true); - //Signal advanced web browsers what HTTP Methods you accept - //base.SetConfig(new EndpointHostConfig()); - Routes.Add("/test/plaintext", "GET"); + //Signal advanced web browsers what HTTP Methods you accept + //base.SetConfig(new EndpointHostConfig()); + Routes.Add<PlainText>("/test/plaintext", "GET"); } } /// <summary> /// *Request* DTO /// </summary> - public class PlainText { + public class PlainText + { /// <summary> /// Controls if the service calls response.ContentType or just new HttpResult /// </summary> - public bool SetContentTypeBrutally { get; set; } + public bool SetContentType { get; set; } /// <summary> /// Text to respond with /// </summary> public string Text { get; set; } } - public class TimedService : ServiceStack.ServiceInterface.Service + [Route("/plain-dto")] + public class PlainDto : IReturn<PlainDto> + { + public string Name { get; set; } + } + + [Route("/httpresult-dto")] + public class HttpResultDto : IReturn<HttpResultDto> { - public object Any(PlainText request) + public string Name { get; set; } + } + + public class HttpResultServices : Service + { + public object Any(PlainText request) { - string contentType = "text/plain"; + var contentType = "text/plain"; var response = new HttpResult(request.Text, contentType); - if(request.SetContentTypeBrutally) { + if (request.SetContentType) + { response.ContentType = contentType; } return response; } - } -#endregion + public object Any(PlainDto request) => request; - private const string ListeningOn = "http://localhost:82/"; - SimpleAppHostHttpListener appHost; + public object Any(HttpResultDto request) => + new HttpResult(request, HttpStatusCode.Created); + } + readonly ServiceStackHost appHost; public HttpResultContentTypeTests() - { - - } - - [TestFixtureSetUp] - public void OnTestFixtureStartUp() - { - appHost = new SimpleAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - - System.Console.WriteLine("ExampleAppHost Created at {0}, listening on {1}", - DateTime.Now, ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - appHost = null; + { + appHost = new SimpleAppHostHttpListener() + .Init() + .Start(Config.ListeningOn); + + Console.WriteLine($"ExampleAppHost Created at {DateTime.Now}, listening on {Config.ListeningOn}"); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); //Clear the logs so other tests dont inherit log entries TestLogger.GetLogs().Clear(); - } + } + [Test] + public void When_Buffered_does_not_return_ChunkedEncoding_for_DTO_responses() + { + var response = Config.ListeningOn.CombineWith("plain-dto").AddQueryParam("name", "foo") + .GetJsonFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.TransferEncoding), Is.Null); + Assert.That(res.GetContentLength(), Is.Not.Null); + }).FromJson<PlainDto>(); + + Assert.That(response.Name, Is.EqualTo("foo")); + } + + [Test] + public void When_Buffered_does_not_return_ChunkedEncoding_for_DTO_responses_in_HttpResult() + { + var response = Config.ListeningOn.CombineWith("httpresult-dto").AddQueryParam("name", "foo") + .GetJsonFromUrl(responseFilter: res => + { + Assert.That(res.GetHeader(HttpHeaders.TransferEncoding), Is.Null); + Assert.That(res.GetContentLength(), Is.Not.Null); + }).FromJson<HttpResultDto>(); + + Assert.That(response.Name, Is.EqualTo("foo")); + } /// <summary> /// This test calls a simple web service which uses HttpResult(string responseText, string contentType) constructor @@ -105,31 +137,28 @@ public void OnTestFixtureTearDown() /// <param name="setContentTypeBrutally">If true the service additionally 'brutally' sets the content type after using HttpResult constructor which should do it anyway</param> //This test case fails on mono 2.6.7 (the content type is 'text/html') [TestCase(false)] - //This test case passes on mono 2.6.7 [TestCase(true)] - public void TestHttpRestulSettingContentType(bool setContentTypeBrutally) { - string text = "Some text"; - string url = string.Format("{0}/test/plaintext?SetContentTypeBrutally={1}&Text={2}", ListeningOn, setContentTypeBrutally,text); - HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest; + public void TestHttpRestulSettingContentType(bool setContentTypeBrutally) + { + var text = "Some text"; + var url = $"{Config.ListeningOn}/test/plaintext?SetContentType={setContentTypeBrutally}&Text={text}"; + var req = WebRequest.Create(url) as HttpWebRequest; HttpWebResponse res = null; - try { - res = (HttpWebResponse)req.GetResponse(); - - string downloaded; - using(StreamReader s = new StreamReader(res.GetResponseStream())) { - downloaded = s.ReadToEnd(); - } + try + { + res = (HttpWebResponse)req.GetResponse(); + + var downloaded = res.GetResponseStream().ReadToEnd(); Assert.AreEqual(text, downloaded, "Checking the downloaded string"); - Assert.AreEqual("text/plain", res.ContentType, "Checking for expected contentType" ); + Assert.AreEqual("text/plain", res.ContentType, "Checking for expected contentType"); } - finally { - if(res != null) { - res.Close(); - } + finally + { + res?.Close(); } } - } -} \ No newline at end of file + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultTests.cs index 111e6e158fe..7e28edbd8dc 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpResultTests.cs @@ -1,105 +1,149 @@ using System.IO; -using System.Text; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Common.Tests; +using ServiceStack.Host; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Tests.Mocks; -using ServiceStack.WebHost.Endpoints.Tests.Support; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class HttpResultTests : TestBase - { - protected override void Configure(Funq.Container container) { } + [TestFixture] + public class HttpResultTests : TestBase + { + protected override void Configure(Funq.Container container) { } - [Test] - public void Can_send_ResponseText_test_with_Custom_Header() - { - var mockResponse = new HttpResponseMock(); + [Test] + public void Can_send_ResponseText_test_with_Custom_Header() + { + var mockResponse = new MockHttpResponse(); - var customText = "<h1>Custom Text</h1>"; + var customText = "<h1>Custom Text</h1>"; - var httpResult = new HttpResult(customText, ContentType.Html) { - Headers = - { - {"X-Custom","Header"} - } - }; - - var reponseWasAutoHandled = mockResponse.WriteToResponse(httpResult, ContentType.Html); - - Assert.That(reponseWasAutoHandled, Is.True); - - var writtenString = mockResponse.GetOutputStreamAsString(); - Assert.That(writtenString, Is.EqualTo(customText)); - Assert.That(mockResponse.Headers["X-Custom"], Is.EqualTo("Header")); - } - - [Test] - public void Can_send_ResponseStream_test_with_Custom_Header() - { - var mockResponse = new HttpResponseMock(); - - var customText = "<h1>Custom Stream</h1>"; - var customTextBytes = customText.ToUtf8Bytes(); - var ms = new MemoryStream(); - ms.Write(customTextBytes, 0, customTextBytes.Length); - - - var httpResult = new HttpResult(ms, ContentType.Html) { - Headers = - { - {"X-Custom","Header"} - } - }; - - var reponseWasAutoHandled = mockResponse.WriteToResponse(httpResult, ContentType.Html); - - Assert.That(reponseWasAutoHandled, Is.True); - - var writtenString = mockResponse.GetOutputStreamAsString(); - Assert.That(writtenString, Is.EqualTo(customText)); - Assert.That(mockResponse.Headers["X-Custom"], Is.EqualTo("Header")); - } - - [Test] - public void Can_send_ResponseText_test_with_StatusDescription() - { - var mockRequest = new MockHttpRequest { ContentType = ContentType.Json }; - var mockRequestContext = new HttpRequestContext(mockRequest, null, new object()); - var mockResponse = new HttpResponseMock(); - - var customStatus = "Custom Status Description"; - - var httpResult = new HttpResult(System.Net.HttpStatusCode.Accepted, customStatus) { - RequestContext = mockRequestContext - }; - - var reponseWasAutoHandled = mockResponse.WriteToResponse(httpResult, ContentType.Html); - - Assert.That(reponseWasAutoHandled, Is.True); - - var statusDesc = mockResponse.StatusDescription; - Assert.That(mockResponse.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.Accepted)); - Assert.That(statusDesc, Is.EqualTo(customStatus)); - } - - [Test] - public void Can_handle_null_HttpResult_StatusDescription() - { - var mockResponse = new HttpResponseMock(); - - var httpResult = new HttpResult(); - httpResult.StatusDescription = null; - - mockResponse.WriteToResponse(httpResult, ContentType.Html); - - Assert.IsNotNull(mockResponse.StatusDescription); - } - } + var httpResult = new HttpResult(customText, MimeTypes.Html) + { + Headers = + { + {"X-Custom","Header"} + } + }; + + var responseWasAutoHandled = mockResponse.WriteToResponse(httpResult, MimeTypes.Html); + + Assert.That(responseWasAutoHandled.Result, Is.True); + + var writtenString = mockResponse.ReadAsString(); + Assert.That(writtenString, Is.EqualTo(customText)); + Assert.That(mockResponse.Headers["X-Custom"], Is.EqualTo("Header")); + } + + [Test] + public void Can_send_ResponseStream_test_with_Custom_Header() + { + var mockResponse = new MockHttpResponse(); + + var customText = "<h1>Custom Stream</h1>"; + var customTextBytes = customText.ToUtf8Bytes(); + var ms = new MemoryStream(); + ms.Write(customTextBytes, 0, customTextBytes.Length); + + + var httpResult = new HttpResult(ms, MimeTypes.Html) + { + Headers = + { + {"X-Custom","Header"} + } + }; + + var responseWasAutoHandled = mockResponse.WriteToResponse(httpResult, MimeTypes.Html); + + Assert.That(responseWasAutoHandled.Result, Is.True); + + var writtenString = mockResponse.ReadAsString(); + Assert.That(writtenString, Is.EqualTo(customText)); + Assert.That(mockResponse.Headers["X-Custom"], Is.EqualTo("Header")); + } + + [Test] + public void Can_send_ResponseText_test_with_StatusDescription() + { + var mockRequest = new MockHttpRequest { ContentType = MimeTypes.Json }; + var mockResponse = mockRequest.Response; + + var customStatus = "Custom Status Description"; + + var httpResult = new HttpResult(System.Net.HttpStatusCode.Accepted, customStatus) + { + RequestContext = mockRequest + }; + + var responseWasAutoHandled = mockResponse.WriteToResponse(httpResult, MimeTypes.Html); + + Assert.That(responseWasAutoHandled.Result, Is.True); + + var statusDesc = mockResponse.StatusDescription; + Assert.That(mockResponse.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.Accepted)); + Assert.That(statusDesc, Is.EqualTo(customStatus)); + } + + [Test] + public void Can_handle_null_HttpResult_StatusDescription() + { + var mockResponse = new MockHttpResponse(); + + var httpResult = new HttpResult { StatusDescription = null }; + + var responseWasAutoHandled = mockResponse.WriteToResponse(httpResult, MimeTypes.Html); + Assert.That(responseWasAutoHandled.Result, Is.True); + + Assert.IsNotNull(mockResponse.StatusDescription); + } + + [Test] + public void Can_change_serialization_options() + { + var mockResponse = new MockHttpResponse(); + + var dto = new Poco(); + Assert.That(dto.ToJson(), Is.EqualTo("{}")); + + var httpResult = new HttpResult(dto) + { + ResultScope = () => JsConfig.With(new Text.Config { IncludeNullValues = true }) + }; + + var responseWasAutoHandled = mockResponse.WriteToResponse(httpResult, MimeTypes.Html); + Assert.That(responseWasAutoHandled.Result, Is.True); + + Assert.That(mockResponse.ReadAsString(), Is.EqualTo("{\"Text\":null}").Or.EqualTo("{\"text\":null}")); + } + + [Test] + public void Can_parse_ExtractHttpRanges() + { + void assertRange(long start, long expectedStart, long end, long expectedEnd) + { + Assert.That(start, Is.EqualTo(expectedStart)); + Assert.That(end, Is.EqualTo(expectedEnd)); + } + + "bytes=0-".ExtractHttpRanges(100, out var rangeStart, out var rangeEnd); + assertRange(rangeStart, 0, rangeEnd, 99); + "bytes=0-99".ExtractHttpRanges(100, out rangeStart, out rangeEnd); + assertRange(rangeStart, 0, rangeEnd, 99); + "bytes=1-2".ExtractHttpRanges(100, out rangeStart, out rangeEnd); + assertRange(rangeStart, 1, rangeEnd, 2); + "bytes=-50".ExtractHttpRanges(100, out rangeStart, out rangeEnd); + assertRange(rangeStart, 49, rangeEnd, 99); + + Assert.Throws<HttpError>(() => + "".ExtractHttpRanges(100, out rangeStart, out rangeEnd)); + Assert.Throws<HttpError>(() => + "-100".ExtractHttpRanges(100, out rangeStart, out rangeEnd)); + Assert.Throws<HttpError>(() => + "0-10,10-20".ExtractHttpRanges(100, out rangeStart, out rangeEnd)); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/HttpUtility.Core.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpUtility.Core.cs new file mode 100644 index 00000000000..8a2965621aa --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/HttpUtility.Core.cs @@ -0,0 +1,25 @@ +#if NETCORE +using System; +using System.Collections.Specialized; +using Microsoft.AspNetCore.WebUtilities; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class HttpUtility + { + public static NameValueCollection ParseQueryString(string query) + { + NameValueCollection result = new NameValueCollection(); + + var queryDict = QueryHelpers.ParseQuery(query); + + foreach(var key in queryDict.Keys) + { + result.Add(key, String.Join("; ", queryDict[key])); + } + + return result; + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/InProcessServiceGatewayRequestResponseFiltersTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/InProcessServiceGatewayRequestResponseFiltersTests.cs new file mode 100644 index 00000000000..2b61fbc3625 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/InProcessServiceGatewayRequestResponseFiltersTests.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class SomeResponse + { + public string Info { get; set; } + } + + public class InternalResponse : SomeResponse + { + } + + public class RequestSync : IReturn<SomeResponse> { } + public class RequestAsync : IReturn<SomeResponse> { } + public class RequestInternal: IGet, IReturn<InternalResponse> { } + + public class FooBarService: Service + { + public SomeResponse Get(RequestSync request) + { + var resp = Gateway.Send(new RequestInternal()); + return new SomeResponse() {Info = resp.Info}; + } + + public async Task<SomeResponse> Get(RequestAsync req) + { + var resp = await Gateway.SendAsync(new RequestInternal()); + return new SomeResponse() {Info = resp.Info}; + } + + public Task<InternalResponse> Get(RequestInternal req) => Task.FromResult(new InternalResponse() {Info = "yay"}); + } + + public class InProcessServiceGatewayRequestResponseFiltersTests + { + class InProcessAppHost : AppSelfHostBase + { + public InProcessAppHost() : base(nameof(InProcessServiceGatewayRequestResponseFiltersTests), + typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + } + } + + private readonly ServiceStackHost _appHost; + private readonly List<string> _filterCallLog = new List<string>(); + private readonly JsonServiceClient _client; + + public InProcessServiceGatewayRequestResponseFiltersTests() + { + _appHost = new InProcessAppHost(); + _appHost.GlobalRequestFilters.Add((req ,resp, dto) => _filterCallLog.Add(req.PathInfo)); + _appHost.GlobalResponseFilters.Add((req, resp, dto) => _filterCallLog.Add(dto.GetType().Name)); + + _appHost.Init() + .Start(Config.ListeningOn); + _client = new JsonServiceClient(Config.ListeningOn); + } + + [TearDown] + public void CleanAfterTest() + { + _filterCallLog.Clear(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + _appHost.Dispose(); + } + + [Test] + public void Should_Not_Call_Filters_When_Using_SyncGateway() + { + var result = _client.Get(new RequestSync()); + Assert.AreEqual("yay", result.Info); + CollectionAssert.AreEqual(new []{ "/json/reply/RequestSync", "SomeResponse" }, _filterCallLog); + } + + [Test] + public void Should_Not_Call_Filters_When_Using_AsyncGateway() + { + var result = _client.Get(new RequestAsync()); + Assert.AreEqual("yay", result.Info); + CollectionAssert.AreEqual(new[] { "/json/reply/RequestAsync", "SomeResponse" }, _filterCallLog); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/CachedMoviesService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/CachedMoviesService.cs index 13fd6d84bf8..15ceb16919f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/CachedMoviesService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/CachedMoviesService.cs @@ -1,8 +1,7 @@ +using System; using System.Runtime.Serialization; -using ServiceStack.Common; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; +using ServiceStack.Data; +using ServiceStack.Redis; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests @@ -10,25 +9,77 @@ namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests [DataContract] [Route("/cached/movies", "GET")] [Route("/cached/movies/genres/{Genre}")] - public class CachedMovies - { - [DataMember] - public string Genre { get; set; } - } + public class CachedMovies : IReturn<MoviesResponse> + { + [DataMember] + public string Genre { get; set; } + } + + [Route("/cached-timeout/movies", "GET")] + public class CachedMoviesWithTimeout : IReturn<MoviesResponse> + { + [DataMember] + public string Genre { get; set; } + } + + [Route("/cached-timeout-redis/movies", "GET")] + public class CachedMoviesWithTimeoutAndRedis : IReturn<MoviesResponse> + { + [DataMember] + public string Genre { get; set; } + } + + [Route("/cached-string/{Id}")] + public class CachedString : IReturn<string> + { + public string Id { get; set; } + } - public class CachedMoviesService : ServiceInterface.Service + public class CachedMoviesService : Service { - public IDbConnectionFactory DbFactory { get; set; } - - public object Get(CachedMovies request) - { - var service = base.ResolveService<MoviesService>(); - - return base.RequestContext.ToOptimizedResultUsingCache( - this.GetCacheClient(), UrnId.Create<Movies>(request.Genre ?? "all"), () => - { - return (MoviesResponse)service.Get(new Movies { Genre = request.Genre }); - }); - } - } + public object Get(CachedMovies request) + { + using (var service = base.ResolveService<MoviesService>()) + { + return base.Request.ToOptimizedResultUsingCache( + this.Cache, UrnId.Create<Movies>(request.Genre ?? "all"), () => + { + return (MoviesResponse)service.Get(new Movies { Genre = request.Genre }); + }); + } + } + + public object Get(CachedMoviesWithTimeout request) + { + using (var service = base.ResolveService<MoviesService>()) + { + return base.Request.ToOptimizedResultUsingCache( + this.Cache, UrnId.Create<Movies>(request.Genre ?? "all"), TimeSpan.FromMinutes(1), () => + { + return (MoviesResponse)service.Get(new Movies { Genre = request.Genre }); + }); + } + } + + public object Get(CachedMoviesWithTimeoutAndRedis request) + { + using (var service = base.ResolveService<MoviesService>()) + { + return base.Request.ToOptimizedResultUsingCache( + new RedisClient(), UrnId.Create<Movies>(request.Genre ?? "all"), TimeSpan.FromMinutes(1), () => + { + return (MoviesResponse)service.Get(new Movies { Genre = request.Genre }); + }); + } + } + + public object Get(CachedString request) + { + return base.Request.ToOptimizedResultUsingCache( + new RedisClient(), UrnId.Create<CachedString>(request.Id ?? "all"), TimeSpan.FromMinutes(1), () => + { + return request.Id; + }); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ConfigureDatabase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ConfigureDatabase.cs index 34046c4be3a..d5c67723cad 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ConfigureDatabase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ConfigureDatabase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using ServiceStack.Data; using ServiceStack.OrmLite; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs index da6b33abec4..7304d4370b0 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ErrorRestTests.cs @@ -1,92 +1,227 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Net; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { - [TestFixture] - public class ErrorRestTests : IntegrationTestBase - { - [Test] - public void ReproduceErrorTest() - { - var restClient = new JsonServiceClient(BaseUrl); - - var errorList = restClient.Get<ErrorCollectionResponse>("error"); - Assert.That(errorList.Result.Count, Is.EqualTo(1)); - - var error = restClient.Post<ErrorResponse>("error", new Error { Id = "Test" }); - Assert.That(error, !Is.Null); - } - - [Test] - public void UseSameRestClientError() - { - var restClient = new JsonServiceClient(BaseUrl); - var errorList = restClient.Get<ErrorCollectionResponse>("error"); - Assert.That(errorList.Result.Count, Is.EqualTo(1)); - - var error = restClient.Get<ErrorResponse>("error/Test"); - Assert.That(error, !Is.Null); - } - } - - [Route("/error")] - [Route("/error/{Id}")] - public class Error - { - public Error() - { - } - - public string Id { get; set; } - public Error Inner { get; set; } - } - - public class ErrorService : ServiceInterface.Service - { - public object Get(Error request) - { - if (request != null && !String.IsNullOrEmpty(request.Id)) - return new ErrorResponse(new Error { Id = "Test" }); - - return new ErrorCollectionResponse(new List<Error> { new Error { Id = "TestCollection" } }); - } - - public object Post(Error request) - { - return new ErrorResponse(request); - } - } - - public class ErrorResponse : IHasResponseStatus - { - public ErrorResponse(Error result) - { - Result = result; - ResponseStatus = new ResponseStatus(); - } - - public Error Result { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - public class ErrorCollectionResponse : IHasResponseStatus - { - public ErrorCollectionResponse(IList<Error> result) - { - Result = new Collection<Error>(result); - ResponseStatus = new ResponseStatus(); - } - - public Collection<Error> Result { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - + [TestFixture] + public class ErrorRestTests : IntegrationTestBase + { + [Test] + public void ReproduceErrorTest() + { + var restClient = new JsonServiceClient(BaseUrl); + + var errorList = restClient.Get<ErrorCollectionResponse>("error"); + Assert.That(errorList.Result.Count, Is.EqualTo(1)); + + var error = restClient.Post<ErrorResponse>("error", new Error { Id = "Test" }); + Assert.That(error, !Is.Null); + } + + [Test] + public void UseSameRestClientError() + { + var restClient = new JsonServiceClient(BaseUrl); + var errorList = restClient.Get<ErrorCollectionResponse>("error"); + Assert.That(errorList.Result.Count, Is.EqualTo(1)); + + var error = restClient.Get<ErrorResponse>("error/Test"); + Assert.That(error, !Is.Null); + } + + [Test] + public void Handles_error_from_Filter() + { + try + { + var client = new JsonServiceClient(BaseUrl); + client.Post(new ActionError { Id = "ActionError" }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(500)); + Assert.That(ex.StatusDescription, Is.EqualTo("NullReferenceException")); + Assert.That(ex.Message, Is.EqualTo("Object reference not set to an instance of an object.")); + } + } + + [Test] + public void Handles_error_from_Filter_async() + { + try + { + var client = new JsonServiceClient(BaseUrl); + client.PostAsync(new ActionError { Id = "ActionError" }).Wait(); + } + catch (AggregateException aex) + { + var ex = (WebServiceException)aex.UnwrapIfSingleException(); + Assert.That(ex.StatusCode, Is.EqualTo(500)); + Assert.That(ex.StatusDescription, Is.EqualTo("NullReferenceException")); + Assert.That(ex.Message, Is.EqualTo("Object reference not set to an instance of an object.")); + } + } + + [Test] + public void Does_handle_304_NotModified_Response() + { + var client = new JsonServiceClient(BaseUrl); + try + { + var response = client.Get(new EchoCustomResponse + { + StatusCode = (int)HttpStatusCode.NotModified, + StatusDescription = "NotModified", + Body = "NOT MODIFIED" + }); + + Assert.Fail("304 Throws"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("NotModified")); + } + } + + [Test] + public void Does_handle_304_NotModified_Response_JsonHttpClient() + { + var client = new JsonHttpClient(BaseUrl); + try + { + var response = client.Get(new EchoCustomResponse + { + StatusCode = (int)HttpStatusCode.NotModified, + StatusDescription = "NotModified", + Body = "NOT MODIFIED" + }); + + Assert.Fail("304 Throws"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo("NotModified")); + } + } + + [Test] + public void Does_handle_304_NotModified_Response_HttpUtils() + { + var url = BaseUrl.CombineWith("/customresponse/304?StatusDescription=NotModified&Body=NOT+MODIFIED"); + try + { + var response = url.GetStringFromUrl(); + + Assert.Fail("304 Throws"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.NotModified)); + } + } + } + + [Route("/error")] + [Route("/error/{Id}")] + public class Error + { + public Error() + { + } + + public string Id { get; set; } + public Error Inner { get; set; } + } + + [Route("/actionerror")] + public class ActionError : IReturn<ActionError> + { + public string Id { get; set; } + } + + public class ActionErrorFilter : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + throw new NullReferenceException(); + } + } + + public class ErrorService : Service + { + public object Get(Error request) + { + if (!string.IsNullOrEmpty(request?.Id)) + return new ErrorResponse(new Error { Id = "Test" }); + + return new ErrorCollectionResponse(new List<Error> { new Error { Id = "TestCollection" } }); + } + + public object Post(Error request) + { + return new ErrorResponse(request); + } + + [ActionErrorFilter] + public object Any(ActionError request) + { + return new ActionError(); + } + + public async Task<string> Any(EchoCustomResponse request) + { + base.Response.StatusCode = request.StatusCode; + base.Response.StatusDescription = request.StatusDescription; + base.Response.ContentType = request.ContentType ?? MimeTypes.PlainText; + + if (request.Body != null) + await base.Response.WriteAsync(request.Body); + + base.Response.EndRequest(skipHeaders:true); + + return request.Body; + } + } + + public class ErrorResponse : IHasResponseStatus + { + public ErrorResponse(Error result) + { + Result = result; + ResponseStatus = new ResponseStatus(); + } + + public Error Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class ErrorCollectionResponse : IHasResponseStatus + { + public ErrorCollectionResponse(IList<Error> result) + { + Result = new Collection<Error>(result); + ResponseStatus = new ResponseStatus(); + } + + public Collection<Error> Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + + [Route("/customresponse/{StatusCode}")] + public class EchoCustomResponse : IReturn<string> + { + public int StatusCode { get; set; } + public string StatusDescription { get; set; } + public string ContentType { get; set; } + public string Body { get; set; } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ExampleConfig.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ExampleConfig.cs index ad8287b3d8b..29a02882737 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ExampleConfig.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ExampleConfig.cs @@ -1,4 +1,3 @@ -using ServiceStack.Common.Utils; using ServiceStack.Configuration; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests @@ -12,7 +11,7 @@ public class ExampleConfig public ExampleConfig() { } - public ExampleConfig(IResourceManager appConfig) + public ExampleConfig(IAppSettings appConfig) { ConnectionString = appConfig.GetString("ConnectionString"); DefaultFibonacciLimit = appConfig.Get("DefaultFibonacciLimit", 10); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs index dbd9ef6b774..4bae9a8244f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/IntegrationTestBase.cs @@ -1,63 +1,65 @@ using System; using Funq; +using NUnit.Framework; using ServiceStack.Configuration; +using ServiceStack.Data; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; using ServiceStack.OrmLite; using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceClient.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { public class IntegrationTestBase - : AppHostHttpListenerBase { - protected const string BaseUrl = "http://localhost:82/"; - - //Fiddler can debug local HTTP requests when using the hostname + protected const string BaseUrl = "http://localhost:1337/"; + + private readonly IntegrationTestAppHost appHost; + public IntegrationTestBase() + { + appHost = new IntegrationTestAppHost(); + appHost.Init(); + appHost.Start(BaseUrl); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + //Fiddler can debug local HTTP requests when using the hostname //private const string BaseUrl = "http://io:8081/"; - //private static ILog log; - - public IntegrationTestBase() - : base("ServiceStack Examples", typeof(RestMovieService).Assembly) + public class IntegrationTestAppHost : AppHostHttpListenerBase { - LogManager.LogFactory = new DebugLogFactory(); - //log = LogManager.GetLogger(GetType()); - Instance = null; - - Init(); - try - { - Start(BaseUrl); - } - catch (Exception ex) - { - Console.WriteLine("Error trying to run ConsoleHost: " + ex.Message); - } - } - - public override void Configure(Container container) - { - container.Register<IResourceManager>(new ConfigurationResourceManager()); - - container.Register(c => new ExampleConfig(c.Resolve<IResourceManager>())); - //var appConfig = container.Resolve<ExampleConfig>(); - - container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - ":memory:", //Use an in-memory database instead - false, //keep the same in-memory db connection open - SqliteOrmLiteDialectProvider.Instance)); - - Routes.Add<Movies>("/custom-movies", "GET") - .Add<Movies>("/custom-movies/genres/{Genre}") - .Add<Movie>("/custom-movies", "POST,PUT") - .Add<Movie>("/custom-movies/{Id}"); - - ConfigureDatabase.Init(container.Resolve<IDbConnectionFactory>()); - } + public IntegrationTestAppHost() + : base("ServiceStack Examples", typeof(RestMovieService).Assembly) + { + LogManager.LogFactory = new DebugLogFactory(); + } + + public override void Configure(Container container) + { +#if !NETCORE + Plugins.Add(new SoapFormat()); +#endif + container.Register<IAppSettings>(new AppSettings()); + + container.Register(c => new ExampleConfig(c.Resolve<IAppSettings>())); + //var appConfig = container.Resolve<ExampleConfig>(); + + container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + Routes.Add<Movies>("/custom-movies", "GET") + .Add<Movies>("/custom-movies/genres/{Genre}") + .Add<Movie>("/custom-movies", "POST,PUT") + .Add<Movie>("/custom-movies/{Id}"); + + ConfigureDatabase.Init(container.Resolve<IDbConnectionFactory>()); + } + } public void SendToEachEndpoint<TRes>(object request, Action<TRes> validate) { @@ -109,4 +111,4 @@ public void DeleteOnEachEndpoint<TRes>(string relativePathOrAbsoluteUri, Action< } } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs index b3dcab9b77a..bdd661cf2a9 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieRestTests.cs @@ -1,10 +1,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { @@ -16,7 +13,7 @@ public class MovieRestTests public void OnBeforeEachTest() { var jsonClient = new JsonServiceClient(BaseUrl); - jsonClient.Post<ResetMoviesResponse>("reset-movies", new ResetMovies()); + jsonClient.Post<ResetMoviesResponse>("reset-movies", new ResetMovies()); } [Test] diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs index b6d75db9d95..1caec5a9cea 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/MovieSoap11Tests.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; +#if !NETCORE using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { @@ -19,8 +15,9 @@ public void OnBeforeEachTest(){ } [Test] - public void Can_list_all_movies(){ - var response = soapClient.Send<RestMoviesResponse>(new RestMovies()); + public void Can_list_all_movies() + { + var response = soapClient.Send<RestMoviesResponse>(new GetRestMovies()); Assert.That(response.Movies, Has.Count.EqualTo(ConfigureDatabase.Top5Movies.Count)); } @@ -32,3 +29,4 @@ public void Can_ResetMovieDatabase() } } } +#endif \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/OAuthIntegrationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/OAuthIntegrationTests.cs new file mode 100644 index 00000000000..69ba6a69af9 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/OAuthIntegrationTests.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Auth; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests +{ + [Ignore("Integration Test")] + public class OAuthIntegrationTests + { + private Dictionary<string,string> AccessTokens { get; set; } + + public OAuthIntegrationTests() + { + AccessTokens = "~/App_Data/accesstokens.txt".MapProjectPath() + .ReadAllText() + .ParseKeyValueText(delimiter:" "); + } + + [Test] + public void Can_authenticate_twitter_with_AccessToken() + { + var client = new JsonServiceClient("http://localhost:11001/"); + + var request = new Authenticate + { + provider = TwitterAuthProvider.Name, + AccessToken = "2931572242-zmVKk5leFHJXJWRUpQqyEkdlRlNbDMjNlUcXViJ", + AccessTokenSecret = AccessTokens[TwitterAuthProvider.Name] + }; + + var response = client.Post(request); + + response.PrintDump(); + + Assert.That(response.UserId, Is.Not.Null); + Assert.That(response.SessionId, Is.Not.Null); + Assert.That(response.DisplayName, Is.EqualTo("TechStacks")); + } + + [Test] + public void Can_authenticate_facebook_with_AccessToken() + { + var client = new JsonServiceClient("http://localhost:11001/"); + + var request = new Authenticate + { + provider = FacebookAuthProvider.Name, + AccessToken = AccessTokens[FacebookAuthProvider.Name], + }; + + var response = client.Post(request); + + response.PrintDump(); + + Assert.That(response.UserId, Is.Not.Null); + Assert.That(response.SessionId, Is.Not.Null); + Assert.That(response.DisplayName, Is.EqualTo("Demis Bellot")); + } + + [Test] + public void Can_authenticate_github_with_AccessToken() + { + var client = new JsonServiceClient("http://localhost:11001/"); + + var request = new Authenticate + { + provider = GithubAuthProvider.Name, + AccessToken = AccessTokens[GithubAuthProvider.Name], + }; + + var response = client.Post(request); + + response.PrintDump(); + + Assert.That(response.UserId, Is.Not.Null); + Assert.That(response.SessionId, Is.Not.Null); + Assert.That(response.UserName, Is.EqualTo("mythz")); + Assert.That(response.DisplayName, Is.EqualTo("Demis Bellot")); + } + + [Test] + public void Can_authenticate_GoogleOAuth2_with_AccessToken() + { + //var client = new JsonServiceClient("http://localhost:11001/"); + var client = new JsonServiceClient("http://localhost:1337/"); + + var request = new Authenticate + { + provider = "GoogleOAuth", + AccessToken = AccessTokens["GoogleOAuth"], + }; + + var response = client.Post(request); + + response.PrintDump(); + + Assert.That(response.UserId, Is.Not.Null); + Assert.That(response.SessionId, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabase.cs index 262a320ea76..58f1f43b862 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabase.cs @@ -1,6 +1,7 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabaseService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabaseService.cs index 514243add34..374d2da9ed3 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabaseService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovieDatabaseService.cs @@ -1,12 +1,8 @@ -using System; -using ServiceStack.ServiceHost; - namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { - public class ResetMovieDatabaseService - : IService<ResetMovieDatabase> + public class ResetMovieDatabaseService : IService { - public object Execute(ResetMovieDatabase request) + public object Any(ResetMovieDatabase request) { return new ResetMovieDatabaseResponse(); } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovies.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovies.cs index 66c058cc468..42fe735a944 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovies.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/ResetMovies.cs @@ -1,8 +1,6 @@ using System.ComponentModel; using System.Runtime.Serialization; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Data; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { @@ -23,9 +21,9 @@ public ResetMoviesResponse() public ResponseStatus ResponseStatus { get; set; } } - public class ResetMoviesService : ServiceInterface.Service + public class ResetMoviesService : Service { - public object OnPost(ResetMovies request) + public object Post(ResetMovies request) { ConfigureDatabase.Init(TryResolve<IDbConnectionFactory>()); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs index b2c4fb7f257..9a5ed31053b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovie.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; /* * Examples of preliminery REST method support in ServiceStack @@ -12,14 +9,24 @@ namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { [DataContract(Namespace = ExampleConfig.DefaultNamespace)] [Route("/restmovies/{Id}")] - public class RestMovies - { - [DataMember(EmitDefaultValue = false)] - public string Id { get; set; } - - [DataMember(EmitDefaultValue = false)] - public RestMovie Movie { get; set; } - } + public class RestMovies + { + [DataMember(EmitDefaultValue = false)] + public string Id { get; set; } + + [DataMember(EmitDefaultValue = false)] + public RestMovie Movie { get; set; } + } + + [DataContract(Namespace = ExampleConfig.DefaultNamespace)] + public class GetRestMovies //For SOAP + { + [DataMember(EmitDefaultValue = false)] + public string Id { get; set; } + + [DataMember(EmitDefaultValue = false)] + public RestMovie Movie { get; set; } + } [DataContract(Namespace = ExampleConfig.DefaultNamespace)] public class RestMoviesResponse diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovieService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovieService.cs index e4e71cc28ae..7aa08e500d3 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovieService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IntegrationTests/RestMovieService.cs @@ -1,69 +1,66 @@ -using System; -using System.Collections.Generic; +using ServiceStack.Data; using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests.IntegrationTests { - /// <summary> - /// An example of a very basic web service - /// </summary> - public class RestMovieService - : IService<RestMovies> - , IRestGetService<RestMovies> - , IRestPutService<RestMovies> - , IRestPostService<RestMovies> - , IRestDeleteService<RestMovies> - , IRequiresRequestContext - { - public IRequestContext RequestContext { get; set; } + /// <summary> + /// An example of a very basic web service + /// </summary> + public class RestMovieService + : IService, IRequiresRequest + { + public IRequest Request { get; set; } - public IDbConnectionFactory DbFactory { get; set; } + public IDbConnectionFactory DbFactory { get; set; } - public object Execute(RestMovies request) - { - return Get(request); - } + public object Any(GetRestMovies request) + { + return Get(request.ConvertTo<RestMovies>()); + } - public object Get(RestMovies request) - { - var response = new RestMoviesResponse(); + public object Get(RestMovies request) + { + var response = new RestMoviesResponse(); - DbFactory.Run(db => - { - if (request.Id != null) - { - var movie = db.GetByIdOrDefault<RestMovie>(request.Id); - if (movie != null) - { - response.Movies.Add(movie); - } - } - else - { - response.Movies = db.Select<RestMovie>(); - } - }); + using (var db = DbFactory.Open()) + { + if (request.Id != null) + { + var movie = db.SingleById<RestMovie>(request.Id); + if (movie != null) + { + response.Movies.Add(movie); + } + } + else + { + response.Movies = db.Select<RestMovie>(); + } + }; - return response; - } + return response; + } - public object Put(RestMovies request) - { - DbFactory.Run(db => db.Save(request.Movie)); - return new RestMoviesResponse(); - } + public object Put(RestMovies request) + { + using (var db = DbFactory.Open()) + db.Save(request.Movie); + return new RestMoviesResponse(); + } - public object Delete(RestMovies request) - { - DbFactory.Run(db => db.DeleteById<RestMovie>(request.Id)); - return new RestMoviesResponse(); - } + public object Delete(RestMovies request) + { + using (var db = DbFactory.Open()) + db.DeleteById<RestMovie>(request.Id); + return new RestMoviesResponse(); + } - public object Post(RestMovies request) - { - DbFactory.Run(db => db.Update(request.Movie)); - return new RestMoviesResponse(); - } - } + public object Post(RestMovies request) + { + using (var db = DbFactory.Open()) + db.Update(request.Movie); + return new RestMoviesResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/InvalidRequests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/InvalidRequests.cs new file mode 100644 index 00000000000..63f16444818 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/InvalidRequests.cs @@ -0,0 +1,58 @@ +using System; +using System.Net; +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class InvalidRequests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(InvalidRequests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + DebugMode = false + }); + } + } + + private readonly ServiceStackHost appHost; + public InvalidRequests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Invalid_Request_does_not_return_StackTrace_when_not_DebugMode() + { + try + { + var response = Config.ListeningOn.CombineWith("*|?") + .GetJsonFromUrl(); + + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.NotFound)); + + if (ex is WebException webEx) + { + var errorBody = webEx.GetResponseBody(); + Assert.That(errorBody.ToLower(), Does.Not.Contain("stacktrace")); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/IocServiceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/IocServiceTests.cs index d0a9ebb0552..6cbb04b1724 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/IocServiceTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/IocServiceTests.cs @@ -1,102 +1,212 @@ using System; using System.Collections.Generic; +using System.Net; using System.Threading; +using Funq; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.ServiceClient.Web; +using ServiceStack.Common.Tests; +using ServiceStack.Configuration; +using ServiceStack.Shared.Tests; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; -using ServiceStack.WebHost.Endpoints.Tests.Support.Services; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class IocServiceTests - { - private const string ListeningOn = "http://localhost:1082/"; - - private const int WaitForRequestCleanup = 100; - + public class IocAppHost : AppHostHttpListenerBase + { + public IocAppHost() + : base("IocApp Service", typeof(IocService).Assembly) { } + + public override void Configure(Container container) + { + IocShared.Configure(this); + } + + public override void Release(object instance) + { + ((IRelease)Container.Adapter).Release(instance); + } + + public override void OnEndRequest(IRequest request = null) + { + base.OnEndRequest(request); + } + + public override object OnPreExecuteServiceFilter(IService service, object request, IRequest httpReq, IResponse httpRes) + { + if (service is IocScopeService) + service.InjectRequestIntoDependencies(httpReq); + return request; + } + } + +#if !NETCORE + [Ignore("Causes dll conflicts in ASP.NET Host projects when run from this test project")] + public class IocServiceAspNetTests : IocServiceTests + { + public override IServiceClient CreateClient(ResetIoc request = null) + { + var client = new JsonServiceClient(Config.AspNetServiceStackBaseUri); + using(client.Post<HttpWebResponse>(request ?? new ResetIoc())){} + return client; + } + } +#endif + + public class IocServiceHttpListenerTests : IocServiceTests + { + private const string ListeningOn = "http://localhost:1082/"; + IocAppHost appHost; - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new IocAppHost(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - if (appHost != null) - { - appHost.Dispose(); - appHost = null; - } - } - - [Test] - public void Can_resolve_all_dependencies() - { - var restClient = new JsonServiceClient(ListeningOn); - try - { - var response = restClient.Get<IocResponse>("ioc"); - var expected = new List<string> { - typeof(FunqDepCtor).Name, - typeof(AltDepCtor).Name, - typeof(FunqDepProperty).Name, - typeof(FunqDepDisposableProperty).Name, - typeof(AltDepProperty).Name, - typeof(AltDepDisposableProperty).Name, - }; - - //Console.WriteLine(response.Results.Dump()); - Assert.That(expected.EquivalentTo(response.Results)); - } - catch (WebServiceException ex) - { - Assert.Fail(ex.ErrorMessage); - } - } - - [Test] - public void Does_dispose_service() - { - IocService.DisposedCount = 0; - IocService.ThrowErrors = false; - - var restClient = new JsonServiceClient(ListeningOn); - restClient.Get<IocResponse>("ioc"); - - Assert.That(IocService.DisposedCount, Is.EqualTo(1)); - } + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new IocAppHost(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + if (appHost != null) + { + appHost.Dispose(); + } + } + + public override IServiceClient CreateClient(ResetIoc request = null) + { + var client = new JsonServiceClient(ListeningOn); + using(client.Post<HttpWebResponse>(request ?? new ResetIoc())){} + return client; + } + } + + [TestFixture] + public abstract class IocServiceTests + { + private const int WaitForRequestCleanup = 200; + + public abstract IServiceClient CreateClient(ResetIoc request = null); + + [Test] + public void Can_resolve_all_dependencies() + { + var client = CreateClient(); + try + { + var response = client.Get<IocResponse>("ioc"); + var expected = new List<string> { + typeof(FunqDepCtor).Name, + typeof(AltDepCtor).Name, + typeof(FunqDepProperty).Name, + typeof(FunqDepDisposableProperty).Name, + typeof(AltDepProperty).Name, + typeof(AltDepDisposableProperty).Name, + }; + + //Console.WriteLine(response.Results.Dump()); + Assert.That(expected.EquivalentTo(response.Results)); + } + catch (WebServiceException ex) + { + Assert.Fail(ex.ErrorMessage); + } + } + + [Test] + public void Can_resolve_all_dependencies_Async() + { + var client = CreateClient(); + try + { + var response = client.Get<IocResponse>("iocasync"); + var expected = new List<string> { + typeof(FunqDepCtor).Name, + typeof(AltDepCtor).Name, + typeof(FunqDepProperty).Name, + typeof(FunqDepDisposableProperty).Name, + typeof(AltDepProperty).Name, + typeof(AltDepDisposableProperty).Name, + }; + + //Console.WriteLine(response.Results.Dump()); + Assert.That(expected.EquivalentTo(response.Results)); + } + catch (WebServiceException ex) + { + Assert.Fail(ex.ErrorMessage); + } + } + + [Test] + public void Does_dispose_service() + { + var client = CreateClient(); + client.Get<IocResponse>("ioc"); + + var stats = client.Get(new IocStats()); + Assert.That(stats.IocService_DisposeCount, Is.EqualTo(1)); + } + + [Test] + public void Does_dispose_service_Async() + { + var client = CreateClient(); + client.Get<IocResponse>("iocasync"); + + var stats = client.Get(new IocStats()); + Assert.That(stats.IocService_DisposeCount, Is.EqualTo(1)); + } [Test] public void Does_dispose_service_when_there_is_an_error() { - IocService.DisposedCount = 0; - IocService.ThrowErrors = true; + var client = CreateClient(new ResetIoc { ThrowErrors = true }); + Assert.Throws<WebServiceException>(() => client.Get<IocResponse>("ioc")); + + var stats = client.Get(new IocStats()); + Assert.That(stats.IocService_DisposeCount, Is.EqualTo(1)); + } - var restClient = new JsonServiceClient(ListeningOn); - Assert.Throws<WebServiceException>(() => restClient.Get<IocResponse>("ioc")); + [Test] + public void Does_dispose_service_when_there_is_an_error_Async() + { + var client = CreateClient(new ResetIoc { ThrowErrors = true }); + Assert.Throws<WebServiceException>(() => client.Get<IocResponse>("iocasync")); - Assert.That(IocService.DisposedCount, Is.EqualTo(1)); + var stats = client.Get(new IocStats()); + Assert.That(stats.IocService_DisposeCount, Is.EqualTo(1)); } [Test] public void Does_create_correct_instances_per_scope() { - FunqRequestScopeDepDisposableProperty.DisposeCount = 0; - AltRequestScopeDepDisposableProperty.DisposeCount = 0; + var client = CreateClient(); + var response1 = client.Get<IocScopeResponse>("iocscope"); + var response2 = client.Get<IocScopeResponse>("iocscope"); - var restClient = new JsonServiceClient(ListeningOn); - var response1 = restClient.Get<IocScopeResponse>("iocscope"); - var response2 = restClient.Get<IocScopeResponse>("iocscope"); + Assert.That(response2.Results[typeof(FunqSingletonScope).Name], Is.EqualTo(1)); + Assert.That(response2.Results[typeof(FunqRequestScope).Name], Is.EqualTo(2)); + Assert.That(response2.Results[typeof(FunqNoneScope).Name], Is.EqualTo(4)); + + Assert.That(response2.InjectsRequest, Is.EqualTo(2)); + + Thread.Sleep(WaitForRequestCleanup); + + var stats = client.Get(new IocStats()); + Assert.That(stats.FunqRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.AltRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + } - response1.PrintDump(); + [Test] + public void Does_create_correct_instances_per_scope_Async() + { + var client = CreateClient(); + var response1 = client.Get<IocScopeResponse>("iocscopeasync"); + var response2 = client.Get<IocScopeResponse>("iocscopeasync"); Assert.That(response2.Results[typeof(FunqSingletonScope).Name], Is.EqualTo(1)); Assert.That(response2.Results[typeof(FunqRequestScope).Name], Is.EqualTo(2)); @@ -104,46 +214,69 @@ public void Does_create_correct_instances_per_scope() Thread.Sleep(WaitForRequestCleanup); - Assert.That(FunqRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - Assert.That(AltRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); + var stats = client.Get(new IocStats()); + Assert.That(stats.FunqRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.AltRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); } [Test] public void Does_create_correct_instances_per_scope_with_exception() { - FunqRequestScopeDepDisposableProperty.DisposeCount = 0; - AltRequestScopeDepDisposableProperty.DisposeCount = 0; + var client = CreateClient(); + try + { + client.Get<IocScopeResponse>("iocscope?Throw=true"); + } + catch { } + try + { + client.Get<IocScopeResponse>("iocscope?Throw=true"); + } + catch { } - var restClient = new JsonServiceClient(ListeningOn); - try { - restClient.Get<IocScopeResponse>("iocscope?Throw=true"); - } catch { } - try { - restClient.Get<IocScopeResponse>("iocscope?Throw=true"); - } catch { } + Thread.Sleep(WaitForRequestCleanup); + + var stats = client.Get(new IocStats()); + Assert.That(stats.FunqRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.AltRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + } + + [Test] + public void Does_create_correct_instances_per_scope_with_exception_Async() + { + var client = CreateClient(); + try + { + client.Get<IocScopeResponse>("iocscopeasync?Throw=true"); + } + catch { } + try + { + client.Get<IocScopeResponse>("iocscopeasync?Throw=true"); + } + catch { } Thread.Sleep(WaitForRequestCleanup); - Assert.That(FunqRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - Assert.That(AltRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); + var stats = client.Get(new IocStats()); + Assert.That(stats.FunqRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.AltRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); } - [Test] - public void Does_AutoWire_ActionLevel_RequestFilters() - { + [Test] + public void Does_AutoWire_ActionLevel_RequestFilters() + { try { - var client = new JsonServiceClient(ListeningOn); + var client = CreateClient(); var response = client.Get(new ActionAttr()); var expected = new List<string> { - typeof(FunqDepProperty).Name, - typeof(FunqDepDisposableProperty).Name, - typeof(AltDepProperty).Name, - typeof(AltDepDisposableProperty).Name, - }; - - response.Results.PrintDump(); + typeof(FunqDepProperty).Name, + typeof(FunqDepDisposableProperty).Name, + typeof(AltDepProperty).Name, + typeof(AltDepDisposableProperty).Name, + }; Assert.That(expected.EquivalentTo(response.Results)); @@ -155,36 +288,69 @@ public void Does_AutoWire_ActionLevel_RequestFilters() } } - private static void ResetDisposables() + [Test] + public void Does_AutoWire_ActionLevel_RequestFilters_Async() { - IocService.DisposedCount = - IocDisposableService.DisposeCount = - FunqSingletonScopeDisposable.DisposeCount = - FunqRequestScopeDisposable.DisposeCount = - FunqNoneScopeDisposable.DisposeCount = - FunqRequestScopeDepDisposableProperty.DisposeCount = - AltRequestScopeDepDisposableProperty.DisposeCount = - 0; + try + { + var client = CreateClient(); + var response = client.Get(new ActionAttrAsync()); + + var expected = new List<string> { + typeof(FunqDepProperty).Name, + typeof(FunqDepDisposableProperty).Name, + typeof(AltDepProperty).Name, + typeof(AltDepDisposableProperty).Name, + }; + + Assert.That(expected.EquivalentTo(response.Results)); + + } + catch (Exception ex) + { + ex.Message.Print(); + throw; + } } [Test] public void Does_dispose_service_and_Request_and_None_scope_but_not_singletons() { - ResetDisposables(); + var client = CreateClient(); + + var response = client.Get(new IocDispose()); + response = client.Get(new IocDispose()); + Thread.Sleep(WaitForRequestCleanup); + + var stats = client.Get(new IocStats()); + Assert.That(stats.Container_disposablesCount, Is.EqualTo(0)); + Assert.That(stats.FunqSingletonScopeDisposable_DisposeCount, Is.EqualTo(0)); + + Assert.That(stats.IocDisposableService_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.FunqRequestScopeDisposable_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.FunqNoneScopeDisposable_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.FunqRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.AltRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + } + + [Test] + public void Does_dispose_service_and_Request_and_None_scope_but_not_singletons_Async() + { + var client = CreateClient(); - var restClient = new JsonServiceClient(ListeningOn); - var response = restClient.Get(new IocDispose()); - response = restClient.Get(new IocDispose()); + var response = client.Get(new IocDisposeAsync()); + response = client.Get(new IocDisposeAsync()); Thread.Sleep(WaitForRequestCleanup); - Assert.That(appHost.Container.disposablesCount, Is.EqualTo(0)); - Assert.That(FunqSingletonScopeDisposable.DisposeCount, Is.EqualTo(0)); + var stats = client.Get(new IocStats()); + Assert.That(stats.Container_disposablesCount, Is.EqualTo(0)); + Assert.That(stats.FunqSingletonScopeDisposable_DisposeCount, Is.EqualTo(0)); - Assert.That(IocDisposableService.DisposeCount, Is.EqualTo(2)); - Assert.That(FunqRequestScopeDisposable.DisposeCount, Is.EqualTo(2)); - Assert.That(FunqNoneScopeDisposable.DisposeCount, Is.EqualTo(2)); - Assert.That(FunqRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); - Assert.That(AltRequestScopeDepDisposableProperty.DisposeCount, Is.EqualTo(2)); + Assert.That(stats.IocDisposableService_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.FunqRequestScopeDisposable_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.FunqNoneScopeDisposable_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.FunqRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); + Assert.That(stats.AltRequestScopeDepDisposableProperty_DisposeCount, Is.EqualTo(2)); } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/AutoQueryIssues.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/AutoQueryIssues.cs new file mode 100644 index 00000000000..59389eb965f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/AutoQueryIssues.cs @@ -0,0 +1,192 @@ +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [Route("/query/employees/{Id}", "GET")] + public class QueryEmployee : QueryDb<Employee> + { + public string Id { get; set; } + } + + [Route("/query/employees", "GET")] + public class QueryEmployees : QueryDb<Employee>, IJoin<Employee, Department> { } + + public class Employee + { + [PrimaryKey] + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + [References(typeof(Department))] + public int DepartmentId { get; set; } + + [DataAnnotations.Ignore] + public Department Department { get; set; } + } + + public class Department + { + [PrimaryKey] + public int Id { get; set; } + public string Name { get; set; } + } + + public class AutoQueryJoinReferenceId + { + private static readonly Department[] SeedDepartments = new[] + { + new Department { Id = 10, Name = "Dept 1" }, + new Department { Id = 20, Name = "Dept 2" }, + new Department { Id = 30, Name = "Dept 3" }, + }; + + public static Employee[] SeedEmployees = new[] + { + new Employee { Id = 1, DepartmentId = 10, FirstName = "First 1", LastName = "Last 1" }, + new Employee { Id = 2, DepartmentId = 20, FirstName = "First 2", LastName = "Last 2" }, + new Employee { Id = 3, DepartmentId = 30, FirstName = "First 3", LastName = "Last 3" }, + }; + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ClientMemoryLeak), typeof(AutoQueryJoinReferenceId).Assembly) {} + + public override void Configure(Container container) + { + ScriptContext.ScriptMethods.AddRange(new ScriptMethods[] { + new DbScriptsAsync(), + new MyValidators(), + }); + + SetConfig(new HostConfig{ UseCamelCase = true}); + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + //var dbFactory = new OrmLiteConnectionFactory(Tests.Config.SqlServerConnString, SqlServerDialect.Provider); + container.Register<IDbConnectionFactory>(dbFactory); + + Plugins.Add(new AutoQueryFeature { MaxLimit = 100 }); + + using (var db = container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropTable<Employee>(); + db.DropTable<Department>(); + db.CreateTable<Department>(); + db.CreateTable<Employee>(); + + db.InsertAll(SeedDepartments); + db.InsertAll(SeedEmployees); + } + } + } + + public IServiceClient client; + private readonly ServiceStackHost appHost; + public AutoQueryJoinReferenceId() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + + client = new JsonServiceClient(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_only_populate_selected_fields() + { + QueryResponse<Employee> response; + response = client.Get(new QueryEmployees { Fields = "id,departmentid" }); + response.PrintDump(); + Assert.That(response.Results.All(x => x.Id > 0 && x.Id < 10)); + Assert.That(response.Results.All(x => x.DepartmentId >= 10)); + + response = client.Get(new QueryEmployees { Fields = "departmentid" }); + response.PrintDump(); + Assert.That(response.Results.All(x => x.Id == 0)); + Assert.That(response.Results.All(x => x.DepartmentId >= 10)); + } + + public partial class CustomFields + { + [Required] + [PrimaryKey] + [CustomField("CHAR(20)")] + public string StringId { get; set; } + [Required] + [CustomField("TINYINT")] + public byte Byte { get; set; } + } + + [Route("/Queries/CustomFields", "GET")] + public partial class CustomFieldsQuery + : QueryDb<CustomFields>, IReturn<QueryResponse<CustomFields>> + { + public CustomFieldsQuery() + { + StringIdBetween = new string[] { }; + StringIdIn = new string[] { }; + ByteBetween = new byte[] { }; + ByteIn = new byte[] { }; + } + + public virtual string StringId { get; set; } + public virtual string StringIdStartsWith { get; set; } + public virtual string StringIdEndsWith { get; set; } + public virtual string StringIdContains { get; set; } + public virtual string StringIdLike { get; set; } + public virtual string[] StringIdBetween { get; set; } + public virtual string[] StringIdIn { get; set; } + public virtual byte? Byte { get; set; } + public virtual byte? ByteGreaterThanOrEqualTo { get; set; } + public virtual byte? ByteGreaterThan { get; set; } + public virtual byte? ByteLessThan { get; set; } + public virtual byte? ByteLessThanOrEqualTo { get; set; } + public virtual byte? ByteNotEqualTo { get; set; } + public virtual byte[] ByteBetween { get; set; } + public virtual byte[] ByteIn { get; set; } + } + + [Test] + public void Can_query_Table_with_Byte_property() + { + using (var db = appHost.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<CustomFields>(); + db.Insert(new CustomFields { StringId = "1001", Byte = 1 }); + db.Insert(new CustomFields { StringId = "1002", Byte = 2 }); + } + + var response = client.Get(new CustomFieldsQuery + { + StringIdIn = new[] { "1001", "1002" }, + }); + Assert.That(response.Results.Map(x => x.Byte), Is.EquivalentTo(new[] { 1, 2 })); + + response = client.Get(new CustomFieldsQuery + { + StringIdIn = new[] { "1001", "1002" }, + Byte = 2 + }); + Assert.That(response.Results.Map(x => x.Byte), Is.EquivalentTo(new[] { (byte)2 })); + + response = client.Get(new CustomFieldsQuery + { + ByteIn = new byte[] { 1, 2 } + }); + Assert.That(response.Results.Map(x => x.Byte), Is.EquivalentTo(new[] { 1, 2 })); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ClientMemoryLeak.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ClientMemoryLeak.cs new file mode 100644 index 00000000000..cf1c0717f50 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ClientMemoryLeak.cs @@ -0,0 +1,123 @@ +using System.Diagnostics; +using System.Reflection; +using Funq; +using NUnit.Framework; +using System.Collections.Generic; +using System.Net; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [Ignore("Regression Test")] + [TestFixture] + public class ClientMemoryLeak + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(typeof(ClientMemoryLeak).Name, typeof(LeakServices).Assembly) + { } + + public override void Configure(Container container) { } + } + + private readonly ServiceStackHost appHost; + public ClientMemoryLeak() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TearDown() + { + appHost.Dispose(); + } + + [Route("/leak/{Name}")] + public class LeakRequest : IReturn<LeakRequest> + { + public string Name { get; set; } + } + + public class LeakServices : Service + { + public object Any(LeakRequest request) + { + return request; + } + } + + [Test] + public void Run_GET_dto_in_loop() + { + var client = new JsonServiceClient(Config.ListeningOn); + + client.Get(new LeakRequest { Name = "warmup" }); + + var sw = Stopwatch.StartNew(); + var elapsedTicks = new List<double> { sw.ElapsedMilliseconds }; + + for (int i = 0; i < 10001; i++) + { + var response = client.Get(new LeakRequest { Name = "request" + i }); + Assert.That(response.Name, Is.EqualTo("request" + i)); + elapsedTicks.Add(sw.ElapsedTicks); + } + + for (int i = 0; i < 10001; i += 1000) + { + "Elapsed Time: {0} ticks for Request at: #{1}".Print( + elapsedTicks[i + 1] - elapsedTicks[i], i); + } + } + + [Test] + public void Run_GET_url_in_loop() + { + var client = new JsonServiceClient(Config.ListeningOn); + + client.Get(new LeakRequest { Name = "warmup" }); + + var sw = Stopwatch.StartNew(); + var elapsedTicks = new List<double> { sw.ElapsedMilliseconds }; + + for (int i = 0; i < 10001; i++) + { + var response = client.Get<LeakRequest>("/leak/request" + i); + Assert.That(response.Name, Is.EqualTo("request" + i)); + elapsedTicks.Add(sw.ElapsedTicks); + } + + for (int i = 0; i < 10001; i += 1000) + { + "Elapsed Time: {0} ticks for Request at: #{1}".Print( + elapsedTicks[i + 1] - elapsedTicks[i], i); + } + } + + [Test] + public void Run_GET_url_HttpWebResponse_in_loop() + { + var client = new JsonServiceClient(Config.ListeningOn); + + client.Get(new LeakRequest { Name = "warmup" }); + + var sw = Stopwatch.StartNew(); + var elapsedTicks = new List<double> { sw.ElapsedMilliseconds }; + + for (int i = 0; i < 10001; i++) + { + using (HttpWebResponse response = client.Get<HttpWebResponse>("/leak/request" + i)) {} + elapsedTicks.Add(sw.ElapsedTicks); + } + + for (int i = 0; i < 10001; i += 1000) + { + "Elapsed Time: {0} ticks for Request at: #{1}".Print( + elapsedTicks[i + 1] - elapsedTicks[i], i); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/CustomPathTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/CustomPathTests.cs new file mode 100644 index 00000000000..1d665283003 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/CustomPathTests.cs @@ -0,0 +1,82 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [TestFixture] + public class CustomPathTests + { + [Test] + public void Can_make_CustomPath_Request_without_HandlerPath() + { + var apiUrl = Config.ListeningOn + "api/"; + + var appHost = new AppHostWithHandlerPath() + .Init() + .Start(apiUrl); + + JsonServiceClient serviceClient = new JsonServiceClient(apiUrl); + + var request = new Hello { Name = "ServiceStack" }; + HelloResponse response = serviceClient.Post(request); + + Assert.That(response.Result.Contains(request.Name)); + + appHost.Dispose(); + } + + [Test] + public void Can_make_CustomPath_Request_with_HandlerPath() + { + var apiUrl = Config.ListeningOn + "api/"; + + var appHost = new AppHostWithoutHandlerPath() + .Init() + .Start(apiUrl); + + JsonServiceClient serviceClient = new JsonServiceClient(apiUrl); + + var request = new Hello { Name = "ServiceStack" }; + HelloResponse response = serviceClient.Post(request); + + Assert.That(response.Result.Contains(request.Name)); + + appHost.Dispose(); + } + } + + public class AppHostWithHandlerPath : AppSelfHostBase + { + public AppHostWithHandlerPath() + : base(nameof(CustomPathTests), typeof(AppHostWithHandlerPath).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + ApiVersion = "v1", + WsdlServiceNamespace = "http://schemas.example.com/", + DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), true) + }); + } + } + + public class AppHostWithoutHandlerPath : AppSelfHostBase + { + public AppHostWithoutHandlerPath() + : base(nameof(CustomPathTests), typeof(AppHostWithoutHandlerPath).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + ApiVersion = "v1", + HandlerFactoryPath = "api", // comment this out and it works + WsdlServiceNamespace = "http://schemas.example.com/", + DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), true) + }); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/EmptyDtoIssue.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/EmptyDtoIssue.cs new file mode 100644 index 00000000000..b131b542621 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/EmptyDtoIssue.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + public class PostEmptyArray : IReturnVoid + { + public int[] Ids { get; set; } + } + + public class GetEmptyArray : IReturn<List<int>> + { + public int[] Ids { get; set; } + } + + public class TestService : Service + { + public void Post(PostEmptyArray e) + { + if (e.Ids == null) + throw new Exception(); + } + + public List<int> Get(GetEmptyArray e) + { + if (e.Ids == null) + throw new Exception(); + + return e.Ids.ToList(); + } + } + + public class EmptyDtoIssue + { + public class EmptyArrayDtoTest + { + public class AppHost : AppHostHttpListenerBase + { + public AppHost() : base(typeof(EmptyArrayDtoTest).Name, typeof(GetEmptyArray).Assembly) { } + + public override void Configure(Container container) { } + } + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_POST_empty_array() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + client.Post(new PostEmptyArray { Ids = new int[] { } }); + } + + [Test] + public void Can_GET_empty_array() + { + + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + client.Get(new GetEmptyArray { Ids = new int[] { } }); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/LoadWwwFormIssue.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/LoadWwwFormIssue.cs new file mode 100644 index 00000000000..b1a85b8b1f0 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/LoadWwwFormIssue.cs @@ -0,0 +1,71 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [Route("/wwwform")] + public class TestForm + { + public string A { get; set; } + } + + public class TestFormService : Service + { + public object Any(TestForm request) + { + using (var cmd = Db.CreateCommand()) + { + var reqAttrs = request.ToObjectDictionary(); + Db.GetDialectProvider().PrepareInsertRowStatement<TestForm>(cmd, reqAttrs); + return cmd.CommandText; + } + } + } + + public class LoadWwwFormIssue + { + public class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(LoadWwwFormIssue), typeof(TestFormService).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + } + } + + private ServiceStackHost appHost; + public LoadWwwFormIssue() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_call_wwwform() + { + string ValidResponse = $"INSERT INTO \"{nameof(TestForm)}\" (\"{nameof(TestForm.A)}\") VALUES (@{nameof(TestForm.A)})"; + + var baseUrl = Config.ListeningOn.CombineWith("wwwform"); + + var responseStr = baseUrl.PostToUrl(null);//"A=B"); + Assert.That(responseStr, Is.EqualTo(ValidResponse)); + + responseStr = baseUrl.PostToUrl("A"); + Assert.That(responseStr, Is.EqualTo(ValidResponse)); + + responseStr = baseUrl.PostStringToUrl("A=B"); + Assert.That(responseStr, Is.EqualTo(ValidResponse)); + + responseStr = baseUrl.GetStringFromUrl(); + Assert.That(responseStr, Is.EqualTo(ValidResponse)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/LocalizationIssues.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/LocalizationIssues.cs new file mode 100644 index 00000000000..3190df0f718 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/LocalizationIssues.cs @@ -0,0 +1,71 @@ +using System.Globalization; +using Funq; +using NUnit.Framework; +using ServiceStack.Common.Tests; +using ServiceStack.Host; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [Route("/test/{Id}")] + public class LocalizationTest : IReturn<LocalizationTest> + { + public string Id { get; set; } + public string Data { get; set; } + } + + public class LocalizationTestService : Service + { + public object Any(LocalizationTest request) => request; + } + + public class LocalizationIssues + { + public class AppHost : AppSelfHostBase + { + public AppHost() : base("Test", typeof(AppHost).Assembly) { } + public override void Configure(Container container) { } + } + + private ServiceStackHost appHost; + + public LocalizationIssues() + { + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("tr-TR"); + + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + appHost.Dispose(); + CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; + } + + [Test] + public void Can_resolve_routes_in_Turkish_Culture() + { + var restPath = new RestPath(typeof(LocalizationTest), "/test/{Id}"); + + foreach (var varName in new[] {"id", "ID", "Id", "iD"}) + { + //$"IsVariable({varName}) = {restPath.IsVariable(varName)}".Print(); + Assert.That(restPath.IsVariable(varName)); + } + + var request = restPath.CreateRequest("/test/3"); + } + + [Test] + public void Can_call_Service_in_Turkish_Culture() + { + var client = new JsonServiceClient(Config.ListeningOn); + var request = new LocalizationTest { Id = "foo" }; + var response = client.Get(request); + Assert.That(response.Id, Is.EqualTo(request.Id)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/NetworkIssues.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/NetworkIssues.cs new file mode 100644 index 00000000000..400b0f61b54 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/NetworkIssues.cs @@ -0,0 +1,51 @@ +using System.Net; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [Route("/wait/{ForMs}")] + public class Wait : IReturn<Wait> + { + public int ForMs { get; set; } + } + + [TestFixture, Ignore("Requires external Services")] + public class NetworkIssues + { + [Test] + public async Task Simulate_broken_Network() + { + var client = new JsonServiceClient("http://test.servicestack.net"); + + var response = await client.GetAsync(new Wait { ForMs = 50000 }); + + } + + [Route("/hello")] + public partial class Hello : IReturn<HelloResponse> + { + public virtual string Name { get; set; } + } + + public partial class HelloResponse + { + public virtual string Result { get; set; } + } + + [Test] + public void Call_TestService_through_Fiddler_Proxy() + { + var client = new JsonServiceClient("http://test.servicestack.net") { + Proxy = new WebProxy("http://localhost:8888") + }; + +// var response = await client.GetAsync(new Hello { Name = "Hello, World! 1 + 1 = 2" }); + var response = client.Get(new Hello { Name = "Hello, World! 1 + 1 = 2" }); + + response.PrintDump(); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/RequestScopeIssue.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/RequestScopeIssue.cs new file mode 100644 index 00000000000..a36c6ffb26c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/RequestScopeIssue.cs @@ -0,0 +1,72 @@ +using System.Threading; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + public class RequestScopeAppHost : AppSelfHostBase + { + public RequestScopeAppHost() + : base(typeof(RequestScopeAppHost).Name, typeof(RequestScopeService).Assembly) {} + + private static int counter = 0; + + public override void Configure(Container container) + { + container.Register(c => new MasterConfig { + Id = Interlocked.Increment(ref counter) + }).ReusedWithin(ReuseScope.Request); + } + } + + public class MasterConfig + { + public int Id { get; set; } + } + + public class GetMasterConfig : IReturn<MasterConfig> { } + + public class RequestScopeService : Service + { + private readonly MasterConfig config; + + public RequestScopeService(MasterConfig config) + { + this.config = config; + } + + public object Any(GetMasterConfig request) + { + return config; + } + } + + [TestFixture] + public class RequestScopeIssue + { + private readonly ServiceStackHost appHost; + + public RequestScopeIssue() + { + appHost = new RequestScopeAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_get_RequestScope_dependency() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + Assert.That(client.Get(new GetMasterConfig()).Id, Is.EqualTo(1)); + Assert.That(client.Get(new GetMasterConfig()).Id, Is.EqualTo(2)); + Assert.That(client.Get(new GetMasterConfig()).Id, Is.EqualTo(3)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ResponseFilterHeadersIssue.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ResponseFilterHeadersIssue.cs new file mode 100644 index 00000000000..1c287ac60fb --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ResponseFilterHeadersIssue.cs @@ -0,0 +1,74 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + public class ResponseFilterHeadersIssue + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ResponseFilterHeadersIssue), typeof(ResponseFilterHeadersIssue).Assembly) { } + public override void Configure(Container container) + { +// Config.GlobalResponseHeaders.Remove(HttpHeaders.Vary); + + SetConfig(new HostConfig { + GlobalResponseHeaders = { + [HttpHeaders.Vary] = "accept,origin,authorization" + } + }); + } + } + + private readonly ServiceStackHost appHost; + public ResponseFilterHeadersIssue() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void ResponseFilterIShouldHaveVaryFilterTest() + { + using (var client = new JsonHttpClient(Config.ListeningOn)) + { + client.ResponseFilter = message => + { + var headers = message.Headers.Vary.Join(","); + Assert.That(headers, Is.EqualTo("accept,origin,authorization")); + Assert.That(message.Headers.CacheControl.ToString(), Is.EqualTo("no-cache")); + }; + + var response = client.Get(new ResponseFilterWithVaryRequest()); + Assert.That(response, Is.EqualTo("Should have vary headers.")); + } + } + } + + [NoCacheResponseFilter] + public class ResponseFilterService : Service + { + public object Get(ResponseFilterWithVaryRequest withVaryRequest) + { + return "Should have vary headers."; + } + } + + public class ResponseFilterWithVaryRequest: IGet, IReturn<string> + { + } + + public class NoCacheResponseFilterAttribute : ResponseFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object responseDto) + { + res.AddHeader("Cache-Control", "no-cache"); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/SerializationIssues.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/SerializationIssues.cs new file mode 100644 index 00000000000..b1f110b7295 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/SerializationIssues.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Reflection; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + [Route("/confirmations", "PUT")] + public class PutConfirmed : IReturn<PutConfirmedResponse> + { + public List<Confirmation> Confirmations { get; set; } + } + + public class Confirmation + { + public Confirmation() + { + ChangeId = 0; + Confirmed = false; + } + public int ChangeId { get; set; } + public bool Confirmed { get; set; } + } + + public class PutConfirmedResponse + { + public bool IsSucceed { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class SerializationIssuesService : Service + { + public object Put(PutConfirmed request) => new PutConfirmedResponse + { + IsSucceed = request.Confirmations[0].Confirmed && request.Confirmations[0].ChangeId == 126552616 + }; + } + + public class SerializationIssues + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(SerializationIssues), typeof(SerializationIssuesService).Assembly) + { + } + + public override void Configure(Container container) + { + } + } + + private readonly ServiceStackHost appHost; + + public SerializationIssues() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_serialize_request() + { + var client = new JsonHttpClient(Config.ListeningOn); + + var response = client.Put(new PutConfirmed + { + Confirmations = new List<Confirmation> + { + new Confirmation + { + ChangeId = 126552616, + Confirmed = true, + } + } + }); + + Assert.That(response.IsSucceed); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ServiceExceptionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ServiceExceptionTests.cs new file mode 100644 index 00000000000..489a9987ece --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/ServiceExceptionTests.cs @@ -0,0 +1,93 @@ +using System; +using System.Reflection; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + public class ThrowSync : IReturn<ThrowSync> { } + public class ThrowAsync : IReturn<ThrowAsync> { } + + public class ServiceExceptionServices : Service + { + public object Any(ThrowSync request) => + throw new WebServiceException(nameof(ThrowSync)); + + public Task<object> Any(ThrowAsync request) => + throw new WebServiceException(nameof(ThrowAsync)); + } + + public class ServiceExceptionTests + { + public static Exception ServiceEx; + public static Exception UnHandledEx; + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ServiceExceptionTests), typeof(ServiceExceptionServices).Assembly) {} + + public override void Configure(Container container) + { + ServiceExceptionHandlers.Add((req, dto, ex) => { + ServiceEx = ex; + return null; + }); + + UncaughtExceptionHandlers.Add((req, res, op, ex) => { + UnHandledEx = ex; + }); + } + } + + private readonly ServiceStackHost appHost; + public ServiceExceptionTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public async Task ThrowSync_ServiceException_only_calls_ServiceExceptionHandlers() + { + ServiceEx = UnHandledEx = null; + var client = new JsonHttpClient(Config.ListeningOn); + + try + { + var response = await client.GetAsync(new ThrowSync()); + Assert.Fail("Should fail"); + } + catch (WebServiceException ex) + { + Assert.That(ServiceEx.Message, Is.EqualTo(nameof(ThrowSync))); + Assert.That(UnHandledEx, Is.Null); + Assert.That(ex.Message, Is.EqualTo(nameof(ThrowSync))); + } + } + + [Test] + public async Task ThrowAsync_ServiceException_only_calls_ServiceExceptionHandlers() + { + ServiceEx = UnHandledEx = null; + var client = new JsonHttpClient(Config.ListeningOn); + + try + { + var response = await client.GetAsync(new ThrowAsync()); + Assert.Fail("Should fail"); + } + catch (WebServiceException ex) + { + Assert.That(ServiceEx.Message, Is.EqualTo(nameof(ThrowAsync))); + Assert.That(UnHandledEx, Is.Null); + Assert.That(ex.Message, Is.EqualTo(nameof(ThrowAsync))); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/XmlContentTypeIssue.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/XmlContentTypeIssue.cs new file mode 100644 index 00000000000..a0af005cb18 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Issues/XmlContentTypeIssue.cs @@ -0,0 +1,66 @@ +using System.Reflection; +using System.Runtime.Serialization; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Issues +{ + + [Route("/testxml", Verbs = "POST")] + [DataContract(Namespace = "")] + public class TestXml + { + [DataMember(Order = 0)] + public string User { get; set; } + } + + public class SimpleXmlService : Service + { + public object Any(TestXml request) + { + return request; + } + } + + [TestFixture] + public class XmlContentTypeIssue + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(typeof(XmlContentTypeIssue).Name, typeof(XmlContentTypeIssue).Assembly) {} + + public override void Configure(Container container) + { + } + } + + private ServiceStackHost appHost; + + public XmlContentTypeIssue() + { + appHost = new AppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_Post_Xml_with_Utf8_charset() + { + var xml = @"<TestXml> + <User>steve</User> + </TestXml>"; + var response = Config.AbsoluteBaseUri.CombineWith("/testxml") + .PostStringToUrl(xml, contentType: "text/xml; charset=utf-8", accept: "application/json"); + + Assert.That(response, Is.EqualTo("{\"User\":\"steve\"}").Or.EqualTo("{\"user\":\"steve\"}")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/JSTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/JSTests.cs new file mode 100644 index 00000000000..cc9e90fbe19 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/JSTests.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class JSTests + { + [Test] + public void Can_parse_dynamic_json() + { + Assert.That(JSON.parse("1"), Is.EqualTo(1)); + Assert.That(JSON.parse("1.1"), Is.EqualTo(1.1)); + Assert.That(JSON.parse("'a'"), Is.EqualTo("a")); + Assert.That(JSON.parse("\"a\""), Is.EqualTo("a")); + Assert.That(JSON.parse("{a:1}"), Is.EqualTo(new Dictionary<string, object> { {"a", 1 }})); + Assert.That(JSON.parse("{\"a\":1}"), Is.EqualTo(new Dictionary<string, object> { {"a", 1 }})); + Assert.That(JSON.parse("[{a:1},{b:2}]"), Is.EqualTo(new List<object> + { + new Dictionary<string, object> { { "a", 1 } }, + new Dictionary<string, object> { { "b", 2 } } + })); + } + + public class CustomFilter : ScriptMethods + { + public string reverse(string text) => new string(text.Reverse().ToArray()); + } + + [Test] + public void Can_eval_js() + { + var scope = JS.CreateScope( + args: new Dictionary<string, object> + { + { "arg", "value"} + }, + functions: new CustomFilter()); + + Assert.That(JS.eval("arg", scope), Is.EqualTo("value")); + + Assert.That(JS.eval("reverse(arg)", scope), Is.EqualTo("eulav")); + + Assert.That(JS.eval("itemsOf(3, padRight(reverse(arg), 8, '_'))", scope), Is.EqualTo(new List<object> { "eulav___", "eulav___", "eulav___" })); + + Assert.That(JS.eval("{a: itemsOf(3, padRight(reverse(arg), 8, '_')) }", scope), Is.EqualTo(new Dictionary<string, object> + { + { "a", new List<object> { "eulav___", "eulav___", "eulav___" } } + })); + + Assert.That(JS.eval("3.itemsOf(arg.reverse().padRight(8, '_'))", scope), Is.EqualTo(new List<object> { "eulav___", "eulav___", "eulav___" })); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/JsonpTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/JsonpTests.cs index e0e29da01a6..ff65b19ea49 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/JsonpTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/JsonpTests.cs @@ -1,21 +1,20 @@ using System; using System.Net; using NUnit.Framework; -using ServiceStack.Common.Web; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; +using ServiceStack.Support; +using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { public class JsonpTests { - protected const string ListeningOn = "http://localhost:82/"; + protected const string ListeningOn = "http://localhost:1337/"; ExampleAppHostHttpListener appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { LogManager.LogFactory = new ConsoleLogFactory(); @@ -25,7 +24,7 @@ public void OnTestFixtureSetUp() appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { Dispose(); @@ -35,28 +34,35 @@ public void Dispose() { if (appHost == null) return; appHost.Dispose(); - appHost = null; } [Test] public void Can_GET_single_Movie_using_RestClient_with_JSONP() { - var url = ListeningOn + "movies/1?callback=cb"; + var url = ListeningOn + "all-movies/1?callback=cb"; string response; - var webReq = (HttpWebRequest)WebRequest.Create(url); + var webReq = WebRequest.CreateHttp(url); webReq.Accept = "*/*"; using (var webRes = webReq.GetResponse()) { - Assert.That(webRes.ContentType, Is.StringStarting(ContentType.JavaScript)); - response = webRes.DownloadText(); + Assert.That(webRes.ContentType, Does.StartWith(MimeTypes.JavaScript)); + response = webRes.ReadToEnd(); } Assert.That(response, Is.Not.Null, "No response received"); Console.WriteLine(response); - Assert.That(response, Is.StringStarting("cb(")); - Assert.That(response, Is.StringEnding(")")); + Assert.That(response, Does.StartWith("cb(")); + Assert.That(response, Does.EndWith(")")); Assert.That(response.Length, Is.GreaterThan(50)); - } + } + + [Test] + public void Can_create_Utf8_callback() + { + var bytes = DataCache.CreateJsonpPrefix("test"); + var fromUtf8 = bytes.FromUtf8Bytes(); + Assert.That(fromUtf8, Is.EqualTo("test(")); + } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/KeyValueDataContractDeserializerTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/KeyValueDataContractDeserializerTests.cs index 9779f125dee..8150d1103bd 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/KeyValueDataContractDeserializerTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/KeyValueDataContractDeserializerTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceModel.Serialization; +using ServiceStack.Common; +using ServiceStack.Serialization; using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/LicenseUsageTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/LicenseUsageTests.cs new file mode 100644 index 00000000000..3f1fb994e03 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/LicenseUsageTests.cs @@ -0,0 +1,296 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System; +using System.Collections.Generic; +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Host; +using ServiceStack.Messaging; +using ServiceStack.RabbitMq; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class FreeLicenseUsageServiceClientTests : LicenseUsageTests + { + [SetUp] + public void SetUp() + { + LicenseUtils.RemoveLicense(); + JsConfig.Reset(); + } + + [TearDown] + public void TearDown() + { +// Licensing.RegisterLicense(new AppSettings().GetString("servicestack:license")); + Licensing.RegisterLicense(Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE")); + } + + [Test] + public void Allows_registration_of_10_operations() + { + using (var appHost = new LicenseTestsAppHost(typeof(Services10))) + { + appHost.Init(); + appHost.Start(Config.ListeningOn); + + Assert.That(appHost.Metadata.GetOperationDtos().Count, Is.EqualTo(10)); + } + } + + [Test] + public void Throws_on_registration_of_11_operations() + { + using (var appHost = new NoLicenseTestsAppHost(typeof(Services10), typeof(Service1))) + { + Assert.Throws(Is.TypeOf<LicenseException>() + .Or.TypeOf<TargetInvocationException>() + .With.Property("InnerException").TypeOf<LicenseException>(), + () => { + appHost.Init(); + appHost.Start(Config.ListeningOn); + }); + } + } + + [Ignore("TODO: Ignore reason"), Test] + public void Allows_MegaDto_through_ServiceClient() + { + using (var appHost = new LicenseTestsAppHost(typeof(MegaDtoService))) + { + appHost.Init(); + appHost.Start(Config.ListeningOn); + + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var request = MegaDto.Create(); + + var response = client.Post(request); + Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id)); + + Assert.Throws<LicenseException>(() => + request.ToJson()); + + response = client.Post(request); + Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id)); + + Assert.Throws<LicenseException>(() => + MegaDto.Create().ToJson()); + } + } + } + + [TestFixture] + public class FreeUsageRabbitMqClientTests : LicenseUsageTests + { + [Ignore("Integration Test"), Test] + public void Allows_MegaDto_through_RabbitMqClients() + { + var mqFactory = new RabbitMqMessageFactory(connectionString: Config.RabbitMQConnString); + + var request = MegaDto.Create(); + + using (var mqClient = mqFactory.CreateMessageProducer()) + { + mqClient.Publish(request); + } + + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get<MegaDto>(QueueNames<MegaDto>.In); + var response = msg.GetBody(); + + Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id)); + } + } + } + + [TestFixture] + public class FreeUsageRedisMqClientTests : LicenseUsageTests + { + [Test] + public void Allows_MegaDto_through_RedisMqClients() + { + var mqFactory = new RedisMessageFactory(new BasicRedisClientManager()); + + var request = MegaDto.Create(); + + using (var mqClient = mqFactory.CreateMessageProducer()) + { + mqClient.Publish(request); + } + + using (var mqClient = mqFactory.CreateMessageQueueClient()) + { + var msg = mqClient.Get<MegaDto>(QueueNames<MegaDto>.In); + var response = msg.GetBody(); + + Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id)); + } + } + } + + [TestFixture] + public class RegisteredLicenseUsageTests : LicenseUsageTests + { + [Test] + public void Allows_registration_of_11_operations() + { +// Licensing.RegisterLicense(new AppSettings().GetString("servicestack:license")); + Licensing.RegisterLicense(Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE")); + + using (var appHost = new LicenseTestsAppHost(typeof(Services10), typeof(Service1))) + { + appHost.Init(); + appHost.Start(Config.ListeningOn); + + Assert.That(appHost.Metadata.GetOperationDtos().Count, Is.EqualTo(11)); + } + } + } + + public class LicenseUsageTests + { + public class T01 { public int Id { get; set; } } + public class T02 { public int Id { get; set; } } + public class T03 { public int Id { get; set; } } + public class T04 { public int Id { get; set; } } + public class T05 { public int Id { get; set; } } + public class T06 { public int Id { get; set; } } + public class T07 { public int Id { get; set; } } + public class T08 { public int Id { get; set; } } + public class T09 { public int Id { get; set; } } + public class T10 { public int Id { get; set; } } + public class T11 { public int Id { get; set; } } + public class T12 { public int Id { get; set; } } + public class T13 { public int Id { get; set; } } + public class T14 { public int Id { get; set; } } + public class T15 { public int Id { get; set; } } + public class T16 { public int Id { get; set; } } + public class T17 { public int Id { get; set; } } + public class T18 { public int Id { get; set; } } + public class T19 { public int Id { get; set; } } + public class T20 { public int Id { get; set; } } + public class T21 { public int Id { get; set; } } + + public class Services10 : IService + { + public void Any(T01 request) { } + public void Any(T02 request) { } + public void Any(T03 request) { } + public void Any(T04 request) { } + public void Any(T05 request) { } + public void Any(T06 request) { } + public void Any(T07 request) { } + public void Any(T08 request) { } + public void Any(T09 request) { } + public void Any(T10 request) { } + } + + public class Service1 : IService + { + public void Any(T11 request) { } + } + + public class MegaDto : IReturn<MegaDto> + { + public T01 T01 { get; set; } + public T02 T02 { get; set; } + public T03 T03 { get; set; } + public T04 T04 { get; set; } + public T05 T05 { get; set; } + public T06 T06 { get; set; } + public T07 T07 { get; set; } + public T08 T08 { get; set; } + public T09 T09 { get; set; } + public T10 T10 { get; set; } + public T11 T11 { get; set; } + public T12 T12 { get; set; } + public T13 T13 { get; set; } + public T14 T14 { get; set; } + public T15 T15 { get; set; } + public T16 T16 { get; set; } + public T17 T17 { get; set; } + public T18 T18 { get; set; } + public T19 T19 { get; set; } + public T20 T20 { get; set; } + public T21 T21 { get; set; } + + public static MegaDto Create() + { + return new MegaDto + { + T01 = new T01 { Id = 1 }, + T02 = new T02 { Id = 1 }, + T03 = new T03 { Id = 1 }, + T04 = new T04 { Id = 1 }, + T05 = new T05 { Id = 1 }, + T06 = new T06 { Id = 1 }, + T07 = new T07 { Id = 1 }, + T08 = new T08 { Id = 1 }, + T09 = new T09 { Id = 1 }, + T10 = new T10 { Id = 1 }, + T11 = new T11 { Id = 1 }, + T12 = new T12 { Id = 1 }, + T13 = new T13 { Id = 1 }, + T14 = new T14 { Id = 1 }, + T15 = new T15 { Id = 1 }, + T16 = new T16 { Id = 1 }, + T17 = new T17 { Id = 1 }, + T18 = new T18 { Id = 1 }, + T19 = new T19 { Id = 1 }, + T20 = new T20 { Id = 1 }, + T21 = new T21 { Id = 1 }, + }; + } + } + + public class MegaDtoService : IService + { + public object Any(MegaDto request) + { + return request; + } + } + + protected class LicenseTestsAppHost : AppHostHttpListenerBase + { + private readonly List<Type> services; + public LicenseTestsAppHost(params Type[] services) + : base(typeof(LicenseTestsAppHost).Name) + { + this.services = new List<Type>(services); + } + + protected override ServiceController CreateServiceController(params Assembly[] assembliesWithServices) + { + return new ServiceController(this, () => services); + } + + public override void Configure(Container container) + { + Plugins.RemoveAll(x => x is NativeTypesFeature); + GetPlugin<MetadataFeature>().ServiceRoutes.Clear(); + } + } + + protected class NoLicenseTestsAppHost : LicenseTestsAppHost + { + public NoLicenseTestsAppHost(params Type[] services) + : base(services) {} + + public override void OnConfigLoad() + { + base.OnConfigLoad(); + LicenseUtils.RemoveLicense(); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ManualValidationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ManualValidationTests.cs new file mode 100644 index 00000000000..9aa9b644daa --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ManualValidationTests.cs @@ -0,0 +1,143 @@ +using System; +using System.Reflection; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class MyRegister : IReturn<EmptyResponse> + { + public string Email { get; set; } + } + + public class MyRegisterValidator : AbstractValidator<MyRegister> + { + public MyRegisterValidator() + { + RuleSet(ApplyTo.Get | ApplyTo.Post | ApplyTo.Put, + () => + { + RuleFor(x => x.Email).EmailAddress(); + }); + } + } + + public class MyRegisterService : Service + { + public object Get(MyRegister request) + { + var validator = new MyRegisterValidator { Request = Request }; + var validationResult = validator.Validate(Request, request); + if (!validationResult.IsValid) + throw validationResult.ToException(); + return new EmptyResponse(); + } + + public async Task<object> Post(MyRegister request) + { + var validator = new MyRegisterValidator { Request = Request }; + var validationResult = await validator.ValidateAsync(Request, request); + if (!validationResult.IsValid) + throw validationResult.ToException(); + return new EmptyResponse(); + } + + public async Task<object> Put(MyRegister request) + { + var validator = new MyRegisterValidator { Request = Request }; + var validationResult = validator.Validate(Request, request); + if (!validationResult.IsValid) + throw validationResult.ToException(); + return new EmptyResponse(); + } + } + + public class ManualValidationTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ManualValidationTests), typeof(MyRegisterService).Assembly) {} + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature { + ScanAppHostAssemblies = false, + }); + } + } + + private readonly ServiceStackHost appHost; + public ManualValidationTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + JsonServiceClient CreateClient() => new JsonServiceClient(Config.ListeningOn); + + private static void AssertMyRegisterManualValidation(WebServiceException e) + { + Assert.That(e.ErrorCode, Is.EqualTo(nameof(MyRegister.Email))); + Assert.That(e.Message, Is.EqualTo("'Email' is not a valid email address.")); + Assert.That(e.ResponseStatus.Errors[0].ErrorCode, Is.EqualTo(nameof(MyRegister.Email))); + Assert.That(e.ResponseStatus.Errors[0].FieldName, Is.EqualTo(nameof(MyRegister.Email))); + Assert.That(e.ResponseStatus.Errors[0].Message, Is.EqualTo("'Email' is not a valid email address.")); + } + + [Test] + public void Can_manual_validate_sync_Get_Validate() + { + var client = CreateClient(); + + try + { + client.Get(new MyRegister { Email = "not.an.email" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + AssertMyRegisterManualValidation(e); + } + } + + [Test] + public async Task Can_manual_validate_async_Post_ValidateAsync() + { + var client = CreateClient(); + + try + { + await client.PostAsync(new MyRegister { Email = "not.an.email" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + AssertMyRegisterManualValidation(e); + } + } + + [Test] + public async Task Can_manual_validate_async_Put_Validate() + { + var client = CreateClient(); + + try + { + await client.PutAsync(new MyRegister { Email = "not.an.email" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException e) + { + AssertMyRegisterManualValidation(e); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/MessageSerializationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/MessageSerializationTests.cs index e87411e09d8..61a3a934de3 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/MessageSerializationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/MessageSerializationTests.cs @@ -1,3 +1,4 @@ +#if NETFX using System; using System.IO; using System.Runtime.Serialization; @@ -6,9 +7,9 @@ using System.Xml; using NUnit.Framework; using ServiceStack.Messaging; -using ServiceStack.ServiceModel.Serialization; +using ServiceStack.Serialization; using Message = System.ServiceModel.Channels.Message; -using DataContractSerializer = ServiceStack.ServiceModel.Serialization.DataContractSerializer; +using DataContractSerializer = ServiceStack.Serialization.DataContractSerializer; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -43,7 +44,7 @@ public void Can_Deserialize_Message_from_GetReaderAtBodyContents() using (var reader = msg.GetReaderAtBodyContents()) { var requestXml = reader.ReadOuterXml(); - var fromRequest = (Reverse)DataContractDeserializer.Instance.Parse(requestXml, typeof(Reverse)); + var fromRequest = (Reverse)DataContractSerializer.Instance.DeserializeFromString(requestXml, typeof(Reverse)); Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); } } @@ -64,6 +65,7 @@ protected override void OnWriteBodyContents(XmlDictionaryWriter writer) } } +#if !NETCORE [Test] public void Can_create_entire_message_from_xml() { @@ -79,10 +81,10 @@ public void Can_create_entire_message_from_xml() var msg = Message.CreateMessage(xnr, msgXml.Length, MessageVersion.Soap12WSAddressingAugust2004); var xml = msg.GetReaderAtBodyContents().ReadOuterXml(); - Console.WriteLine("BODY: " + DataContractSerializer.Instance.Parse(request)); + Console.WriteLine("BODY: " + DataContractSerializer.Instance.SerializeToString(request)); Console.WriteLine("EXPECTED BODY: " + xml); - var fromRequest = (Reverse)DataContractDeserializer.Instance.Parse(xml, typeof(Reverse)); + var fromRequest = (Reverse)DataContractSerializer.Instance.DeserializeFromString(xml, typeof(Reverse)); Assert.That(fromRequest.Value, Is.EqualTo(request.Value)); } @@ -149,10 +151,11 @@ public void Can_create_message_from_xml() requestXml = reader.ReadOuterXml(); } - var requestType = typeof (Reverse); - var request = (Reverse)DataContractDeserializer.Instance.Parse(requestXml, requestType); + var requestType = typeof(Reverse); + var request = (Reverse)DataContractSerializer.Instance.DeserializeFromString(requestXml, requestType); Assert.That(request.Value, Is.EqualTo("Testing")); } +#endif public class DtoBodyWriter : BodyWriter { @@ -165,7 +168,7 @@ public DtoBodyWriter(object dto) protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { - var xml = DataContractSerializer.Instance.Parse(dto); + var xml = DataContractSerializer.Instance.SerializeToString(dto); writer.WriteString(xml); } } @@ -185,6 +188,5 @@ protected override void OnWriteBodyContents(XmlDictionaryWriter writer) } } } - - -} \ No newline at end of file +} +#endif diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/MockSessionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/MockSessionTests.cs new file mode 100644 index 00000000000..dd4ba649a38 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/MockSessionTests.cs @@ -0,0 +1,152 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Testing; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class MockSessionTests + { + public static AuthUserSession CreateUserSession() + { + return new AuthUserSession + { + UserAuthId = "1", + Language = "en", + PhoneNumber = "*****", + FirstName = "Test", + LastName = "User", + PrimaryEmail = "test@email.com", + UserAuthName = "Mocked", + UserName = "Mocked", + }; + } + + [Test] + public void Can_Mock_Session_in_Container() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => host.RegisterService(typeof(MockSessionTestService)), + ConfigureContainer = x => x.Register<IAuthSession>(c => CreateUserSession()) + }.Init()) + { + var response = appHost.ExecuteService(new MockSessionTest()) as AuthUserSession; + + Assert.That(response.UserAuthId, Is.EqualTo("1")); + Assert.That(response.UserAuthName, Is.EqualTo("Mocked")); + Assert.That(response.PrimaryEmail, Is.EqualTo("test@email.com")); + } + } + + [Test] + public void Can_Mock_UnitTest_Session_in_IOC_with_MockHttpRequest() + { + using (new BasicAppHost + { + ConfigureContainer = container => + container.Register<IAuthSession>(c => CreateUserSession()) + }.Init()) + { + var service = new SessionService + { + Request = new MockHttpRequest() + }; + var session = service.GetSession(); + Assert.That(session.UserAuthId, Is.EqualTo("1")); + Assert.That(session.UserAuthName, Is.EqualTo("Mocked")); + } + } + + [Test] + public void Can_Mock_IntegrationTest_Session_with_Request() + { + using (new BasicAppHost(typeof(SessionService).Assembly).Init()) + { + var req = new MockHttpRequest + { + Items = { [Keywords.Session] = new AuthUserSession { UserName = "Mocked" } } + }; + + using (var service = HostContext.ResolveService<SessionService>(req)) + { + Assert.That(service.GetSession().UserName, Is.EqualTo("Mocked")); + } + } + } + + [Test] + public void Can_Mock_Session_in_RequestFilterAttribute() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => + { + host.RegisterService(typeof(MockSessionTestService)); + } + }.Init()) + { + var response = appHost.ExecuteService(new MockSessionAttributeTest()) as AuthUserSession; + + Assert.That(response.UserAuthId, Is.EqualTo("1")); + Assert.That(response.UserAuthName, Is.EqualTo("Mocked")); + Assert.That(response.PrimaryEmail, Is.EqualTo("test@email.com")); + } + } + + public class AppHost : AppSelfHostBase + { + public AppHost() + : base("Mock Session Integration Test", typeof(MockSessionTestService).Assembly) { } + + public override void Configure(Container container) + { + GlobalRequestFilters.Add((req, res, dto) => + { + req.Items[Keywords.Session] = new AuthUserSession + { + UserAuthId = "1", + Language = "en", + PhoneNumber = "*****", + FirstName = "Test", + LastName = "User", + PrimaryEmail = "test@emailtest.com", + UserAuthName = "testuser", + }; + }); + } + } + + [Test] + public void Can_Mock_Session_in_RequestFilter_in_IntegrationTest() + { + using (new AppHost().Init().Start(Config.AbsoluteBaseUri)) + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var response = client.Get(new MockSessionTest()); + + Assert.That(response.UserAuthId, Is.EqualTo("1")); + Assert.That(response.UserAuthName, Is.EqualTo("testuser")); + Assert.That(response.PrimaryEmail, Is.EqualTo("test@emailtest.com")); + } + } + } + + public class MockSessionTest : IReturn<AuthUserSession> { } + public class MockSessionAttributeTest : IReturn<AuthUserSession> { } + + public class UseMockedSession : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) => + req.Items[Keywords.Session] = MockSessionTests.CreateUserSession(); + } + + public class MockSessionTestService : Service + { + public object Any(MockSessionTest request) => SessionAs<AuthUserSession>(); + + [UseMockedSession] + public object Any(MockSessionAttributeTest request) => SessionAs<AuthUserSession>(); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ModuleTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ModuleTests.cs new file mode 100644 index 00000000000..616fa841659 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ModuleTests.cs @@ -0,0 +1,52 @@ +using System.Linq; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Testing; + +namespace ServiceStack.WebHost.Endpoints.Tests; + +public class ModuleTests +{ + private ServiceStackHost appHost; + private IVirtualPathProvider ssResources; + public ModuleTests() + { + appHost = new BasicAppHost().Init(); + ssResources = appHost.GetVirtualFileSources() + .FirstOrDefault(x => x is ResourceVirtualFiles rvfs && rvfs.RootNamespace == nameof(ServiceStack)); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_search_modules_resources_folder() + { + var uiIndexFile = ssResources.GetFile("/modules/ui/index.html"); + Assert.That(uiIndexFile, Is.Not.Null); + + var sharedComponentFiles = ssResources.GetAllMatchingFiles("/modules/shared/*.html").ToList(); + Assert.That(sharedComponentFiles.Count, Is.GreaterThanOrEqualTo(8)); + + var componentFiles = ssResources.GetAllMatchingFiles("/modules/ui/components/*.html").ToList(); + Assert.That(componentFiles.Count, Is.GreaterThanOrEqualTo(6)); + + var adminUiJsFiles = ssResources.GetAllMatchingFiles("/modules/admin-ui/js/*.js").ToList(); + Assert.That(adminUiJsFiles.Count, Is.GreaterThanOrEqualTo(3)); + + var adminUiCssFiles = ssResources.GetAllMatchingFiles("/modules/admin-ui/css/*.css").ToList(); + Assert.That(adminUiCssFiles.Count, Is.GreaterThanOrEqualTo(1)); + + var adminUiHtmlFiles = ssResources.GetAllMatchingFiles("/modules/admin-ui/components/*.html").ToList(); + Assert.That(adminUiHtmlFiles.Count, Is.GreaterThanOrEqualTo(3)); + } + + [Test] + public void Tailwind_did_gen_properly() + { + var uiCss = ssResources.GetFile("/modules/shared/css/ui.css"); + Assert.That(uiCss, Is.Not.Null); + + var uiCssContents = uiCss.ReadAllText(); + Assert.That(uiCssContents, Does.Contain("col-span-3")); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/MultiTennantAppHostTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/MultiTennantAppHostTests.cs new file mode 100644 index 00000000000..823e0574d6d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/MultiTennantAppHostTests.cs @@ -0,0 +1,235 @@ +using System.Data; +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class MultiTenantChangeDbAppHost : AppSelfHostBase + { + public MultiTenantChangeDbAppHost() + : base("Multi Tenant Test", typeof (MultiTenantChangeDbAppHost).Assembly) {} + + public override void Configure(Container container) + { + container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory( + "~/App_Data/master.sqlite".MapAbsolutePath(), SqliteDialect.Provider)); + + var dbFactory = container.Resolve<IDbConnectionFactory>(); + + const int noOfTenants = 3; + + using (var db = dbFactory.OpenDbConnection()) { + InitDb(db, "MASTER", "Masters inc."); + } + + noOfTenants.Times(i => { + var tenantId = "T0" + (i + 1); + using var db = dbFactory.OpenDbConnectionString(GetTenantConnString(tenantId)); + InitDb(db, tenantId, "ACME {0} inc.".Fmt(tenantId)); + }); + + RegisterTypedRequestFilter<IForTenant>((req,res,dto) => + req.Items[Keywords.DbInfo] = new ConnectionInfo { ConnectionString = GetTenantConnString(dto.TenantId)}); + } + + public void InitDb(IDbConnection db, string tenantId, string company) + { + db.DropAndCreateTable<TenantConfig>(); + db.Insert(new TenantConfig { Id = tenantId, Company = company }); + } + + public string GetTenantConnString(string tenantId) => tenantId != null + ? "~/App_Data/tenant-{0}.sqlite".Fmt(tenantId).MapAbsolutePath() + : null; + } + + [TestFixture] + public class MultiTenantChangeDbAppHostTests + { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new MultiTenantChangeDbAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_use_different_tenant_connections() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var response = client.Get(new GetTenant()); + Assert.That(response.Config.Company, Is.EqualTo("Masters inc.")); + + response = client.Get(new GetTenant { TenantId = "T01" }); + Assert.That(response.Config.Company, Is.EqualTo("ACME T01 inc.")); + + response = client.Get(new GetTenant { TenantId = "T02" }); + Assert.That(response.Config.Company, Is.EqualTo("ACME T02 inc.")); + + response = client.Get(new GetTenant { TenantId = "T03" }); + Assert.That(response.Config.Company, Is.EqualTo("ACME T03 inc.")); + + Assert.Throws<WebServiceException>(() => + client.Get(new GetTenant { TenantId = "T04" })); + } + } + + /* + Common Service + */ + + public interface IForTenant + { + string TenantId { get; } + } + + public class TenantConfig + { + public string Id { get; set; } + public string Company { get; set; } + } + + public class GetTenant : IForTenant, IReturn<GetTenantResponse> + { + public string TenantId { get; set; } + } + + public class GetTenantResponse + { + public TenantConfig Config { get; set; } + } + + public class MultiTenantService : Service + { + public object Any(GetTenant request) + { + return new GetTenantResponse + { + Config = Db.Select<TenantConfig>().FirstOrDefault(), + }; + } + } + + /* + Alternative way to support multi tenancy using a Custom DB Factory + */ + public class MultiTenantCustomDbFactoryAppHost : AppSelfHostBase + { + public MultiTenantCustomDbFactoryAppHost() + : base("Multi Tenant Test", typeof(MultiTenantCustomDbFactoryAppHost).Assembly) { } + + public override void Configure(Container container) + { + var dbFactory = new OrmLiteConnectionFactory( + "~/App_Data/master.sqlite".MapAbsolutePath(), SqliteDialect.Provider); + + const int noOfTenants = 3; + + container.Register<IDbConnectionFactory>(c => + new MultiTenantDbFactory(dbFactory)); + + var multiDbFactory = (MultiTenantDbFactory)container.Resolve<IDbConnectionFactory>(); + + using (var db = multiDbFactory.OpenTenant()) { + InitDb(db, "MASTER", "Masters inc."); + } + + noOfTenants.Times(i => { + var tenantId = "T0" + (i + 1); + using var db = multiDbFactory.OpenTenant(tenantId); + InitDb(db, tenantId, "ACME {0} inc.".Fmt(tenantId)); + }); + + GlobalRequestFilters.Add((req, res, dto) => { + if (dto is IForTenant forTenant) + RequestContext.Instance.Items.Add("TenantId", forTenant.TenantId); + }); + } + + public void InitDb(IDbConnection db, string tenantId, string company) + { + db.DropAndCreateTable<TenantConfig>(); + db.Insert(new TenantConfig { Id = tenantId, Company = company }); + } + + public class MultiTenantDbFactory : IDbConnectionFactory + { + private readonly IDbConnectionFactory dbFactory; + + public MultiTenantDbFactory(IDbConnectionFactory dbFactory) + { + this.dbFactory = dbFactory; + } + + public IDbConnection OpenDbConnection() + { + var tenantId = RequestContext.Instance.Items["TenantId"] as string; + return OpenTenant(tenantId); + } + + public IDbConnection OpenTenant(string tenantId = null) + { + return tenantId != null + ? dbFactory.OpenDbConnectionString( + "~/App_Data/tenant-{0}.sqlite".Fmt(tenantId).MapAbsolutePath()) + : dbFactory.OpenDbConnection(); + } + + public IDbConnection CreateDbConnection() => dbFactory.CreateDbConnection(); + } + } + + [TestFixture] + public class MultiTenantCustomDbFactoryAppHostTests + { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new MultiTenantCustomDbFactoryAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_use_different_tenant_connections() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var response = client.Get(new GetTenant()); + Assert.That(response.Config.Company, Is.EqualTo("Masters inc.")); + + response = client.Get(new GetTenant { TenantId = "T01" }); + Assert.That(response.Config.Company, Is.EqualTo("ACME T01 inc.")); + + response = client.Get(new GetTenant { TenantId = "T02" }); + Assert.That(response.Config.Company, Is.EqualTo("ACME T02 inc.")); + + response = client.Get(new GetTenant { TenantId = "T03" }); + Assert.That(response.Config.Company, Is.EqualTo("ACME T03 inc.")); + + Assert.Throws<WebServiceException>(() => + client.Get(new GetTenant { TenantId = "T04" })); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/NestedServiceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/NestedServiceTests.cs new file mode 100644 index 00000000000..12f70af6319 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/NestedServiceTests.cs @@ -0,0 +1,73 @@ +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class NestedServiceTests + { + protected const string ListeningOn = "http://localhost:1337/"; + + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new ExampleAppHostHttpListener(); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_call_nested_service_with_ServiceClient() + { + var client = new JsonServiceClient(ListeningOn); + + var reqRoot = new Root { Id = 1 }; + Assert.That(reqRoot.ToGetUrl(), Is.EqualTo("/root/1")); + + var reqNested = new Root.Nested { Id = 2 }; + Assert.That(reqNested.ToGetUrl(), Is.EqualTo("/root.nested/2")); + + var root = client.Get(reqRoot); + Assert.That(root.Id, Is.EqualTo(1)); + + var nested = client.Get(reqNested); + Assert.That(nested.Id, Is.EqualTo(2)); + } + } + + + [Route("/root/{Id}")] + public class Root : IReturn<Root> + { + public int Id { get; set; } + + [Route("/root.nested/{Id}")] + public class Nested : IReturn<Root.Nested> + { + public int Id { get; set; } + } + } + + public class NestedService : Service + { + public object Any(Root request) + { + return request; + } + + public object Any(Root.Nested request) + { + return request; + } + } + +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreExtensions.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreExtensions.cs new file mode 100644 index 00000000000..9b41a8904e9 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreExtensions.cs @@ -0,0 +1,61 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public static class NetCoreExtensions + { +#if NETCORE + public static HttpWebResponse GetResponse(this HttpWebRequest request) + { + return (HttpWebResponse)PclExport.Instance.GetResponse(request); + } + + public static void AddRange(this HttpWebRequest request, int from, int? to) + { + var rangeSpecifier = "bytes"; + var curRange = request.Headers[HttpRequestHeader.Range]; + + if (string.IsNullOrEmpty(curRange)) + { + curRange = rangeSpecifier + "="; + } + else + { + if (string.Compare(curRange.Substring(0, curRange.IndexOf('=')), rangeSpecifier, StringComparison.OrdinalIgnoreCase) != 0) + throw new NotSupportedException("Invalid Range: " + curRange); + curRange = string.Empty; + } + curRange += from.ToString(); + if (to != null) { + curRange += "-" + to; + } + request.Headers[HttpRequestHeader.Range] = curRange; + } + + public static void Close(this HttpWebResponse response) + { + response.Dispose(); + } +#endif + public static void SetUserAgent(this HttpWebRequest request, string userAgent) + { +#if NETCORE + request.Headers[HttpRequestHeader.UserAgent] = userAgent; +#else + request.UserAgent = userAgent; +#endif + } + + public static void SetContentLength(this HttpWebRequest request, int contentLength) + { +#if NETCORE + request.Headers[HttpRequestHeader.ContentLength] = contentLength.ToString(); +#else + request.ContentLength = contentLength; +#endif + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreIocTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreIocTests.cs new file mode 100644 index 00000000000..83c55aea32b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreIocTests.cs @@ -0,0 +1,80 @@ +#if NETCORE + +using System.Reflection; +using System.Threading; +using Funq; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class NetCoreIocTests + { + private readonly ServiceStackHost appHost; + public NetCoreIocTests() => appHost = new AppHost().Init().Start(Config.ListeningOn); + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(NetCoreIocTests), typeof(NetCoreIocTests).Assembly) {} + + public override void Configure(IServiceCollection services) + { + services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); + services.AddSingleton(c => new SingletonDep()); + services.AddScoped(c => new ScopedDep()); + } + + public override void Configure(Container container) {} + } + + [Test] + public void Does_resolve_scoped_deps_when() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Get(new NetCoreIocTest()); + Assert.That(response.SingletonDepCounter, Is.EqualTo(1)); + Assert.That(response.ScopedDepCounter, Is.EqualTo(1)); + + response = client.Get(new NetCoreIocTest()); + Assert.That(response.SingletonDepCounter, Is.EqualTo(1)); + Assert.That(response.ScopedDepCounter, Is.EqualTo(2)); + } + } + + public class NetCoreIocTest : IReturn<NetCoreIocTestResponse> {} + + public class NetCoreIocTestResponse + { + public int SingletonDepCounter { get; set; } + public int ScopedDepCounter { get; set; } + } + + public class SingletonDep + { + public static int Counter; + public SingletonDep() => Interlocked.Increment(ref Counter); + } + public class ScopedDep + { + public static int Counter; + public ScopedDep() => Interlocked.Increment(ref Counter); + } + + public class NetCoreScopedTestServices : Service + { + public SingletonDep Singleton { get; set; } + public ScopedDep Scoped { get; set; } + + public object Any(NetCoreIocTest request) => new NetCoreIocTestResponse { + SingletonDepCounter = SingletonDep.Counter, + ScopedDepCounter = ScopedDep.Counter + }; + } + +} + +#endif \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreTestsRunner.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreTestsRunner.cs new file mode 100644 index 00000000000..e31b9c04c28 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/NetCoreTestsRunner.cs @@ -0,0 +1,36 @@ +#if NUNITLITE +using NUnitLite; +using NUnit.Common; +using System.Reflection; +using ServiceStack.Text; +using System; +using System.Globalization; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class NetCoreTestsRunner + { + /// <summary> + /// The main program executes the tests. Output may be routed to + /// various locations, depending on the arguments passed. + /// </summary> + /// <remarks>Run with --help for a full list of arguments supported</remarks> + /// <param name="args"></param> + public static int Main(string[] args) + { + var licenseKey = Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE"); + if (licenseKey.IsNullOrEmpty()) + throw new ArgumentNullException("SERVICESTACK_LICENSE", "Add Environment variable for SERVICESTACK_LICENSE"); + + Licensing.RegisterLicense(licenseKey); + //"ActivatedLicenseFeatures: ".Print(LicenseUtils.ActivatedLicenseFeatures()); + + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); + JsConfig.InitStatics(); + //JsonServiceClient client = new JsonServiceClient(); + var writer = new ExtendedTextWrapper(Console.Out); + return new AutoRun(((IReflectableType)typeof(NetCoreTestsRunner)).GetTypeInfo().Assembly).Execute(args, writer, Console.In); + } + } +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/NewApiTodos.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/NewApiTodos.cs index 2b5450442f6..c4cf747293d 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/NewApiTodos.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/NewApiTodos.cs @@ -2,11 +2,7 @@ using System.Linq; using Funq; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints; +using ServiceStack; namespace NewApi.Todos { @@ -26,6 +22,8 @@ public override void Configure(Container container) public class Todos : IReturn<List<Todo>> { public long[] Ids { get; set; } + + public Todos() {} public Todos(params long[] ids) { this.Ids = ids; @@ -104,11 +102,11 @@ public void DeleteByIds(params long[] ids) [TestFixture] public class NewApiTodosTests { - const string BaseUri = "http://localhost:82/"; + const string BaseUri = "http://localhost:1337/"; AppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new AppHost(); @@ -116,11 +114,10 @@ public void TestFixtureSetUp() appHost.Start(BaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -145,4 +142,4 @@ public void Run() } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs index 77aa35f0760..118b72bcd95 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/OperationTests.cs @@ -1,38 +1,48 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Runtime.Serialization; using System.Threading; +using System.Threading.Tasks; using System.Web.UI; using Funq; using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints.Support.Metadata.Controls; -using ServiceStack.WebHost.Endpoints.Tests.Support; +using ServiceStack.Common.Tests; +using ServiceStack.Metadata; +using ServiceStack.Testing; +using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; namespace ServiceStack.WebHost.Endpoints.Tests { public class OperationTestsAppHost : AppHostHttpListenerBase { - public OperationTestsAppHost() : base(typeof(GetCustomer).Name, typeof(GetCustomer).Assembly) { } + public OperationTestsAppHost() : base(nameof(GetCustomer), typeof(GetCustomer).Assembly) { } public override void Configure(Container container) { } } [TestFixture] - public class OperationTests : MetadataTestBase + public class OperationTests : IService { - private OperationTestsAppHost _appHost; - private OperationControl _operationControl; + private OperationTestsAppHost appHost; + private OperationControl operationControl; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { - _appHost = new OperationTestsAppHost(); - _appHost.Init(); - - _operationControl = new OperationControl + appHost = new OperationTestsAppHost(); + appHost.Init(); +#if NETCORE + appHost.Start(Config.ListeningOn); +#endif + + var dummyServiceType = GetType(); + appHost.Metadata.Add(dummyServiceType, typeof(GetCustomer), typeof(GetCustomerResponse)); + appHost.Metadata.Add(dummyServiceType, typeof(GetCustomers), typeof(GetCustomersResponse)); + appHost.Metadata.Add(dummyServiceType, typeof(StoreCustomer), null); + + operationControl = new OperationControl { HttpRequest = new MockHttpRequest {PathInfo = "", RawUrl = "http://localhost:4444/metadata"}, MetadataConfig = ServiceEndpointsMetadataConfig.Create(""), @@ -42,52 +52,52 @@ public void OnTestFixtureSetUp() ResponseMessage = "(HttpWebResponse)", Title = "Metadata page", OperationName = "operationname", - MetadataHtml = "<p>Operation</p>" + MetadataHtml = "<p>Operation</p>", }; } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { - _appHost.Dispose(); + appHost.Dispose(); } [TearDown] public void OnTearDown() { - _appHost.Config.WebHostUrl = null; + if (appHost?.Config?.WebHostUrl != null) + appHost.Config.WebHostUrl = null; } [Test] - public void OperationControl_render_creates_link_back_to_main_page_using_WebHostUrl_when_set() + public async Task OperationControl_render_creates_link_back_to_main_page_using_WebHostUrl_when_set() { - _appHost.Config.WebHostUrl = "https://host.example.com/_api"; - - var stringWriter = new StringWriter(); - _operationControl.Render(new HtmlTextWriter(stringWriter)); + appHost.Config.WebHostUrl = "https://host.example.com/_api"; - string html = stringWriter.ToString(); + using var ms = MemoryStreamFactory.GetStream(); + await operationControl.RenderAsync(ms); + + string html = await ms.ReadToEndAsync(); Assert.IsTrue(html.Contains("<a href=\"https://host.example.com/_api/metadata\">&lt;back to all web services</a>")); } [Test] - public void OperationControl_render_creates_link_back_to_main_page_using_relative_uri_when_WebHostUrl_not_set() + public async Task OperationControl_render_creates_link_back_to_main_page_using_relative_uri_when_WebHostUrl_not_set() { - var stringWriter = new StringWriter(); - _operationControl.Render(new HtmlTextWriter(stringWriter)); - - string html = stringWriter.ToString(); - Assert.IsTrue(html.Contains("<a href=\"/metadata\">&lt;back to all web services</a>")); + using var ms = MemoryStreamFactory.GetStream(); + await operationControl.RenderAsync(ms); + string html = await ms.ReadToEndAsync(); + Assert.That(html, Does.Contain("<a href=\"http://localhost/metadata\">&lt;back to all web services</a>")); } [Test] public void When_culture_is_turkish_operations_containing_capital_I_are_still_visible() { - Metadata.Add(GetType(), typeof(HelloImage), null); + appHost.Metadata.Add(GetType(), typeof(HelloImage), null); using (new CultureSwitch("tr-TR")) { - Assert.IsTrue(Metadata.IsVisible(_operationControl.HttpRequest, Format.Json, "HelloImage")); + Assert.IsTrue(appHost.Metadata.IsVisible(operationControl.HttpRequest, Format.Json, "HelloImage")); } } } @@ -103,15 +113,24 @@ public class CultureSwitch : IDisposable public CultureSwitch(string culture) { +#if NETCORE + _currentCulture = CultureInfo.CurrentCulture; + CultureInfo.CurrentCulture = new CultureInfo(culture); +#else var currentThread = Thread.CurrentThread; _currentCulture = currentThread.CurrentCulture; var switchCulture = CultureInfo.GetCultureInfo(culture); currentThread.CurrentCulture = switchCulture; +#endif } public void Dispose() { +#if NETCORE + CultureInfo.CurrentCulture = _currentCulture; +#else Thread.CurrentThread.CurrentCulture = _currentCulture; +#endif } } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/PartialContentResultTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/PartialContentResultTests.cs index bbd1e45919e..7b01ccfd38f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/PartialContentResultTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/PartialContentResultTests.cs @@ -1,19 +1,13 @@ using System; using System.IO; -using System.Net; using System.Text; using System.Threading; +using System.Threading.Tasks; using Funq; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; +using ServiceStack.Common.Tests; +using ServiceStack.Testing; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Support.Mocks; -using ServiceStack.WebHost.Endpoints.Tests.Mocks; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -31,14 +25,14 @@ public class PartialFromMemory { } [Route("/partialfiles/text")] public class PartialFromText { } - public class PartialContentService : ServiceInterface.Service + public class PartialContentService : Service { public object Get(PartialFile request) { if (request.RelativePath.IsNullOrEmpty()) throw new ArgumentNullException("RelativePath"); - string filePath = "~/{0}".Fmt(request.RelativePath).MapProjectPath(); + string filePath = "~/{0}".Fmt(request.RelativePath).MapProjectPlatformPath(); if (!File.Exists(filePath)) throw new FileNotFoundException(request.RelativePath); @@ -73,35 +67,24 @@ public override void Configure(Container container) {} [TestFixture] public class PartialContentResultTests { - public const string BaseUri = Config.ServiceStackBaseUri; - public const string ListeningOn = Config.AbsoluteBaseUri; + string BaseUri = Config.ServiceStackBaseUri; + string ListeningOn = Config.AbsoluteBaseUri; - private PartialContentAppHost appHost; + private ServiceStackHost appHost; - readonly FileInfo uploadedFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath()); - readonly FileInfo uploadedTextFile = new FileInfo("~/TestExistingDir/textfile.txt".MapProjectPath()); + readonly FileInfo uploadedFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPlatformPath()); + readonly FileInfo uploadedTextFile = new FileInfo("~/TestExistingDir/textfile.txt".MapProjectPlatformPath()); - [TestFixtureSetUp] + [OneTimeSetUp] public void TextFixtureSetUp() { - try - { - appHost = new PartialContentAppHost(); - appHost.Init(); - appHost.Start(ListeningOn); - } - catch (Exception ex) - { - throw ex; - } + appHost = new PartialContentAppHost() + .Init() + .Start(ListeningOn); } - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - if (appHost != null) appHost.Dispose(); - appHost = null; - } + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost?.Dispose(); [Test] public void Can_StaticFile_GET_200_OK_response_for_file_with_no_range_header() @@ -109,7 +92,7 @@ public void Can_StaticFile_GET_200_OK_response_for_file_with_no_range_header() "File size {0}".Print(uploadedFile.Length); byte[] actualContents = "{0}/TestExistingDir/upload.html".Fmt(BaseUri).GetBytesFromUrl( - responseFilter: httpRes => "Content-Length header {0}".Print(httpRes.Headers["Content-Length"])); + responseFilter: httpRes => $"Content-Length header {httpRes.GetContentLength()}".Print()); "response size {0}".Fmt(actualContents.Length); @@ -122,7 +105,7 @@ public void Can_GET_200_OK_response_for_file_with_no_range_header() "File size {0}".Print(uploadedFile.Length); byte[] actualContents = "{0}/partialfiles/TestExistingDir/upload.html".Fmt(BaseUri).GetBytesFromUrl( - responseFilter: httpRes => "Content-Length header {0}".Print(httpRes.Headers["Content-Length"])); + responseFilter: httpRes => $"Content-Length header {httpRes.GetContentLength()}".Print()); "response size {0}".Fmt(actualContents.Length); @@ -133,11 +116,11 @@ public void Can_GET_200_OK_response_for_file_with_no_range_header() public void Can_StaticFile_GET_206_Partial_response_for_file_with_range_header() { var actualContents = "{0}/TestExistingDir/upload.html".Fmt(BaseUri).GetStringFromUrl( - requestFilter: httpReq => httpReq.AddRange(5, 11), + requestFilter: httpReq => httpReq.With(c => c.SetRange(5, 11)), responseFilter: httpRes => { - "Content-Length header {0}".Print(httpRes.Headers["Content-Length"]); - Assert.That(httpRes.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadedFile.Name))); + $"Content-Length header {httpRes.GetContentLength()}".Print(); + Assert.That(httpRes.MatchesContentType(MimeTypes.GetMimeType(uploadedFile.Name))); }); "Response length {0}".Print(actualContents.Length); @@ -148,11 +131,11 @@ public void Can_StaticFile_GET_206_Partial_response_for_file_with_range_header() public void Can_GET_206_Partial_response_for_file_with_range_header() { var actualContents = "{0}/partialfiles/TestExistingDir/upload.html".Fmt(BaseUri).GetStringFromUrl( - requestFilter: httpReq => httpReq.AddRange(5, 11), + requestFilter: httpReq => httpReq.With(c => c.SetRange(5, 11)), responseFilter: httpRes => { - "Content-Length header {0}".Print(httpRes.Headers["Content-Length"]); - Assert.That(httpRes.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadedFile.Name))); + $"Content-Length header {httpRes.GetContentLength()}".Print(); + Assert.That(httpRes.MatchesContentType(MimeTypes.GetMimeType(uploadedFile.Name))); }); "Response length {0}".Print(actualContents.Length); @@ -163,8 +146,8 @@ public void Can_GET_206_Partial_response_for_file_with_range_header() public void Can_GET_206_Partial_response_for_memory_with_range_header() { var actualContents = "{0}/partialfiles/memory?mimeType=audio/mpeg".Fmt(BaseUri).GetStringFromUrl( - requestFilter: httpReq => httpReq.AddRange(5, 9), - responseFilter: httpRes => "Content-Length header {0}".Print(httpRes.Headers["Content-Length"])); + requestFilter: httpReq => httpReq.With(c => c.SetRange(5, 9)), + responseFilter: httpRes => $"Content-Length header {httpRes.GetContentLength()}".Print()); "Response Length {0}".Print(actualContents.Length); Assert.That(actualContents, Is.EqualTo("67890")); @@ -174,18 +157,18 @@ public void Can_GET_206_Partial_response_for_memory_with_range_header() public void Can_GET_206_Partial_response_for_text_with_range_header() { var actualContents = "{0}/partialfiles/text".Fmt(BaseUri).GetStringFromUrl( - requestFilter: httpReq => httpReq.AddRange(5, 9), - responseFilter: httpRes => "Content-Length header {0}".Print(httpRes.Headers["Content-Length"])); + requestFilter: httpReq => httpReq.With(c => c.SetRange(5, 9)), + responseFilter: httpRes => $"Content-Length header {httpRes.GetContentLength()}".Print()); "Response Length {0}".Print(actualContents.Length); Assert.That(actualContents, Is.EqualTo("67890")); } [Test] - public void Can_respond_to_non_range_requests_with_200_OK_response() + public async Task Can_respond_to_non_range_requests_with_200_OK_response() { - var mockRequest = new HttpRequestMock(); - var mockResponse = new HttpResponseMock(); + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); string customText = "1234567890"; byte[] customTextBytes = customText.ToUtf8Bytes(); @@ -194,24 +177,55 @@ public void Can_respond_to_non_range_requests_with_200_OK_response() var httpResult = new HttpResult(ms, "audio/mpeg"); - bool reponseWasAutoHandled = mockResponse.WriteToResponse(mockRequest, httpResult); - Assert.That(reponseWasAutoHandled, Is.True); + bool responseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); + Assert.That(responseWasAutoHandled, Is.True); - string writtenString = mockResponse.GetOutputStreamAsString(); + string writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo(customText)); - Assert.That(mockResponse.Headers["Content-Range"], Is.Null); + Assert.That(mockResponse.Headers.ContainsKey("Content-Range"), Is.False); Assert.That(mockResponse.Headers["Accept-Ranges"], Is.EqualTo("bytes")); Assert.That(mockResponse.StatusCode, Is.EqualTo(200)); } [Test] - public void Can_seek_from_beginning_to_end() + public async Task Can_seek_from_beginning_to_end() + { + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); + + mockRequest.Headers[HttpHeaders.Range] = "bytes=0-"; + + string customText = "1234567890"; + byte[] customTextBytes = customText.ToUtf8Bytes(); + var ms = new MemoryStream(); + ms.Write(customTextBytes, 0, customTextBytes.Length); + + var httpResult = new HttpResult(ms, "audio/mpeg"); + + bool reponseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); + Assert.That(reponseWasAutoHandled, Is.True); + + string writtenString = mockResponse.ReadAsString(); + Assert.That(writtenString, Is.EqualTo(customText)); + + Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 0-9/10")); + Assert.That(mockResponse.Headers["Content-Length"], Is.EqualTo(writtenString.Length.ToString())); + Assert.That(mockResponse.Headers["Accept-Ranges"], Is.EqualTo("bytes")); + Assert.That(mockResponse.StatusCode, Is.EqualTo(206)); + } + + [Test] + public async Task Can_seek_from_beginning_to_further_than_end() { - var mockRequest = new HttpRequestMock(); - var mockResponse = new HttpResponseMock(); + // Not sure if this would ever occur in real streaming scenarios, but it does occur + // when some crawlers use range headers to specify a max size to return. + // e.g. Facebook crawler always sends range header of 'bytes=0-524287'. + + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); - mockRequest.Headers[HttpHeaders.Range] = "bytes=0"; + mockRequest.Headers[HttpHeaders.Range] = "bytes=0-524287"; string customText = "1234567890"; byte[] customTextBytes = customText.ToUtf8Bytes(); @@ -220,10 +234,10 @@ public void Can_seek_from_beginning_to_end() var httpResult = new HttpResult(ms, "audio/mpeg"); - bool reponseWasAutoHandled = mockResponse.WriteToResponse(mockRequest, httpResult); + bool reponseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); Assert.That(reponseWasAutoHandled, Is.True); - string writtenString = mockResponse.GetOutputStreamAsString(); + string writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo(customText)); Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 0-9/10")); @@ -233,10 +247,10 @@ public void Can_seek_from_beginning_to_end() } [Test] - public void Can_seek_from_beginning_to_middle() + public async Task Can_seek_from_beginning_to_middle() { - var mockRequest = new HttpRequestMock(); - var mockResponse = new HttpResponseMock(); + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); mockRequest.Headers[HttpHeaders.Range] = "bytes=0-2"; @@ -248,10 +262,10 @@ public void Can_seek_from_beginning_to_middle() var httpResult = new HttpResult(ms, "audio/mpeg"); - bool reponseWasAutoHandled = mockResponse.WriteToResponse(mockRequest, httpResult); + bool reponseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); Assert.That(reponseWasAutoHandled, Is.True); - string writtenString = mockResponse.GetOutputStreamAsString(); + string writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo("123")); Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 0-2/10")); @@ -261,11 +275,11 @@ public void Can_seek_from_beginning_to_middle() } [Test] - public void Can_seek_from_middle_to_end() + public async Task Can_seek_from_middle_to_end() { - var mockRequest = new HttpRequestMock(); + var mockRequest = new MockHttpRequest(); mockRequest.Headers.Add("Range", "bytes=4-"); - var mockResponse = new HttpResponseMock(); + var mockResponse = new MockHttpResponse(mockRequest); string customText = "1234567890"; byte[] customTextBytes = customText.ToUtf8Bytes(); @@ -275,10 +289,10 @@ public void Can_seek_from_middle_to_end() var httpResult = new HttpResult(ms, "audio/mpeg"); - bool reponseWasAutoHandled = mockResponse.WriteToResponse(mockRequest, httpResult); + bool reponseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); Assert.That(reponseWasAutoHandled, Is.True); - string writtenString = mockResponse.GetOutputStreamAsString(); + string writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo("567890")); Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 4-9/10")); @@ -288,11 +302,11 @@ public void Can_seek_from_middle_to_end() } [Test] - public void Can_seek_from_middle_to_middle() + public async Task Can_seek_from_middle_to_middle() { - var mockRequest = new HttpRequestMock(); + var mockRequest = new MockHttpRequest(); mockRequest.Headers.Add("Range", "bytes=3-5"); - var mockResponse = new HttpResponseMock(); + var mockResponse = new MockHttpResponse(mockRequest); string customText = "1234567890"; byte[] customTextBytes = customText.ToUtf8Bytes(); @@ -302,10 +316,10 @@ public void Can_seek_from_middle_to_middle() var httpResult = new HttpResult(ms, "audio/mpeg"); - bool reponseWasAutoHandled = mockResponse.WriteToResponse(mockRequest, httpResult); - Assert.That(reponseWasAutoHandled, Is.True); + bool responseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); + Assert.That(responseWasAutoHandled, Is.True); - string writtenString = mockResponse.GetOutputStreamAsString(); + string writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo("456")); Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 3-5/10")); @@ -315,7 +329,7 @@ public void Can_seek_from_middle_to_middle() } [Test] - public void Can_use_fileStream() + public async Task Can_use_fileStream() { byte[] fileBytes = uploadedTextFile.ReadFully(); string fileText = Encoding.ASCII.GetString(fileBytes); @@ -323,16 +337,16 @@ public void Can_use_fileStream() "File content size {0}".Print(fileBytes.Length); "File content is {0}".Print(fileText); - var mockRequest = new HttpRequestMock(); - var mockResponse = new HttpResponseMock(); + var mockRequest = new MockHttpRequest(); + var mockResponse = new MockHttpResponse(mockRequest); mockRequest.Headers.Add("Range", "bytes=6-8"); var httpResult = new HttpResult(uploadedTextFile, "audio/mpeg"); - bool reponseWasAutoHandled = mockResponse.WriteToResponse(mockRequest, httpResult); + bool reponseWasAutoHandled = await mockResponse.WriteToResponse(mockRequest, httpResult); Assert.That(reponseWasAutoHandled, Is.True); - string writtenString = mockResponse.GetOutputStreamAsString(); + string writtenString = mockResponse.ReadAsString(); Assert.That(writtenString, Is.EqualTo(fileText.Substring(6, 3))); Assert.That(mockResponse.Headers["Content-Range"], Is.EqualTo("bytes 6-8/33")); @@ -342,7 +356,7 @@ public void Can_use_fileStream() } [Test] - [Explicit("Helps debugging when you need to find out WTF is going on")] + [Ignore("Helps debugging when you need to find out WTF is going on")] public void Run_for_30secs() { Thread.Sleep(30000); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/PasswordHasherTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/PasswordHasherTests.cs new file mode 100644 index 00000000000..40968b6cd93 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/PasswordHasherTests.cs @@ -0,0 +1,272 @@ +using System; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Data; +using ServiceStack.OrmLite; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public abstract class PasswordHasherTestsBase + { + protected ServiceStackHost appHost; + + protected class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(PasswordHasherTestsBase), typeof(PasswordHasherTestsBase).Assembly) {} + + public bool UsePasswordHasher { get; set; } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DebugMode = true + }); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(AppSettings), + }) + { + IncludeRegistrationService = true + }); + + container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register<IAuthRepository>(c => + new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())); + + container.Resolve<IAuthRepository>().InitSchema(); + + var authRepo = container.Resolve<IAuthRepository>(); + + Config.UseSaltedHash = UsePasswordHasher; + + authRepo.CreateUserAuth(new UserAuth + { + UserName = "oldUser", + Email = "oldUser@email.com", + DisplayName = "Old User", + FirstName = "Old", + LastName = "User", + }, "oldpass"); + + Config.UseSaltedHash = !UsePasswordHasher; + + authRepo.CreateUserAuth(new UserAuth + { + UserName = "newUser", + Email = "newUser@email.com", + DisplayName = "New User", + FirstName = "New", + LastName = "User", + }, "newpass"); + } + } + + protected readonly IUserAuth origNewUser; + protected readonly IUserAuth origOldUser; + + protected PasswordHasherTestsBase() + { + appHost = CreateAppHost(); + + origNewUser = appHost.GetAuthRepository().GetUserAuthByUserName("newUser"); + origOldUser = appHost.GetAuthRepository().GetUserAuthByUserName("oldUser"); + } + + protected abstract ServiceStackHost CreateAppHost(); + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + protected virtual JsonServiceClient CreateClient() => new JsonServiceClient(Config.ListeningOn); + + protected void AssertUsedNewPasswordHasher(IUserAuth user) + { + Assert.That(user.PasswordHash != null && user.Salt == null); + + byte[] decodedHashedPassword = Convert.FromBase64String(user.PasswordHash); + + Assert.That(decodedHashedPassword[0], Is.EqualTo(0x01)); + Assert.That(appHost.TryResolve<IPasswordHasher>().Version, Is.EqualTo(0x01)); + } + + protected void AssertUsedOldSaltedHash(IUserAuth user) => Assert.That(user.PasswordHash != null && user.Salt != null); + } + + class PasswordHasherUpgradeTests : PasswordHasherTestsBase + { + protected override ServiceStackHost CreateAppHost() => new AppHost + { + UsePasswordHasher = true, + } + .Init() + .Start(Config.ListeningOn); + + [Test] + public void Does_use_old_SaltedHash_for_oldUser() + { + AssertUsedOldSaltedHash(origOldUser); + } + + [Test] + public void Does_use_new_PasswordHasher_for_newUser() + { + AssertUsedNewPasswordHasher(origNewUser); + } + + [Test] + public void Can_authenticate_with_oldUser_which_upgrade_to_PasswordHash() + { + var client = CreateClient(); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "oldUser", + Password = "oldpass", + }); + + Assert.That(response.DisplayName, Is.EqualTo("Old User")); + + var oldUserAfterAuth = appHost.GetAuthRepository().GetUserAuthByUserName("oldUser"); + AssertUsedNewPasswordHasher(oldUserAfterAuth); + + //Can re-auth after password hash upgrade + response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "oldUser", + Password = "oldpass", + }); + + Assert.That(response.DisplayName, Is.EqualTo("Old User")); + AssertUsedNewPasswordHasher(oldUserAfterAuth); + } + + [Test] + public void Can_Autenticate_with_newUser_which_retains_new_PasswordHash() + { + var client = CreateClient(); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "newUser", + Password = "newpass", + }); + + Assert.That(response.DisplayName, Is.EqualTo("New User")); + + var newUserAfterAuth = appHost.GetAuthRepository().GetUserAuthByUserName("newUser"); + AssertUsedNewPasswordHasher(newUserAfterAuth); + } + + [Test] + public void New_registered_user_uses_new_PasswordHash() + { + var client = CreateClient(); + + var response = client.Post(new Register + { + UserName = "newUser2", + Email = "newUser2@email.com", + DisplayName = "New User2", + FirstName = "New2", + LastName = "User", + Password = "newpass2" + }); + + var newUser2 = appHost.GetAuthRepository().GetUserAuthByUserName("newUser2"); + AssertUsedNewPasswordHasher(newUser2); + + client.Post(new Authenticate + { + provider = "credentials", + UserName = "newUser2", + Password = "newpass2", + }); + } + } + + public class PasswordHasherDowngradeTests : PasswordHasherTestsBase + { + protected override ServiceStackHost CreateAppHost() => new AppHost + { + UsePasswordHasher = false, + } + .Init() + .Start(Config.ListeningOn); + + [Test] + public void Does_use_new_PasswordHasher_for_oldUser() + { + AssertUsedNewPasswordHasher(origOldUser); + } + + [Test] + public void Does_use_old_SaltedHash_for_newUser() + { + AssertUsedOldSaltedHash(origNewUser); + } + + [Test] + public void Can_authenticate_with_oldUser_which_downgrades_to_SaltedHash() + { + var client = CreateClient(); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "oldUser", + Password = "oldpass", + }); + + Assert.That(response.DisplayName, Is.EqualTo("Old User")); + + var oldUserAfterAuth = appHost.GetAuthRepository().GetUserAuthByUserName("oldUser"); + AssertUsedOldSaltedHash(oldUserAfterAuth); + + //Can re-auth after password hash downgrade + response = client.Post(new Authenticate + { + provider = "credentials", + UserName = "oldUser", + Password = "oldpass", + }); + + Assert.That(response.DisplayName, Is.EqualTo("Old User")); + AssertUsedOldSaltedHash(oldUserAfterAuth); + } + + [Test] + public void New_registered_user_uses_old_SaltedHash() + { + var client = CreateClient(); + + var response = client.Post(new Register + { + UserName = "newUser2", + Email = "newUser2@email.com", + DisplayName = "New User2", + FirstName = "New2", + LastName = "User", + Password = "newpass2" + }); + + var newUser2 = appHost.GetAuthRepository().GetUserAuthByUserName("newUser2"); + AssertUsedOldSaltedHash(newUser2); + + client.Post(new Authenticate + { + provider = "credentials", + UserName = "newUser2", + Password = "newpass2", + }); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/AssemblyInfo.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/AssemblyInfo.cs index de4b923b1f2..4ea3fe1bfdd 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/AssemblyInfo.cs @@ -1,44 +1,10 @@ using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Serialization; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceStack.WebHost.Endpoints.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceStack.WebHost.Endpoints.Tests")] -[assembly: AssemblyCopyright("Copyright © 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a10fdf44-0168-49d4-9f25-0dfac96998ea")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] //Default DataContract namespace instead of tempuri.org //Note: doesn't work for ilmerged assemblies -[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.ServiceInterface.ServiceModel")] [assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.Endpoints.Tests.Support.Operations")] [assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.Endpoints.Tests.IntegrationTests")] [assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.Endpoints.Tests.Support.Host")] diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/launchSettings.json b/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/launchSettings.json new file mode 100644 index 00000000000..a28e6aaa3d4 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Properties/launchSettings.json @@ -0,0 +1,22 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63815/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ServiceStack.WebHost.Endpoints.Tests": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ProtoBufServiceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ProtoBufServiceTests.cs index 47e49fd6646..1f2e5371bfb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ProtoBufServiceTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ProtoBufServiceTests.cs @@ -1,139 +1,183 @@ -using System; -using System.Runtime.Serialization; +using System.Runtime.Serialization; using System.Text; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.ProtoBuf; using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { - [DataContract] - public class ProtoBufEmail - { - [DataMember(Order = 1)] - public string ToAddress { get; set; } - [DataMember(Order = 2)] - public string FromAddress { get; set; } - [DataMember(Order = 3)] - public string Subject { get; set; } - [DataMember(Order = 4)] - public string Body { get; set; } - [DataMember(Order = 5)] - public byte[] AttachmentData { get; set; } - - public bool Equals(ProtoBufEmail other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Equals(other.ToAddress, ToAddress) - && Equals(other.FromAddress, FromAddress) - && Equals(other.Subject, Subject) - && Equals(other.Body, Body) - && other.AttachmentData.EquivalentTo(AttachmentData); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (ProtoBufEmail)) return false; - return Equals((ProtoBufEmail) obj); - } - - public override int GetHashCode() - { - unchecked - { - int result = (ToAddress != null ? ToAddress.GetHashCode() : 0); - result = (result*397) ^ (FromAddress != null ? FromAddress.GetHashCode() : 0); - result = (result*397) ^ (Subject != null ? Subject.GetHashCode() : 0); - result = (result*397) ^ (Body != null ? Body.GetHashCode() : 0); - result = (result*397) ^ (AttachmentData != null ? AttachmentData.GetHashCode() : 0); - return result; - } - } - } - - [DataContract] - public class ProtoBufEmailResponse - { - [DataMember(Order = 1)] - public ResponseStatus ResponseStatus { get; set; } - } - - public class ProtoBufEmailService : ServiceInterface.Service - { + [Route("/protobufemail")] + [DataContract] + public class ProtoBufEmail + { + [DataMember(Order = 1)] + public string ToAddress { get; set; } + + [DataMember(Order = 2)] + public string FromAddress { get; set; } + + [DataMember(Order = 3)] + public string Subject { get; set; } + + [DataMember(Order = 4)] + public string Body { get; set; } + + [DataMember(Order = 5)] + public byte[] AttachmentData { get; set; } + + public bool Equals(ProtoBufEmail other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.ToAddress, ToAddress) + && Equals(other.FromAddress, FromAddress) + && Equals(other.Subject, Subject) + && Equals(other.Body, Body) + && other.AttachmentData.EquivalentTo(AttachmentData); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(ProtoBufEmail)) return false; + return Equals((ProtoBufEmail) obj); + } + + public override int GetHashCode() + { + unchecked + { + int result = (ToAddress != null ? ToAddress.GetHashCode() : 0); + result = (result * 397) ^ (FromAddress != null ? FromAddress.GetHashCode() : 0); + result = (result * 397) ^ (Subject != null ? Subject.GetHashCode() : 0); + result = (result * 397) ^ (Body != null ? Body.GetHashCode() : 0); + result = (result * 397) ^ (AttachmentData != null ? AttachmentData.GetHashCode() : 0); + return result; + } + } + } + + [DataContract] + public class ProtoBufEmailResponse + { + [DataMember(Order = 1)] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ProtoBufEmailService : Service + { public object Any(ProtoBufEmail request) - { - return request; - } - } - - - [TestFixture] - public class ProtoBufServiceTests - { - protected const string ListeningOn = "http://localhost:85/"; - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - LogManager.LogFactory = new ConsoleLogFactory(); - - appHost = new ExampleAppHostHttpListener(); - appHost.Plugins.Add(new ProtoBufFormat()); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - Dispose(); - } - - public void Dispose() - { - if (appHost == null) return; - appHost.Dispose(); - appHost = null; - } - - [Test] - public void Can_Send_ProtoBuf_request() - { - var client = new ProtoBufServiceClient(ListeningOn); - - var request = new ProtoBufEmail { - ToAddress = "to@email.com", - FromAddress = "from@email.com", - Subject = "Subject", - Body = "Body", - AttachmentData = Encoding.UTF8.GetBytes("AttachmentData"), - }; - - try - { - var response = client.Send<ProtoBufEmail>(request); - - Console.WriteLine(response.Dump()); - - Assert.That(response.Equals(request)); - } - catch (WebServiceException webEx) - { - Console.WriteLine(webEx.ResponseDto.Dump()); - } - } - - } + { + return request; + } + } + + + [TestFixture] + public class ProtoBufServiceTests + { + protected const string ListeningOn = "http://localhost:1337/"; + + ExampleAppHostHttpListener appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + LogManager.LogFactory = new ConsoleLogFactory(); + + appHost = new ExampleAppHostHttpListener(); + appHost.Plugins.Add(new ProtoBufFormat()); + appHost.Init(); + appHost.Start(ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + Dispose(); + } + + public void Dispose() + { + if (appHost == null) return; + appHost.Dispose(); + } + + private static ProtoBufEmail CreateProtoBufEmail() + { + var request = new ProtoBufEmail { + ToAddress = "to@email.com", + FromAddress = "from@email.com", + Subject = "Subject", + Body = "Body", + AttachmentData = Encoding.UTF8.GetBytes("AttachmentData"), + }; + return request; + } + + [Test] + public void Can_Serialize_ProtoBufEmail_with_RecyclableMemoryStream() + { + var request = CreateProtoBufEmail(); + + // using var ms = new MemoryStream(); + using var ms = MemoryStreamFactory.GetStream(); + ProtoBufFormat.Serialize(request, ms); + + ms.Position = 0; + var response = ProtoBufFormat.Deserialize(request.GetType(), ms); + + Assert.That(response.Equals(request)); + } + + [Test] + public void Can_Send_ProtoBuf_request() + { + var client = new ProtoBufServiceClient(ListeningOn) { + RequestFilter = req => + Assert.That(req.Accept, Is.EqualTo(MimeTypes.ProtoBuf)) + }; + + var request = CreateProtoBufEmail(); + var response = client.Send<ProtoBufEmail>(request); + + response.PrintDump(); + Assert.That(response.Equals(request)); + } + + [Test] + public async Task Can_Send_ProtoBuf_request_Async() + { + var client = new ProtoBufServiceClient(ListeningOn) { + RequestFilter = req => + Assert.That(req.Accept, Is.EqualTo(MimeTypes.ProtoBuf)) + }; + + var request = CreateProtoBufEmail(); + var response = await client.SendAsync<ProtoBufEmail>(request); + + response.PrintDump(); + Assert.That(response.Equals(request)); + } + + [Test] + public void Does_return_ProtoBuf_when_using_ProtoBuf_Content_Type_and_Wildcard() + { + var bytes = ListeningOn.CombineWith("protobufemail") + .PostBytesToUrl(accept: "{0}, */*".Fmt(MimeTypes.ProtoBuf), + contentType: MimeTypes.ProtoBuf, + requestBody: CreateProtoBufEmail().ToProtoBuf(), + responseFilter: res => Assert.That(res.MatchesContentType(MimeTypes.ProtoBuf))); + + Assert.That(bytes.Length, Is.GreaterThan(0)); + + bytes = ListeningOn.CombineWith("protobufemail") + .GetBytesFromUrl(accept: "{0}, */*".Fmt(MimeTypes.ProtoBuf), + responseFilter: res => Assert.That(res.MatchesContentType(MimeTypes.ProtoBuf))); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RawRequestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RawRequestTests.cs index fd144ddbf6a..c97a984f328 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RawRequestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RawRequestTests.cs @@ -1,88 +1,190 @@ -using System; -using System.IO; -using System.Net; +using System.IO; +using System.Threading.Tasks; +using Funq; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.Tests +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests { - [RestService("/rawrequest")] - public class RawRequest : IRequiresRequestStream - { - public Stream RequestStream { get; set; } - } - - public class RawRequestResponse - { - public string Result { get; set; } - } - - public class RawRequestService : IService<RawRequest> - { - public object Execute(RawRequest request) - { - var rawRequest = request.RequestStream.ToUtf8String(); - return new RawRequestResponse { Result = rawRequest }; - } - } - - [TestFixture] - public class RawRequestTests - { - static class Config - { - public const string AbsoluteBaseUri = "http://localhost:82/"; - } - - ExampleAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureStartUp() - { - appHost = new ExampleAppHostHttpListener(); - appHost.Init(); - appHost.Start(Config.AbsoluteBaseUri); - - System.Console.WriteLine("RawRequestTests Created at {0}, listening on {1}", - DateTime.Now, Config.AbsoluteBaseUri); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - appHost = null; - } - - [Test] - public void Can_POST_raw_request() - { - var rawData = "<<(( 'RAW_DATA' ))>>"; - var requestUrl = Config.AbsoluteBaseUri + "/rawrequest"; - var json = requestUrl.PutToUrl(rawData, ContentType.Json); - var response = json.FromJson<RawRequestResponse>(); - Assert.That(response.Result, Is.EqualTo(rawData)); - } - - [Test] - public void Can_PUT_raw_request() - { - var rawData = "<<(( 'RAW_DATA' ))>>"; - var requestUrl = Config.AbsoluteBaseUri + "/rawrequest"; - var json = requestUrl.PutToUrl(rawData, ContentType.Json); - var response = json.FromJson<RawRequestResponse>(); - Assert.That(response.Result, Is.EqualTo(rawData)); - } - - } + [Route("/rawbytesrequest")] + public class RawBytesRequest : IRequiresRequestStream + { + public Stream RequestStream { get; set; } + } + + [Route("/rawrequest")] + public class RawRequest : IRequiresRequestStream + { + public Stream RequestStream { get; set; } + } + + [Route("/rawrequest/{Path}")] + public class RawRequestWithParam : IRequiresRequestStream + { + public string Path { get; set; } + public string Param { get; set; } + public Stream RequestStream { get; set; } + } + + public class RawRequestResponse + { + public string Result { get; set; } + } + + [Restrict(RequestAttributes.Xml)] + [Route("/Leads/LeadData/", "POST", Notes = "LMS - DirectApi")] + public class CustomXml : IRequiresRequestStream + { + public Stream RequestStream { get; set; } + } + + [Route("/rawsvg/{Letter}", "GET")] + public class RawSvg + { + public string Letter { get; set; } + } + + public class RawRequestService : Service + { + public async Task<object> Any(RawBytesRequest request) + { + var rawRequest = await request.RequestStream.ReadFullyAsync(); + return new RawRequestResponse { Result = rawRequest.FromUtf8Bytes() }; + } + + public async Task<object> Any(RawRequest request) + { + var rawRequest = await request.RequestStream.ReadToEndAsync(); + return new RawRequestResponse { Result = rawRequest }; + } + + public async Task<object> Any(RawRequestWithParam request) + { + var rawRequest = await request.RequestStream.ReadToEndAsync(); + return new RawRequestResponse { Result = request.Path + ":" + request.Param + ":" + rawRequest }; + } + + public async Task<object> Any(CustomXml request) + { + var xml = await request.RequestStream.ReadToEndAsync(); + return xml; + } + + private const string SvgTemplate = @"<svg width=""100"" height=""100"" xmlns=""http://www.w3.org/2000/svg""> + <g> + <rect x=""0"" y=""0"" width=""100"" height=""100"" id=""canvas_background"" fill=""#999999""/> + </g> + <g> + <text x=""50%"" y=""60%"" alignment-baseline=""middle"" text-anchor=""middle"" fill=""#ffffff"" font-size=""80"" font-family=""Helvetica, Arial, sans-serif"" font-weight=""bold"">LETTER</text> + </g> +</svg>"; + + public object Get(RawSvg request) + { + Response.ContentType = MimeTypes.GetMimeType("svg"); + return SvgTemplate.Replace("LETTER", (request.Letter ?? "A").Substring(0, 1).ToUpper()); + } + } + + [TestFixture] + public class RawRequestTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(RawRequestTests), typeof(RawRequestService).Assembly) {} + + public override void Configure(Container container) + { + } + } + + private readonly ServiceStackHost appHost; + public RawRequestTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_POST_raw_request() + { + var rawData = "<<(( 'RAW_DATA' ))>>"; + var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; + var json = requestUrl.PostStringToUrl(rawData, contentType: MimeTypes.PlainText, accept: MimeTypes.Json); + var response = json.FromJson<RawRequestResponse>(); + Assert.That(response.Result, Is.EqualTo(rawData)); + } + + [Test] + public void Can_POST_raw_request_to_predefined_route() + { + var rawData = "{\"raw\":\"json\"}"; + var requestUrl = Config.ServiceStackBaseUri + "/json/reply/RawRequest"; + var json = requestUrl.PostJsonToUrl(rawData); + var response = json.FromJson<RawRequestResponse>(); + Assert.That(response.Result, Is.EqualTo(rawData)); + } + + [Test] + public void Can_POST_raw_request_with_params() + { + var rawData = "<<(( 'RAW_DATA' ))>>"; + var requestUrl = Config.ServiceStackBaseUri + "/rawrequest/Foo?Param=Bar"; + var json = requestUrl.PostStringToUrl(rawData, contentType: MimeTypes.PlainText, accept: MimeTypes.Json); + var response = json.FromJson<RawRequestResponse>(); + var expected = "{0}:{1}:{2}".Fmt("Foo", "Bar", rawData); + Assert.That(response.Result, Is.EqualTo(expected)); + } + + [Test] + public void Can_PUT_raw_request() + { + var rawData = "<<(( 'RAW_DATA' ))>>"; + var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; + var json = requestUrl.PutStringToUrl(rawData, contentType: MimeTypes.PlainText, accept: MimeTypes.Json); + var response = json.FromJson<RawRequestResponse>(); + Assert.That(response.Result, Is.EqualTo(rawData)); + } + + [Test] + public void Can_POST_Custom_XML() + { + var xml = @"<LeadApplications> + <LeadApplication> + <Email>daffy.duck@example.com</Email> + <FirstName>Joey</FirstName> + <MiddleName>Disney</MiddleName> + <LastName>Duck</LastName> + <Street1>1 Disneyland Street</Street1> + <Street2>2 Disneyland Street</Street2> + <City>PAUMA VALLEY</City> + <State>CA</State> + <Zip>92503</Zip> + </LeadApplication> + </LeadApplications>"; + + var requestUrl = Config.ServiceStackBaseUri + "/Leads/LeadData/"; + var responseXml = requestUrl.PostXmlToUrl(xml); + + Assert.That(responseXml, Is.EqualTo(xml)); + } + + [Test] + public void Can_download_svg() + { + var requestUrl = Config.ServiceStackBaseUri + "/rawsvg/M"; + var svg = requestUrl.GetStringFromUrl( + accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + responseFilter: res => Assert.That(res.GetHeader(HttpHeaders.ContentType), Does.StartWith(MimeTypes.ImageSvg))); + + Assert.That(svg, Does.Contain(">M</text>")); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RedirectPathTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RedirectPathTests.cs new file mode 100644 index 00000000000..ce95571e136 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RedirectPathTests.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class RedirectPathTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(RedirectPathTests), typeof(RedirectPathTests).Assembly) + { + } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DefaultRedirectPath = "~/does-resolve" + }); + } + + public override string ResolveAbsoluteUrl(string virtualPath, IRequest httpReq) + { + return virtualPath == "~/does-resolve" + ? base.ResolveAbsoluteUrl("~/webpage.html", httpReq) + : base.ResolveAbsoluteUrl(virtualPath, httpReq); + } + } + + private readonly ServiceStackHost appHost; + + public RedirectPathTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void DefaultRedirectPath_RelativeUrl_does_resolve() + { + var html = Config.ListeningOn.GetStringFromUrl(); + Assert.That(html, Does.Contain("Default index")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RemoteEndDropsConnectionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RemoteEndDropsConnectionTests.cs index 87446e347be..3ed5423e481 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RemoteEndDropsConnectionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RemoteEndDropsConnectionTests.cs @@ -3,7 +3,6 @@ using System.Threading; using NUnit.Framework; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; using System.Linq; @@ -12,7 +11,7 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class RemoteEndDropsConnectionTests { - private const string ListeningOn = "http://localhost:82/"; + private const string ListeningOn = "http://localhost:1337/"; ExampleAppHostHttpListener appHost; public RemoteEndDropsConnectionTests() @@ -20,7 +19,7 @@ public RemoteEndDropsConnectionTests() LogManager.LogFactory = new TestLogFactory(); } - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureStartUp() { appHost = new ExampleAppHostHttpListener(); @@ -28,15 +27,14 @@ public void OnTestFixtureStartUp() appHost.Init(); appHost.Start(ListeningOn); - Console.WriteLine("ExampleAppHost Created at {0}, listening on {1}", + Console.WriteLine(@"ExampleAppHost Created at {0}, listening on {1}", DateTime.Now, ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [SetUp] @@ -56,7 +54,7 @@ public void TearDown() /// <summary> /// *Request* DTO /// </summary> - [ServiceStack.ServiceHost.RestService("/test/timed", "GET")] + [Route("/test/timed", "GET")] public class Timed { /// <summary> @@ -65,7 +63,7 @@ public class Timed public int Milliseconds { get; set; } } - public class TimedService : ServiceInterface.Service + public class TimedService : Service { public object Any(Timed request) { @@ -84,13 +82,15 @@ public object Any(Timed request) [TestCase(true)] public void TestClientDropsConnection(bool writeErrorsToResponse) { - EndpointHost.Config.WriteErrorsToResponse = writeErrorsToResponse; + HostContext.Config.WriteErrorsToResponse = writeErrorsToResponse; const int sleepMs = 1000; var url = string.Format("{0}test/timed?Milliseconds={1}", ListeningOn, sleepMs); var req = WebRequest.Create(url) as HttpWebRequest; //Set a short timeout so we'll give up before the request is processed +#if !NETCORE req.Timeout = 100; +#endif try { var res = (HttpWebResponse)req.GetResponse(); @@ -108,7 +108,7 @@ public void TestClientDropsConnection(bool writeErrorsToResponse) foreach (var pair in TestLogger.GetLogs()) { - Console.WriteLine("TEST: {0}: {1}", pair.Key, pair.Value); + Console.WriteLine(@"TEST: {0}: {1}", pair.Key, pair.Value); } if (!writeErrorsToResponse) @@ -129,4 +129,4 @@ public void TestClientDropsConnection(bool writeErrorsToResponse) } } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ReplyAllTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ReplyAllTests.cs new file mode 100644 index 00000000000..1035976dc69 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ReplyAllTests.cs @@ -0,0 +1,736 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Redis; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ReplyAllAppHost : AppSelfHostBase + { + public ReplyAllAppHost() + : base(typeof(ReplyAllTests).Name, typeof(ReplyAllService).Assembly) + { } + + public override void Configure(Container container) + { + GlobalRequestFilters.Add((rew, res, dto) => + ReplyAllRequestAttribute.AssertSingleDto(dto)); + + GlobalResponseFilters.Add((rew, res, dto) => + ReplyAllResponseAttribute.AssertSingleDto(dto)); + + container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.Register<IRedisClientsManager>(c => + new RedisManagerPool()); + } + } + + public class ReplyAllRequestAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + AssertSingleDto(requestDto); + } + + public static void AssertSingleDto(object dto) + { + if (!(dto is BatchThrows || dto is BatchThrowsAsync || dto is NoRepeat || dto is HelloAll || dto is HelloAllAsync || dto is HelloAllVoid || dto is HelloAllVoidAsync || dto is HelloGet || dto is HelloAllCustom || dto is HelloAllTransaction || dto is Request)) + throw new Exception("Invalid " + dto.GetType().Name); + } + } + + public class ReplyAllResponseAttribute : ResponseFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object responseDto) + { + AssertSingleDto(responseDto); + } + + public static void AssertSingleDto(object dto) + { + if (!(dto == null || dto is Task || dto is BatchThrowsResponse || dto is NoRepeatResponse || dto is HelloAllResponse || dto is HelloAllCustomResponse + || dto is HelloAllTransactionResponse || dto is IHttpResult)) + throw new Exception("Invalid " + dto.GetType().Name); + } + } + + public class ReplyAllArrayRequestAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + if (requestDto.GetType() != typeof(HelloAllCustom[])) + throw new Exception("Invalid " + requestDto.GetType().Name); + } + } + + public class ReplyAllArrayResponseAttribute : ResponseFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object responseDto) + { + //still based on Response of Service + if (responseDto.GetType() != typeof(List<HelloAllCustomResponse>)) + throw new Exception("Invalid " + responseDto.GetType().Name); + } + } + + public class HelloAll : IReturn<HelloAllResponse> + { + public string Name { get; set; } + } + + public class HelloAllAsync : IReturn<HelloAllResponse> + { + public string Name { get; set; } + } + + public class HelloAllVoid : IReturnVoid + { + public static int Counter; + + public string Name { get; set; } + } + + public class HelloAllVoidAsync : IReturnVoid + { + public static int Counter; + + public string Name { get; set; } + } + + public class HelloGet : IReturn<HelloAllResponse> + { + public string Name { get; set; } + } + + public class HelloAllResponse + { + public string Result { get; set; } + } + + public class HelloAllCustom : IReturn<HelloAllCustomResponse> + { + public string Name { get; set; } + } + + public class HelloAllCustomResponse + { + public string Result { get; set; } + } + + public class HelloAllTransaction : IReturn<HelloAllTransactionResponse> + { + public string Name { get; set; } + } + + public class HelloAllTransactionResponse + { + public string Result { get; set; } + } + + public class Request : IReturnVoid + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class ReplyAllService : Service + { + public static int TimesExecuted = 0; + + [ReplyAllRequest] + [ReplyAllResponse] + public object Any(HelloAll request) + { + TimesExecuted++; + return new HelloAllResponse { Result = "Hello, {0}!".Fmt(request.Name) }; + } + + [ReplyAllRequest] + [ReplyAllResponse] + public object Any(HelloAllAsync request) + { + return Task.FromResult(new HelloAllResponse { Result = "Hello, {0}!".Fmt(request.Name) }); + } + + public object Get(HelloGet request) + { + return new HelloAllResponse { Result = "Hello, {0}!".Fmt(request.Name) }; + } + + public void Any(HelloAllVoid request) + { + HelloAllVoid.Counter++; + } + + public async Task Any(HelloAllVoidAsync request) + { + HelloAllVoidAsync.Counter++; + await Task.FromResult(0); + } + + [ReplyAllRequest] + [ReplyAllResponse] + public object Any(HelloAllCustom request) + { + return new HelloAllCustomResponse { Result = "Hello, {0}!".Fmt(request.Name) }; + } + + [ReplyAllArrayRequest] + [ReplyAllArrayResponse] + public object Any(HelloAllCustom[] requests) + { + return requests.Map(x => new HelloAllCustomResponse + { + Result = "Custom, {0}!".Fmt(x.Name) + }); + } + + public object Any(HelloAllTransaction request) + { + if (request.Name == "Bar") + throw new ArgumentException("No Bar allowed here"); + + Db.Insert(request); + + return new HelloAllTransactionResponse { Result = "Hello, {0}!".Fmt(request.Name) }; + } + + public object Any(HelloAllTransaction[] requests) + { + using (var trans = Db.OpenTransaction()) + { + var response = requests.Map(Any); + + trans.Commit(); + + return response; + } + } + + public void Any(Request request) + { + Redis.Store(request); + } + + public void Any(Request[] requests) + { + Redis.StoreAll(requests); + } + } + + public class NoRepeat : IReturn<NoRepeatResponse> + { + public Guid Id { get; set; } + } + + public class NoRepeatResponse + { + public Guid Id { get; set; } + } + + public class BatchThrows : IReturn<BatchThrowsResponse> + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class BatchThrowsAsync : IReturn<BatchThrowsResponse> + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class BatchThrowsResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class AutoBatchServices : IService + { + private static readonly HashSet<Guid> ReceivedGuids = new HashSet<Guid>(); + + public NoRepeatResponse Any(NoRepeat request) + { + if (ReceivedGuids.Contains(request.Id)) + throw new ArgumentException("Id {0} already received".Fmt(request.Id)); + + ReceivedGuids.Add(request.Id); + + return new NoRepeatResponse + { + Id = request.Id + }; + } + + public object Any(BatchThrows request) + { + throw new Exception("Batch Throws"); + } + + public async Task Any(BatchThrowsAsync request) + { + await Task.Delay(0); + + throw new Exception("Batch Throws"); + } + } + + public class ReplyAllJsonServiceClientTests : ReplyAllTests + { + public override IServiceClient CreateClient(string baseUri) + { + return new JsonServiceClient(baseUri); + } + + public override IServiceClientAsync CreateClientAsync(string baseUri) + { + return new JsonServiceClient(baseUri); + } + } + + public class ReplyAllJsonHttpClientTests : ReplyAllTests + { + public override IServiceClient CreateClient(string baseUri) + { + return new JsonHttpClient(baseUri); + } + + public override IServiceClientAsync CreateClientAsync(string baseUri) + { + return new JsonHttpClient(baseUri); + } + } + + public class ReplyAllXmlServiceClientTests : ReplyAllTests + { + public override IServiceClient CreateClient(string baseUri) + { + return new XmlServiceClient(baseUri); + } + + public override IServiceClientAsync CreateClientAsync(string baseUri) + { + return new XmlServiceClient(baseUri); + } + } + + public class ReplyAllCsvServiceClientTests : ReplyAllTests + { + public override IServiceClient CreateClient(string baseUri) + { + return new CsvServiceClient(baseUri); + } + + public override IServiceClientAsync CreateClientAsync(string baseUri) + { + return new CsvServiceClient(baseUri); + } + } + + [TestFixture] + public abstract class ReplyAllTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new ReplyAllAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public abstract IServiceClient CreateClient(string baseUri); + public abstract IServiceClientAsync CreateClientAsync(string baseUri); + + [Test] + public void Can_send_single_HelloAll_request() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var request = new HelloAll { Name = "Foo" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo("Hello, Foo!")); + } + + [Test] + public async Task Can_send_single_HelloAllAsync_request() + { + var client = CreateClientAsync(Config.AbsoluteBaseUri); + + var request = new HelloAllAsync { Name = "Foo" }; + var response = await client.SendAsync<HelloAllResponse>(request); + Assert.That(response.Result, Is.EqualTo("Hello, Foo!")); + } + + [Test] + public void Can_send_multi_reply_HelloAll_requests() + { + ReplyAllService.TimesExecuted = 0; + + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAll { Name = "Foo" }, + new HelloAll { Name = "Bar" }, + new HelloAll { Name = "Baz" }, + }; + + var responses = client.SendAll(requests); + var results = responses.Map(x => x.Result); + + Assert.That(results, Is.EquivalentTo(new[] { + "Hello, Foo!", "Hello, Bar!", "Hello, Baz!" + })); + + Assert.That(ReplyAllService.TimesExecuted, Is.EqualTo(requests.Length)); + } + + [Test] + public async Task Can_send_multi_reply_HelloAllAsync_requests() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllAsync { Name = "Foo" }, + new HelloAllAsync { Name = "Bar" }, + new HelloAllAsync { Name = "Baz" }, + }; + + var responses = await client.SendAllAsync(requests); + var results = responses.Map(x => x.Result); + + Assert.That(results, Is.EquivalentTo(new[] { + "Hello, Foo!", "Hello, Bar!", "Hello, Baz!" + })); + } + + [Test] + public void Can_send_multi_reply_HelloGet_requests() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri) + { + RequestFilter = req => + req.Headers[HttpHeaders.XHttpMethodOverride] = HttpMethods.Get + }; + + var requests = new[] + { + new HelloGet { Name = "Foo" }, + new HelloGet { Name = "Bar" }, + new HelloGet { Name = "Baz" }, + }; + + client.Get(new HelloGet { Name = "aaa" }); + + var responses = client.SendAll(requests); + var results = responses.Map(x => x.Result); + + Assert.That(results, Is.EquivalentTo(new[] { + "Hello, Foo!", "Hello, Bar!", "Hello, Baz!" + })); + } + + [Test] + public void Can_send_multi_HelloAllVoid() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllVoid { Name = "Foo" }, + new HelloAllVoid { Name = "Bar" }, + new HelloAllVoid { Name = "Baz" }, + }; + + client.SendAllOneWay(requests); + } + + [Test] + public void Can_send_PublishAll_HelloAllVoid() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllVoid { Name = "Foo" }, + new HelloAllVoid { Name = "Bar" }, + new HelloAllVoid { Name = "Baz" }, + }; + + client.PublishAll(requests); + } + + [Test] + public void Can_send_multi_HelloAllVoidAsync() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllVoidAsync { Name = "Foo" }, + new HelloAllVoidAsync { Name = "Bar" }, + new HelloAllVoidAsync { Name = "Baz" }, + }; + + client.SendAllOneWay(requests); + } + + [Test] + public async Task Can_send_PublishAllAsync_HelloAllVoidAsync() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllVoidAsync { Name = "Foo" }, + new HelloAllVoidAsync { Name = "Bar" }, + new HelloAllVoidAsync { Name = "Baz" }, + }; + + await client.PublishAllAsync(requests); + } + + [Test] + public void Can_send_single_HelloAllCustom_request() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var request = new HelloAllCustom { Name = "Foo" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo("Hello, Foo!")); + } + + [Test] + public void Can_send_multi_reply_HelloAllCustom_requests() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllCustom { Name = "Foo" }, + new HelloAllCustom { Name = "Bar" }, + new HelloAllCustom { Name = "Baz" }, + }; + + var responses = client.SendAll(requests); + var results = responses.Map(x => x.Result); + + Assert.That(results, Is.EquivalentTo(new[] { + "Custom, Foo!", "Custom, Bar!", "Custom, Baz!" + })); + } + + [Test] + public async Task Can_send_async_multi_reply_HelloAllCustom_requests() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllCustom { Name = "Foo" }, + new HelloAllCustom { Name = "Bar" }, + new HelloAllCustom { Name = "Baz" }, + }; + + var responses = await client.SendAllAsync(requests); + var results = responses.Map(x => x.Result); + + Assert.That(results, Is.EquivalentTo(new[] { + "Custom, Foo!", "Custom, Bar!", "Custom, Baz!" + })); + } + + [Test] + public void Can_send_multi_oneway_HelloAllCustom_requests() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new HelloAllCustom { Name = "Foo" }, + new HelloAllCustom { Name = "Bar" }, + new HelloAllCustom { Name = "Baz" }, + }; + + client.SendAllOneWay(requests); + } + + [Test] + public void Can_send_multiple_single_HelloAllTransaction() + { + using (var db = appHost.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<HelloAllTransaction>(); + } + + var client = CreateClient(Config.AbsoluteBaseUri); + + var names = new[] { "Foo", "Bar", "Baz" }; + + try + { + foreach (var name in names) + { + client.Send(new HelloAllTransaction { Name = name }); + } + + Assert.Fail("Should throw on Bar"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(ArgumentException).Name)); + } + + using (var db = appHost.Resolve<IDbConnectionFactory>().Open()) + { + var allRequests = db.Select<HelloAllTransaction>(); + Assert.That(allRequests.Count, Is.EqualTo(1)); + Assert.That(allRequests[0].Name, Is.EqualTo("Foo")); + } + } + + [Test] + public void Sending_multiple_HelloAllTransaction_does_rollback_transaction() + { + using (var db = appHost.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<HelloAllTransaction>(); + } + + var client = CreateClient(Config.AbsoluteBaseUri); + var requests = new[] + { + new HelloAllTransaction { Name = "Foo" }, + new HelloAllTransaction { Name = "Bar" }, + new HelloAllTransaction { Name = "Baz" }, + }; + + try + { + var responses = client.SendAll(requests); + + Assert.Fail("Should throw on Bar"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(ArgumentException).Name)); + } + + using (var db = appHost.Resolve<IDbConnectionFactory>().Open()) + { + var allRequests = db.Select<HelloAllTransaction>(); + Assert.That(allRequests.Count, Is.EqualTo(0)); + } + } + + [Test] + public void Can_store_multiple_requests_with_SendAllOneWay() + { + using (var redis = appHost.Resolve<IRedisClientsManager>().GetClient()) + { + redis.FlushAll(); + + var client = CreateClient(Config.AbsoluteBaseUri); + var requests = new[] + { + new Request { Id = 1, Name = "Foo" }, + new Request { Id = 2, Name = "Bar" }, + new Request { Id = 3, Name = "Baz" }, + }; + + client.SendAllOneWay(requests); + + var savedRequests = redis.As<Request>().GetAll(); + + Assert.That(savedRequests.Map(x => x.Name), Is.EquivalentTo(new[] { + "Foo", "Bar", "Baz" + })); + } + } + + [Test] + public void Does_not_repeat() + { + var client = CreateClient(Config.AbsoluteBaseUri); + var batch = new[] { new NoRepeat { Id = Guid.NewGuid() }, new NoRepeat { Id = Guid.NewGuid() } }; + + var results = client.SendAll(batch); + var guids = results.Select(r => r.Id); + Assert.IsTrue(guids.SequenceEqual(batch.Select(b => b.Id))); + } + + [Test] + public void Does_throw_WebServiceException_on_Error() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new BatchThrows { Id = 1, Name = "Foo" }, + new BatchThrows { Id = 2, Name = "Bar" }, + new BatchThrows { Id = 3, Name = "Baz" }, + }; + + try + { + var responses = client.SendAll(requests); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(Exception).Name)); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(typeof(Exception).Name)); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("Batch Throws")); + Assert.That(ex.ResponseHeaders[HttpHeaders.XAutoBatchCompleted], Is.EqualTo("0")); + } + } + + [Test] + public async Task Does_throw_WebServiceException_on_Error_Async() + { + var client = CreateClient(Config.AbsoluteBaseUri); + + var requests = new[] + { + new BatchThrowsAsync { Id = 1, Name = "Foo" }, + new BatchThrowsAsync { Id = 2, Name = "Bar" }, + new BatchThrowsAsync { Id = 3, Name = "Baz" }, + }; + + try + { + var responses = await client.SendAllAsync(requests); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(Exception).Name)); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(typeof(Exception).Name)); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("Batch Throws")); + Assert.That(ex.ResponseHeaders[HttpHeaders.XAutoBatchCompleted], Is.EqualTo("0")); + } + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestContextTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestContextTests.cs index dd7d9c457f3..c13328288e9 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestContextTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestContextTests.cs @@ -4,9 +4,9 @@ using System.Net; using Funq; using NUnit.Framework; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; +using ServiceStack.Common; using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; namespace ServiceStack.WebHost.Endpoints.Tests @@ -14,8 +14,6 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class RequestContextTests { - private const string ListeningOn = "http://localhost:82/"; - public class HeadersAppHostHttpListener : AppHostHttpListenerBase { @@ -24,10 +22,10 @@ public HeadersAppHostHttpListener() public override void Configure(Container container) { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); + HostContext.Config.GlobalResponseHeaders.Clear(); //Signal advanced web browsers what HTTP Methods you accept - base.SetConfig(new EndpointHostConfig + base.SetConfig(new HostConfig { GlobalResponseHeaders = { @@ -36,10 +34,9 @@ public override void Configure(Container container) }, }); - this.RequestFilters.Add((req, res, dto) => + this.GlobalRequestFilters.Add((req, res, dto) => { - var requestFilter = dto as RequestFilter; - if (requestFilter != null) + if (dto is RequestFilter requestFilter) { res.StatusCode = requestFilter.StatusCode; if (!requestFilter.HeaderName.IsNullOrEmpty()) @@ -53,54 +50,49 @@ public override void Configure(Container container) HeadersAppHostHttpListener appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { appHost = new HeadersAppHostHttpListener(); appHost.Init(); - appHost.Start(ListeningOn); + appHost.Start(Config.ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); } - static string GetReceivedHeaderValue(string headerName) - { - var webRequest = (HttpWebRequest)WebRequest.Create( - ListeningOn + "json/syncreply/Headers?Name=" + headerName.UrlEncode()); - - var json = new StreamReader(webRequest.GetResponse().GetResponseStream()).ReadToEnd(); - Console.WriteLine(json); - - var response = JsonSerializer.DeserializeFromString<HeadersResponse>(json); - - return response.Value; - } - public static Dictionary<string, string> GetResponseHeaders(String url) { - var webRequest = (HttpWebRequest)WebRequest.Create(url); + try + { + var webRequest = WebRequest.CreateHttp(url); + + var webResponse = webRequest.GetResponse(); - var webResponse = webRequest.GetResponse(); + var map = new Dictionary<string, string>(); + for (var i = 0; i < webResponse.Headers.Count; i++) + { + var header = webResponse.Headers.AllKeys[i]; + map[header] = webResponse.Headers[header]; + } - var map = new Dictionary<string, string>(); - for (var i = 0; i < webResponse.Headers.Count; i++) + return map; + } + catch (WebException e) { - var header = webResponse.Headers.Keys[i]; - map[header] = webResponse.Headers[header]; + Console.WriteLine(e); + throw; } - - return map; } [Test] public void Can_resolve_CustomHeader() { - var webRequest = (HttpWebRequest)WebRequest.Create( - ListeningOn + "json/syncreply/Headers?Name=X-CustomHeader"); + var webRequest = WebRequest.CreateHttp( + Config.ListeningOn + "json/reply/Headers?Name=X-CustomHeader"); webRequest.Headers["X-CustomHeader"] = "CustomValue"; var response = JsonSerializer.DeserializeFromStream<HeadersResponse>( @@ -112,7 +104,7 @@ public void Can_resolve_CustomHeader() [Test] public void Does_Send_Global_Headers() { - var headers = GetResponseHeaders(ListeningOn + "json/syncreply/Headers"); + var headers = GetResponseHeaders(Config.ListeningOn + "json/reply/Headers"); Assert.That(headers["Access-Control-Allow-Origin"], Is.EqualTo("*")); Assert.That(headers["Access-Control-Allow-Methods"], Is.EqualTo("GET, POST, PUT, DELETE, OPTIONS")); } @@ -122,8 +114,8 @@ public void Does_return_bare_401_StatusCode() { try { - var webRequest = (HttpWebRequest)WebRequest.Create( - ListeningOn + "json/syncreply/RequestFilter?StatusCode=401"); + var webRequest = WebRequest.CreateHttp( + Config.ListeningOn + "json/reply/RequestFilter?StatusCode=401"); webRequest.GetResponse(); @@ -141,8 +133,8 @@ public void Does_return_bare_401_with_AuthRequired_header() { try { - var webRequest = (HttpWebRequest)WebRequest.Create(ListeningOn - + "json/syncreply/RequestFilter?StatusCode=401" + var webRequest = WebRequest.CreateHttp(Config.ListeningOn + + "json/reply/RequestFilter?StatusCode=401" + "&HeaderName=" + HttpHeaders.WwwAuthenticate + "&HeaderValue=" + "Basic realm=\"Auth Required\"".UrlEncode()); @@ -162,4 +154,4 @@ public void Does_return_bare_401_with_AuthRequired_header() } -} \ No newline at end of file +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs index 92834edefc4..45ee693d754 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestFiltersTests.cs @@ -2,511 +2,670 @@ using System.IO; using System.Net; using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters; using System.Text; -using System.Threading; +using System.Threading.Tasks; using Funq; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Host; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { - [DataContract] - [Route("/secure")] - public class Secure - { - [DataMember] - public string UserName { get; set; } - } - - [DataContract] - public class SecureResponse : IHasResponseStatus - { - [DataMember] - public string Result { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class SecureService : IService<Secure> - { - public object Execute(Secure request) - { - return new SecureResponse { Result = "Confidential" }; - } - } - - [DataContract] - [Route("/insecure")] - public class Insecure - { - [DataMember] - public string UserName { get; set; } - } - - [DataContract] - public class InsecureResponse : IHasResponseStatus - { - [DataMember] - public string Result { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class InsecureService : IService<Insecure> - { - public object Execute(Insecure request) - { - return new InsecureResponse { Result = "Public" }; - } - } - - [TestFixture] - public abstract class RequestFiltersTests - { - private const string ListeningOn = "http://localhost:82/"; - private const string ServiceClientBaseUri = "http://localhost:82/"; - - private const string AllowedUser = "user"; - private const string AllowedPass = "p@55word"; - - public class RequestFiltersAppHostHttpListener - : AppHostHttpListenerBase - { - private Guid currentSessionGuid; - - public RequestFiltersAppHostHttpListener() - : base("Request Filters Tests", typeof(GetFactorialService).Assembly) { } - - public override void Configure(Container container) - { - this.RequestFilters.Add((req, res, dto) => - { - var userPass = req.GetBasicAuthUserAndPassword(); - if (userPass == null) - { - return; - } - - var userName = userPass.Value.Key; - if (userName == AllowedUser && userPass.Value.Value == AllowedPass) - { - currentSessionGuid = Guid.NewGuid(); - var sessionKey = userName + "/" + currentSessionGuid.ToString("N"); - - //set session for this request (as no cookies will be set on this request) - req.Items["ss-session"] = sessionKey; - res.SetPermanentCookie("ss-session", sessionKey); - } - }); - this.RequestFilters.Add((req, res, dto) => - { - if (dto is Secure) - { - var sessionId = req.GetItemOrCookie("ss-session") ?? string.Empty; - var sessionIdParts = sessionId.SplitOnFirst('/'); - if (sessionIdParts.Length < 2 || sessionIdParts[0] != AllowedUser || sessionIdParts[1] != currentSessionGuid.ToString("N")) - { - res.ReturnAuthRequired(); - } - } - }); - } - } - - RequestFiltersAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new RequestFiltersAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - EndpointHandlerBase.ServiceManager = null; - } - - protected abstract IServiceClient CreateNewServiceClient(); - protected abstract IRestClientAsync CreateNewRestClientAsync(); - - protected virtual string GetFormat() - { - return null; - } - - private static void Assert401(IServiceClient client, WebServiceException ex) - { - if (client is Soap11ServiceClient || client is Soap12ServiceClient) - { - if (ex.StatusCode != 401) - { - Console.WriteLine("WARNING: SOAP clients returning 500 instead of 401"); - } - return; - } - - Console.WriteLine(ex); - Assert.That(ex.StatusCode, Is.EqualTo(401)); - } - - private static void FailOnAsyncError<T>(T response, Exception ex) - { - Assert.Fail(ex.Message); - } - - private static bool Assert401(object response, Exception ex) - { - var webEx = (WebServiceException)ex; - Assert.That(webEx.StatusCode, Is.EqualTo(401)); - return true; - } - - [Test] - public void Can_login_with_Basic_auth_to_access_Secure_service() - { - var format = GetFormat(); - if (format == null) return; - - var req = (HttpWebRequest)WebRequest.Create( - string.Format("http://localhost:82/{0}/syncreply/Secure", format)); - - req.Headers[HttpHeaders.Authorization] - = "basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(AllowedUser + ":" + AllowedPass)); - - var dtoString = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd(); - Assert.That(dtoString.Contains("Confidential")); - Console.WriteLine(dtoString); - } - - [Test] - public void Can_login_with_Basic_auth_to_access_Secure_service_using_ServiceClient() - { - var format = GetFormat(); - if (format == null) return; - - var client = CreateNewServiceClient(); - client.SetCredentials(AllowedUser, AllowedPass); - - var response = client.Send<SecureResponse>(new Secure()); - - Assert.That(response.Result, Is.EqualTo("Confidential")); - } - - [Test] - public void Can_login_with_Basic_auth_to_access_Secure_service_using_RestClientAsync() - { - var format = GetFormat(); - if (format == null) return; - - var client = CreateNewRestClientAsync(); - client.SetCredentials(AllowedUser, AllowedPass); - - SecureResponse response = null; - client.GetAsync<SecureResponse>(ServiceClientBaseUri + "secure", - r => response = r, FailOnAsyncError); - - Thread.Sleep(2000); - Assert.That(response.Result, Is.EqualTo("Confidential")); - } - - [Test] - public void Can_login_without_authorization_to_access_Insecure_service() - { - var format = GetFormat(); - if (format == null) return; - - var req = (HttpWebRequest)WebRequest.Create( - string.Format("{0}{1}/syncreply/Insecure", ServiceClientBaseUri, format)); - - req.Headers[HttpHeaders.Authorization] - = "basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(AllowedUser + ":" + AllowedPass)); - - var dtoString = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd(); - Assert.That(dtoString.Contains("Public")); - Console.WriteLine(dtoString); - } - - [Test] - public void Can_login_without_authorization_to_access_Insecure_service_using_ServiceClient() - { - var format = GetFormat(); - if (format == null) return; - - var client = CreateNewServiceClient(); - - var response = client.Send<InsecureResponse>(new Insecure()); - - Assert.That(response.Result, Is.EqualTo("Public")); - } - - [Test] - public void Can_login_without_authorization_to_access_Insecure_service_using_RestClientAsync() - { - var format = GetFormat(); - if (format == null) return; - - var client = CreateNewRestClientAsync(); - - InsecureResponse response = null; - client.GetAsync<InsecureResponse>(ServiceClientBaseUri + "insecure", - r => response = r, FailOnAsyncError); - - Thread.Sleep(2000); - Assert.That(response.Result, Is.EqualTo("Public")); - } - - [Test] - public void Can_login_with_session_cookie_to_access_Secure_service() - { - var format = GetFormat(); - if (format == null) return; - - var req = (HttpWebRequest)WebRequest.Create( - string.Format("http://localhost:82/{0}/syncreply/Secure", format)); - - req.Headers[HttpHeaders.Authorization] - = "basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(AllowedUser + ":" + AllowedPass)); - - var res = (HttpWebResponse)req.GetResponse(); - var cookie = res.Cookies["ss-session"]; - if (cookie != null) - { - req = (HttpWebRequest)WebRequest.Create( - string.Format("http://localhost:82/{0}/syncreply/Secure", format)); - req.CookieContainer.Add(new Cookie("ss-session", cookie.Value)); - - var dtoString = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd(); - Assert.That(dtoString.Contains("Confidential")); - Console.WriteLine(dtoString); - } - } - - [Test] - public void Get_401_When_accessing_Secure_using_fake_sessionid_cookie() - { - var format = GetFormat(); - if (format == null) return; - - var req = (HttpWebRequest)WebRequest.Create( - string.Format("http://localhost:82/{0}/syncreply/Secure", format)); - - req.CookieContainer = new CookieContainer(); - req.CookieContainer.Add(new Cookie("ss-session", AllowedUser + "/" + Guid.NewGuid().ToString("N"), "/", "localhost")); - - try - { - var res = req.GetResponse(); - } - catch (WebException x) - { - Assert.That(((HttpWebResponse)x.Response).StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); - } - } - - [Test] - public void Get_401_When_accessing_Secure_using_ServiceClient_without_Authorization() - { - var client = CreateNewServiceClient(); - - try - { - var response = client.Send<SecureResponse>(new Secure()); - Console.WriteLine(response.Dump()); - } - catch (WebServiceException ex) - { - Assert401(client, ex); - return; - } - Assert.Fail("Should throw WebServiceException.StatusCode == 401"); - } - - [Test] - public void Get_401_When_accessing_Secure_using_RestClient_GET_without_Authorization() - { - var client = CreateNewRestClientAsync(); - if (client == null) return; - - SecureResponse response = null; - var wasError = false; - client.GetAsync<SecureResponse>(ServiceClientBaseUri + "secure", - r => response = r, (r, ex) => wasError = Assert401(r, ex)); - - Thread.Sleep(1000); - Assert.That(wasError, Is.True, - "Should throw WebServiceException.StatusCode == 401"); - Assert.IsNull(response); - } - - [Test] - public void Get_401_When_accessing_Secure_using_RestClient_DELETE_without_Authorization() - { - var client = CreateNewRestClientAsync(); - if (client == null) return; - - SecureResponse response = null; - var wasError = false; - client.DeleteAsync<SecureResponse>(ServiceClientBaseUri + "secure", - r => response = r, (r, ex) => wasError = Assert401(r, ex)); - - Thread.Sleep(1000); - Assert.That(wasError, Is.True, - "Should throw WebServiceException.StatusCode == 401"); - Assert.IsNull(response); - } - - [Test] - public void Get_401_When_accessing_Secure_using_RestClient_POST_without_Authorization() - { - var client = CreateNewRestClientAsync(); - if (client == null) return; - - SecureResponse response = null; - var wasError = false; - client.PostAsync<SecureResponse>(ServiceClientBaseUri + "secure", new Secure(), - r => response = r, (r, ex) => wasError = Assert401(r, ex)); - - Thread.Sleep(1000); - Assert.That(wasError, Is.True, - "Should throw WebServiceException.StatusCode == 401"); - Assert.IsNull(response); - } - - [Test] - public void Get_401_When_accessing_Secure_using_RestClient_PUT_without_Authorization() - { - var client = CreateNewRestClientAsync(); - if (client == null) return; - - SecureResponse response = null; - var wasError = false; - client.PutAsync<SecureResponse>(ServiceClientBaseUri + "secure", new Secure(), - r => response = r, (r, ex) => wasError = Assert401(r, ex)); - - Thread.Sleep(1000); - Assert.That(wasError, Is.True, - "Should throw WebServiceException.StatusCode == 401"); - Assert.IsNull(response); - } - - - public class UnitTests : RequestFiltersTests - { - protected override IServiceClient CreateNewServiceClient() - { - EndpointHandlerBase.ServiceManager = new ServiceManager(typeof(SecureService).Assembly).Init(); - return new DirectServiceClient(EndpointHandlerBase.ServiceManager); - } - - protected override IRestClientAsync CreateNewRestClientAsync() - { - return null; //TODO implement REST calls with DirectServiceClient (i.e. Unit Tests) - //EndpointHandlerBase.ServiceManager = new ServiceManager(true, typeof(SecureService).Assembly); - //return new DirectServiceClient(EndpointHandlerBase.ServiceManager); - } - } - - public class XmlIntegrationTests : RequestFiltersTests - { - protected override string GetFormat() - { - return "xml"; - } - - protected override IServiceClient CreateNewServiceClient() - { - return new XmlServiceClient(ServiceClientBaseUri); - } - - protected override IRestClientAsync CreateNewRestClientAsync() - { - return new XmlRestClientAsync(ServiceClientBaseUri); - } - } - - [TestFixture] - public class JsonIntegrationTests : RequestFiltersTests - { - protected override string GetFormat() - { - return "json"; - } - - protected override IServiceClient CreateNewServiceClient() - { - return new JsonServiceClient(ServiceClientBaseUri); - } - - protected override IRestClientAsync CreateNewRestClientAsync() - { - return new JsonRestClientAsync(ServiceClientBaseUri); - } - } - - [TestFixture] - public class JsvIntegrationTests : RequestFiltersTests - { - protected override string GetFormat() - { - return "jsv"; - } - - protected override IServiceClient CreateNewServiceClient() - { - return new JsvServiceClient(ServiceClientBaseUri); - } - - protected override IRestClientAsync CreateNewRestClientAsync() - { - return new JsvRestClientAsync(ServiceClientBaseUri); - } - } - -#if !MONOTOUCH - - [TestFixture] - public class Soap11IntegrationTests : RequestFiltersTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new Soap11ServiceClient(ServiceClientBaseUri); - } - - protected override IRestClientAsync CreateNewRestClientAsync() - { - return null; - } - } - - [TestFixture] - public class Soap12IntegrationTests : RequestFiltersTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new Soap12ServiceClient(ServiceClientBaseUri); - } - - protected override IRestClientAsync CreateNewRestClientAsync() - { - return null; - } - } + [DataContract] + [Route("/secure")] + public class Secure + { + [DataMember] + public string UserName { get; set; } + } + + [DataContract] + public class SecureResponse : IHasResponseStatus + { + [DataMember] + public string Result { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class SecureService : IService + { + public object Any(Secure request) + { + return new SecureResponse { Result = "Confidential" }; + } + } + + [DataContract] + [Route("/insecure")] + public class Insecure + { + [DataMember] + public string UserName { get; set; } + } + + [DataContract] + public class InsecureResponse : IHasResponseStatus + { + [DataMember] + public string Result { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class InsecureService : IService + { + public object Any(Insecure request) + { + return new InsecureResponse { Result = "Public" }; + } + } + + [DataContract(Namespace = HostConfig.DefaultWsdlNamespace)] + public class SoapDeserializationException : IReturn<SoapDeserializationExceptionResponse> { } + + [DataContract(Namespace = HostConfig.DefaultWsdlNamespace)] + public class SoapDeserializationExceptionResponse + { + [DataMember(EmitDefaultValue = false, IsRequired = true)] + public string RequiredProperty { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + [DataContract(Namespace = HostConfig.DefaultWsdlNamespace)] + public class SoapFaultTest : IReturn<SoapFaultTestResponse> { } + + [DataContract(Namespace = HostConfig.DefaultWsdlNamespace)] + public class SoapFaultTestResponse + { + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class SoapServices : Service + { + public object Any(SoapDeserializationException request) + { + return new SoapDeserializationExceptionResponse(); + } + + public object Any(SoapFaultTest request) + { + throw new Exception("Test SOAP Fault"); + } + } + + public class ThrowsInFilterAttribute : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var dto = (ThrowsInFilter)requestDto; + + var status = (HttpStatusCode)dto.StatusCode.GetValueOrDefault(400); + var errorMsg = dto.Message ?? nameof(ThrowsInFilter); + + if (dto.ExceptionType == nameof(HttpError)) + throw new HttpError(status, errorMsg); + + throw new Exception(errorMsg); + } + } + + public class ThrowsInFilter : IReturn<ThrowsInFilter> + { + public string ExceptionType { get; set; } + public string Message { get; set; } + public int? StatusCode { get; set; } + } + + [ThrowsInFilter] + public class ThrowsInFilterService : Service + { + public object Any(ThrowsInFilter request) => request; + } + + [TestFixture] + public abstract class RequestFiltersTests + { + private const string AllowedUser = "user"; + private const string AllowedPass = "p@55word"; + + public class RequestFiltersAppHostHttpListener + : AppHostHttpListenerBase + { + private Guid currentSessionGuid; + + public RequestFiltersAppHostHttpListener() + : base("Request Filters Tests", typeof(GetFactorialService).Assembly) { } + + public override void Configure(Container container) + { +#if !NETCORE + Plugins.Add(new SoapFormat()); +#endif + + this.GlobalRequestFilters.Add((req, res, dto) => + { + var userPass = req.GetBasicAuthUserAndPassword(); + if (userPass == null) + { + return; + } + + var userName = userPass.Value.Key; + if (userName == AllowedUser && userPass.Value.Value == AllowedPass) + { + currentSessionGuid = Guid.NewGuid(); + var sessionKey = userName + "/" + currentSessionGuid.ToString("N"); + + //set session for this request (as no cookies will be set on this request) + req.Items["ss-session"] = sessionKey; + res.SetPermanentCookie("ss-session", sessionKey); + } + }); + this.GlobalRequestFilters.Add((req, res, dto) => + { + if (dto is Secure) + { + var sessionId = req.GetItemOrCookie("ss-session") ?? string.Empty; + var sessionIdParts = sessionId.SplitOnFirst('/'); + if (sessionIdParts.Length < 2 || sessionIdParts[0] != AllowedUser || sessionIdParts[1] != currentSessionGuid.ToString("N")) + { + res.ReturnAuthRequired(); + } + } + if (dto is SoapDeserializationException) + { + req.Response.UseBufferedStream = true; + } + }); +#if !NETCORE + this.ServiceExceptionHandlers.Add((req, dto, ex) => + { + if (dto is SoapDeserializationException) + return new SoapDeserializationExceptionResponse { RequiredProperty = "ServiceExceptionHandlers" }; + + if (dto is SoapFaultTest) + { + if (req.GetItem(Keywords.SoapMessage) is System.ServiceModel.Channels.Message requestMsg) + { + var msgVersion = requestMsg.Version; + using (var response = System.Xml.XmlWriter.Create(req.Response.OutputStream)) + { + var message = System.ServiceModel.Channels.Message.CreateMessage( + msgVersion, new System.ServiceModel.FaultCode("Receiver"), ex.Message, null); + message.WriteMessage(response); + } + req.Response.End(); + } + } + + return null; + }); +#endif + } + } + + RequestFiltersAppHostHttpListener appHost; + + string ServiceClientBaseUri = Config.ListeningOn; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new RequestFiltersAppHostHttpListener(); + appHost.Init(); + appHost.Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + protected abstract IServiceClient CreateNewServiceClient(); + protected abstract IHttpRestClientAsync CreateNewRestClientAsync(); + + protected virtual string GetFormat() + { + return null; + } + + private static void Assert401(IServiceClient client, WebServiceException ex) + { +#if !NETCORE + if (client is Soap11ServiceClient || client is Soap12ServiceClient) + { + if (ex.StatusCode != 401) + { + Console.WriteLine("WARNING: SOAP clients returning 500 instead of 401"); + } + return; + } +#endif + Console.WriteLine(ex); + Assert.That(ex.StatusCode, Is.EqualTo(401)); + } + + private static void FailOnAsyncError<T>(T response, Exception ex) + { + Assert.Fail(ex.Message); + } + + private static bool Assert401(Exception ex) + { + var webEx = (WebServiceException)ex; + Assert.That(webEx.StatusCode, Is.EqualTo(401)); + return true; + } + + [Test] + public void Can_login_with_Basic_auth_to_access_Secure_service() + { + var format = GetFormat(); + if (format == null) return; + + var req = WebRequest.CreateHttp(ServiceClientBaseUri.CombineWith("{0}/reply/Secure".Fmt(format))); + + req.Headers[HttpHeaders.Authorization] + = "basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(AllowedUser + ":" + AllowedPass)); + + var dtoString = req.GetResponse().GetResponseStream().ReadToEnd(); + Assert.That(dtoString.Contains("Confidential")); + Console.WriteLine(dtoString); + } + + [Test] + public void Can_login_with_Basic_auth_to_access_Secure_service_using_ServiceClient() + { + var format = GetFormat(); + if (format == null) return; + + var client = CreateNewServiceClient(); + client.SetCredentials(AllowedUser, AllowedPass); + + var response = client.Send<SecureResponse>(new Secure()); + + Assert.That(response.Result, Is.EqualTo("Confidential")); + } + + [Test] + public async Task Can_login_with_Basic_auth_to_access_Secure_service_using_RestClientAsync() + { + var format = GetFormat(); + if (format == null) return; + + var client = CreateNewRestClientAsync(); + client.SetCredentials(AllowedUser, AllowedPass); + + var response = await client.GetAsync<SecureResponse>(ServiceClientBaseUri + "secure"); + + Assert.That(response.Result, Is.EqualTo("Confidential")); + } + + [Test] + public void Can_login_without_authorization_to_access_Insecure_service() + { + var format = GetFormat(); + if (format == null) return; + + var req = WebRequest.CreateHttp($"{ServiceClientBaseUri}{format}/reply/Insecure"); + + req.Headers[HttpHeaders.Authorization] + = "basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(AllowedUser + ":" + AllowedPass)); + + var dtoString = req.GetResponse().GetResponseStream().ReadToEnd(); + Assert.That(dtoString.Contains("Public")); + Console.WriteLine(dtoString); + } + + [Test] + public void Can_login_without_authorization_to_access_Insecure_service_using_ServiceClient() + { + var format = GetFormat(); + if (format == null) return; + + var client = CreateNewServiceClient(); + + var response = client.Send<InsecureResponse>(new Insecure()); + + Assert.That(response.Result, Is.EqualTo("Public")); + } + + [Test] + public async Task Can_login_without_authorization_to_access_Insecure_service_using_RestClientAsync() + { + var format = GetFormat(); + if (format == null) return; + + var client = CreateNewRestClientAsync(); + + var response = await client.GetAsync<InsecureResponse>(ServiceClientBaseUri + "insecure"); + + Assert.That(response.Result, Is.EqualTo("Public")); + } + + [Test] + public void Can_login_with_session_cookie_to_access_Secure_service() + { + var format = GetFormat(); + if (format == null) return; + + var req = WebRequest.CreateHttp(ServiceClientBaseUri.CombineWith("{0}/reply/Secure".Fmt(format))); + + req.Headers[HttpHeaders.Authorization] + = "basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(AllowedUser + ":" + AllowedPass)); + + var res = (HttpWebResponse)req.GetResponse(); + var cookie = res.Cookies["ss-session"]; + if (cookie != null) + { + req = WebRequest.CreateHttp(ServiceClientBaseUri.CombineWith("{0}/reply/Secure".Fmt(format))); + req.CookieContainer.Add(new Uri(ServiceClientBaseUri), new Cookie("ss-session", cookie.Value)); + + var dtoString = req.GetResponse().GetResponseStream().ReadToEnd(); + Assert.That(dtoString.Contains("Confidential")); + Console.WriteLine(dtoString); + } + } + + [Test] + public void Get_401_When_accessing_Secure_using_fake_sessionid_cookie() + { + var format = GetFormat(); + if (format == null) return; + + var req = WebRequest.CreateHttp(ServiceClientBaseUri.CombineWith("{0}/reply/Secure".Fmt(format))); + + req.CookieContainer = new CookieContainer(); + req.CookieContainer.Add(new Uri("http://localhost"), new Cookie("ss-session", AllowedUser + "/" + Guid.NewGuid().ToString("N"), "/", "localhost")); + + try + { + var res = req.GetResponse(); + } + catch (WebException x) + { + Assert.That(((HttpWebResponse)x.Response).StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); + } + } + + [Test] + public void Get_401_When_accessing_Secure_using_ServiceClient_without_Authorization() + { + var client = CreateNewServiceClient(); + + try + { + var response = client.Send<SecureResponse>(new Secure()); + Console.WriteLine(response.Dump()); + } + catch (WebServiceException ex) + { + Assert401(client, ex); + return; + } + Assert.Fail("Should throw WebServiceException.StatusCode == 401"); + } + + [Test] + public async Task Does_populate_ResponseStatus_when_Exception_thrown_in_RequestFilter() + { + var client = CreateNewRestClientAsync(); + if (client == null) return; + + try + { + var response = await client.PostAsync(new ThrowsInFilter + { + StatusCode = 409, + ExceptionType = nameof(HttpError), + Message = "POST HttpError CONFLICT", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(409)); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo("Conflict")); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("POST HttpError CONFLICT")); + } + + try + { + var response = await client.PostAsync(new ThrowsInFilter + { + ExceptionType = nameof(Exception), + Message = "POST Generic Exception", + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(500)); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo("Exception")); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("POST Generic Exception")); + } + } + + [Test] + public async Task Get_401_When_accessing_Secure_using_RestClient_GET_without_Authorization() + { + var client = CreateNewRestClientAsync(); + if (client == null) return; + + try + { + await client.GetAsync<SecureResponse>(ServiceClientBaseUri + "secure"); + Assert.Fail("Should throw WebServiceException.StatusCode == 401"); + } + catch (WebServiceException webEx) + { + Assert401(webEx); + Assert.That(webEx.ResponseDto, Is.Null); + } + } + + [Test] + public async Task Get_401_When_accessing_Secure_using_RestClient_DELETE_without_Authorization() + { + var client = CreateNewRestClientAsync(); + if (client == null) return; + + try + { + await client.DeleteAsync<SecureResponse>(ServiceClientBaseUri + "secure"); + Assert.Fail("Should throw WebServiceException.StatusCode == 401"); + } + catch (WebServiceException webEx) + { + Assert401(webEx); + Assert.That(webEx.ResponseDto, Is.Null); + } + } + + [Test] + public async Task Get_401_When_accessing_Secure_using_RestClient_POST_without_Authorization() + { + var client = CreateNewRestClientAsync(); + if (client == null) return; + + try + { + await client.PostAsync<SecureResponse>(ServiceClientBaseUri + "secure", new Secure()); + Assert.Fail("Should throw WebServiceException.StatusCode == 401"); + } + catch (WebServiceException webEx) + { + Assert401(webEx); + Assert.That(webEx.ResponseDto, Is.Null); + } + } + + [Test] + public async Task Get_401_When_accessing_Secure_using_RestClient_PUT_without_Authorization() + { + var client = CreateNewRestClientAsync(); + if (client == null) return; + + try + { + await client.PutAsync<SecureResponse>(ServiceClientBaseUri + "secure", new Secure()); + Assert.Fail("Should throw WebServiceException.StatusCode == 401"); + } + catch (WebServiceException webEx) + { + Assert401(webEx); + Assert.That(webEx.ResponseDto, Is.Null); + } + } + + public class UnitTests : RequestFiltersTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new DirectServiceClient(appHost.ServiceController); + } + + protected override IHttpRestClientAsync CreateNewRestClientAsync() + { + return null; //TODO implement REST calls with DirectServiceClient (i.e. Unit Tests) + //EndpointHandlerBase.ServiceManager = new ServiceManager(true, typeof(SecureService).Assembly); + //return new DirectServiceClient(EndpointHandlerBase.ServiceManager); + } + } + + public class XmlIntegrationTests : RequestFiltersTests + { + protected override string GetFormat() + { + return "xml"; + } + + protected override IServiceClient CreateNewServiceClient() + { + return new XmlServiceClient(ServiceClientBaseUri); + } + + protected override IHttpRestClientAsync CreateNewRestClientAsync() + { + return new XmlServiceClient(ServiceClientBaseUri); + } + } + + [TestFixture] + public class JsonIntegrationTests : RequestFiltersTests + { + protected override string GetFormat() + { + return "json"; + } + + protected override IServiceClient CreateNewServiceClient() + { + return new JsonServiceClient(ServiceClientBaseUri); + } + + protected override IHttpRestClientAsync CreateNewRestClientAsync() + { + return new JsonServiceClient(ServiceClientBaseUri); + } + } + + [TestFixture] + public class JsvIntegrationTests : RequestFiltersTests + { + protected override string GetFormat() + { + return "jsv"; + } + + protected override IServiceClient CreateNewServiceClient() + { + return new JsvServiceClient(ServiceClientBaseUri); + } + + protected override IHttpRestClientAsync CreateNewRestClientAsync() + { + return new JsvServiceClient(ServiceClientBaseUri); + } + } + +#if !NETCORE + + [TestFixture] + public class Soap11IntegrationTests : RequestFiltersTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new Soap11ServiceClient(ServiceClientBaseUri); + } + + protected override IHttpRestClientAsync CreateNewRestClientAsync() + { + return null; + } + } + + [TestFixture] + public class Soap12IntegrationTests : RequestFiltersTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new Soap12ServiceClient(ServiceClientBaseUri); + } + + protected override IHttpRestClientAsync CreateNewRestClientAsync() + { + return null; + } + + [Test] + public void Response_serialization_errors_does_call_ServiceExceptionHandlers() + { + var client = CreateNewServiceClient(); + var response = client.Send(new SoapDeserializationException()); + Assert.That(response.RequiredProperty, Is.EqualTo("ServiceExceptionHandlers")); + } + + [Test] + public void Does_return_Custom_SoapFault() + { + var responseSoap = ServiceClientBaseUri.CombineWith("/Soap12") + .SendStringToUrl(method: "POST", + requestBody: @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"" xmlns:a=""http://www.w3.org/2005/08/addressing""> + <s:Header> + <a:Action s:mustUnderstand=""1"">SoapFaultTest</a:Action> + <a:MessageID>urn:uuid:84d9f946-d3c3-4252-84ff-0b306ce53386</a:MessageID> + <a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> + </a:ReplyTo> + <a:To s:mustUnderstand=""1"">http://localhost:20000/Soap12</a:To> + </s:Header> + <s:Body> + <SoapFaultTest xmlns=""http://schemas.servicestack.net/types"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""/> + </s:Body> + </s:Envelope>", + contentType: "application/soap+xml; charset=utf-8", + responseFilter: res => { }); + + Assert.That(responseSoap, Is.EqualTo( + @"<?xml version=""1.0"" encoding=""utf-8""?><s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope""><s:Body><s:Fault><s:Code><s:Value>s:Receiver</s:Value></s:Code><s:Reason><s:Text xml:lang=""en-US"">Test SOAP Fault</s:Text></s:Reason></s:Fault></s:Body></s:Envelope>")); + } + + } #endif - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestInfoTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestInfoTests.cs new file mode 100644 index 00000000000..3f1cf6d2e5f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestInfoTests.cs @@ -0,0 +1,152 @@ +using System.Net; +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.Api.OpenApi; +using ServiceStack.Host.Handlers; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class RequestInfoServices : Service {} + + public partial class RequestInfoTests + { + public string BaseUrl = Config.ListeningOn; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(RequestInfoTests), typeof(RequestInfoServices).Assembly) {} + + public override void Configure(Container container) + { +#if NETCORE + var useProjectPath = MapProjectPath("~/"); // .NET Core accurately reports the ContentPath from where it's run +#else + var useProjectPath = MapProjectPath("~/../"); +#endif + + var parentDir = useProjectPath.Replace("\\", "/").TrimEnd('/').LastRightPart('/'); + Assert.That(parentDir, Is.EqualTo("ServiceStack.WebHost.Endpoints.Tests")); + + SetConfig(new HostConfig + { + DebugMode = true, + WebHostPhysicalPath = useProjectPath + }); + + Plugins.Add(new OpenApiFeature()); + } + } + + private readonly ServiceStackHost appHost; + + public RequestInfoTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private RequestInfoResponse GetRequestInfoForPath(string path) + { + var url = BaseUrl.CombineWith(path).AddQueryParam("debug", "requestinfo"); + var json = url.GetJsonFromUrl(); + var info = json.FromJson<RequestInfoResponse>(); + return info; + } + + private void AssertHasContent(string pathInfo, string accept, string containsContent) + { + var url = BaseUrl.CombineWith(pathInfo); + var content = url.GetStringFromUrl(accept: accept); + Assert.That(content, Does.Contain(containsContent)); + } + + [Test] + public void Does_return_expected_content() + { + AssertHasContent("metadata", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("metadata/", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("dir", MimeTypes.Html, "<h1>dir/index.html</h1>"); + AssertHasContent("dir/", MimeTypes.Html, "<h1>dir/index.html</h1>"); + AssertHasContent("dir/sub", MimeTypes.Html, "<h1>dir/sub/index.html</h1>"); + AssertHasContent("dir/sub/", MimeTypes.Html, "<h1>dir/sub/index.html</h1>"); + AssertHasContent("swagger-ui", MimeTypes.Html, "<title>Swagger UI</title>"); + AssertHasContent("swagger-ui/", MimeTypes.Html, "<title>Swagger UI</title>"); + } + + [Test] + public void Does_have_correct_path_info() + { + Assert.That(GetRequestInfoForPath("dir/").PathInfo, Is.EqualTo("/dir/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("swagger-ui/").PathInfo, Is.EqualTo("/swagger-ui/")); + } + + [Test] + public void Does_return_expected_request_info() + { + var info = GetRequestInfoForPath("metadata"); + + info.PrintDump(); + + Assert.That(info.ServiceName, Is.EqualTo(nameof(RequestInfoTests))); + Assert.That(info.HttpMethod, Is.EqualTo("GET")); + Assert.That(info.PathInfo, Is.EqualTo("/metadata")); + Assert.That(info.RawUrl, Is.EqualTo("/metadata?debug=requestinfo")); + Assert.That(info.AbsoluteUri, Is.EqualTo("http://localhost:20000/metadata?debug=requestinfo")); + } + } + +#if NETFX + public partial class RequestInfoTests + { + private void DoesRedirectToRemoveTrailingSlash(string dirWIthoutSlash) + { + BaseUrl.CombineWith(dirWIthoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWIthoutSlash + "/"))); + }); + } + + private void DoesRedirectToAddTrailingSlash(string dirWithoutSlash) + { + BaseUrl.CombineWith(dirWithoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWithoutSlash.TrimEnd('/')))); + }); + } + + [Test] + public void Does_redirect_dirs_without_trailing_slash() + { + DoesRedirectToRemoveTrailingSlash("dir"); + DoesRedirectToRemoveTrailingSlash("dir/sub"); + DoesRedirectToRemoveTrailingSlash("swagger-ui"); + } + + [Test] + public void Does_redirect_metadata_page_to_without_slash() + { + DoesRedirectToAddTrailingSlash("metadata/"); + } + } +#endif + + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestLogsFeatureTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestLogsFeatureTests.cs new file mode 100644 index 00000000000..0b310ee7cbd --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestLogsFeatureTests.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.Admin; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/requestlogs-test")] + public class RequestLogsTest : IReturn<RequestLogsTest> + { + public string Name { get; set; } + } + + [Route("/requestlogs-error-test")] + public class RequestLogsErrorTest : IReturn<RequestLogsErrorTest> + { + public string Message { get; set; } + } + + class MyServices : Service + { + public object Any(RequestLogsTest request) => request; + + public object Any(RequestLogsErrorTest request) => + throw new Exception("Error: " + request.Message); + } + + public class RequestLogsFeatureTests + { + private readonly ServiceStackHost appHost; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(RequestLogsFeatureTests), typeof(MyServices).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DebugMode = true + }); + + Plugins.Add(new RequestLogsFeature + { + LimitToServiceRequests = false + }); + + Plugins.Add(new CorsFeature()); + } + } + + public RequestLogsFeatureTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_log_Service_request() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestFilter = req => req.Referer = Config.ListeningOn + }; + + var response = client.Get(new RequestLogsTest { Name = "foo1" }); + + var json = Config.ListeningOn.CombineWith("requestlogs").GetJsonFromUrl(); + var requestLogs = json.FromJson<RequestLogsResponse>(); + var requestLog = requestLogs.Results.First(); + var request = (RequestLogsTest)requestLog.RequestDto; + Assert.That(request.Name, Is.EqualTo("foo1")); + Assert.That(requestLog.Referer, Is.EqualTo(Config.ListeningOn)); + } + + [Test] + public void Does_log_autobatch_request() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestFilter = req => req.Referer = Config.ListeningOn + }; + + var request = new[] + { + new RequestLogsTest { Name = "foo1" }, + new RequestLogsTest { Name = "bar1" } + }; + var response = client.SendAll(request); + + var json = Config.ListeningOn.CombineWith("requestlogs").GetJsonFromUrl(); + var requestLogs = json.FromJson<RequestLogsResponse>(); + var requestLog = requestLogs.Results.First(); + + var loggedRequests = requestLog.RequestDto.ConvertTo<List<RequestLogsTest>>(); + + Assert.That(request is IEnumerable<RequestLogsTest>); + Assert.That(loggedRequests is IEnumerable<RequestLogsTest>); + + Assert.That(loggedRequests.First().Name, Is.EqualTo("foo1")); + Assert.That(loggedRequests.Last().Name, Is.EqualTo("bar1")); + + Assert.That(requestLog.Referer, Is.EqualTo(Config.ListeningOn)); + } + + [Test] + public void Does_log_Error_request() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestFilter = req => req.Referer = Config.ListeningOn + }; + + try + { + var response = client.Get(new RequestLogsErrorTest { Message = "foo2" }); + } + catch (WebServiceException ex) + { + Assert.That(ex.Message, Is.EqualTo("Error: foo2")); + var json = Config.ListeningOn.CombineWith("requestlogs").GetJsonFromUrl(); + var requestLogs = json.FromJson<RequestLogsResponse>(); + var requestLog = requestLogs.Results.First(); + var request = (RequestLogsErrorTest)requestLog.RequestDto; + Assert.That(request.Message, Is.EqualTo("foo2")); + Assert.That(requestLog.Referer, Is.EqualTo(Config.ListeningOn)); + } + } + + [Test] + public void Does_log_Options_request() + { + var response = Config.ListeningOn.CombineWith("requestlogs-test") + .AddQueryParam("name", "foo3") + .OptionsFromUrl(requestFilter: req => req.With(c => c.Referer = Config.ListeningOn)); + + var json = Config.ListeningOn.CombineWith("requestlogs").GetJsonFromUrl(); + var requestLogs = json.FromJson<RequestLogsResponse>(); + var requestLog = requestLogs.Results.First(); + Assert.That(requestLog.HttpMethod, Is.EqualTo("OPTIONS")); + Assert.That(requestLog.Referer, Is.EqualTo(Config.ListeningOn)); + } + + [Test] + public void Does_log_error_response() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestFilter = req => req.Referer = Config.ListeningOn + }; + + try + { + var response = client.Get(new RequestLogsErrorTest { Message = "foo2" }); + } + catch (WebServiceException ex) + { + Assert.That(ex.Message, Is.EqualTo("Error: foo2")); + var json = Config.ListeningOn.CombineWith("requestlogs").GetJsonFromUrl(); + var requestLogs = json.FromJson<RequestLogsResponse>(); + var requestLog = requestLogs.Results.First(); + var request = (RequestLogsErrorTest)requestLog.RequestDto; + Assert.That(requestLog.ErrorResponse != null); + Assert.That(requestLog.ErrorResponse is ErrorResponse); + var responseStatus = requestLog.ErrorResponse.GetResponseStatus(); + Assert.That(responseStatus.Message == "Error: foo2"); + } + } + + [Test] + public void Does_log_autobatch_error_response() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestFilter = req => req.Referer = Config.ListeningOn + }; + + var request = new[] + { + new RequestLogsErrorTest { Message = "foo1" }, + new RequestLogsErrorTest { Message = "bar1" } + }; + + try + { + var response = client.SendAll(request); + } + catch (WebServiceException ex) + { + + var json = Config.ListeningOn.CombineWith("requestlogs").GetJsonFromUrl(); + var requestLogs = json.FromJson<RequestLogsResponse>(); + var requestLog = requestLogs.Results.First(); + + Assert.That(requestLog.ErrorResponse != null); + Assert.That(requestLog.ErrorResponse is ErrorResponse); + var responseStatus = requestLog.ErrorResponse.GetResponseStatus(); + Assert.That(responseStatus.Message == "Error: foo1"); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestPipelineTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestPipelineTests.cs new file mode 100644 index 00000000000..08ff58e0770 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestPipelineTests.cs @@ -0,0 +1,242 @@ +using System; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public interface ITestFilters + { + bool GlobalRequestFilter { get; set; } + bool ServiceRequestAttributeFilter { get; set; } + bool ActionRequestAttributeFilter { get; set; } + bool Service { get; set; } + bool ActionResponseAttributeFilter { get; set; } + bool ServiceResponseAttributeFilter { get; set; } + bool GlobalResponseFilter { get; set; } + } + + public class TestFiltersSync : IReturn<TestFiltersSync>, ITestFilters + { + public bool GlobalRequestFilter { get; set; } + public bool ServiceRequestAttributeFilter { get; set; } + public bool ActionRequestAttributeFilter { get; set; } + public bool Service { get; set; } + public bool ActionResponseAttributeFilter { get; set; } + public bool ServiceResponseAttributeFilter { get; set; } + public bool GlobalResponseFilter { get; set; } + } + + public class TestFiltersAsync : IReturn<TestFiltersAsync>, ITestFilters + { + public bool GlobalRequestFilter { get; set; } + public bool ServiceRequestAttributeFilter { get; set; } + public bool ActionRequestAttributeFilter { get; set; } + public bool Service { get; set; } + public bool ActionResponseAttributeFilter { get; set; } + public bool ServiceResponseAttributeFilter { get; set; } + public bool GlobalResponseFilter { get; set; } + } + + public class ServiceRequestFilterAttribute : RequestFilterAttribute, IDisposable + { + public DisposableDependency Dep { get; set; } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + Dep.AssertNotDisposed(); + + ((ITestFilters)requestDto).ServiceRequestAttributeFilter = true; + } + + public void Dispose() + { + Dep.Dispose(); + } + } + + public class ActionRequestFilterAttribute : RequestFilterAttribute, IDisposable + { + public DisposableDependency Dep { get; set; } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + Dep.AssertNotDisposed(); + + ((ITestFilters)requestDto).ActionRequestAttributeFilter = true; + } + + public void Dispose() + { + Dep.Dispose(); + } + } + + public class ServiceResponseFilterAttribute : ResponseFilterAttribute, IDisposable + { + public DisposableDependency Dep { get; set; } + + public override void Execute(IRequest req, IResponse res, object responseDto) + { + Dep.AssertNotDisposed(); + + ((ITestFilters)responseDto).ServiceResponseAttributeFilter = true; + } + + public void Dispose() + { + Dep.Dispose(); + } + } + + public class ActionResponseFilterAttribute : ResponseFilterAttribute, IDisposable + { + public DisposableDependency Dep { get; set; } + + public override void Execute(IRequest req, IResponse res, object responseDto) + { + Dep.AssertNotDisposed(); + + ((ITestFilters)responseDto).ActionResponseAttributeFilter = true; + } + + public void Dispose() + { + Dep.Dispose(); + } + } + + [ServiceRequestFilter] + [ServiceResponseFilter] + public class RequestPipelineService : Service + { + public DisposableDependency Dep { get; set; } + + [ActionRequestFilter] + [ActionResponseFilter] + public object Any(TestFiltersSync request) + { + Dep.AssertNotDisposed(); + + request.Service = true; + + return request; + } + + [ActionRequestFilter] + [ActionResponseFilter] + public async Task<TestFiltersAsync> Any(TestFiltersAsync request) + { + await Task.Delay(100); + + Dep.AssertNotDisposed(); + + return await Task.Factory.StartNew(() => + { + Task.Delay(100); + + Dep.AssertNotDisposed(); + + request.Service = true; + return request; + }); + } + + public override void Dispose() + { + base.Dispose(); + Dep.Dispose(); + } + } + + public class DisposableDependency : IDisposable + { + private bool isDisposed; + + public void AssertNotDisposed() + { + if (isDisposed) + throw new ObjectDisposedException("DisposableDependency"); + } + + public void Dispose() + { + isDisposed = true; + } + } + + public class RequestPipelineAppHost : AppHostHttpListenerBase + { + public RequestPipelineAppHost() : base(typeof(RequestPipelineTests).Name, typeof(RequestPipelineService).Assembly) { } + + public override void Configure(Container container) + { + container.Register(c => new DisposableDependency()).ReusedWithin(ReuseScope.None); + + this.GlobalRequestFilters.Add((req, res, dto) => ((ITestFilters)dto).GlobalRequestFilter = true); + this.GlobalResponseFilters.Add((req, res, dto) => ((ITestFilters)dto).GlobalResponseFilter = true); + } + } + + [TestFixture] + public class RequestPipelineTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new RequestPipelineAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public bool AllFieldsTrue(ITestFilters dto) + { + if (!dto.GlobalRequestFilter) + return false; + if (!dto.ServiceRequestAttributeFilter) + return false; + if (!dto.ActionRequestAttributeFilter) + return false; + if (!dto.Service) + return false; + if (!dto.ActionResponseAttributeFilter) + return false; + if (!dto.ServiceResponseAttributeFilter) + return false; + if (!dto.GlobalResponseFilter) + return false; + + return true; + } + + [Test] + public void Does_fire_all_filters_sync() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = client.Get(new TestFiltersSync()); + + Assert.That(AllFieldsTrue(response), Is.True); + } + + [Test] + public async Task Does_fire_all_filters_async() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var response = await client.GetAsync(new TestFiltersAsync()); + + Assert.That(AllFieldsTrue(response)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RequestTypedFilterTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestTypedFilterTests.cs new file mode 100644 index 00000000000..adbfe64619d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RequestTypedFilterTests.cs @@ -0,0 +1,147 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Model; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public interface IHasSharedProperty + { + string SharedProperty { get; set; } + } + + [Route("/tenant/{TenantName}/resourceType1")] + public class ResourceType1 : IReturn<ResourceType1>, IHasSharedProperty + { + public string TenantName { get; set; } + + public string SubResourceName { get; set; } + + public string Arg1 { get; set; } + + public string SharedProperty { get; set; } + } + + [Route("/tenant/{TenantName}/resourceType2")] + public class ResourceType2 : IReturn<ResourceType2>, IHasSharedProperty + { + public string TenantName { get; set; } + + public string SubResourceName { get; set; } + + public string Arg1 { get; set; } + + public string SharedProperty { get; set; } + } + + public interface IClearLongId + { + long Id { get; set; } + } + + public class TypedResponseFilter1 : IReturn<TypedResponseFilter1>, IClearLongId + { + public long Id { get; set; } + } + + public class TypedFilterService : Service + { + public object Any(ResourceType1 request) + { + return request; + } + + public object Any(ResourceType2 request) + { + return request; + } + + public object Any(TypedResponseFilter1 request) + { + return request; + } + } + + [TestFixture] + public class RequestTypedFilterTests + { + public class TypedFilterAppHost : AppSelfHostBase + { + public TypedFilterAppHost() + : base("Typed Filters", typeof(TypedFilterService).Assembly) + { + } + + public override void Configure(Container container) + { + RegisterTypedRequestFilter<ResourceType1>((req, res, dto) => + { + var route = req.GetRoute(); + if (route != null && route.Path == "/tenant/{TenantName}/resourceType1") + { + dto.SubResourceName = "CustomResource"; + } + }); + RegisterTypedRequestFilter<IHasSharedProperty>((req, res, dtoInterface) => + { + dtoInterface.SharedProperty = "Is Shared"; + }); + RegisterTypedResponseFilter<IClearLongId>((req, res, dtoInterface) => + { + dtoInterface.Id = 0; + }); + } + } + + ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new TypedFilterAppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_modify_requestDto_with_TypedRequestFilter() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Get(new ResourceType1 + { + Arg1 = "arg1", + TenantName = "tennant" + }); + + Assert.That(response.Arg1, Is.EqualTo("arg1")); + Assert.That(response.TenantName, Is.EqualTo("tennant")); + Assert.That(response.SubResourceName, Is.EqualTo("CustomResource")); + } + + [Test] + public void Does_execute_requestDto_interfaces_typedfilters() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var response1 = client.Get(new ResourceType1 { TenantName = "tennant" }); + Assert.That(response1.SharedProperty, Is.EqualTo("Is Shared")); + + var response2 = client.Get(new ResourceType2 { TenantName = "tennant" }); + Assert.That(response2.SharedProperty, Is.EqualTo("Is Shared")); + } + + [Test] + public void Does_execute_requestDto_interfaces_TypedResponsefilters() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var response1 = client.Get(new TypedResponseFilter1 { Id = 1 }); + Assert.That(response1.Id, Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RestHandlerTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RestHandlerTests.cs index ae02e631cc5..8bb65c5df9d 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RestHandlerTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RestHandlerTests.cs @@ -1,59 +1,70 @@ -using System.Collections.Specialized; -using Moq; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.ServiceHost; +using ServiceStack.Host; +using ServiceStack.Web; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { [TestFixture] public class RestHandlerTests { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new TestAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + [Test] - public void Throws_binding_exception_when_unable_to_match_path_values() + public async Task Throws_binding_exception_when_unable_to_match_path_values() { var path = "/request/{will_not_match_property_id}/pathh"; var request = ConfigureRequest(path); - var response = new Mock<IHttpResponse>().Object; - ConfigureHost(); + var response = request.Response; var handler = new RestHandler { RestPath = new RestPath(typeof(RequestType), path) }; - Assert.Throws<RequestBindingException>(() => handler.ProcessRequest(request, response, string.Empty)); + await handler.ProcessRequestAsync(request, response, string.Empty); + Assert.That(response.StatusCode, Is.EqualTo(400)); } [Test] - public void Throws_binding_exception_when_unable_to_bind_request() + public async Task Throws_binding_exception_when_unable_to_bind_request() { var path = "/request/{id}/path"; var request = ConfigureRequest(path); - var response = new Mock<IHttpResponse>().Object; - ConfigureHost(); + var response = request.Response; var handler = new RestHandler { RestPath = new RestPath(typeof(RequestType), path) }; - Assert.Throws<RequestBindingException>(() => handler.ProcessRequest(request, response, string.Empty)); - } - - private IHttpRequest ConfigureRequest(string path) - { - var request = new Mock<IHttpRequest>(); - request.Expect(x => x.QueryString).Returns(new NameValueCollection()); - request.Expect(x => x.PathInfo).Returns(path); - - return request.Object; - } + await handler.ProcessRequestAsync(request, response, string.Empty); + Assert.That(response.StatusCode, Is.EqualTo(400)); + } - private void ConfigureHost() - { - var host = ServiceHostTestBase.CreateAppHost(); - EndpointHost.ConfigureHost(host, string.Empty, new ServiceManager(typeof(RestHandlerTests).Assembly).Init()); - } + private IHttpRequest ConfigureRequest(string path) + { + var request = new BasicHttpRequest { + PathInfo = path + }; + return request; + } public class RequestType { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs index 5c4316724ec..97bfb92a5b2 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteInferenceTests.cs @@ -1,10 +1,8 @@ using System.Linq; using NUnit.Framework; -using ServiceStack.Common; using ServiceStack.DataAnnotations; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Host; +using ServiceStack.Testing; using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; using ServiceStack.WebHost.Endpoints.Tests.Support.Types; @@ -15,29 +13,28 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class RouteInferenceTests { - ServiceRoutes routes = new ServiceRoutes(); - BasicAppHost loadAppHost; + ServiceStackHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void InferRoutes() { - loadAppHost = new BasicAppHost().Init(); + appHost = new BasicAppHost().Init(); RouteNamingConvention.PropertyNamesToMatch.Add("Key"); RouteNamingConvention.AttributeNamesToMatch.Add(typeof(KeyAttribute).Name); - routes.AddFromAssembly(typeof(RouteInferenceTests).Assembly); + appHost.Routes.AddFromAssembly(typeof(RouteInferenceTests).Assembly); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { - loadAppHost.Dispose(); + appHost.Dispose(); } [Test] public void Should_infer_route_from_RequestDTO_type() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestNoMembers) select r).FirstOrDefault(); @@ -59,7 +56,7 @@ public void Should_infer_route_from_RequestDTO_type() [Test] public void Should_infer_route_from_AnyPublicProperty_named_Id() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestWithMemberCalledId) //routes without {placeholders} are tested above && r.PathComponentsCount > 1 @@ -74,7 +71,7 @@ public void Should_infer_route_from_AnyPublicProperty_named_Id() [Test] public void Should_infer_route_from_AnyPublicProperty_named_Ids() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestWithMemberCalledIds) //routes without {placeholders} are tested above && r.PathComponentsCount > 1 @@ -89,7 +86,7 @@ public void Should_infer_route_from_AnyPublicProperty_named_Ids() [Test] public void Should_infer_route_from_AnyPublicProperty_in_MatchingNameStrategy() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestWithMemberCalledSpecialName) //routes without {placeholders} are tested above && r.PathComponentsCount > 1 @@ -104,7 +101,7 @@ public void Should_infer_route_from_AnyPublicProperty_in_MatchingNameStrategy() [Test] public void Should_infer_route_from_AnyPublicProperty_with_PrimaryKeyAttribute() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestWithPrimaryKeyAttribute) //routes without {placeholders} are tested above && r.PathComponentsCount > 1 @@ -120,7 +117,7 @@ public void Should_infer_route_from_AnyPublicProperty_with_PrimaryKeyAttribute() [Test] public void Should_infer_route_from_AnyPublicProperty_in_MatchingAttributeStrategy() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestWithMemberWithKeyAttribute) //routes without {placeholders} are tested above && r.PathComponentsCount > 1 @@ -136,7 +133,7 @@ public void Should_infer_route_from_AnyPublicProperty_in_MatchingAttributeStrate [Test] public void Should_infer_route_from_AnyPubicProperty_FromAnyStrategy_AndCompositeTheRoute() { - var restPath = (from r in routes.RestPaths + var restPath = (from r in appHost.RestPaths where r.RequestType == typeof(RequestWithCompositeKeys) //routes without {placeholders} are tested above && r.PathComponentsCount > 1 diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RouteMatchTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteMatchTests.cs new file mode 100644 index 00000000000..9661b8e75ae --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteMatchTests.cs @@ -0,0 +1,394 @@ +using System; +using System.Net; +using Funq; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/matches/html", Matches = "AcceptsHtml")] + public class MatchesHtml : IReturn<MatchesHtml> + { + public string Name { get; set; } + } + + [Route("/matches/json", Matches = "AcceptsJson")] + public class MatchesJson : IReturn<MatchesJson> + { + public string Name { get; set; } + } + + public class MatchesCsv : IReturn<MatchesCsv> + { + public string Name { get; set; } + } + + [Route("/{SlugFirst}/matchrule")] + public class MatchesNotFirstInt + { + public string SlugFirst { get; set; } + } + + [Route("/{IdFirst}/matchrule", Matches = @"{int}/**")] + public class MatchesFirstInt + { + public int IdFirst { get; set; } + } + + [Route("/matchrule/{SlugLast}")] + public class MatchesNotLastInt + { + public string SlugLast { get; set; } + } + + [Route("/matchrule/{IdLast}", Matches = @"**/{int}")] + public class MatchesLastInt + { + public int IdLast { get; set; } + } + + [Route("/matchrule/{Slug2}/remaining/path")] + public class MatchesSecondSlug + { + public string Slug2 { get; set; } + } + + [Route("/matchrule/{Id2}/remaining/path", Matches = @"path/{int}/**")] + public class MatchesSecondInt + { + public int Id2 { get; set; } + } + + [Route("/remaining/path/{Slug2}/matchrule")] + public class MatchesSecondLastSlug + { + public string Slug2 { get; set; } + } + + [Route("/remaining/path/{Id2}/matchrule", Matches = @"**/{int}/path")] + public class MatchesSecondLastInt + { + public int Id2 { get; set; } + } + + [Route("/matchregex/{Slug}")] + public class MatchesSlug + { + public string Slug { get; set; } + } + + [Route("/matchregex/{Id}", Matches = @"PathInfo =~ \/[0-9]+$")] + public class MatchesInt + { + public int Id { get; set; } + } + + [Route("/matchexact/{Exact}", Matches = @"UserAgent = specific-client")] + public class MatchesExactUserAgent + { + public string Exact { get; set; } + } + + [Route("/matchexact/{Any}")] + public class MatchesAnyUserAgent + { + public string Any { get; set; } + } + + [Route("/matchsite/{Mobile}", Matches = "IsMobile")] + public class MatchMobileSite + { + public string Mobile { get; set; } + } + + [Route("/matchsite/{Desktop}")] + public class MatchDesktopSite + { + public string Desktop { get; set; } + } + + [Route("/matchauth/{Authenticated}", Matches = "IsAuthenticated")] + public class MatchAuthenticated + { + public string Authenticated { get; set; } + } + + [Route("/matchauth/{Unauthenticated}")] + public class MatchUnauthenticated + { + public string Unauthenticated { get; set; } + } + + public class RouteMatchService : Service + { + public object Any(MatchesHtml request) => request; + public object Any(MatchesJson request) => request; + public object Any(MatchesCsv request) => request; + + public object Any(MatchesNotFirstInt request) => request; + public object Any(MatchesFirstInt request) => request; + + public object Any(MatchesNotLastInt request) => request; + public object Any(MatchesLastInt request) => request; + + public object Any(MatchesSecondSlug request) => request; + public object Any(MatchesSecondInt request) => request; + + public object Any(MatchesSecondLastSlug request) => request; + public object Any(MatchesSecondLastInt request) => request; + + public object Any(MatchesSlug request) => request; + public object Any(MatchesInt request) => request; + + public object Any(MatchesExactUserAgent request) => request; + public object Any(MatchesAnyUserAgent request) => request; + + public object Any(MatchMobileSite request) => request; + public object Any(MatchDesktopSite request) => request; + + public object Any(MatchAuthenticated request) => request; + public object Any(MatchUnauthenticated request) => request; + } + + public class RouteMatchTests + { + private readonly ServiceStackHost appHost; + public IServiceClient CreateClient() => new JsonServiceClient(Config.ListeningOn); + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(RouteMatchTests), typeof(RouteMatchService).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + RequestRules = + { + { "CustomAcceptsCsv", httpReq => httpReq.Accept?.IndexOf(MimeTypes.Csv) >= 0 }, + }, + AdminAuthSecret = "secretz" + }); + + Routes.Add(typeof(MatchesCsv), "/matches/csv", null, null, null, matches:"CustomAcceptsCsv"); + } + } + + public RouteMatchTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_match_builtin_RequestRules_JSON() + { + var client = CreateClient(); + + var response = client.Get(new MatchesJson { Name = "JSON" }); + Assert.That(response.Name, Is.EqualTo("JSON")); + + try + { + var html = Config.ListeningOn.AppendPath("matches/json").AddQueryParam("name", "JSON") + .GetStringFromUrl(accept: MimeTypes.Html); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.NotFound)); + } + } + + [Test] + public void Does_match_builtin_RequestRules_HTML() + { + var client = CreateClient(); + + var html = Config.ListeningOn.AppendPath("matches/html").AddQueryParam("name", "HTML") + .GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html, Does.StartWith("<")); + + try + { + var response = client.Get(new MatchesHtml { Name = "HTML" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(404)); + } + } + + [Test] + public void Does_match_new_RequestRules_CSV() + { + var client = CreateClient(); + + var csv = Config.ListeningOn.AppendPath("matches/csv").AddQueryParam("name", "CSV") + .GetStringFromUrl(accept: MimeTypes.Csv); + Assert.That(csv.NormalizeNewLines(), Is.EqualTo("Name\nCSV")); + + try + { + var response = client.Get(new MatchesCsv { Name = "CSV" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(404)); + } + } + + [Test] + public void Can_match_on_builtin_FirstInt() + { + var json = Config.ListeningOn.AppendPath("1/matchrule") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"idfirst\":1}")); + } + + [Test] + public void Can_match_on_builtin_NotFirstInt() + { + var json = Config.ListeningOn.AppendPath("name/matchrule") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"slugfirst\":\"name\"}")); + } + + [Test] + public void Can_match_on_builtin_LastInt() + { + var json = Config.ListeningOn.AppendPath("matchrule/1") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"idlast\":1}")); + } + + [Test] + public void Can_match_on_builtin_NotLastInt() + { + var json = Config.ListeningOn.AppendPath("matchrule/name") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"sluglast\":\"name\"}")); + } + + [Test] + public void Can_match_on_builtin_Second_Int() + { + var json = Config.ListeningOn.AppendPath("matchrule/1/remaining/path") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"id2\":1}")); + } + + [Test] + public void Can_match_on_builtin_Second_NotInt() + { + var json = Config.ListeningOn.AppendPath("matchrule/name/remaining/path") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"slug2\":\"name\"}")); + } + + [Test] + public void Can_match_on_builtin_SecondLast_Int() + { + var json = Config.ListeningOn.AppendPath("/remaining/path/1/matchrule") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"id2\":1}")); + } + + [Test] + public void Can_match_on_builtin_SecondLast_NotInt() + { + var json = Config.ListeningOn.AppendPath("/remaining/path/name/matchrule") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"slug2\":\"name\"}")); + } + + [Test] + public void Can_match_on_regex_int_id() + { + var json = Config.ListeningOn.AppendPath("matchregex/1") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"id\":1}")); + } + + [Test] + public void Can_match_on_regex_slug() + { + var json = Config.ListeningOn.AppendPath("matchregex/name") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"slug\":\"name\"}")); + } + + [Test] + public void Can_match_on_exact_UserAgent() + { + var json = Config.ListeningOn.AppendPath("matchexact/specific-client") + .GetJsonFromUrl(req => req.With(c => c.UserAgent = "specific-client")); + + Assert.That(json.ToLower(), Is.EqualTo("{\"exact\":\"specific-client\"}")); + } + + [Test] + public void Can_match_on_any_UserAgent() + { + var json = Config.ListeningOn.AppendPath("matchexact/any-client") + .GetJsonFromUrl(req => req.With(c => c.UserAgent = "any-client")); + + Assert.That(json.ToLower(), Is.EqualTo("{\"any\":\"any-client\"}")); + } + + [Test] + public void Does_match_builtin_IsMobile_Rule_with_iPhone6UA() + { + const string iPhone6UA = "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25"; + var json = Config.ListeningOn.AppendPath("matchsite/iPhone6") + .GetJsonFromUrl(req => req.With(c => c.UserAgent = iPhone6UA)); + + Assert.That(json.ToLower(), Is.EqualTo("{\"mobile\":\"iphone6\"}")); + } + + [Test] + public void Does_not_match_builtin_IsMobile_Rule_with_SafariUA() + { + const string SafariUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"; + var json = Config.ListeningOn.AppendPath("matchsite/Safari") + .GetJsonFromUrl(req => req.With(c => c.UserAgent = SafariUA)); + + Assert.That(json.ToLower(), Is.EqualTo("{\"desktop\":\"safari\"}")); + } + + [Test] + public void Can_match_on_IsAuthenticated_using_AuthSecret() + { + var json = Config.ListeningOn.AppendPath("matchauth/secure") + .AddQueryParam("authsecret","secretz") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"authenticated\":\"secure\"}")); + } + + [Test] + public void Does_not_match_on_IsAuthenticated_when_not_authenticated() + { + var json = Config.ListeningOn.AppendPath("matchauth/public") + .GetJsonFromUrl(); + + Assert.That(json.ToLower(), Is.EqualTo("{\"unauthenticated\":\"public\"}")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RoutePriorityTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RoutePriorityTests.cs new file mode 100644 index 00000000000..5431b0d466c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RoutePriorityTests.cs @@ -0,0 +1,63 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using NUnit.Framework; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/category/priority")] + public class RoutePriority + { + public string Id { get; set; } + } + + public class RoutePriorityService : IService + { + public object Get(RoutePriority request) + { + return Run(request, ApplyTo.Get); + } + + public object Put(RoutePriority request) + { + return Run(request, ApplyTo.Put); + } + + public object Post(RoutePriority request) + { + return Run(request, ApplyTo.Post); + } + + protected virtual object Run(RoutePriority request, ApplyTo method) + { + return request.AsTypeString(); + } + } + + [TestFixture] + public class RoutePriorityTests + { + [Test] + public void Prefer_user_defined_routes_first() + { + using (var appHost = new BasicAppHost + { + ConfigureAppHost = host => + { + host.Routes.AddFromAssembly(typeof(RoutePriorityTests).Assembly); + }, + }.Init()) + { + var emptyUrl = new RoutePriority().ToGetUrl(); + Assert.That(emptyUrl, Is.EqualTo("/category/priority")); + + var autoRouteWithIdUrl = new RoutePriority { Id = "foo" }.ToGetUrl(); + Assert.That(autoRouteWithIdUrl, Is.EqualTo("/RoutePriority/foo")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RouteTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteTests.cs index 3d3f61183b0..3a4b6fd8990 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/RouteTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RouteTests.cs @@ -1,11 +1,14 @@ -using Funq; +using System; +using System.Net; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; +using ServiceStack.Formats; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Formats; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -14,7 +17,7 @@ public class RouteTests { private RouteAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new RouteAppHost(); @@ -22,11 +25,10 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -35,11 +37,38 @@ public void Can_download_original_route() var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo") .GetStringFromUrl(responseFilter: httpRes => { - httpRes.ContentType.Print(); - Assert.That(httpRes.ContentType.MatchesContentType(ContentType.Html)); + Assert.That(httpRes.MatchesContentType(MimeTypes.Html)); }); - Assert.That(response, Is.StringStarting("<!doctype html>")); + Assert.That(response, Does.StartWith("<!doctype html>")); + } + + [Test] + public void Can_download_original_route_with_Accept_json() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo") + .GetStringFromUrl( + requestFilter: req => req.With(c => c.Accept = MimeTypes.Json), + responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.Json)); + }); + + Assert.That(response.ToLower(), Is.EqualTo("{\"data\":\"foo\"}")); + } + + [Test] + public void Can_download_original_route_with_trailing_slash_and_Accept_json() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo/") + .GetStringFromUrl( + requestFilter: req => req.With(c => c.Accept = MimeTypes.Json), + responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.Json)); + }); + + Assert.That(response.ToLower(), Is.EqualTo("{\"data\":\"foo\"}")); } [Test] @@ -48,11 +77,24 @@ public void Can_download_original_route_with_json_extension() var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.json") .GetStringFromUrl(responseFilter: httpRes => { - httpRes.ContentType.Print(); - Assert.That(httpRes.ContentType.MatchesContentType(ContentType.Json)); + Assert.That(httpRes.MatchesContentType(MimeTypes.Json)); }); - Assert.That(response.ToLower(), Is.EqualTo( "{\"data\":\"foo\"}")); + Assert.That(response.ToLower(), Is.EqualTo("{\"data\":\"foo\"}")); + } + + [Test] + public void Can_process_plaintext_as_JSON() + { + var response = Config.AbsoluteBaseUri.CombineWith("/custom") + .PostStringToUrl("{\"data\":\"foo\"}", + contentType:MimeTypes.PlainText, + responseFilter: httpRes => + { + Assert.That(httpRes.MatchesContentType(MimeTypes.Json)); + }); + + Assert.That(response.ToLower(), Is.EqualTo("{\"data\":\"foo\"}")); } [Test] @@ -61,11 +103,10 @@ public void Can_download_original_route_with_xml_extension() var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.xml") .GetStringFromUrl(responseFilter: httpRes => { - httpRes.ContentType.Print(); - Assert.That(httpRes.ContentType.MatchesContentType(ContentType.Xml)); + Assert.That(httpRes.MatchesContentType(MimeTypes.Xml)); }); - Assert.That(response, Is.EqualTo("<CustomRoute xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.servicestack.net/types\"><Data>foo</Data></CustomRoute>")); + Assert.That(response, Is.EqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?><CustomRoute xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.servicestack.net/types\"><Data>foo</Data></CustomRoute>")); } [Test] @@ -74,11 +115,10 @@ public void Can_download_original_route_with_html_extension() var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.html") .GetStringFromUrl(responseFilter: httpRes => { - httpRes.ContentType.Print(); - Assert.That(httpRes.ContentType.MatchesContentType(ContentType.Html)); + Assert.That(httpRes.MatchesContentType(MimeTypes.Html)); }); - Assert.That(response, Is.StringStarting("<!doctype html>")); + Assert.That(response, Does.StartWith("<!doctype html>")); } [Test] @@ -87,25 +127,210 @@ public void Can_download_original_route_with_csv_extension() var response = Config.AbsoluteBaseUri.CombineWith("/custom/foo.csv") .GetStringFromUrl(responseFilter: httpRes => { - httpRes.ContentType.Print(); - Assert.That(httpRes.ContentType.MatchesContentType(ContentType.Csv)); + Assert.That(httpRes.MatchesContentType(MimeTypes.Csv)); }); Assert.That(response, Is.EqualTo("Data\r\nfoo\r\n")); } + + [Test] + public void Does_encode_route_with_backslash() + { + var request = new CustomRoute { Data = "D\\SN" }; + Assert.That(request.ToUrl(), Is.EqualTo("/custom/D%5CSN")); + Assert.That(request.ToUrl().UrlDecode(), Is.EqualTo("/custom/D\\SN")); + + //HttpListener and ASP.NET hosts doesn't support `\` or %5C in urls + //var client = new JsonServiceClient(Config.AbsoluteBaseUri); + //var response = client.Get(request); + //Assert.That(response.Data, Is.EqualTo("D\\SN")); + } + + [Test] + public void Does_encode_QueryString() + { + var msg = "Field with comma, to demonstrate. "; + var response = Config.AbsoluteBaseUri.CombineWith("/custom") + .PostToUrl(new CustomRoute { Data = msg }, + requestFilter:req => req.With(c => c.Accept = MimeTypes.Json)); + + response.Print(); + + var dto = response.FromJson<CustomRoute>(); + Assert.That(dto.Data, Is.EqualTo(msg)); + + response = Config.AbsoluteBaseUri.CombineWith("/custom") + .PostToUrl(new CustomRoute { Data = msg }.ToStringDictionary(), + requestFilter:req => req.With(c => c.Accept = MimeTypes.Json)); + + response.Print(); + + dto = response.FromJson<CustomRoute>(); + Assert.That(dto.Data, Is.EqualTo(msg)); + } + + [Test] + public void Can_download_route_with_dot_seperator() + { + var response = Config.AbsoluteBaseUri.CombineWith("/customdot/id.data") + .GetJsonFromUrl() + .FromJson<CustomRouteDot>(); + + Assert.That(response.Id, Is.EqualTo("id")); + Assert.That(response.Data, Is.EqualTo("data")); + } + + [Test] + public void Can_download_route_with_dot_seperator_and_extension() + { + var response = Config.AbsoluteBaseUri.CombineWith("/pics/100x100/1.png") + .GetJsonFromUrl() + .FromJson<GetPngPic>(); + + Assert.That(response.Size, Is.EqualTo("100x100")); + Assert.That(response.Id, Is.EqualTo("1")); + } + + [Test] + public void Can_download_route_with_dot_seperator_and_extension_with_jsonserviceclient() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var request = new GetPngPic { + Id = "1", + Size = "100x100", + }; + + Assert.That(request.ToGetUrl(), Is.EqualTo("/pics/100x100/1.png")); + + var response = client.Get<GetPngPic>(request); + + Assert.That(response.Size, Is.EqualTo("100x100")); + Assert.That(response.Id, Is.EqualTo("1")); + } + + [Test] + public void Does_populate_version_when_using_Version_Abbreviation() + { + var response = Config.AbsoluteBaseUri.CombineWith("/versioned-request?v=1") + .GetJsonFromUrl() + .FromJson<RequestWithVersion>(); + + Assert.That(response.Version, Is.EqualTo(1)); + + response = Config.AbsoluteBaseUri.CombineWith("/versioned-request/1?v=2") + .GetJsonFromUrl() + .FromJson<RequestWithVersion>(); + + Assert.That(response.Version, Is.EqualTo(2)); + + response = Config.AbsoluteBaseUri.CombineWith("/versioned-request/1?v=4&Version=3") + .GetJsonFromUrl() + .FromJson<RequestWithVersion>(); + + Assert.That(response.Version, Is.EqualTo(3)); + } + + [Test] + public async Task Does_send_version_using_JsonServiceClient() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var response = client.Send(new RequestWithVersion { Version = 1 }); + Assert.That(response.Version, Is.EqualTo(1)); + + response = await client.SendAsync(new RequestWithVersion { Version = 1 }); + Assert.That(response.Version, Is.EqualTo(1)); + + client.Version = 1; + response = client.Send(new RequestWithVersion()); + Assert.That(response.Version, Is.EqualTo(1)); + + response = await client.SendAsync(new RequestWithVersion()); + Assert.That(response.Version, Is.EqualTo(1)); + } + + [Test] + public async Task Does_send_version_using_JsonHttpClient() + { + var client = new JsonHttpClient(Config.AbsoluteBaseUri); + var response = client.Send(new RequestWithVersion { Version = 1 }); + Assert.That(response.Version, Is.EqualTo(1)); + + response = await client.SendAsync(new RequestWithVersion { Version = 1 }); + Assert.That(response.Version, Is.EqualTo(1)); + + client.Version = 1; + response = client.Send(new RequestWithVersion()); + Assert.That(response.Version, Is.EqualTo(1)); + + response = await client.SendAsync(new RequestWithVersion()); + Assert.That(response.Version, Is.EqualTo(1)); + } + + [Test] + public async Task Can_POST_to_IdWithAlias_with_JsonServiceClient_async() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var response = await client.PostAsync(new IdWithAlias { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + } + + [Test] + public async Task Can_POST_to_IdWithAlias_with_JsonHttpClient_async() + { + var client = new JsonHttpClient(Config.AbsoluteBaseUri); + + var response = await client.PostAsync(new IdWithAlias { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + } + + [Test] + public void Can_create_request_DTO_from_URL() + { + Assert.That(HostContext.Metadata.CreateRequestFromUrl("/hello") is Hello); + + var request = (Hello)HostContext.Metadata.CreateRequestFromUrl("/hello/foo"); + Assert.That(request.Name, Is.EqualTo("foo")); + + request = (Hello)HostContext.Metadata.CreateRequestFromUrl("http://domain.org/hello/foo"); + Assert.That(request.Name, Is.EqualTo("foo")); + + request = (Hello)HostContext.Metadata.CreateRequestFromUrl("https://www.sub.domain.org/hello/foo"); + Assert.That(request.Name, Is.EqualTo("foo")); + + request = (Hello)HostContext.Metadata.CreateRequestFromUrl("/hello?name=bar"); + Assert.That(request.Name, Is.EqualTo("bar")); + + var responseType = HostContext.Metadata.GetResponseTypeByRequest(request.GetType()); + Assert.That(responseType, Is.EqualTo(typeof(HelloResponse))); + + request = (Hello)HostContext.Metadata.CreateRequestFromUrl("/hello?name=gateway"); + var response = (HelloResponse)HostContext.AppHost.GetServiceGateway(new BasicRequest()).Send(responseType, request); + Assert.That(response.Result, Is.EqualTo("Hello, gateway")); + } } public class RouteAppHost : AppHostHttpListenerBase { - public RouteAppHost() : base(typeof(BufferedRequestTests).Name, typeof(CustomRouteService).Assembly) { } + public RouteAppHost() : base(nameof(BufferedRequestTests), typeof(CustomRouteService).Assembly) { } public override void Configure(Container container) { - SetConfig(new EndpointHostConfig { + SetConfig(new HostConfig + { AllowRouteContentTypeExtensions = true }); Plugins.Add(new CsvFormat()); //required to allow .csv + + ContentTypes.Register(MimeTypes.PlainText, + (req, o, stream) => JsonSerializer.SerializeToStream(o.GetType(), stream), + JsonSerializer.DeserializeFromStream); + + PreRequestFilters.Add((req, res) => { + if (req.ContentType.MatchesContentType(MimeTypes.PlainText)) + req.ResponseContentType = MimeTypes.Json; + }); } } @@ -116,11 +341,318 @@ public class CustomRoute : IReturn<CustomRoute> public string Data { get; set; } } + [Route("/customdot/{Id}.{Data}")] + public class CustomRouteDot : IReturn<CustomRouteDot> + { + public string Id { get; set; } + public string Data { get; set; } + } + + [Route("/pics/{Size}/{Id}.png", "GET")] + public class GetPngPic + { + public string Id { get; set; } + + public string Size { get; set; } + } + + [Route("/versioned-request")] + [Route("/versioned-request/{Id}")] + public class RequestWithVersion : IReturn<RequestWithVersion>, IHasVersion + { + public int Id { get; set; } + public int Version { get; set; } + } + + [Route("/thing/{Id}/point", "POST")] + [DataContract] + public class IdWithAlias : IReturn<IdWithAlias> + { + [DataMember(Name = "id")] + public int Id { get; set; } + } + + public class CustomRouteService : IService { - public object Any(CustomRoute request) + public object Any(CustomRoute request) => request; + public object Any(CustomRouteDot request) => request; + public object Any(GetPngPic request) => request; + public object Any(RequestWithVersion request) => request; + public object Any(IdWithAlias request) => request; + } + + [TestFixture] + public class ModifiedRouteTests + { + private ModifiedRouteAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new ModifiedRouteAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); +// appHost.Start(Config.AnyHostBaseUrl); //go through fiddler + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_URL_Decode_PathInfo() + { + var client = new JsonServiceClient(Config.ListeningOn); +// var client = new JsonServiceClient("http://test.servicestack.net"); + + var pathInfo = "ern::Closer2U::Userprofile::1c7e9ead-c7d9-46f8-a0cc-2777c4373ac4"; + var response = client.Get(new CustomRoute { + Data = pathInfo + }); + + Assert.That(response.Data, Is.EqualTo(pathInfo)); + } + + [Test] + public void Can_download_modified_routes() + { + try + { + var notFound = Config.AbsoluteBaseUri.CombineWith("/modified/foo.csv") + .GetStringFromUrl(); + Assert.Fail("Existing route should be modified"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.NotFound)); + } + + var response = Config.AbsoluteBaseUri.CombineWith("/prefix/modified/foo.csv") + .GetStringFromUrl(); + + Assert.That(response, Is.EqualTo("Data\r\nfoo\r\n")); + } + } + + public class ModifiedRouteAppHost : AppHostHttpListenerBase + { + public ModifiedRouteAppHost() : base(nameof(BufferedRequestTests), typeof(CustomRouteService).Assembly) { } + + public override void Configure(Container container) + { + } + + public override RouteAttribute[] GetRouteAttributes(System.Type requestType) + { + var routes = base.GetRouteAttributes(requestType); + if (requestType != typeof(ModifiedRoute)) return routes; + + routes.Each(x => x.Path = "/prefix" + x.Path); + return routes; + } + } + + [Route("/modified")] + [Route("/modified/{Data}")] + public class ModifiedRoute : IReturn<ModifiedRoute> + { + public string Data { get; set; } + } + + public class ModifiedRouteService : IService + { + public object Any(ModifiedRoute request) { return request; } } + + [TestFixture] + public class InvalidRouteTests + { + public class UnknownRoute { } + + class InvalidRoutesAppHost : AppSelfHostBase + { + public InvalidRoutesAppHost() : base(nameof(InvalidRoutesAppHost), typeof(InvalidRoutesAppHost).Assembly) { } + + public override void Configure(Container container) + { + Routes.Add<UnknownRoute>("/unknownroute"); + } + } + + [Test] + public void Throws_error_when_registering_route_for_unknown_Service() + { + using (var appHost = new InvalidRoutesAppHost() + .Init() + .Start(Config.AbsoluteBaseUri)) + { + try + { + var json = Config.AbsoluteBaseUri.CombineWith("/unknownroute").GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.MethodNotAllowed)); + } + } + } + } + + [Route("/routeinfo/{Path*}")] + public class GetRouteInfo + { + public string Path { get; set; } + } + + public class GetRouteInfoResponse + { + public string BaseUrl { get; set; } + public string ResolvedUrl { get; set; } + } + + public class RouteInfoService : Service + { + public object Any(GetRouteInfo request) + { + return new GetRouteInfoResponse + { + BaseUrl = base.Request.GetBaseUrl(), + ResolvedUrl = base.Request.ResolveAbsoluteUrl("~/resolved") + }; + } + } + + class RouteInfoAppHost : AppSelfHostBase + { + public RouteInfoAppHost() : base(typeof(RouteInfoAppHost).Name, typeof(RouteInfoAppHost).Assembly) { } + public override void Configure(Container container) + { + CatchAllHandlers.Add((httpMethod, pathInfo, filePath) => + { + if (pathInfo.StartsWith("/swagger-ui")) + { + return new CustomResponseHandler((req, res) => + new GetRouteInfoResponse + { + BaseUrl = req.GetBaseUrl(), + ResolvedUrl = req.ResolveAbsoluteUrl("~/resolved") + }); + } + return null; + }); + } + } + + public class RouteInfoPathTests + { + [Test] + public void RootPath_returns_BaseUrl() + { + var url = Config.ServiceStackBaseUri; + using (var appHost = new RouteInfoAppHost() + .Init() + .Start(url + "/")) + { + var response = url.CombineWith("/routeinfo").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir/sub").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/swagger-ui").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/swagger-ui/").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + } + } + + [Test] + public void ApiPath_returns_BaseUrl() + { + var url = Config.AbsoluteBaseUri.AppendPath("api"); + using (var appHost = new RouteInfoAppHost() + .Init() + .Start(url + "/")) + { + var response = url.CombineWith("/routeinfo").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir/sub").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/swagger-ui").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/swagger-ui/").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + } + } + + [Test] + public void ApiV1Path_returns_BaseUrl() + { + var url = Config.AbsoluteBaseUri.AppendPath("api").AppendPath("v1"); + using (var appHost = new RouteInfoAppHost() + .Init() + .Start(url + "/")) + { + var response = url.CombineWith("/routeinfo").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir/sub").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/swagger-ui").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/swagger-ui/").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + } + } + + [Test] + public void Does_NormalizePathInfo() + { + Assert.That(ServiceStackHost.NormalizePathInfo("/api/a", "api"), Is.EqualTo("/a")); + Assert.That(ServiceStackHost.NormalizePathInfo("/api/a/b", "api"), Is.EqualTo("/a/b")); + Assert.That(ServiceStackHost.NormalizePathInfo("/a", "api"), Is.EqualTo("/a")); + Assert.That(ServiceStackHost.NormalizePathInfo("/a/b", "api"), Is.EqualTo("/a/b")); + Assert.That(ServiceStackHost.NormalizePathInfo("/apikeys", "api"), Is.EqualTo("/apikeys")); + Assert.That(ServiceStackHost.NormalizePathInfo("/apikeys/a", "api"), Is.EqualTo("/apikeys/a")); + Assert.That(ServiceStackHost.NormalizePathInfo("/apikeys/a/b", "api"), Is.EqualTo("/apikeys/a/b")); + } + + } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RoutingPageTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RoutingPageTests.cs new file mode 100644 index 00000000000..94aa64f94d8 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RoutingPageTests.cs @@ -0,0 +1,271 @@ +using System; +using System.IO; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class RoutingPageTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(RoutingPageTests), typeof(RoutingPageTests).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + DebugMode = true, // need this to disable caching + }); + Plugins.Add(new SharpPagesFeature()); + } + } + + protected ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [SetUp] + public void SetUp() + { + try + { + appHost.VirtualFileSources.GetMemoryVirtualFiles().Clear(); + appHost.VirtualFileSources.GetFileSystemVirtualFiles().DeleteFolder("dir"); + } + catch (IOException e) + { + //sometimes throws The process cannot access the file 'bundle.js' because it is being used by another process. + } + } + + public static StringDictionary Files = new StringDictionary { + { "dir/contacts/_layout.html", PageHtml("{{ page }}") }, + { "dir/contacts/index.html", "<h2>/contacts/index.html</h2>" }, + { "dir/contacts/_id/edit.html", "<h2>/_id/edit.html {{id}}</h2>" }, + { "dir/contacts/edit/_id.html", "<h2>/edit/_id.html {{id}}</h2>" }, + }; + + static string PageHtml(string pageHtml) => $"<html><body><h1>/contacts/_layout.html</h1>{pageHtml}</body></html>"; + + public static StringDictionary Expected = new StringDictionary { + { "dir/contacts/index.html", PageHtml("<h2>/contacts/index.html</h2>") }, + { "dir/contacts/index", PageHtml("<h2>/contacts/index.html</h2>") }, + { "dir/contacts/", PageHtml("<h2>/contacts/index.html</h2>") }, + { "dir/contacts/1/edit", PageHtml("<h2>/_id/edit.html 1</h2>") }, + { "dir/contacts/edit/1", PageHtml("<h2>/edit/_id.html 1</h2>") }, + }; + + private static void AssertCanGetRoutingPages(IVirtualFiles vfs, Action fn=null) + { + Files.ForEach(vfs.WriteFile); + + foreach (var entry in Expected) + { + entry.Key.Print(); + var html = Config.ListeningOn.CombineWith(entry.Key).GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(entry.Value)); + } + + fn?.Invoke(); + } + + [Test] + public void Can_get_routing_pages_from_FileSystemVirtualFiles() + { + AssertCanGetRoutingPages(appHost.VirtualFileSources.GetFileSystemVirtualFiles()); + } + + [Test] + public void Can_get_routing_pages_from_MemoryVirtualFiles() + { + AssertCanGetRoutingPages(appHost.VirtualFileSources.GetMemoryVirtualFiles()); + } + + [Test] + public void Can_get_routing_pages_from_FileSystemVirtualFiles_when_file_in_MemoryVfs() + { + var memFs = appHost.VirtualFileSources.GetMemoryVirtualFiles(); + memFs.WriteFile("alt-dir/page.html", "<h2>alt-dir/page.html</h2>"); + + AssertCanGetRoutingPages(appHost.VirtualFileSources.GetFileSystemVirtualFiles(), () => { + var html = Config.ListeningOn.CombineWith("alt-dir/page").GetStringFromUrl(accept:MimeTypes.Html); + Assert.That(html, Is.EqualTo("<h2>alt-dir/page.html</h2>")); + }); + } + + [Test] + public void Can_get_routing_pages_from_FileSystemVirtualFiles_when_file_in_dir_in_MemoryVfs() + { + var memFs = appHost.VirtualFileSources.GetMemoryVirtualFiles(); + memFs.WriteFile("dir/page.html", "<h2>dir/page.html</h2>"); + memFs.WriteFile("dir/contacts/page.html", "<h2>dir/contacts/page.html</h2>"); + + AssertCanGetRoutingPages(appHost.VirtualFileSources.GetFileSystemVirtualFiles(), () => { + var html = Config.ListeningOn.CombineWith("dir/page").GetStringFromUrl(accept:MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo("<h2>dir/page.html</h2>")); + + html = Config.ListeningOn.CombineWith("dir/contacts/page").GetStringFromUrl(accept:MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(PageHtml("<h2>dir/contacts/page.html</h2>"))); + }); + } + + static string BundledJsPageHtml(string pageHtml) => $"<html><body><script src=\"/dir/js/bundle.js\"></script><h1>/contacts/_layout.html</h1>{pageHtml}</body></html>"; + + public static StringDictionary BundledJsFiles => new StringDictionary { + { "dir/js/default.js", "function fn(){ }" }, + { "dir/lib/js/a.js", "function a(){ }" }, + { "dir/lib/js/b.js", "function b(){ }" }, + { "dir/lib/js/c.js", "function c(){ }" }, + { "dir/contacts/_layout.html", "<html><body>{{ ['/dir/lib/js','/dir/js/default.js'] | bundleJs({disk:false,out:'/dir/js/bundle.js'}) }}<h1>/contacts/_layout.html</h1>{{page}}</body></html>" }, + { "dir/contacts/index.html", "<h2>/contacts/index.html</h2>" }, + { "dir/contacts/_id/edit.html", "<h2>/_id/edit.html {{id}}</h2>" }, + { "dir/contacts/edit/_id.html", "<h2>/edit/_id.html {{id}}</h2>" }, + }; + + public static StringDictionary BundledJsExpected => new StringDictionary { + { "dir/contacts/", BundledJsPageHtml("<h2>/contacts/index.html</h2>") }, + { "dir/contacts/1/edit", BundledJsPageHtml("<h2>/_id/edit.html 1</h2>") }, + { "dir/contacts/edit/1", BundledJsPageHtml("<h2>/edit/_id.html 1</h2>") }, + }; + + public static string ExpectedBundleJs = "function a(){};\n\nfunction b(){};\n\nfunction c(){};\n\nfunction fn(){};"; + + [Test] + public void Can_get_Routing_Page_after_in_Memory_js_Bundle() + { + var fs = appHost.VirtualFileSources.GetFileSystemVirtualFiles(); + BundledJsFiles.ForEach(fs.WriteFile); + + foreach (var entry in BundledJsExpected) + { + entry.Key.Print(); + var html = Config.ListeningOn.CombineWith(entry.Key).GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(entry.Value)); + } + + var memFs = appHost.VirtualFileSources.GetMemoryVirtualFiles(); + var bundleJs = memFs.GetFile("dir/js/bundle.js")?.ReadAllText(); + Assert.That(bundleJs, Is.Not.Null); + $"\nbundle.js:\n{bundleJs}".Print(); + Assert.That(bundleJs.NormalizeNewLines(), Is.EqualTo(ExpectedBundleJs)); + + bundleJs = Config.ListeningOn.CombineWith("/dir/js/bundle.js").GetStringFromUrl(); + Assert.That(bundleJs.NormalizeNewLines(), Is.EqualTo(ExpectedBundleJs)); + } + + public static string ExpectedOnDiskBundleJs = "function a(){ }\nfunction b(){ }\nfunction c(){ }\nfunction fn(){ }"; + + [Test] + public void Can_get_Routing_Page_after_on_disk_js_Bundle() + { + var fs = appHost.VirtualFileSources.GetFileSystemVirtualFiles(); + var files = BundledJsFiles; + files["dir/contacts/_layout.html"] = files["dir/contacts/_layout.html"] + .Replace("disk:false", "disk:true,minify:false"); + files.ForEach(fs.WriteFile); + + foreach (var entry in BundledJsExpected) + { + entry.Key.Print(); + var html = Config.ListeningOn.CombineWith(entry.Key).GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(entry.Value)); + } + + var bundleJs = fs.GetFile("dir/js/bundle.js")?.ReadAllText(); + Assert.That(bundleJs, Is.Not.Null); + $"\nbundle.js:\n{bundleJs}".Print(); + Assert.That(bundleJs.NormalizeNewLines(), Is.EqualTo(ExpectedOnDiskBundleJs)); + + bundleJs = Config.ListeningOn.CombineWith("/dir/js/bundle.js").GetStringFromUrl(); + Assert.That(bundleJs.NormalizeNewLines(), Is.EqualTo(ExpectedOnDiskBundleJs)); + } + + static string BundledCssPageHtml(string pageHtml) => $"<html><body><link rel=\"stylesheet\" href=\"/dir/css/bundle.css\"><h1>/contacts/_layout.html</h1>{pageHtml}</body></html>"; + + public static StringDictionary BundledCssFiles => new StringDictionary { + { "dir/css/default.css", "body { }" }, + { "dir/lib/css/a.css", ".a { }" }, + { "dir/lib/css/b.css", ".b { }" }, + { "dir/lib/css/c.css", ".c { }" }, + { "dir/contacts/_layout.html", "<html><body>{{ ['/dir/lib/css','/dir/css/default.css'] | bundleCss({disk:false,out:'/dir/css/bundle.css'}) }}<h1>/contacts/_layout.html</h1>{{page}}</body></html>" }, + { "dir/contacts/index.html", "<h2>/contacts/index.html</h2>" }, + { "dir/contacts/_id/edit.html", "<h2>/_id/edit.html {{id}}</h2>" }, + { "dir/contacts/edit/_id.html", "<h2>/edit/_id.html {{id}}</h2>" }, + }; + + public static StringDictionary BundledCssExpected => new StringDictionary { + { "dir/contacts/", BundledCssPageHtml("<h2>/contacts/index.html</h2>") }, + { "dir/contacts/1/edit", BundledCssPageHtml("<h2>/_id/edit.html 1</h2>") }, + { "dir/contacts/edit/1", BundledCssPageHtml("<h2>/edit/_id.html 1</h2>") }, + }; + + public static string ExpectedBundleCss = ".a{}\n.b{}\n.c{}\nbody{}"; + + [Test] + public void Can_get_Routing_Page_after_in_Memory_css_Bundle() + { + var fs = appHost.VirtualFileSources.GetFileSystemVirtualFiles(); + BundledCssFiles.ForEach(fs.WriteFile); + + foreach (var entry in BundledCssExpected) + { + entry.Key.Print(); + var html = Config.ListeningOn.CombineWith(entry.Key).GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(entry.Value)); + } + + var memFs = appHost.VirtualFileSources.GetMemoryVirtualFiles(); + var bundleCss = memFs.GetFile("dir/css/bundle.css")?.ReadAllText(); + Assert.That(bundleCss, Is.Not.Null); + $"\nbundle.css:\n{bundleCss}".Print(); + Assert.That(bundleCss.NormalizeNewLines(), Is.EqualTo(ExpectedBundleCss)); + + bundleCss = Config.ListeningOn.CombineWith("/dir/css/bundle.css").GetStringFromUrl(); + Assert.That(bundleCss.NormalizeNewLines(), Is.EqualTo(ExpectedBundleCss)); + } + + public static string ExpectedOnDiskBundleCss = ".a { }\n.b { }\n.c { }\nbody { }"; + + [Test] + public void Can_get_Routing_Page_after_on_disk_css_Bundle() + { + var fs = appHost.VirtualFileSources.GetFileSystemVirtualFiles(); + var files = BundledCssFiles; + files["dir/contacts/_layout.html"] = files["dir/contacts/_layout.html"] + .Replace("disk:false", "disk:true,minify:false"); + files.ForEach(fs.WriteFile); + + foreach (var entry in BundledCssExpected) + { + entry.Key.Print(); + var html = Config.ListeningOn.CombineWith(entry.Key).GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(entry.Value)); + } + + var bundleCss = fs.GetFile("dir/css/bundle.css")?.ReadAllText(); + Assert.That(bundleCss, Is.Not.Null); + $"\nbundle.js:\n{bundleCss}".Print(); + Assert.That(bundleCss.NormalizeNewLines(), Is.EqualTo(ExpectedOnDiskBundleCss)); + + bundleCss = Config.ListeningOn.CombineWith("/dir/css/bundle.css").GetStringFromUrl(); + Assert.That(bundleCss.NormalizeNewLines(), Is.EqualTo(ExpectedOnDiskBundleCss)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/RuntimeAttributeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/RuntimeAttributeTests.cs new file mode 100644 index 00000000000..aa4fd32fbf3 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/RuntimeAttributeTests.cs @@ -0,0 +1,104 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.DataAnnotations; +using ServiceStack.Host; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class RuntimeAttributes : IReturn<RuntimeAttributes> + { + public int Id { get; set; } + } + + public class RuntimeAttributeService : Service + { + public object Any(RuntimeAttributes request) + { + return request; + } + } + + public class RuntimeAttributeRequestFilter : RequestFilterAttribute + { + public override void Execute(IRequest req, IResponse res, object requestDto) + { + ((RuntimeAttributes)requestDto).Id++; + } + } + + [TestFixture] + public class RuntimeAttributeTests + { + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetUp() + { + appHost = new RuntimeAttributeAppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + public class RuntimeAttributeAppHost : AppSelfHostBase + { + public RuntimeAttributeAppHost() + : base(typeof(RuntimeAttributeTests).Name, typeof (RuntimeAttributeAppHost).Assembly) + { + typeof(RuntimeAttributes) + .AddAttributes(new RuntimeAttributeRequestFilter()); + + typeof(Register) + .AddAttributes(new RouteAttribute("/custom-register")) + .AddAttributes(new RestrictAttribute(RequestAttributes.Json)); + } + + public override void Configure(Container container) + { + this.RegisterService<RegisterService>("/register"); + + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new BasicAuthProvider(), + })); + } + } + + [Test] + public void Does_add_CustomAttributes_to_when_added_in_AppHost_constructor() + { + var restPath = RestHandler.FindMatchingRestPath("GET", "/custom-register", out _); + + Assert.That(restPath, Is.Not.Null); + Assert.That(restPath.RequestType, Is.EqualTo(typeof(Register))); + + //Allows JSON + appHost.ServiceController.AssertServiceRestrictions(typeof(Register), RequestAttributes.Json); + + Assert.Throws<UnauthorizedAccessException>(() => + appHost.ServiceController.AssertServiceRestrictions(typeof(Register), RequestAttributes.Xml)); + } + + [Test] + public void Can_add_RequestFilter_attribute_in_Configure() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var response = client.Get(new RuntimeAttributes { Id = 1 }); + + Assert.That(response.Id, Is.EqualTo(2)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/BinaryExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/BinaryExpressionTests.cs new file mode 100644 index 00000000000..02352846c53 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/BinaryExpressionTests.cs @@ -0,0 +1,352 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class BinaryExpressionTests + { + [Test] + public void Does_parse_basic_binary_expressions() + { + JsToken expr; + + "1 + 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)))); + + "1 - 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsSubtraction.Operator, new JsLiteral(2)))); + + "1 * 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsMultiplication.Operator, new JsLiteral(2)))); + + "1 / 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsDivision.Operator, new JsLiteral(2)))); + + "1 & 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsBitwiseAnd.Operator, new JsLiteral(2)))); + + "1 | 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsBitwiseOr.Operator, new JsLiteral(2)))); + + "1 ^ 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsBitwiseXOr.Operator, new JsLiteral(2)))); + + "1 << 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsBitwiseLeftShift.Operator, new JsLiteral(2)))); + + "1 >> 2".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsBitwiseRightShift.Operator, new JsLiteral(2)))); + } + + [Test] + public void Does_parse_composite_binary_expressions() + { + JsToken expr; + + "1 + 2 + 3".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)), + JsAddition.Operator, + new JsLiteral(3) + ) + )); + + "1 + 2 + 3 + 4".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression( + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)), + JsAddition.Operator, + new JsLiteral(3)), + JsAddition.Operator, + new JsLiteral(4) + ) + )); + } + + [Test] + public void Does_parse_binary_expressions_with_precedence() + { + JsToken expr; + + "1 + 2 * 3".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsLiteral(1), + JsAddition.Operator, + new JsBinaryExpression(new JsLiteral(2), JsMultiplication.Operator, new JsLiteral(3)) + ) + )); + + "1 + 2 * 3 - 4".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression( + new JsLiteral(1), + JsAddition.Operator, + new JsBinaryExpression(new JsLiteral(2), JsMultiplication.Operator, new JsLiteral(3))), + JsSubtraction.Operator, + new JsLiteral(4) + ) + )); + + "1 + 2 * 3 - 4 / 5".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression( + new JsLiteral(1), + JsAddition.Operator, + new JsBinaryExpression(new JsLiteral(2), JsMultiplication.Operator, new JsLiteral(3))), + JsSubtraction.Operator, + new JsBinaryExpression(new JsLiteral(4), JsDivision.Operator, new JsLiteral(5))) + ) + ); + } + + [Test] + public void Does_parse_binary_expression_with_brackets() + { + JsToken expr; + + "(1 + 2)".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)) + )); + + "(1 + 2) * 3".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)), + JsMultiplication.Operator, + new JsLiteral(3) + ) + )); + + "(1 + 2) * (3 - 4)".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)), + JsMultiplication.Operator, + new JsBinaryExpression(new JsLiteral(3), JsSubtraction.Operator, new JsLiteral(4)) + ) + )); + + "(1 + 2) * ((3 - 4) / 5)".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsBinaryExpression( + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2)), + JsMultiplication.Operator, + new JsBinaryExpression( + new JsBinaryExpression(new JsLiteral(3), JsSubtraction.Operator, new JsLiteral(4)), + JsDivision.Operator, + new JsLiteral(5) + ) + ) + )); + } + + [Test] + public void Does_parse_logical_expressions() + { + JsToken expr; + + "!(true || false)".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsUnaryExpression( + JsNot.Operator, + new JsLogicalExpression(new JsLiteral(true), JsOr.Operator, new JsLiteral(false)) + ) + )); + } + + [Test] + public void Does_parse_binary_and_logical_expressions() + { + JsToken expr; + + "[1 + 2 * 3 > one && 1 * 2 < ten]".ParseJsExpression(out expr); + + Assert.That(expr, Is.EqualTo( + new JsArrayExpression( + new JsLogicalExpression( + new JsBinaryExpression( + new JsBinaryExpression( + new JsLiteral(1), + JsAddition.Operator, + new JsBinaryExpression( + new JsLiteral(2), + JsMultiplication.Operator, + new JsLiteral(3) + ) + ), + JsGreaterThan.Operator, + new JsIdentifier("one") + ), + JsAnd.Operator, + new JsBinaryExpression( + new JsBinaryExpression( + new JsLiteral(1), + JsMultiplication.Operator, + new JsLiteral(2) + ), + JsLessThan.Operator, + new JsIdentifier("ten") + ) + ) + )) + ); + } + + [Test] + public void Does_parse_unary_expression() + { + JsToken expr; + + "-1".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsUnaryExpression(JsMinus.Operator, new JsLiteral(1)))); + "+1".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsUnaryExpression(JsPlus.Operator, new JsLiteral(1)))); + "!true".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsUnaryExpression(JsNot.Operator, new JsLiteral(true)))); + } + + [Test] + public void Does_evaluate_templates_with_expressions() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 1 + 2 }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ 1 - 2 }}"), Is.EqualTo("-1")); + Assert.That(context.EvaluateScript("{{ 1 * 2 }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ 1 / 2 }}"), Is.EqualTo("0.5")); + Assert.That(context.EvaluateScript("{{ 1 / 2.0 }}"), Is.EqualTo("0.5")); + Assert.That(context.EvaluateScript("{{ 1 & 2 }}"), Is.EqualTo("0")); + //Needs to be in brackets so it's not considered as different filter expressions + Assert.That(context.EvaluateScript("{{ (1 | 2) }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ 1 ^ 2 }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ 1 << 2 }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ 1 >> 2 }}"), Is.EqualTo("0")); + + Assert.That(context.EvaluateScript("{{ 1 + 2 + 3 }}"), Is.EqualTo("6")); + Assert.That(context.EvaluateScript("{{ 1 + 2 + 3 + 4 }}"), Is.EqualTo("10")); + + Assert.That(context.EvaluateScript("{{ 1 + 2 * 3 }}"), Is.EqualTo("7")); + Assert.That(context.EvaluateScript("{{ 1 + 2 * 3 - 4 }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ 1 + 2 * 3 - 4 / 5 }}"), Is.EqualTo("6.2")); + Assert.That(context.EvaluateScript("{{ 1 + 2 * 3 - 4 / 5.0 }}"), Is.EqualTo("6.2")); + + Assert.That(context.EvaluateScript("{{ (1 + 2) }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ (1 + 2) * 3 }}"), Is.EqualTo("9")); + Assert.That(context.EvaluateScript("{{ (1 + 2) * (3 - 4) }}"), Is.EqualTo("-3")); + Assert.That(context.EvaluateScript("{{ (1 + 2) * ((3 - 4) / 5.0) }}"), + Is.EqualTo("-0.6").Or.EqualTo("-0.6000000000000001")); // .NET Core 3.1+ + } + + [Test] + public void Does_evaluate_binary_expressions_with_filters() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 1 + 2 * 3 | add(3) }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ (1 | 2) | add(3) }}"), Is.EqualTo("6")); + + Assert.That(context.EvaluateScript("{{ add(1 + 2 * 3, 4) | add(-5) }}"), Is.EqualTo("6")); + + Assert.That(context.EvaluateScript("{{ [1+2,1+2*3] | sum }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ {a:1+2*3} | get('a') }}"), Is.EqualTo("7")); + } + + [Test] + public void Does_evaluate_binary_and_logical_expressions() + { + var context = new ScriptContext { + Args = { + ["one"] = 1, + ["ten"] = 10, + }, + }.Init(); + + Assert.That(context.EvaluateScript("{{ [1 + 2 * 3 > one && 1 * 2 < ten] | get(0) }}"), Is.EqualTo("True")); + } + + private static ScriptContext CreateContext() + { + var context = new ScriptContext { + Args = { + ["a"] = null, + ["b"] = 2, + ["empty"] = "", + ["f"] = false, + ["zero"] = 0, + ["t"] = true, + ["one"] = 1, + ["obj"] = new Dictionary<string, object>(), + ["array"] = new List<object>(), + } + }.Init(); + return context; + } + + [Test] + public void Does_evaluate_Coalescing_expressions() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript("{{ null ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ a ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ '' ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ empty ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ f ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 0 ?? 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ zero ?? 1 }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ true ?? 1 }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ t ?? 1 }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ b ?? 1 }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ 2 ?? 1 }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ 1 ?? 2 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ one ?? 2 }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ 0 ?? 2 > 1 ? 'Y' : 'N' }}"), Is.EqualTo("Y")); + Assert.That(context.EvaluateScript("{{ 2 ?? 0 > 1 ? 'Y' : 'N' }}"), Is.EqualTo("Y")); + } + + [Test] + public void Does_use_truthy_for_logical_expression() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript("{{#if null}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if a}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if unknown}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if 0}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if ''}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if empty}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if false}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + + Assert.That(context.EvaluateScript("{{#if a && true}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if a && t}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if true && a}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if unknown && true}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if true && unknown}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if empty && true}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if true && empty}}f{{else}}t{{/if}}"), Is.EqualTo("t")); + + Assert.That(context.EvaluateScript("{{#if a || true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if true || a}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if unknown || true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if true || unknown}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if empty || true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if true || empty}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + + Assert.That(context.EvaluateScript("{{#if {} && true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if obj && true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if [] && true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + Assert.That(context.EvaluateScript("{{#if array && true}}t{{else}}f{{/if}}"), Is.EqualTo("t")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CachingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CachingTests.cs new file mode 100644 index 00000000000..5da37df3949 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CachingTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class CachingTests + { + [Test] + public void Can_use_ReadOnlyMemory_as_Dictionary_key() + { + var i = 0; + var map = new ConcurrentDictionary<ReadOnlyMemory<char>,int>(); + var key = "key".AsMemory(); + map.GetOrAdd(key, _ => ++i); + map.GetOrAdd(key, _ => ++i); + + Assert.That(i, Is.EqualTo(1)); + Assert.That(map.Count, Is.EqualTo(1)); + + map.GetOrAdd("key".AsMemory(), _ => ++i); + map.GetOrAdd("key".AsMemory(), _ => ++i); + Assert.That(i, Is.EqualTo(1)); + Assert.That(map.Count, Is.EqualTo(1)); + } + + [Test] + public void Cant_use_ReadOnlyMemory_from_different_string_as_Dictionary_Key() + { + var i = 0; + var map = new ConcurrentDictionary<ReadOnlyMemory<char>, int>(); + var key = "key".AsMemory(); + map.GetOrAdd("1key".AsMemory().Slice(1), _ => ++i); + map.GetOrAdd("2key".AsMemory().Slice(1), _ => ++i); + + Assert.That("1key".AsMemory().Slice(1).ToString(), Is.EqualTo("key")); + Assert.That("2key".AsMemory().Slice(1).ToString(), Is.EqualTo("key")); + + Assert.That(i, Is.EqualTo(2)); + Assert.That(map.Count, Is.EqualTo(2)); + } + + [Test] + public void Unique_Template_Should_Be_Cached_Only_Once() + { + var context = new ScriptContext + { + ScriptBlocks = { new EvalScriptBlock() }, + Args = { + ["templates"] = new List<string> { + "1. {{income ?? 1000}} - {{expenses}}", + "2. {{income ?? 2000}} - {{expenses}}", + "3. {{income ?? 3000}} - {{expenses}}", + } + } + }.Init(); + + 10000.Times(() => + { + var result = context.EvaluateScript(@"{{#each templates}}{{index}}{{/each}}"); + Assert.That(result, Is.EqualTo("012")); + }); + + Assert.That(context.Cache.Count, Is.EqualTo(1)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CallExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CallExpressionTests.cs new file mode 100644 index 00000000000..5e0d23953cd --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CallExpressionTests.cs @@ -0,0 +1,79 @@ +using System; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class CallExpressionTests + { + [Test] + public void Does_parse_call_expression() + { + JsCallExpression expr; + + "a".AsSpan().ParseJsCallExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsCallExpression(new JsIdentifier("a")))); + "a()".AsSpan().ParseJsCallExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsCallExpression(new JsIdentifier("a")))); + } + + [Test] + public void Can_parse_expressions_with_methods() + { + JsToken token; + + "mod(it,3) != 0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsBinaryExpression( + new JsCallExpression( + new JsIdentifier("mod"), + new JsIdentifier("it"), + new JsLiteral(3) + ), + JsNotEquals.Operator, + new JsLiteral(0) + ) + )); + + "{ a: add(it % add(it + 1, 1 | it)) }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsObjectExpression( + new JsProperty( + new JsIdentifier("a"), + new JsCallExpression( + new JsIdentifier("add"), + new JsBinaryExpression( + new JsIdentifier("it"), + JsMod.Operator, + new JsCallExpression( + new JsIdentifier("add"), + new JsBinaryExpression( + new JsIdentifier("it"), + JsAddition.Operator, + new JsLiteral(1) + ), + new JsBinaryExpression( + new JsLiteral(1), + JsBitwiseOr.Operator, + new JsIdentifier("it") + ) + ) + ) + ) + ) + ))); + } + + [Test] + public void Does_evaluate_nested_call_expressions() + { + var context = new ScriptContext { + Args = { + ["it"] = 10 + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ { a: add(it % 3,1) * 2, b: 2 * 3 + incr(4 + decr(5)) } |> values |> sum |> currency }}"), + Is.EqualTo("$19.00")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CodeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CodeTests.cs new file mode 100644 index 00000000000..d72e3569fb2 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CodeTests.cs @@ -0,0 +1,228 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.IO; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [Page("foreach-code")] + public class ForEachCodeExample : SharpCodePage + { + public string render(string title, string[] items) => $@" +<h1>{title}</h1> +<ul> + {items.Map(x => $"<li>{x}</li>").Join("")} +</ul> +"; + } + + [Page("dir/foreach-code")] + [PageArg("title", "Dir foreach code")] + public class DirForEachCodeExample : SharpCodePage + { + public string render(string title, string[] items) => $@" +<h1>{title}</h1> +<ul> + {items.Map(x => $"<li>{x}</li>").Join("")} +</ul> +"; + } + + [Page("codepage-dep")] + public class CodePageWithDep : SharpCodePage + { + public IAppSettings AppSettings { get; set; } + + public string render(string key, string content) => $@" +<h2>{AppSettings.GetString(key)}</h2> +<p> + {content} +</p> +"; + } + + public class CodeTests + { + [Test] + public void Can_remove_TemplateContext_defaults() + { + var context = new ScriptContext() + .RemoveFilters(x => true) + .RemoveBlocks(x => true) + .RemovePlugins(x => true) + .Init(); + + Assert.That(context.ScriptMethods.Count, Is.EqualTo(0)); + Assert.That(context.ScriptBlocks.Count, Is.EqualTo(0)); + Assert.That(context.Plugins.Count, Is.EqualTo(0)); + } + + [Test] + public void Can_remove_individual_blocks() + { + var context = new ScriptContext { + OnAfterPlugins = ctx => ctx.RemoveBlocks(x => x.Name == "capture") + } + .Init(); + + Assert.That(context.ScriptBlocks.Any(x => x is CaptureScriptBlock), Is.False); + } + + [Test] + public void Can_execute_CodePage() + { + var context = new ScriptContext + { + Args = + { + ["items"] = new[] {"A", "B", "C"} + }, + ScanTypes = {typeof(ForEachCodeExample)} + }.Init(); + + var page = context.GetCodePage("foreach-code"); + var html = new PageResult(page) + { + Args = + { + ["title"] = "For each code" + } + }.Result; + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<h1>For each code</h1> +<ul> + <li>A</li><li>B</li><li>C</li> +</ul> +".NormalizeNewLines())); + } + + private static void WriteLayouts(ScriptContext context) + { + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body id=root> +{{ page }} +</body> +</html> +"); + + context.VirtualFiles.WriteFile("dir/_layout.html", @" +<html> +<body id=dir> +{{ page }} +</body> +</html> +"); + } + + [Test] + public void Can_execute_CodePage_with_Layout() + { + var context = new ScriptContext + { + Args = + { + ["items"] = new[] {"A", "B", "C"} + }, + ScanTypes = {typeof(ForEachCodeExample)} + }.Init(); + + WriteLayouts(context); + + var page = context.GetCodePage("foreach-code"); + var html = new PageResult(page) + { + Args = + { + ["title"] = "For each code" + } + }.Result; + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +<h1>For each code</h1> +<ul> + <li>A</li><li>B</li><li>C</li> +</ul> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Can_execute_nested_CodePage_with_Layout() + { + var context = new ScriptContext + { + Args = + { + ["items"] = new[] {"A", "B", "C"} + }, + ScanTypes = {typeof(DirForEachCodeExample)} + }.Init(); + + WriteLayouts(context); + + var page = context.GetCodePage("dir/foreach-code"); + var html = new PageResult(page).Result; + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=dir> + +<h1>Dir foreach code</h1> +<ul> + <li>A</li><li>B</li><li>C</li> +</ul> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Can_execute_CodePage_with_Dep() + { + var context = new ScriptContext + { + ScanTypes = {typeof(CodePageWithDep)} + }.Init(); + + WriteLayouts(context); + + context.Container.AddSingleton<IAppSettings>(() => new SimpleAppSettings(new Dictionary<string, string> { + ["foo"] = "bar" + })); + + var page = context.GetCodePage("codepage-dep"); + page.Args["content"] = "The Content"; + + var html = new PageResult(page) + { + Args = + { + ["key"] = "foo" + } + }.Result; + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +<h2>bar</h2> +<p> + The Content +</p> + +</body> +</html> +".NormalizeNewLines())); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CustomScriptMethodsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CustomScriptMethodsTests.cs new file mode 100644 index 00000000000..22d328f892d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/CustomScriptMethodsTests.cs @@ -0,0 +1,53 @@ +using System; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class CustomScriptMethodsTests + { + [Flags] + public enum Options + { + None = 0, + Option1 = 1, + Option2 = 1 << 1, + Option4 = 1 << 2, + } + + public class EnumFilter : ScriptMethods + { + public bool hasOptionsFlag(Options source, Options value) => source.HasFlag(value); + } + + [Test] + public void Can_access_flag_enums() + { + var context = new ScriptContext + { + ScriptMethods = {new EnumFilter()}, + Args = + { + ["options0"] = Options.None, + ["options1"] = Options.Option1, + ["options2"] = Options.Option2, + ["options4"] = Options.Option4, + ["options3"] = (Options.Option1 | Options.Option2) + } + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ hasOptionsFlag(options3, 'Option1') }}"), + Is.EqualTo("True")); + + Assert.That(context.EvaluateScript(@"{{ hasFlag(options3, 'Option1') }},{{ hasFlag(options3, 1) }},{{ hasFlag(options3, options1) }}"), + Is.EqualTo("True,True,True")); + Assert.That(context.EvaluateScript(@"{{ hasFlag(options3, 'Option4') }},{{ hasFlag(options3, 4) }},{{ hasFlag(options3, options4) }}"), + Is.EqualTo("False,False,False")); + + Assert.That(context.EvaluateScript(@"{{ isEnum(options1, 'Option1') }},{{ isEnum(options1, 1) }},{{ isEnum(options1, options1) }}"), + Is.EqualTo("True,True,True")); + Assert.That(context.EvaluateScript(@"{{ isEnum(options3, 'Option1') }},{{ isEnum(options3, 1) }},{{ isEnum(options3, options1) }}"), + Is.EqualTo("False,False,False")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/DefaultScriptsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/DefaultScriptsTests.cs new file mode 100644 index 00000000000..6e474859094 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/DefaultScriptsTests.cs @@ -0,0 +1,2121 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Logging; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class DefaultScriptsTests + { + public ScriptContext CreateContext(Dictionary<string, object> args = null) + { + var context = new ScriptContext + { + Args = + { + ["foo"] = "bar", + ["intVal"] = 1, + ["doubleVal"] = 2.2 + } + }.Init(); + + args.Each((key,val) => context.Args[key] = val); + + return context; + } + + [Test] + public async Task Does_default_filter_raw() + { + var context = CreateContext(); + context.VirtualFiles.WriteFile("page.html", "<h1>{{ '<script>' }}</h1>"); + context.VirtualFiles.WriteFile("page-raw.html", "<h1>{{ '<script>' |> raw }}</h1>"); + + var result = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("<h1>&lt;script&gt;</h1>")); + + result = await new PageResult(context.GetPage("page-raw")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("<h1><script></h1>")); + } + + [Test] + public async Task Does_default_filter_json() + { + var context = CreateContext(); + context.VirtualFiles.WriteFile("page.html", "var model = {{ model |> json }};"); + + var result = await new PageResult(context.GetPage("page")) + { + Model = new Model + { + Id = 1, + Name = "foo" + } + }.RenderToStringAsync(); + + Assert.That(result, Is.EqualTo("var model = {\"Id\":1,\"Name\":\"foo\"};")); + + result = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("var model = null;")); + + context.VirtualFiles.WriteFile("page-null.html", "var nil = {{ null |> json }};"); + result = await new PageResult(context.GetPage("page-null")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("var nil = null;")); + } + + [Test] + public void Can_quote_strings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 'single quotes' }} +{{ ""double quotes"" }} +{{ `backticks` }} +{{ ′prime quoutes′ }} +".NormalizeNewLines()), Is.EqualTo(@" +single quotes +double quotes +backticks +prime quoutes +".NormalizeNewLines())); + } + + [Test] + public void Can_escape_strings() + { + var context = new ScriptContext + { + Args = + { + ["json"] = "{\"key\":\"single'back`tick\"}", + ["prime"] = "{\"key\":\"single'prime′quote\"}", + ["hasNewLines"] = "has\nnew\r\nlines" + } + }.Init(); + + Assert.That(context.EvaluateScript("var s = '{{ json |> escapeSingleQuotes |> raw }}'"), Is.EqualTo("var s = '{\"key\":\"single\\'back`tick\"}'")); + Assert.That(context.EvaluateScript("var s = `{{ json |> escapeBackticks |> raw }}`"), Is.EqualTo("var s = `{\"key\":\"single'back\\`tick\"}`")); + Assert.That(context.EvaluateScript("var s = ′{{ prime |> escapePrimeQuotes |> raw }}′"), Is.EqualTo("var s = ′{\"key\":\"single'prime\\′quote\"}′")); + Assert.That(context.EvaluateScript("var s = '{{ json |> jsString }}'"), Is.EqualTo("var s = '{\"key\":\"single\\'back`tick\"}'")); + Assert.That(context.EvaluateScript("var s = {{ json |> jsQuotedString }}"), Is.EqualTo("var s = '{\"key\":\"single\\'back`tick\"}'")); + + Assert.That(context.EvaluateScript("var s = '{{ hasNewLines |> jsString }}'"), Is.EqualTo(@"var s = 'has\nnew\r\nlines'")); + + Assert.That(context.EvaluateScript(@"{{ [{x:1,y:2},{x:3,y:4}] |> json |> assignTo:json }}var s = '{{ json |> jsString }}';"), + Is.EqualTo("var s = '[{\"x\":1,\"y\":2},{\"x\":3,\"y\":4}]';")); + + Assert.That(context.EvaluateScript(@"{{ `[ + {""name"":""Mc Donald's""} +]` |> raw |> assignTo:json }} +var obj = {{ json }}; +var str = '{{ json |> jsString }}'; +var str = {{ json |> jsQuotedString }}; +var escapeSingle = '{{ ""single' quote's"" |> escapeSingleQuotes |> escapeNewLines |> raw }}'; +var escapeDouble = ""{{ 'double"" quote""s' |> escapeDoubleQuotes |> escapeNewLines |> raw }}""; +".NormalizeNewLines()), Is.EqualTo(@" +var obj = [ + {""name"":""Mc Donald's""} +]; +var str = '[\n {""name"":""Mc Donald\'s""}\n]'; +var str = '[\n {""name"":""Mc Donald\'s""}\n]'; +var escapeSingle = 'single\' quote\'s'; +var escapeDouble = ""double\"" quote\""s""; +".NormalizeNewLines())); + + } + + [Test] + public async Task Does_default_filter_appSetting() + { + var context = CreateContext().Init(); + context.AppSettings.Set("copyright", "&copy; 2008-2017 ServiceStack"); + context.VirtualFiles.WriteFile("page.html", "<footer>{{ 'copyright' |> appSetting |> raw }}</footer>"); + + var result = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + + Assert.That(result, Is.EqualTo("<footer>&copy; 2008-2017 ServiceStack</footer>")); + } + + [Test] + public async Task Does_default_filter_arithmetic_using_filter() + { + var context = CreateContext().Init(); + context.VirtualFiles.WriteFile("page.html", @" +1 + 1 = {{ 1 |> add(1) }} +2 x 2 = {{ 2 |> mul(2) }} or {{ 2 |> multiply(2) }} +3 - 3 = {{ 3 |> sub(3) }} or {{ 3 |> subtract(3) }} +4 / 4 = {{ 4 |> div(4) }} or {{ 4 |> divide(4) }}"); + + var result = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +1 + 1 = 2 +2 x 2 = 4 or 4 +3 - 3 = 0 or 0 +4 / 4 = 1 or 1 +".NormalizeNewLines())); + } + + [Test] + public async Task Does_default_filter_arithmetic_using_pipeline_operator() + { + var context = CreateContext().Init(); + context.VirtualFiles.WriteFile("page.html", @" +1 + 1 = {{ 1 |> add(1) }} +2 x 2 = {{ 2 |> mul(2) }} or {{ 2 |> multiply(2) }} +3 - 3 = {{ 3 |> sub(3) }} or {{ 3 |> subtract(3) }} +4 / 4 = {{ 4 |> div(4) }} or {{ 4 |> divide(4) }}"); + + var result = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +1 + 1 = 2 +2 x 2 = 4 or 4 +3 - 3 = 0 or 0 +4 / 4 = 1 or 1 +".NormalizeNewLines())); + } + + [Test] + public async Task Does_default_filter_arithmetic_without_filter() + { + var context = CreateContext().Init(); + context.VirtualFiles.WriteFile("page.html", @" +1 + 1 = {{ add(1,1) }} +2 x 2 = {{ mul(2,2) }} or {{ multiply(2,2) }} +3 - 3 = {{ sub(3,3) }} or {{ subtract(3,3) }} +4 / 4 = {{ div(4,4) }} or {{ divide(4,4) }}"); + + var html = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +1 + 1 = 2 +2 x 2 = 4 or 4 +3 - 3 = 0 or 0 +4 / 4 = 1 or 1 +".NormalizeNewLines())); + } + + [Test] + public void Can_use_default_filter_arithmetic_with_shorthand_notation() + { + var context = new ScriptContext + { + Args = + { + ["num"] = 1 + } + }.Init(); + + context.VirtualFiles.WriteFile("page.html", @" +{{ num |> add(9) |> assignTo('ten') }} +square = {{ 'square-partial' |> partial({ ten }) }} +"); + + context.VirtualFiles.WriteFile("square-partial.html", "{{ ten }} x {{ ten }} = {{ ten |> multiply(ten) }}"); + + Assert.That(new PageResult(context.GetPage("page")).Result.NormalizeNewLines(), Is.EqualTo(@" +square = 10 x 10 = 100".NormalizeNewLines())); + } + + [Test] + public void Can_increment_and_decrement() + { + var context = new ScriptContext + { + Args = + { + ["ten"] = 10 + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> incr }}")).Result, Is.EqualTo("2")); + Assert.That(new PageResult(context.OneTimePage("{{ ten |> incr }}")).Result, Is.EqualTo("11")); + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> incrBy(2) }}")).Result, Is.EqualTo("3")); + Assert.That(new PageResult(context.OneTimePage("{{ ten |> incrBy(2) }}")).Result, Is.EqualTo("12")); + Assert.That(new PageResult(context.OneTimePage("{{ incr(1) }}")).Result, Is.EqualTo("2")); + Assert.That(new PageResult(context.OneTimePage("{{ incr(ten) }}")).Result, Is.EqualTo("11")); + Assert.That(new PageResult(context.OneTimePage("{{ incrBy(ten,2) }}")).Result, Is.EqualTo("12")); + + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> decr }}")).Result, Is.EqualTo("0")); + Assert.That(new PageResult(context.OneTimePage("{{ ten |> decrBy(2) }}")).Result, Is.EqualTo("8")); + } + + [Test] + public void Can_increment_and_decrement_pipeline_operator() + { + var context = new ScriptContext + { + Args = + { + ["ten"] = 10 + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> incr }}")).Result, Is.EqualTo("2")); + Assert.That(new PageResult(context.OneTimePage("{{ ten |> incr }}")).Result, Is.EqualTo("11")); + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> incrBy(2) }}")).Result, Is.EqualTo("3")); + Assert.That(new PageResult(context.OneTimePage("{{ ten |> incrBy(2) }}")).Result, Is.EqualTo("12")); + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> decr }}")).Result, Is.EqualTo("0")); + Assert.That(new PageResult(context.OneTimePage("{{ ten |> decrBy(2) }}")).Result, Is.EqualTo("8")); + } + + [Test] + public void Can_compare_numbers() + { + var context = new ScriptContext + { + Args = + { + ["two"] = 2 + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 2 |> greaterThan(1) }}")).Result, Is.EqualTo("True")); + Assert.That(new PageResult(context.OneTimePage("{{ two |> greaterThan(1) }}")).Result, Is.EqualTo("True")); + Assert.That(new PageResult(context.OneTimePage("{{ greaterThan(two,1) }}")).Result, Is.EqualTo("True")); + Assert.That(new PageResult(context.OneTimePage("{{ greaterThan(2,2) }}")).Result, Is.EqualTo("False")); + Assert.That(new PageResult(context.OneTimePage("{{ greaterThan(two,2) }}")).Result, Is.EqualTo("False")); + Assert.That(new PageResult(context.OneTimePage("{{ greaterThan(two,two) }}")).Result, Is.EqualTo("False")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'two > 1' |> if(gt(two,1)) |> raw }}")).Result, Is.EqualTo("two > 1")); + Assert.That(new PageResult(context.OneTimePage("{{ 'two > 2' |> if(greaterThan(two,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'two > 3' |> if(greaterThan(two,3)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'two > two' |> if(greaterThan(two,two)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'two >= two' |> if(greaterThanEqual(two,two)) |> raw }}")).Result, Is.EqualTo("two >= two")); + + Assert.That(new PageResult(context.OneTimePage("{{ '1 >= 2' |> if(greaterThanEqual(1,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 >= 2' |> if(greaterThanEqual(2,2)) |> raw }}")).Result, Is.EqualTo("2 >= 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '3 >= 2' |> if(greaterThanEqual(3,2)) |> raw }}")).Result, Is.EqualTo("3 >= 2")); + + Assert.That(new PageResult(context.OneTimePage("{{ '1 > 2' |> if(greaterThan(1,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 > 2' |> if(greaterThan(2,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '3 > 2' |> if(greaterThan(3,2)) |> raw }}")).Result, Is.EqualTo("3 > 2")); + + Assert.That(new PageResult(context.OneTimePage("{{ '1 <= 2' |> if(lessThanEqual(1,2)) |> raw }}")).Result, Is.EqualTo("1 <= 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 <= 2' |> if(lessThanEqual(2,2)) |> raw }}")).Result, Is.EqualTo("2 <= 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '3 <= 2' |> if(lessThanEqual(3,2)) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ '1 < 2' |> if(lessThan(1,2)) |> raw }}")).Result, Is.EqualTo("1 < 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 < 2' |> if(lessThan(2,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '3 < 2' |> if(lessThan(3,2)) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ '2 > 2' |> if(gt(2,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 >= 2' |> if(gte(2,2)) |> raw }}")).Result, Is.EqualTo("2 >= 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 <= 2' |> if(lte(2,2)) |> raw }}")).Result, Is.EqualTo("2 <= 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 < 2' |> if(lt(2,2)) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ '2 == 2' |> if(equals(2,2)) }}")).Result, Is.EqualTo("2 == 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 == 2' |> if(eq(2,2)) }}")).Result, Is.EqualTo("2 == 2")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 != 2' |> if(notEquals(2,2)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '2 != 2' |> if(not(2,2)) }}")).Result, Is.EqualTo("")); + } + + [Test] + public void Can_compare_strings() + { + var context = new ScriptContext + { + Args = + { + ["foo"] = "foo", + ["bar"] = "bar" + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'foo > \"foo\"' |> if(gt(foo,\"foo\")) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'foo >= \"foo\"' |> if(gte(foo,\"foo\")) |> raw }}")).Result, Is.EqualTo("foo >= \"foo\"")); + Assert.That(new PageResult(context.OneTimePage("{{ 'foo <= \"foo\"' |> if(lte(foo,\"foo\")) |> raw }}")).Result, Is.EqualTo("foo <= \"foo\"")); + Assert.That(new PageResult(context.OneTimePage("{{ 'foo < \"foo\"' |> if(lt(foo,\"foo\")) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'bar > \"foo\"' |> if(gt(bar,\"foo\")) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'bar >= \"foo\"' |> if(gte(bar,\"foo\")) |> raw }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'bar <= \"foo\"' |> if(lte(bar,\"foo\")) |> raw }}")).Result, Is.EqualTo("bar <= \"foo\"")); + Assert.That(new PageResult(context.OneTimePage("{{ 'bar < \"foo\"' |> if(lt(bar,\"foo\")) |> raw }}")).Result, Is.EqualTo("bar < \"foo\"")); + } + + [Test] + public void Can_compare_DateTime() + { + var context = new ScriptContext + { + Args = + { + ["year2000"] = new DateTime(2000,1,1), + ["year2100"] = new DateTime(2100,1,1) + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'now > year2000' |> if(gt(now,year2000)) |> raw }}")).Result, Is.EqualTo("now > year2000")); + Assert.That(new PageResult(context.OneTimePage("{{ 'now >= year2000' |> if(gte(now,year2000)) |> raw }}")).Result, Is.EqualTo("now >= year2000")); + Assert.That(new PageResult(context.OneTimePage("{{ 'now <= year2000' |> if(lte(now,year2000)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'now < year2000' |> if(lt(now,year2000)) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'now > year2100' |> if(gt(now,year2100)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'now >= year2100' |> if(gte(now,year2100)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'now <= year2100' |> if(lte(now,year2100)) |> raw }}")).Result, Is.EqualTo("now <= year2100")); + Assert.That(new PageResult(context.OneTimePage("{{ 'now < year2100' |> if(lt(now,year2100)) |> raw }}")).Result, Is.EqualTo("now < year2100")); + + Assert.That(new PageResult(context.OneTimePage("{{ '\"2001-01-01\" > year2100' |> if(gt(\"2001-01-01\",year2100)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '\"2001-01-01\" >= year2100' |> if(gte(\"2001-01-01\",year2100)) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '\"2001-01-01\" <= year2100' |> if(lte(\"2001-01-01\",year2100)) |> raw }}")).Result, Is.EqualTo("\"2001-01-01\" <= year2100")); + Assert.That(new PageResult(context.OneTimePage("{{ '\"2001-01-01\" < year2100' |> if(lt(\"2001-01-01\",year2100)) |> raw }}")).Result, Is.EqualTo("\"2001-01-01\" < year2100")); + } + + [Test] + public void Can_use_logical_boolean_operators() + { + var context = new ScriptContext + { + Args = + { + ["foo"] = "foo", + ["bar"] = "bar", + ["year2000"] = new DateTime(2000,1,1), + ["year2100"] = new DateTime(2100,1,1), + ["contextTrue"] = true, + ["contextFalse"] = false + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(true,true)' |> if(OR(true,true)) |> raw }}")).Result, Is.EqualTo("OR(true,true)")); + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(true,false)' |> if(OR(true,false)) |> raw }}")).Result, Is.EqualTo("OR(true,false)")); + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(false,false)' |> if(OR(false,false)) |> raw }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'AND(true,true)' |> if(AND(true,true)) |> raw }}")).Result, Is.EqualTo("AND(true,true)")); + Assert.That(new PageResult(context.OneTimePage("{{ 'AND(true,false)' |> if(AND(true,false)) |> raw }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'AND(false,false)' |> if(AND(false,false)) |> raw }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(contextTrue,contextTrue)' |> if(OR(contextTrue,contextTrue)) |> raw }}")).Result, Is.EqualTo("OR(contextTrue,contextTrue)")); + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(contextTrue,contextFalse)' |> if(OR(contextTrue,contextFalse)) |> raw }}")).Result, Is.EqualTo("OR(contextTrue,contextFalse)")); + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(contextFalse,contextFalse)' |> if(OR(contextFalse,contextFalse)) |> raw }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'OR(gt(now,year2000),eq(\"foo\",bar))' |> if(OR(gt(now,year2000),eq(\"foo\",bar))) |> raw }}")).Result, + Is.EqualTo("OR(gt(now,year2000),eq(\"foo\",bar))")); + + Assert.That(new PageResult(context.OneTimePage(@"{{ 'OR(gt(now,year2000),eq(""foo"",bar))' |> + if ( + OR ( + gt ( now, year2000 ), + eq ( ""foo"", bar ) + ) + ) |> raw }}")).Result, + Is.EqualTo("OR(gt(now,year2000),eq(\"foo\",bar))")); + + + Assert.That(new PageResult(context.OneTimePage(@"{{ 'OR(AND(gt(now,year2000),eq(""foo"",bar)),AND(gt(now,year2000),eq(""foo"",foo)))' |> + if ( + OR ( + AND ( + gt ( now, year2000 ), + eq ( ""foo"", bar ) + ), + AND ( + gt ( now, year2000 ), + eq ( ""foo"", foo ) + ) + ) + ) |> raw }}")).Result, + Is.EqualTo(@"OR(AND(gt(now,year2000),eq(""foo"",bar)),AND(gt(now,year2000),eq(""foo"",foo)))")); + } + + [Test] + public async Task Does_default_filter_arithmetic_chained_filters() + { + var context = CreateContext().Init(); + + Assert.That((((1 + 2) * 3) / 4) - 5, Is.EqualTo(- 3)); + Assert.That((((1 + 2) * 3) / 4d) - 5, Is.EqualTo(-2.75)); + Assert.That(1 + 2 * 3 / 4 - 5, Is.EqualTo(-3)); + Assert.That(1 + 2 * 3 / 4d - 5, Is.EqualTo(-2.5)); + + context.VirtualFiles.WriteFile("page-chained.html", + @"(((1 + 2) * 3) / 4) - 5 = {{ 1 |> add(2) |> multiply(3) |> divide(4) |> subtract(5) }}"); + var result = await new PageResult(context.GetPage("page-chained")).RenderToStringAsync(); + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@"(((1 + 2) * 3) / 4) - 5 = -2.75".NormalizeNewLines())); + + context.VirtualFiles.WriteFile("page-ordered.html", + @"1 + 2 * 3 / 4 - 5 = {{ 1 |> add( divide(multiply(2,3), 4) ) |> subtract(5) }}"); + result = await new PageResult(context.GetPage("page-ordered")).RenderToStringAsync(); + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@"1 + 2 * 3 / 4 - 5 = -2.5".NormalizeNewLines())); + } + + [Test] + public async Task Does_default_filter_currency() + { + var context = CreateContext().Init(); + context.Args[nameof(ScriptConfig.DefaultCulture)] = new CultureInfo("en-US"); + + context.VirtualFiles.WriteFile("page-default.html", "Cost: {{ 99.99 |> currency }}"); + context.VirtualFiles.WriteFile("page-culture.html", "Cost: {{ 99.99 |> currency(culture) |> raw }}"); + + var result = await new PageResult(context.GetPage("page-default")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("Cost: $99.99")); + + result = await new PageResult(context.GetPage("page-culture")) {Args = {["culture"] = "en-AU"}}.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("Cost: $99.99")); + + result = await new PageResult(context.GetPage("page-culture")) {Args = {["culture"] = "en-GB"}}.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("Cost: £99.99")); + + result = await new PageResult(context.GetPage("page-culture")) {Args = {["culture"] = "fr-FR"}}.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("Cost: 99,99 €")); + } + + [Test] + public async Task Does_default_filter_format() + { + var context = CreateContext().Init(); + context.VirtualFiles.WriteFile("page.html", "{{ 3.14159 |> format('N2') }}"); + + var result = await new PageResult(context.GetPage("page")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("3.14")); + } + + [Test] + public async Task Does_default_filter_dateFormat() + { + var context = CreateContext().Init(); + context.VirtualFiles.WriteFile("dateFormat-default.html", "{{ date |> dateFormat }}"); + context.VirtualFiles.WriteFile("dateFormat-custom.html", "{{ date |> dateFormat(format) }}"); + + var result = await new PageResult(context.GetPage("dateFormat-default")) + { + Args = { ["date"] = new DateTime(2001,01,01,1,1,1,1, DateTimeKind.Utc) } + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("2001-01-01")); + + context.Args[ScriptConstants.DefaultDateFormat] = "dd/MM/yyyy"; + result = await new PageResult(context.GetPage("dateFormat-default")) + { + Args = { ["date"] = new DateTime(2001,01,01,1,1,1,1, DateTimeKind.Utc) } + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("01/01/2001")); + + result = await new PageResult(context.GetPage("dateFormat-custom")) + { + Args = + { + ["date"] = new DateTime(2001,01,01,1,1,1,1, DateTimeKind.Utc), + ["format"] = "dd.MM.yyyy" + } + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("01.01.2001")); + } + + [Test] + public void Does_default_time_format() + { + var context = new ScriptContext + { + Args = + { + ["time"] = new TimeSpan(1,2,3,4,5), + ["date"] = new DateTime(2001,2,3,4,5,6,7) + } + }.Init(); + + var result = context.EvaluateScript("Time: {{ time |> timeFormat }}"); + Assert.That(result, Is.EqualTo("Time: 2:03:04")); + + result = context.EvaluateScript("Time: {{ time |> timeFormat('g') }}"); + Assert.That(result, Is.EqualTo("Time: 1:2:03:04.005")); + + result = context.EvaluateScript("Time: {{ date.TimeOfDay |> timeFormat('g') }}"); + Assert.That(result, Is.EqualTo("Time: 4:05:06.007")); + + // Normal quoted strings pass string verbatim + result = context.EvaluateScript(@"Time: {{ date.TimeOfDay |> timeFormat(′h\:mm\:ss′) }}"); + Assert.That(result, Is.EqualTo("Time: 4:05:06")); + + // Template literals unescapes strings + result = context.EvaluateScript(@"Time: {{ date.TimeOfDay |> timeFormat(`h\\:mm\\:ss`) }}"); + Assert.That(result, Is.EqualTo("Time: 4:05:06")); + } + + [Test] + public void Does_unescape_string() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{′′}}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{``}}"), Is.EqualTo("")); + + // `backticks` unescape strings, all other quoted strings use verbatim strings + Assert.That(context.EvaluateScript(@"{{′\ ′[0] |> toCharCode}}"), Is.EqualTo("92")); //= [\] + Assert.That(context.EvaluateScript(@"{{`\ `[0] |> toCharCode}}"), Is.EqualTo("32")); //= [ ] + Assert.That(context.EvaluateScript(@"{{`\\` |> toCharCode}}"), Is.EqualTo("92")); //= [/] + + Assert.That(context.EvaluateScript("{{′\n′}}"), Is.EqualTo("\n")); + Assert.That(context.EvaluateScript("{{`a\nb`}}"), Is.EqualTo("a\nb")); + Assert.That(context.EvaluateScript("{{′\"′|raw}}"), Is.EqualTo("\"")); + Assert.That(context.EvaluateScript("{{`\"`|raw}}"), Is.EqualTo("\"")); + } + + [Test] + public async Task Does_default_filter_dateTimeFormat() + { + var context = CreateContext().Init(); + context.VirtualFiles.WriteFile("dateTimeFormat-default.html", "{{ date |> dateTimeFormat }}"); + context.VirtualFiles.WriteFile("dateTimeFormat-custom.html", "{{ date |> dateFormat(format) }}"); + + var result = await new PageResult(context.GetPage("dateTimeFormat-default")) + { + Args = { ["date"] = new DateTime(2001,01,01,1,1,1,1, DateTimeKind.Utc) } + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("2001-01-01 01:01:01Z")); + + context.Args[ScriptConstants.DefaultDateTimeFormat] = "dd/MM/yyyy hh:mm"; + result = await new PageResult(context.GetPage("dateTimeFormat-default")) + { + Args = { ["date"] = new DateTime(2001,01,01,1,1,1,1, DateTimeKind.Utc) } + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("01/01/2001 01:01")); + + result = await new PageResult(context.GetPage("dateTimeFormat-custom")) + { + Args = + { + ["date"] = new DateTime(2001,01,01,1,1,1,1, DateTimeKind.Utc), + ["format"] = "dd.MM.yyyy hh.mm.ss" + } + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("01.01.2001 01.01.01")); + } + + [Test] + public void Does_default_spaces_and_indents() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ indent }}"), Is.EqualTo("\t")); + Assert.That(context.EvaluateScript("{{ 4 |> indents }}"), Is.EqualTo("\t\t\t\t")); + + Assert.That(context.EvaluateScript("{{ space }}"), Is.EqualTo(" ")); + Assert.That(context.EvaluateScript("{{ 4 |> spaces }}"), Is.EqualTo(" ")); + + Assert.That(context.EvaluateScript("{{ 4 |> repeating(' ') }}"), Is.EqualTo(" ")); + Assert.That(context.EvaluateScript("{{ ' ' |> repeat(4) }}"), Is.EqualTo(" ")); + Assert.That(context.EvaluateScript("{{ '.' |> repeat(3) }}"), Is.EqualTo("...")); + + var newLine = Environment.NewLine; + Assert.That(context.EvaluateScript("{{ newLine }}"), Is.EqualTo(newLine)); + Assert.That(context.EvaluateScript("{{ 4 |> newLines }}"), Is.EqualTo(newLine + newLine + newLine + newLine)); + + context = new ScriptContext + { + Args = + { + [ScriptConstants.DefaultIndent] = " ", + [ScriptConstants.DefaultNewLine] = "\n" + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ indent }}"), Is.EqualTo(" ")); + Assert.That(context.EvaluateScript("{{ 4 |> newLines }}"), Is.EqualTo("\n\n\n\n")); + } + + [Test] + public async Task Does_default_filter_string_filters() + { + var context = CreateContext().Init(); + + context.VirtualFiles.WriteFile("page-humanize.html", "{{ 'a_varName' |> humanize }}"); + var result = await new PageResult(context.GetPage("page-humanize")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("A Var Name")); + + context.VirtualFiles.WriteFile("page-titleCase.html", "{{ 'war and peace' |> titleCase }}"); + result = await new PageResult(context.GetPage("page-titleCase")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("War And Peace")); + + context.VirtualFiles.WriteFile("page-lower.html", "{{ 'Title Case' |> lower }}"); + result = await new PageResult(context.GetPage("page-lower")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("title case")); + + context.VirtualFiles.WriteFile("page-upper.html", "{{ 'Title Case' |> upper }}"); + result = await new PageResult(context.GetPage("page-upper")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("TITLE CASE")); + + context.VirtualFiles.WriteFile("page-pascalCase.html", "{{ 'camelCase' |> pascalCase }}"); + result = await new PageResult(context.GetPage("page-pascalCase")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("CamelCase")); + + context.VirtualFiles.WriteFile("page-camelCase.html", "{{ 'PascalCase' |> camelCase }}"); + result = await new PageResult(context.GetPage("page-camelCase")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("pascalCase")); + + context.VirtualFiles.WriteFile("page-substring.html", "{{ 'This is a short sentence' |> substring(8) }}... {{ 'These three words' |> substring(6,5) }}"); + result = await new PageResult(context.GetPage("page-substring")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("a short sentence... three")); + + context.VirtualFiles.WriteFile("page-pad.html", "<h1>{{ '7' |> padLeft(3) }}</h1><h2>{{ 'tired' |> padRight(10) }}</h2>"); + result = await new PageResult(context.GetPage("page-pad")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("<h1> 7</h1><h2>tired </h2>")); + + context.VirtualFiles.WriteFile("page-padchar.html", "<h1>{{ '7' |> padLeft(3,'0') }}</h1><h2>{{ 'tired' |> padRight(10,'z') }}</h2>"); + result = await new PageResult(context.GetPage("page-padchar")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("<h1>007</h1><h2>tiredzzzzz</h2>")); + + context.VirtualFiles.WriteFile("page-repeat.html", "<h1>long time ago{{ ' ...' |> repeat(3) }}</h1>"); + result = await new PageResult(context.GetPage("page-repeat")).RenderToStringAsync(); + Assert.That(result, Is.EqualTo("<h1>long time ago ... ... ...</h1>")); + } + + [Test] + public void Does_default_filter_with_no_args() + { + var context = CreateContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ now |> dateFormat('yyyy-MM-dd') }}")).Result, Is.EqualTo(DateTime.Now.ToString("yyyy-MM-dd"))); + Assert.That(new PageResult(context.OneTimePage("{{ utcNow |> dateFormat('yyyy-MM-dd') }}")).Result, Is.EqualTo(DateTime.UtcNow.ToString("yyyy-MM-dd"))); + } + + [Test] + public void Can_build_urls_using_filters() + { + var context = CreateContext(new Dictionary<string, object>{ {"baseUrl", "http://example.org" }}).Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ baseUrl |> addPaths(['customers',1,'orders']) |> raw }}")).Result, + Is.EqualTo("http://example.org/customers/1/orders")); + + Assert.That(new PageResult(context.OneTimePage("{{ baseUrl |> addQueryString({ id: 1, foo: 'bar' }) |> raw }}")).Result, + Is.EqualTo("http://example.org?id=1&foo=bar")); + + Assert.That(new PageResult(context.OneTimePage("{{ baseUrl |> addQueryString({ id: 1, foo: 'bar' }) |> addHashParams({ hash: 'value' }) |> raw }}")).Result, + Is.EqualTo("http://example.org?id=1&foo=bar#hash=value")); + } + + [Test] + public void Can_build_urls_using_empty_strings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ '' |> addQueryString({ redirect:null }) }}"), + Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ '/' |> addQueryString({ redirect:null }) }}"), + Is.EqualTo("/")); + } + + [Test] + public void Can_assign_result_to_variable() + { + string result; + var context = new ScriptContext + { + Args = + { + ["num"] = 1, + ["items"] = new[]{ "foo", "bar", "qux" } + }, + FilterTransformers = + { + ["markdown"] = MarkdownPageFormat.TransformToHtml + } + }.Init(); + + result = new PageResult(context.OneTimePage(@" +{{ num |> incr |> assignTo('result') }} +result={{ result }} +")).Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo("result=2")); + + result = new PageResult(context.OneTimePage(@" +{{ '<li> {{it}} </li>' |> selectEach(items) |> assignTo('result') }} +<ul>{{ result |> raw }}</ul> +")).Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo("<ul><li> foo </li><li> bar </li><li> qux </li></ul>")); + + result = new PageResult(context.OneTimePage(@" +{{ ' - {{it}}' |> appendLine |> selectEach(items) |> markdown |> assignTo('result') }} +<div>{{ result |> raw }}</div> +")).Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo("<div><ul>\n<li>foo</li>\n<li>bar</li>\n<li>qux</li>\n</ul>\n</div>")); + + ConsoleLogFactory.Configure(); + result = new PageResult(context.OneTimePage(@" +{{ ' - {{it}}' |> appendLine |> selectEach(items) |> markdown |> assignTo('result') }} +<div>{{ result |> raw }}</div> +")).Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo("<div><ul>\n<li>foo</li>\n<li>bar</li>\n<li>qux</li>\n</ul>\n</div>")); + } + + [Test] + public void Can_assign_to_array_index() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ [1,2,3,4,5] |> assignTo: numbers }} +{{ numbers |> do: assign('numbers[index]', multiply(numbers[index], numbers[index])) }} +{{ numbers |> join }}").Trim(), Is.EqualTo("1,4,9,16,25")); + + Assert.That(context.EvaluateScript(@" +{{ [1,2,3,4,5] |> assignTo: numbers }} +{{ numbers |> do: assign('numbers[index]', numbers[index] * numbers[index]) }} +{{ numbers |> join }}").Trim(), Is.EqualTo("1,4,9,16,25")); + } + + [Test] + public void Can_assign_to_array_index_with_arrow_function() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ [1,2,3,4,5] |> assignTo => numbers }} +{{ numbers |> do => assign('numbers[index]', numbers[index] * numbers[index]) }} +{{ numbers |> join }}").Trim(), Is.EqualTo("1,4,9,16,25")); + + Assert.That(context.EvaluateScript(@" +{{ [1,2,3,4,5] |> assignTo => numbers }} +{{ numbers |> do => assign(`num${index}`, it * it) }} +{{ num0 }},{{ num1 }},{{ num2 }},{{ num3 }},{{ num4 }}").Trim(), Is.EqualTo("1,4,9,16,25")); + } + + [Test] + public void Can_assign_to_variables_in_partials() + { + var context = new ScriptContext + { + Args = + { + ["num"] = 1 + } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body> +<header> +layout num = {{ num }} +pageMetaTitle = {{ pageMetaTitle }} +inlinePageTitle = {{ inlinePageTitle }} +pageResultTitle = {{ pageResultTitle }} +</header> +{{ 'add-partial' |> partial({ num: 100 }) }} +{{ page }} +{{ 'add-partial' |> partial({ num: 400 }) }} +<footer> +layout num = {{ num }} +inlinePageTitle = {{ inlinePageTitle }} +</footer> +</body> +</html> +"); + + context.VirtualFiles.WriteFile("page.html", @" +<!-- +pageMetaTitle: page meta title +--> +<section> +{{ 'page inline title' |> upper |> assignTo('inlinePageTitle') }} +{{ 'add-partial' |> partial({ num: 200 }) }} +{{ num |> add(1) |> assignTo('num') }} +<h2>page num = {{ num }}</h2> +{{ 'add-partial' |> partial({ num: 300 }) }} +</section>"); + + context.VirtualFiles.WriteFile("add-partial.html", @" +{{ num |> add(10) |> assignTo('num') }} +<h3>partial num = {{ num }}</h3>"); + + var result = new PageResult(context.GetPage("page")) + { + Args = + { + ["pageResultTitle"] = "page result title" + } + }.Result; + + /* NOTES: + 1. Page Args and Page Result Args are *always* visible to Layout as they're known before page is executed + 2. Args created during Page execution are *only* visible in Layout after page is rendered (i.e. executed) + 3. Args assigned in partials are retained within their scope + */ + + Assert.That(result.RemoveNewLines(), Is.EqualTo(@" +<html> +<body> +<header> +layout num = 1 +pageMetaTitle = page meta title +inlinePageTitle = +pageResultTitle = page result title +</header> +<h3>partial num = 110</h3> +<section> +<h3>partial num = 210</h3> +<h2>page num = 2</h2> +<h3>partial num = 310</h3> +</section> +<h3>partial num = 410</h3> +<footer> +layout num = 2 +inlinePageTitle = PAGE INLINE TITLE +</footer> +</body> +</html> +".RemoveNewLines())); + } + + [Test] + public void Does_not_select_template_with_null_target() + { + var context = new ScriptContext().Init(); + + var result = context.EvaluateScript("{{ null |> select: was called }}"); + + Assert.That(result, Is.EqualTo(string.Empty)); + } + + [Test] + public void Can_parseKeyValueText() + { + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() } + }.Init(); + + context.VirtualFiles.WriteFile("expenses.txt", @" +Rent 1000 +TV 50 +Internet 50 +Mobile 50 +Food 400 +"); + + var output = context.EvaluateScript(@" +{{ 'expenses.txt' |> includeFile |> assignTo: expensesText }} +{{ expensesText |> parseKeyValueText |> assignTo: expenses }} +Expenses: +{{ expenses |> toList |> select: { it.Key |> padRight(10) }{ it.Value }\n }} +{{ '-' |> repeat(15) }} +Total {{ expenses |> values |> sum }} +"); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +Expenses: +Rent 1000 +TV 50 +Internet 50 +Mobile 50 +Food 400 + +--------------- +Total 1550 +".NormalizeNewLines())); + + } + + public class ModelValues + { + public int Id { get; set; } + public TimeSpan TimeSpan { get; set; } + public DateTime DateTime { get; set; } + } + + [Test] + public void Can_order_by_different_data_types() + { + var items = new[] + { + new ModelValues { Id = 1, DateTime = new DateTime(2001,01,01), TimeSpan = TimeSpan.FromSeconds(1) }, + new ModelValues { Id = 2, DateTime = new DateTime(2001,01,02), TimeSpan = TimeSpan.FromSeconds(2) } + }; + + var context = new ScriptContext + { + Args = + { + ["items"] = items + } + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ items + |> orderByDescending: it.DateTime + |> first |> property: Id }}"), Is.EqualTo("2")); + + Assert.That(context.EvaluateScript(@"{{ items + |> orderByDescending: it.TimeSpan + |> first |> property: Id }}"), Is.EqualTo("2")); + } + + [Test] + public void Can_use_not_operator_in_boolean_expression() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ var items = ['A','B','C'] }} +{{ !items.contains('A') |> iif('Y','N') }}").Trim(), Is.EqualTo("N")); + + Assert.That(context.EvaluateScript(@" +{{ var items = ['A','B','C'] }} +{{ 'Y' |> ifElse(!items.contains('D'), 'N') }}").Trim(), Is.EqualTo("Y")); + + Assert.That(context.EvaluateScript(@" +{{ var items = ['A','B','C'] }} +{{ 'Y' |> ifElse(not(items.contains('D')),'N') }}").Trim(), Is.EqualTo("Y")); + + Assert.That(context.EvaluateScript(@" +{{ var items = ['A','B','C'] }} +{{ ['B','C','D'] |> where => !items.contains(it) |> first }}").Trim(), Is.EqualTo("D")); + } + + [Test] + public void Does_fmt() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'in {0} middle' |> fmt('the') }}"), + Is.EqualTo("in the middle")); + Assert.That(context.EvaluateScript("{{ 'in {0} middle of the {1}' |> fmt('the', 'night') }}"), + Is.EqualTo("in the middle of the night")); + Assert.That(context.EvaluateScript("{{ 'in {0} middle of the {1} I go {2}' |> fmt('the', 'night', 'walking') }}"), + Is.EqualTo("in the middle of the night I go walking")); + Assert.That(context.EvaluateScript("{{ 'in {0} middle of the {1} I go {2} in my {3}' |> fmt(['the', 'night', 'walking', 'sleep']) }}"), + Is.EqualTo("in the middle of the night I go walking in my sleep")); + + Assert.That(context.EvaluateScript("{{ 'I owe {0:c}' |> fmt(123.45) }}"), + Is.EqualTo("I owe $123.45")); + } + + [Test] + public void Does_appendFmt() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'in ' |> appendFmt('{0} middle','the') }}"), + Is.EqualTo("in the middle")); + Assert.That(context.EvaluateScript("{{ 'in ' |> appendFmt('{0} middle of the {1}', 'the', 'night') }}"), + Is.EqualTo("in the middle of the night")); + Assert.That(context.EvaluateScript("{{ 'in ' |> appendFmt('{0} middle of the {1} I go {2}', 'the', 'night', 'walking') }}"), + Is.EqualTo("in the middle of the night I go walking")); + Assert.That(context.EvaluateScript("{{ 'in ' |> appendFmt('{0} middle of the {1} I go {2} in my {3}', ['the', 'night', 'walking', 'sleep']) }}"), + Is.EqualTo("in the middle of the night I go walking in my sleep")); + + Assert.That(context.EvaluateScript("{{ 'I ' |> appendFmt('owe {0:c}', 123.45) }}"), + Is.EqualTo("I owe $123.45")); + } + + [Test] + public void Can_use_exist_tests_on_non_existing_arguments() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = "value", + ["list"] = new[]{ 1, 2, 3 }, + ["emptyList"] = new int[0], + ["map"] = new Dictionary<string, object> { {"a", 1}, {"b", 2} }, + ["emptyMap"] = new Dictionary<string, object>() + } + }.Init(); + + context.VirtualFiles.WriteFile("h1.html", "<h1>{{ it }}</h1>"); + + + Assert.That(context.EvaluateScript("{{ arg |> ifExists }}"), Is.EqualTo("value")); + Assert.That(context.EvaluateScript("{{ noArg |> ifExists }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ 1 |> ifExists(arg) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> ifExists(noArg) }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ 1 |> ifNotExists(arg) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> ifNotExists(noArg) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> ifNo(arg) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> ifNo(noArg) }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ arg |> selectPartial: h1 }}"), Is.EqualTo("<h1>value</h1>")); + Assert.That(context.EvaluateScript("{{ noArg |> selectPartial: h1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ list |> ifNotEmpty |> join }}"), Is.EqualTo("1,2,3")); + Assert.That(context.EvaluateScript("{{ noList |> ifNotEmpty }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ 1 |> ifNotEmpty(list) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> ifNotEmpty(emptyList) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> ifNotEmpty(noList) }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ 1 |> ifEmpty(list) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> ifEmpty(emptyList) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> ifEmpty(noList) }}"), Is.EqualTo("1")); + } + + [Test] + public void Does_not_emit_binding_on_empty_Key_Value() + { + var context = new ScriptContext + { + Args = + { + ["row"] = new List<KeyValuePair<string,object>> + { + new KeyValuePair<string, object>("arg", "value"), + new KeyValuePair<string, object>("enmptyArg", ""), + new KeyValuePair<string, object>("nullArg", null) + } + } + }.Init(); + + var output = context.EvaluateScript("{{ row |> select: <i>{ it.Key }</i><b>{ it.Value }</b> }}"); + Assert.That(output, Is.EqualTo("<i>arg</i><b>value</b><i>enmptyArg</i><b></b><i>nullArg</i><b></b>")); + } + + [Test] + public void Does_resolve_partials_and_files_using_cascading_resolution() + { + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() } + }.Init(); + + context.VirtualFiles.WriteFile("root-partial.html", @"root-partial.html"); + context.VirtualFiles.WriteFile("root-file.txt", @"root-file.txt"); + context.VirtualFiles.WriteFile("partial.html", @"partial.html"); + context.VirtualFiles.WriteFile("file.txt", @"file.txt"); + + context.VirtualFiles.WriteFile("dir/partial.html", @"dir/partial.html"); + context.VirtualFiles.WriteFile("dir/file.txt", @"dir/file.txt"); + + context.VirtualFiles.WriteFile("dir/dir-partial.html", @"dir/dir-partial.html"); + context.VirtualFiles.WriteFile("dir/dir-file.txt", @"dir/dir-file.txt"); + + context.VirtualFiles.WriteFile("dir/sub/partial.html", @"dir/sub/partial.html"); + context.VirtualFiles.WriteFile("dir/sub/file.txt", @"dir/sub/file.txt"); + + context.VirtualFiles.WriteFile("page.html", @"partial: {{ 'partial' |> partial }} +file: {{ 'file.txt' |> includeFile }} +root-partial: {{ 'root-partial' |> partial }} +root-file: {{ 'root-file.txt' |> includeFile }}"); + + context.VirtualFiles.WriteFile("dir/page.html", @"partial: {{ 'partial' |> partial }} +file: {{ 'file.txt' |> includeFile }} +root-partial: {{ 'root-partial' |> partial }} +root-file: {{ 'root-file.txt' |> includeFile }}"); + + context.VirtualFiles.WriteFile("dir/sub/page.html", @"partial: {{ 'partial' |> partial }} +file: {{ 'file.txt' |> includeFile }} +root-partial: {{ 'root-partial' |> partial }} +root-file: {{ 'root-file.txt' |> includeFile }} +dir-partial: {{ 'dir-partial' |> partial }} +dir-file: {{ 'dir-file.txt' |> includeFile }}"); + + Assert.That(new PageResult(context.GetPage("page")).Result.NormalizeNewLines(), + Is.EqualTo(@" +partial: partial.html +file: file.txt +root-partial: root-partial.html +root-file: root-file.txt".NormalizeNewLines())); + + Assert.That(new PageResult(context.GetPage("dir/page")).Result.NormalizeNewLines(), + Is.EqualTo(@" +partial: dir/partial.html +file: dir/file.txt +root-partial: root-partial.html +root-file: root-file.txt".NormalizeNewLines())); + + Assert.That(new PageResult(context.GetPage("dir/sub/page")).Result.NormalizeNewLines(), + Is.EqualTo(@" +partial: dir/sub/partial.html +file: dir/sub/file.txt +root-partial: root-partial.html +root-file: root-file.txt +dir-partial: dir/dir-partial.html +dir-file: dir/dir-file.txt +".NormalizeNewLines())); + } + + [Test] + public void Can_use_end_to_discard_return_value() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("partial.html", "partial"); + + Assert.That(context.EvaluateScript("{{ 1 |> end }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ add(1,1) |> end }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 'partial' |> partial |> end }}"), Is.EqualTo("")); + } + + [Test] + public void Can_use_split_with_different_delimiters() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'a,b,c' |> split |> join('|') }}"), Is.EqualTo("a|b|c")); + Assert.That(context.EvaluateScript("{{ 'a:b:c' |> split(':') |> join('|') }}"), Is.EqualTo("a|b|c")); + Assert.That(context.EvaluateScript("{{ 'a::b::c' |> split('::') |> join('|') }}"), Is.EqualTo("a|b|c")); + Assert.That(context.EvaluateScript("{{ 'a:b/c' |> split([':','/']) |> join('|') }}"), Is.EqualTo("a|b|c")); + Assert.That(context.EvaluateScript("{{ 'a::b//c' |> split(['::','//']) |> join('|') }}"), Is.EqualTo("a|b|c")); + } + + [Test] + public void Can_use_length_filters() + { + var context = new ScriptContext + { + Args = + { + ["items"] = new[]{1,2,3} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ items |> length }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ items |> hasMinCount(0) |> iif(1,0) }}:{{ items |> hasMinCount(3) |> iif(1,0) }}:{{ items |> hasMinCount(4) |> iif(1,0) }}"), Is.EqualTo("1:1:0")); + Assert.That(context.EvaluateScript("{{ items |> hasMaxCount(0) |> iif(1,0) }}:{{ items |> hasMaxCount(3) |> iif(1,0) }}:{{ items |> hasMaxCount(4) |> iif(1,0) }}"), Is.EqualTo("0:1:1")); + + Assert.That(context.EvaluateScript("{{ null |> hasMinCount(0) |> iif(1,0) }}:{{ 1 |> hasMinCount(1) |> iif(1,0) }}:{{ 'a' |> hasMinCount(0) |> iif(1,0) }}"), Is.EqualTo("0:0:1")); + Assert.That(context.EvaluateScript("{{ null |> length }}:{{ 1 |> length }}:{{ 'a' |> length }}"), Is.EqualTo("0:0:1")); + + Assert.That(context.EvaluateScript("{{ [1,2] |> hasMinCount(0) |> iif(1,0) }}:{{ 1 |> hasMinCount(1) |> iif(1,0) }}:{{ 'a' |> hasMinCount(0) |> iif(1,0) }}"), Is.EqualTo("1:0:1")); + Assert.That(context.EvaluateScript("{{ noArg |> hasMinCount(0) |> iif(1,0) }}:{{ items |> hasMinCount(1) |> ifUse(length(items)) }}"), Is.EqualTo("0:3")); + } + + [Test] + public void Can_use_test_isTest_filters() + { + var context = new ScriptContext + { + Args = + { + ["string"] = "foo", + ["int"] = 1, + ["long"] = (long)1, + ["byte"] = (byte)1, + ["double"] = 1.1, + ["float"] = (float)1.1, + ["decimal"] = (decimal)1.1, + ["bool"] = true, + ["char"] = 'c', + ["chars"] = new[]{ 'a','b','c' }, + ["bytes"] = new byte[]{ 1, 2, 3 }, + ["intDictionary"] = new Dictionary<int, int>(), + ["stringDictionary"] = new Dictionary<string, string>(), + ["objectDictionary"] = new Dictionary<string, object>(), + ["objectList"] = new List<object>(), + ["objectArray"] = new object[]{ 1, "a" }, + ["anonObject"] = new { id = 1 }, + ["context"] = new ScriptContext(), + ["tuple"] = Tuple.Create(1, "a"), + ["keyValuePair"] = new KeyValuePair<int,string>(1,"a") + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ 'a' |> isString |> iif(1,0) }}:{{ 1 |> isString |> iif(1,0) }}"), Is.EqualTo("1:0")); + Assert.That(context.EvaluateScript("{{ 'a' |> isInt |> iif(1,0) }}:{{ 1 |> isInt |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isLong |> iif(1,0) }}:{{ 1 |> toLong |> isLong |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isDouble |> iif(1,0) }}:{{ 1.1 |> isDouble |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isFloat |> iif(1,0) }}:{{ 1.1 |> toFloat |> isFloat |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isDecimal |> iif(1,0) }}:{{ 1.1 |> toDecimal |> isDecimal |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isBool |> iif(1,0) }}:{{ false |> isBool |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isChar |> iif(1,0) }}:{{ 'a' |> toChar |> isChar |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isChars |> iif(1,0) }}:{{ 'a' |> toChars |> isChars |> iif(1,0) }}:{{ ['a','b'] |> toChars |> isChars |> iif(1,0) }}"), Is.EqualTo("0:1:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isByte |> iif(1,0) }}:{{ 1 |> toByte |> isByte |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ bytes |> isBytes |> iif(1,0) }}:{{ 'a' |> isBytes |> iif(1,0) }}:{{ 'a' |> toUtf8Bytes |> isBytes |> iif(1,0) }}"), Is.EqualTo("1:0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isList |> iif(1,0) }}:{{ {a:1} |> isList |> iif(1,0) }}:{{ ['a'] |> isList |> iif(1,0) }}"), Is.EqualTo("0:0:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isEnumerable |> iif(1,0) }}:{{ 1 |> isEnumerable |> iif(1,0) }}:{{ ['a'] |> isEnumerable |> iif(1,0) }}:{{ {a:1} |> isEnumerable |> iif(1,0) }}"), Is.EqualTo("1:0:1:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isDictionary |> iif(1,0) }}:{{ {a:1} |> isDictionary |> iif(1,0) }}:{{ ['a'] |> isDictionary |> iif(1,0) }}"), Is.EqualTo("0:1:0")); + Assert.That(context.EvaluateScript("{{ {a:'a'} |> isStringDictionary |> iif(1,0) }}:{{ {a:1} |> isStringDictionary |> iif(1,0) }}:{{ stringDictionary |> isStringDictionary |> iif(1,0) }}"), Is.EqualTo("0:0:1")); + Assert.That(context.EvaluateScript("{{ {a:'a'} |> isObjectDictionary |> iif(1,0) }}:{{ {a:1} |> isObjectDictionary |> iif(1,0) }}:{{ stringDictionary |> isObjectDictionary |> iif(1,0) }}"), Is.EqualTo("1:1:0")); + Assert.That(context.EvaluateScript("{{ 'a' |> isNumber |> iif(1,0) }}:{{ 1 |> isNumber |> iif(1,0) }}:{{ 1.1 |> isNumber |> iif(1,0) }}"), Is.EqualTo("0:1:1")); + Assert.That(context.EvaluateScript("{{ 'a' |> isRealNumber |> iif(1,0) }}:{{ 1 |> isRealNumber |> iif(1,0) }}:{{ 1.1 |> isRealNumber |> iif(1,0) }}"), Is.EqualTo("0:0:1")); + Assert.That(context.EvaluateScript("{{ objectList |> isArray |> iif(1,0) }}:{{ objectArray |> isArray |> iif(1,0) }}:{{ [1,'a'] |> isArray |> iif(1,0) }}"), Is.EqualTo("0:1:0")); + Assert.That(context.EvaluateScript("{{ anonObject |> isAnonObject |> iif(1,0) }}:{{ context |> isAnonObject |> iif(1,0) }}:{{ {a:1} |> isAnonObject |> iif(1,0) }}"), Is.EqualTo("1:0:0")); + Assert.That(context.EvaluateScript("{{ context |> isClass |> iif(1,0) }}:{{ 1 |> isClass |> iif(1,0) }}"), Is.EqualTo("1:0")); + Assert.That(context.EvaluateScript("{{ context |> isValueType |> iif(1,0) }}:{{ 1 |> isValueType |> iif(1,0) }}"), Is.EqualTo("0:1")); + Assert.That(context.EvaluateScript("{{ {a:1} |> isKeyValuePair |> iif(1,0) }}:{{ keyValuePair |> isKeyValuePair |> iif(1,0) }}:{{ {a:1} |> toList |> get(0) |> isKeyValuePair |> iif(1,0) }}"), Is.EqualTo("0:1:1")); + + Assert.That(context.EvaluateScript("{{ 'a' |> isType('string') |> iif(1,0) }}:{{ string |> isType('String') |> iif(1,0) }}:{{ 1 |> isString |> iif(1,0) }}"), Is.EqualTo("1:1:0")); + } + + [Test] + public void Can_use_eval() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = "value" + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ '1' |> eval |> typeName }}"), Is.EqualTo("Int32")); + Assert.That(context.EvaluateScript("{{ 'arg' |> eval }}"), Is.EqualTo("value")); + Assert.That(context.EvaluateScript("{{ `'arg'` |> eval }}"), Is.EqualTo("arg")); + Assert.That(context.EvaluateScript("{{ '{a:1}' |> eval |> get: a }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ '{a:arg}' |> eval |> get: a }}"), Is.EqualTo("value")); + Assert.That(context.EvaluateScript("{{ '[1]' |> eval |> get(0) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ '[{a:arg}]' |> eval |> get(0) |> get:a }}"), Is.EqualTo("value")); + + Assert.That(context.EvaluateScript("{{ 'incr(1)' |> eval }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ '{a:incr(1)}' |> eval |> get: a }}"), Is.EqualTo("2")); + } + + [Test] + public void Can_parse_JSON() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ '1' |> parseJson |> typeName }}"), Is.EqualTo("Int32")); + Assert.That(context.EvaluateScript("{{ 'arg' |> parseJson }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ `'arg'` |> parseJson }}"), Is.EqualTo("arg")); + Assert.That(context.EvaluateScript("{{ '{a:1}' |> parseJson |> get: a }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ '{a:arg}' |> parseJson |> get: a }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ '[1]' |> parseJson |> get(0) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ '[{a:arg}]' |> parseJson |> get(0) |> get:a }}"), Is.EqualTo("")); + } + + [Test] + public void Can_stop_filter_execution_with_end() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = "foo", + ["items"] = new[]{1,2,3} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ 1 |> end }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> endIfNull }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ null |> endIfNull |> default('unreachable') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ arg |> endIfNull |> useFmt('{0} + {1} = {2}',1,2,3) }}"), Is.EqualTo("1 + 2 = 3")); + Assert.That(context.EvaluateScript("{{ arg |> endIfNotNull |> use('bar') |> assignTo: arg }}{{ arg }}"), Is.EqualTo("foo")); + Assert.That(context.EvaluateScript("{{ noArg |> endIfExists |> use('bar') |> assignTo: noArg }}{{ noArg }}"), Is.EqualTo("bar")); + Assert.That(context.EvaluateScript("{{ [] |> endIfEmpty |> default('unreachable') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ items |> endIfNotEmpty |> use([4,5,6]) |> assignTo: items }}{{ items |> join }}"), Is.EqualTo("1,2,3")); + Assert.That(context.EvaluateScript("{{ nums |> endIfNotEmpty |> use([4,5,6]) |> assignTo: nums }}{{ nums |> join }}"), Is.EqualTo("4,5,6")); + Assert.That(context.EvaluateScript("{{ 1 |> endIfFalsy |> default('unreachable') }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 0 |> endIfFalsy |> default('unreachable') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ arg |> endIfTruthy |> use('bar') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ one |> endIfTruthy |> use(1) |> assignTo: one }}{{ one }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> endIf(true) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> endIf(false) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> endIfAny: it == 4\n |> join }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> endIfAny: it == 5\n |> join }}"), Is.EqualTo("0,1,2,3,4")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> endIfAll: lt(it,4)\n |> join }}"), Is.EqualTo("0,1,2,3,4")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> endIfAll: lt(it,5)\n |> join }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ 1 |> endWhere: isString(it) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 'a' |> endWhere: isString(it) }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ endIf(true) |> use(1) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ endIf(false) |> use(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ true |> ifEnd |> use(1) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ false |> ifEnd |> use(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ true |> ifNotEnd |> use(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifNotEnd |> use(1) }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ doIf(true) |> use(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ doIf(false) |> use(1) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ true |> ifDo |> use(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifDo |> use(1) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ true |> ifDo |> select: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifDo |> select: 1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ true |> ifUse(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifUse(1) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> useIf(true) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> useIf(false) }}"), Is.EqualTo("")); + } + + [Test] + public void Can_chain_end_filters_together() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = "foo", + ["empty"] = "", + ["nil"] = null, + ["items"] = new[]{1,2,3}, + ["none"] = new int[]{} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ arg |> endIfNull |> endIfNotNull(noArg) |> select: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ noArg |> endIfExists |> endIfExists(noArg2) |> select: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ empty |> endIfNull |> endIfNotNull(nil) |> select: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ empty |> endIfNull |> endIfNull(nil) |> select: 1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ items |> endIfEmpty |> endIfNotEmpty(none) |> select: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ items |> endIfNotEmpty |> select: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ none |> endIfEmpty |> select: 1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ endIf(isEmpty(items)) |> endIf(!isEmpty(none)) |> select: 1 }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ noArg |> endIfExists |> endIfNull(none) |> use(1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ arg |> endIfEmpty |> endIfEmpty(items) |> join }}"), Is.EqualTo("1,2,3")); + } + + [Test] + public void Can_continue_filter_execution_with_only() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = "foo", + ["items"] = new[]{1,2,3} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ 1 |> onlyIfNotNull }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ null |> onlyIfNotNull |> default('unreachable') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ arg |> onlyIfNotNull |> useFmt('{0} + {1} = {2}',1,2,3) }}"), Is.EqualTo("1 + 2 = 3")); + Assert.That(context.EvaluateScript("{{ arg |> onlyIfNull |> use('bar') |> assignTo: arg }}{{ arg }}"), Is.EqualTo("foo")); + Assert.That(context.EvaluateScript("{{ noArg |> onlyIfNull |> use('bar') |> assignTo: noArg }}{{ noArg }}"), Is.EqualTo("bar")); + Assert.That(context.EvaluateScript("{{ [] |> onlyIfNotEmpty |> default('unreachable') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ items |> onlyIfEmpty |> use([4,5,6]) |> assignTo: items }}{{ items |> join }}"), Is.EqualTo("1,2,3")); + Assert.That(context.EvaluateScript("{{ nums |> onlyIfEmpty |> use([4,5,6]) |> assignTo: nums }}{{ nums |> join }}"), Is.EqualTo("4,5,6")); + Assert.That(context.EvaluateScript("{{ 1 |> onlyIfTruthy |> default('unreachable') }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 0 |> onlyIfTruthy |> default('unreachable') }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ arg |> onlyIfFalsy |> show: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ one |> onlyIfFalsy |> use(1) |> assignTo: one }}{{ one }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> onlyIf(false) }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> onlyIf(true) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> onlyIfAll: lt(it,4)\n |> join }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> onlyIfAll: lt(it,5)\n |> join }}"), Is.EqualTo("0,1,2,3,4")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> onlyIfAny: it == 4\n |> join }}"), Is.EqualTo("0,1,2,3,4")); + Assert.That(context.EvaluateScript("{{ 5 |> times |> onlyIfAny: it == 5\n |> join }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ 1 |> onlyWhere: !isString(it) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 'a' |> onlyWhere: !isString(it) }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ onlyIf(false) |> show: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ onlyIf(true) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ true |> ifOnly |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifOnly |> show: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ true |> ifNotOnly |> show: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ false |> ifNotOnly |> show: 1 }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ doIf(true) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ doIf(false) |> show: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ true |> ifDo |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifDo |> show: 1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ true |> ifShow: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false |> ifShow: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> showIf(true) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> showIf(false) }}"), Is.EqualTo("")); + } + + [Test] + public void Can_chain_only_filters_together() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = "foo", + ["empty"] = "", + ["nil"] = null, + ["items"] = new[]{1,2,3}, + ["none"] = new int[]{} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ arg |> onlyIfNotNull |> onlyIfNull(noArg) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ noArg |> onlyIfNull |> onlyIfNull(noArg2) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ empty |> onlyIfNotNull |> onlyIfNull(nil) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ empty |> onlyIfNotNull |> onlyIfNotNull(nil) |> show: 1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ items |> onlyIfNotEmpty |> onlyIfEmpty(none) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ items |> onlyIfEmpty |> show: 1 }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ none |> onlyIfNotEmpty |> show: 1 }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ onlyIf(!isEmpty(items)) |> onlyIf(isEmpty(none)) |> show: 1 }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ noArg |> onlyIfNull |> onlyIfNotNull(none) |> show: 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ arg |> onlyIfNotEmpty |> onlyIfNotEmpty(items) |> join }}"), Is.EqualTo("1,2,3")); + } + + [Test] + public void Can_flatten() + { + var context = new ScriptContext { + Args = { + ["nestedInts"] = new [] { new[]{1,2,3},new[]{4,5,6} }, + ["nestedInts2"] = new [] { new[]{new[]{1,2},new[]{3}},new[]{new[]{4},new[]{5,6}} }, + ["nestedStrings"] = new [] { new[]{"A","B","C"},new[]{"D","E","F"} }, + ["nestedStrings2"] = new [] { new[]{new[]{"A","B"},new[]{"C"}},new[]{new[]{"D"},new[]{"E","F"}} }, + } + }.Init(); + + Assert.That(context.Evaluate<List<object>>("{{ nestedInts |> flat |> return }}"), + Is.EquivalentTo(new[]{ 1,2,3,4,5,6 })); + Assert.That(context.Evaluate<List<object>>("{{ nestedInts2 |> flatten |> return }}"), + Is.EquivalentTo(new[]{ 1,2,3,4,5,6 })); + + Assert.That(context.Evaluate<List<object>>("{{ nestedStrings |> flat |> return }}"), + Is.EquivalentTo(new[]{ "A","B","C","D","E","F" })); + Assert.That(context.Evaluate<List<object>>("{{ nestedStrings2 |> flatten |> return }}"), + Is.EquivalentTo(new[]{ "A","B","C","D","E","F" })); + + Assert.That(context.Evaluate<List<object>>("{{ [ [1,2,[3], [4,[5,6]] ] ] |> flatten |> return }}"), + Is.EquivalentTo(new[]{ 1,2,3,4,5,6 })); + } + + + [Test] + public void Does_show() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 1 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> show: 2 }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ 1 |> use('({0})') |> fmt: 2 }}"), Is.EqualTo("(2)")); + Assert.That(context.EvaluateScript("{{ 1 |> showFmt('({0})',2) }}"), Is.EqualTo("(2)")); + Assert.That(context.EvaluateScript("{{ 1 |> use(2) |> format('0.00') }}"), Is.EqualTo("2.00")); + Assert.That(context.EvaluateScript("{{ 1 |> showFormat(2,'0.00') }}"), Is.EqualTo("2.00")); + + Assert.That(context.EvaluateScript("{{ 1 |> show: <h1>title</h1> }}"), Is.EqualTo("&lt;h1&gt;title&lt;/h1&gt;")); + Assert.That(context.EvaluateScript("{{ 1 |> showRaw: <h1>title</h1> }}"), Is.EqualTo("<h1>title</h1>")); + Assert.That(context.EvaluateScript("{{ 1 |> showFmtRaw('<h1>{0}</h1>',2) }}"), Is.EqualTo("<h1>2</h1>")); + + Assert.That(context.EvaluateScript("{{ 2 |> formatRaw: <h1>{0}</h1> }}"), Is.EqualTo("<h1>2</h1>")); + } + + [Test] + public void Does_conditional_error_handling() + { + var context = new ScriptContext + { + Args = + { + ["invalid"] = true + } + }.Init(); + + Assert.That(context.EvaluateScript( + @"{{ invalid |> ifDo |> select: <div class=""alert alert-danger"">Argument is invalid.</div> }}"), + Is.EqualTo(@"<div class=""alert alert-danger"">Argument is invalid.</div>")); + + } + + [Test] + public void Does_match_pathInfo() + { + var context = new ScriptContext + { + Args = + { + ["PathInfo"] = "/dir/sub" + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ '/dir/sub' |> matchesPathInfo }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ 1 |> ifMatchesPathInfo('/dir/sub/') }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> ifMatchesPathInfo('/dir/su') |> otherwise: 0 }}"), Is.EqualTo("0")); + } + + [Test] + public void Can_addTo_existing_collection() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 1 |> addTo: nums }} +{{ 2 |> addTo: nums }} +{{ 3 |> addTo: nums }} +{{ nums |> join }} +".NormalizeNewLines()), Is.EqualTo("1,2,3")); + + Assert.That(context.EvaluateScript(@" +{{ [1] |> addTo: nums }} +{{ [2] |> addTo: nums }} +{{ [3] |> addTo: nums }} +{{ nums |> join }} +".NormalizeNewLines()), Is.EqualTo("1,2,3")); + } + + [Test] + public void Can_addToGlobal_existing_collection() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 1 |> addToGlobal: nums }} +{{ 2 |> addToGlobal: nums }} +{{ 3 |> addToGlobal: nums }} +{{ nums |> join }} +".NormalizeNewLines()), Is.EqualTo("1,2,3")); + + Assert.That(context.EvaluateScript(@" +{{ [1] |> addToGlobal: nums }} +{{ [2] |> addToGlobal: nums }} +{{ [3] |> addToGlobal: nums }} +{{ nums |> join }} +".NormalizeNewLines()), Is.EqualTo("1,2,3")); + } + + [Test] + public void Can_addToStart_of_an_existing_collection() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 1 |> addToStart: nums }} +{{ 2 |> addToStart: nums }} +{{ 3 |> addToStart: nums }} +{{ nums |> join }} +".NormalizeNewLines()), Is.EqualTo("3,2,1")); + } + + [Test] + public void Can_addToStartGlobal_of_an_existing_collection() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 1 |> addToStartGlobal: nums }} +{{ 2 |> addToStartGlobal: nums }} +{{ 3 |> addToStartGlobal: nums }} +{{ nums |> join }} +".NormalizeNewLines()), Is.EqualTo("3,2,1")); + } + + [Test] + public void Can_appendTo_existing_string() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 'a' |> appendTo: string }} +{{ 'b' |> appendTo: string }} +{{ 'c' |> appendTo: string }} +{{ string }} +".NormalizeNewLines()), Is.EqualTo("abc")); + } + + [Test] + public void Can_appendToGlobal_existing_string() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 'a' |> appendToGlobal: string }} +{{ 'b' |> appendToGlobal: string }} +{{ 'c' |> appendToGlobal: string }} +{{ string }} +".NormalizeNewLines()), Is.EqualTo("abc")); + } + + [Test] + public void Can_prependTo_existing_string() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 'a' |> prependTo: string }} +{{ 'b' |> prependTo: string }} +{{ 'c' |> prependTo: string }} +{{ string }} +".NormalizeNewLines()), Is.EqualTo("cba")); + } + + [Test] + public void Can_prependToGlobal_existing_string() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 'a' |> prependToGlobal: string }} +{{ 'b' |> prependToGlobal: string }} +{{ 'c' |> prependToGlobal: string }} +{{ string }} +".NormalizeNewLines()), Is.EqualTo("cba")); + } + + [Test] + public void Can_addItem_and_toQueryString() + { + var context = new ScriptContext + { + Args = + { + ["nvc"] = new NameValueCollection {["a"] = "1"}, + ["obj"] = new Dictionary<string, object> { ["a"] = "1" }, + ["str"] = new Dictionary<string, string> { ["a"] = "1" } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ nvc |> addItem({b:2}) |> toQueryString |> raw }}"), + Is.EqualTo("?a=1&b=2")); + + Assert.That(context.EvaluateScript("{{ obj |> addItem({b:2}) |> toQueryString |> raw }}"), + Is.EqualTo("?a=1&b=2")); + Assert.That(context.EvaluateScript("{{ obj |> addItem(pair('b',2)) |> toQueryString |> raw }}"), + Is.EqualTo("?a=1&b=2")); + + Assert.That(context.EvaluateScript("{{ str |> addItem({b:'2'}) |> toQueryString |> raw }}"), + Is.EqualTo("?a=1&b=2")); + Assert.That(context.EvaluateScript("{{ str |> addItem(pair('b','2')) |> toQueryString |> raw }}"), + Is.EqualTo("?a=1&b=2")); + } + + [Test] + public void Return_does_stop_all_execution() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@"A{{ return }}B"), Is.EqualTo("A")); + + var pageResult = new PageResult(context.OneTimePage("A{{ 1 |> return }}B")); + Assert.That(pageResult.Result, Is.EqualTo("A")); + Assert.That(pageResult.ReturnValue.Result, Is.EqualTo(1)); + + pageResult = new PageResult(context.OneTimePage("A{{ 1 |> return({ a: 1 }) }}B")); + Assert.That(pageResult.Result, Is.EqualTo("A")); + Assert.That(pageResult.ReturnValue.Result, Is.EqualTo(1)); + Assert.That(pageResult.ReturnValue.Args, Is.EquivalentTo(new Dictionary<string,object> + { + { "a", 1 } + })); + } + + [Test] + public void Can_use_resolveAsset_to_resolve_external_paths() + { + var context = new ScriptContext + { + Args = + { + [ScriptConstants.AssetsBase] = "http://example.com/assets/" + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ 'img/logo.png' |> resolveAsset }}"), Is.EqualTo("http://example.com/assets/img/logo.png")); + Assert.That(context.EvaluateScript("{{ '/img/logo.png' |> resolveAsset }}"), Is.EqualTo("http://example.com/assets/img/logo.png")); + } + + [Test] + public void Returns_path_when_no_assetsBase_exists() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'img/logo.png' |> resolveAsset }}"), Is.EqualTo("img/logo.png")); + Assert.That(context.EvaluateScript("{{ '/img/logo.png' |> resolveAsset }}"), Is.EqualTo("/img/logo.png")); + } + + [Test] + public void Can_use_isNull_on_nested_properties() + { + var sampleModel = new + { + StringProperty = "Hello", + NullStringProperty = (string)null + }; + + var context = new ScriptContext().Init(); + + var args = new Dictionary<string, object> { { "sampleArg", sampleModel } }; + Assert.That(context.EvaluateScript("{{ sampleArg |> isNull }}", args), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ sampleArg.StringProperty |> isNull }}", args), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ sampleArg.NullStringProperty |> isNull }}", args), Is.EqualTo("True")); + } + + [Test] + public void Can_detect_empty_values() + { + var context = new ScriptContext { + Args = { + ["nullArg"] = null, + ["emptyArg"] = "", + ["whitespace"] = " ", + ["foo"] = "foo" + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ unknown |> isNull }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ nullArg |> isNull }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ '' |> isNull }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ `` |> isNull }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ emptyArg |> isNull }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ null |> isEmpty }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ '' |> isEmpty }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ `` |> isEmpty }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ emptyArg |> isEmpty }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ ' ' |> isEmpty }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ ` ` |> isEmpty }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ whitespace |> isEmpty }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ ' ' |> IsNullOrWhiteSpace }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ ` ` |> IsNullOrWhiteSpace }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ whitespace |> IsNullOrWhiteSpace }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ 'foo' |> IsNullOrWhiteSpace }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ foo |> IsNullOrWhiteSpace }}"), Is.EqualTo("False")); + } + + public class ShadowScripts : ScriptMethods + { + public int add(int x, int y) => x * y; + } + + [Test] + public void Can_shadow_default_ScriptMethods_with_InsertScriptMethods() + { + var context = new ScriptContext { + InsertScriptMethods = { new ShadowScripts() } + }.Init(); + + var result = context.Evaluate<int>("{{ add(4,4) |> return }}"); + Assert.That(result, Is.EqualTo(16)); + } + + [Test] + public void Arguments_can_shadow_existing_filters() + { + var context = new ScriptContext { + Args = { + ["min"] = -1 + } + }.Init(); + + var output = context.EvaluateScript("{{ 1 |> assignTo: max}}{{min}}:{{max}}", new ObjectDictionary { + ["max"] = 1 + }); + Assert.That(output, Is.EqualTo("-1:1")); + } + + class A + { + public int a { get; set; } + public A(int a) => this.a = a; + } + + class B + { + public int a { get; set; } + public string b { get; set; } + public B(int a, string b) + { + this.a = a; + this.b = b; + } + } + + [Test] + public void Can_use_textDump() + { + var context = new ScriptContext().Init(); + + var kvpA1 = new KeyValuePair<string,object>("a",1); + var kvpA2 = new KeyValuePair<string,object>("a",2); + var kvpBx = new KeyValuePair<string,object>("b","x"); + var kvpBy = new KeyValuePair<string,object>("b","y"); + + + Assert.That(context.EvaluateScript("{{ {a:1} |> textDump }}").NormalizeNewLines(), + Is.EqualTo("|||\n|-|-|\n| a | 1 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump }}", new ObjectDictionary { ["o"] = new A(1) }).NormalizeNewLines(), + Is.EqualTo("|||\n|-|-|\n| a | 1 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump }}", new ObjectDictionary { ["o"] = kvpA1 }).NormalizeNewLines(), + Is.EqualTo("|||\n|-|-|\n| a | 1 |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ {a:1,b:'x'} |> textDump }}").NormalizeNewLines(), + Is.EqualTo("|||\n|-|-|\n| a | 1 |\n| b | x |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump }}", new ObjectDictionary { ["o"] = new B(1, "x") }).NormalizeNewLines(), + Is.EqualTo("|||\n|-|-|\n| a | 1 |\n| b | x |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump }}", new ObjectDictionary { ["o"] = new[]{ kvpA1, kvpBx } }).NormalizeNewLines(), + Is.EqualTo("|||\n|-|-|\n| a | 1 |\n| b | x |".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ {a:1} |> textDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("| C ||\n|---|---|\n| a | 1 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new A(1) }).NormalizeNewLines(), + Is.EqualTo("| C ||\n|---|---|\n| a | 1 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = kvpA1 }).NormalizeNewLines(), + Is.EqualTo("| C ||\n|---|---|\n| a | 1 |".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ [{a:1},{a:2}] |> textDump({ caption: 'C', rowNumbers:false }) }}").NormalizeNewLines(), + Is.EqualTo("C\n\n| a |\n|---|\n| 1 |\n| 2 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C', rowNumbers:false }) }}", new ObjectDictionary { ["o"] = new[]{ new A(1), new A(2) } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| a |\n|---|\n| 1 |\n| 2 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C', rowNumbers:false }) }}", new ObjectDictionary { ["o"] = new[]{ kvpA1, kvpA2 } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| a |\n|---|\n| 1 |\n| 2 |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ [{a:1,b:'x'},{a:2,b:'y'}] |> textDump({ caption: 'C', rowNumbers:false }) }}").NormalizeNewLines(), + Is.EqualTo("C\n\n| a | b |\n|---|---|\n| 1 | x |\n| 2 | y |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C', rowNumbers:false }) }}", new ObjectDictionary { ["o"] = new[]{ new B(1, "x"), new B(2, "y") } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| a | b |\n|---|---|\n| 1 | x |\n| 2 | y |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C', rowNumbers:false }) }}", new ObjectDictionary { ["o"] = new[]{ new[]{ kvpA1, kvpBx }, new[]{ kvpA2, kvpBy } } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| a | b |\n|---|---|\n| 1 | x |\n| 2 | y |".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ [{a:1},{a:2}] |> textDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("C\n\n| # | a |\n|---|---|\n| 1 | 1 |\n| 2 | 2 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ new A(1), new A(2) } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| # | a |\n|---|---|\n| 1 | 1 |\n| 2 | 2 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ kvpA1, kvpA2 } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| # | a |\n|---|---|\n| 1 | 1 |\n| 2 | 2 |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ [{a:1,b:'x'},{a:2,b:'y'}] |> textDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("C\n\n| # | a | b |\n|---|---|---|\n| 1 | 1 | x |\n| 2 | 2 | y |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ new B(1, "x"), new B(2, "y") } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| # | a | b |\n|---|---|---|\n| 1 | 1 | x |\n| 2 | 2 | y |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> textDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ new[]{ kvpA1, kvpBx }, new[]{ kvpA2, kvpBy } } }).NormalizeNewLines(), + Is.EqualTo("C\n\n| # | a | b |\n|---|---|---|\n| 1 | 1 | x |\n| 2 | 2 | y |".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ [1,2] |> textDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("| C |\n|---|\n| 1 |\n| 2 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ ['a','b'] |> textDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("| C |\n|---|\n| a |\n| b |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ [1,2] |> textDump }}").NormalizeNewLines(), + Is.EqualTo("||\n|-|\n| 1 |\n| 2 |".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ ['a','b'] |> textDump }}").NormalizeNewLines(), + Is.EqualTo("||\n|-|\n| a |\n| b |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ [] |> textDump({ caption: 'C', captionIfEmpty: 'E' }) }}").NormalizeNewLines(), + Is.EqualTo("E".NormalizeNewLines())); + } + + [Test] + public void Can_use_htmlDump() + { + var context = new ScriptContext().Init(); + + var kvpA1 = new KeyValuePair<string,object>("a",1); + var kvpA2 = new KeyValuePair<string,object>("a",2); + var kvpBx = new KeyValuePair<string,object>("b","x"); + var kvpBy = new KeyValuePair<string,object>("b","y"); + + + Assert.That(context.EvaluateScript("{{ {a:1} |> htmlDump }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><th>a</th><td>1</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump }}", new ObjectDictionary { ["o"] = new A(1) }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><th>a</th><td>1</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump }}", new ObjectDictionary { ["o"] = kvpA1 }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><th>a</th><td>1</td></tr></tbody></table>".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ {a:1,b:'x'} |> htmlDump }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><th>a</th><td>1</td></tr><tr><th>b</th><td>x</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ {a:1,b:'x'} |> htmlDump }}", new ObjectDictionary { ["o"] = new B(1, "x") }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><th>a</th><td>1</td></tr><tr><th>b</th><td>x</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ {a:1,b:'x'} |> htmlDump }}", new ObjectDictionary { ["o"] = new[]{ kvpA1, kvpBx } }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><th>a</th><td>1</td></tr><tr><th>b</th><td>x</td></tr></tbody></table>".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ {a:1} |> htmlDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><tbody><tr><th>a</th><td>1</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new A(1) }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><tbody><tr><th>a</th><td>1</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = kvpA1 }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><tbody><tr><th>a</th><td>1</td></tr></tbody></table>".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ [{a:1},{a:2}] |> htmlDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr><tr><td>2</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ new A(1), new A(2) } }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr><tr><td>2</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ kvpA1, kvpA2 } }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr><tr><td>2</td></tr></tbody></table>".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ [{a:1,b:'x'},{a:2,b:'y'}] |> htmlDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>x</td></tr><tr><td>2</td><td>y</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ new B(1, "x"), new B(2, "y") } }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>x</td></tr><tr><td>2</td><td>y</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ o |> htmlDump({ caption: 'C' }) }}", new ObjectDictionary { ["o"] = new[]{ new[]{ kvpA1, kvpBx }, new[]{ kvpA2, kvpBy } } }).NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>x</td></tr><tr><td>2</td><td>y</td></tr></tbody></table>".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ [1,2] |> htmlDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><tbody><tr><td>1</td></tr><tr><td>2</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ ['a','b'] |> htmlDump({ caption: 'C' }) }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><caption>C</caption><tbody><tr><td>a</td></tr><tr><td>b</td></tr></tbody></table>".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ [1,2] |> htmlDump }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><td>1</td></tr><tr><td>2</td></tr></tbody></table>".NormalizeNewLines())); + Assert.That(context.EvaluateScript("{{ ['a','b'] |> htmlDump }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table\"><tbody><tr><td>a</td></tr><tr><td>b</td></tr></tbody></table>".NormalizeNewLines())); + + + Assert.That(context.EvaluateScript("{{ [] |> htmlDump({ caption: 'C', captionIfEmpty: 'E', className:'table-bordered' }) }}").NormalizeNewLines(), + Is.EqualTo("<table class=\"table-bordered\"><caption>E</caption></table>".NormalizeNewLines())); + } + + [Test] + public void Can_use_array_methods() + { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array + var context = new ScriptContext { + Args = { + ["fruits"] = new List<object> { "Apple", "Banana" } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{fruits[0]}}"), Is.EqualTo("Apple")); + Assert.That(context.EvaluateScript("{{fruits[fruits.Count - 1]}}"), Is.EqualTo("Banana")); + Assert.That(context.EvaluateScript("{{ [] |> to => result}}{{fruits.forEach((item,index) => result.push(`${item} ${index}`))}}{{result |> join}}"), + Is.EqualTo("Apple 0,Banana 1")); + Assert.That(context.EvaluateScript("{{#each fruits}}{{`${it} ${index},`}}{{/each}}"), + Is.EqualTo("Apple 0,Banana 1,")); + Assert.That(context.EvaluateScript("{{fruits.push('Orange')}} => {{fruits |> join}}"), + Is.EqualTo("3 => Apple,Banana,Orange")); + Assert.That(context.EvaluateScript("{{fruits.pop()}}"), + Is.EqualTo("Orange")); + Assert.That(context.EvaluateScript("{{fruits.shift()}}"), + Is.EqualTo("Apple")); + Assert.That(context.EvaluateScript("{{fruits.unshift('Strawberry')}} => {{fruits |> join}}"), + Is.EqualTo("2 => Strawberry,Banana")); + Assert.That(context.EvaluateScript("{{fruits.push('Mango')}} : {{fruits.indexOf('Banana')}}"), + Is.EqualTo("3 : 1")); + Assert.That(context.EvaluateScript("{{fruits.indexOf('Banana')}}"), + Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{fruits.splice(fruits.indexOf('Banana'),1) |> join}} : {{fruits |> join}}"), + Is.EqualTo("Banana : Strawberry,Mango")); + Assert.That(context.EvaluateScript("{{fruits.Count}} : {{fruits.slice().push('Pear')}} : {{fruits.Count}}"), + Is.EqualTo("2 : 3 : 2")); + } + + [Test] + public void Can_use_array_splice() + { + var context = new ScriptContext { + Args = { + ["vegetables"] = new List<object> { "Cabbage", "Turnip", "Radish", "Carrot" } + } + }.Init(); + + + Assert.That(context.EvaluateScript("{{vegetables.splice(1,2) |> join}} : {{ vegetables |> join }}"), + Is.EqualTo("Turnip,Radish : Cabbage,Carrot")); + } + + [Test] + public void Can_use_other_array_methods() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{['a', 'b', 'c'].concat(['d', 'e', 'f']) |> join}}"), + Is.EqualTo("a,b,c,d,e,f")); + + Assert.That(context.EvaluateScript("{{[1, 30, 39, 29, 10, 13].every(x => x < 40)}}"), + Is.EqualTo("True")); + + Assert.That(context.EvaluateScript("{{['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'].filter(word => word.Length > 6) |> join}}"), + Is.EqualTo("exuberant,destruction,present")); + + Assert.That(context.EvaluateScript("{{[5, 12, 8, 130, 44].find(x => x > 10) |> join}}"), + Is.EqualTo("12")); + + Assert.That(context.EvaluateScript("{{[5, 12, 8, 130, 44].findIndex(x => x > 13) |> join}}"), + Is.EqualTo("3")); + + Assert.That(context.EvaluateScript("{{[1, 2, [3, 4, [5, 6]]].flat(2) |> join}}"), + Is.EqualTo("1,2,3,4,5,6")); + + Assert.That(context.EvaluateScript("{{[1, 2, 3, 4].flatMap(x => [x * 2]) |> join}}"), + Is.EqualTo("2,4,6,8")); + + Assert.That(context.EvaluateScript("{{[1, 2, 3].includes(2)}}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{['cat', 'dog', 'bat'].includes('cat')}}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{['cat', 'dog', 'bat'].includes('at')}}"), Is.EqualTo("False")); + + Assert.That(context.EvaluateScript("{{['ant', 'bison', 'camel', 'duck', 'bison'].indexOf('bison')}}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{['ant', 'bison', 'camel', 'duck', 'bison'].indexOf('bison',2)}}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{['ant', 'bison', 'camel', 'duck', 'bison'].indexOf('giraffe')}}"), Is.EqualTo("-1")); + + Assert.That(context.EvaluateScript("{{['Fire', 'Air', 'Water'].join()}}"), Is.EqualTo("Fire,Air,Water")); + Assert.That(context.EvaluateScript("{{['Fire', 'Air', 'Water'].join('')}}"), Is.EqualTo("FireAirWater")); + Assert.That(context.EvaluateScript("{{['Fire', 'Air', 'Water'].join('-')}}"), Is.EqualTo("Fire-Air-Water")); + + Assert.That(context.EvaluateScript("{{['a', 'b', 'c'].keys() |> join}}"), Is.EqualTo("0,1,2")); + + Assert.That(context.EvaluateScript("{{['Dodo', 'Tiger', 'Penguin', 'Dodo'].lastIndexOf('Dodo')}}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{['Dodo', 'Tiger', 'Penguin', 'Dodo'].lastIndexOf('Tiger')}}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{[1, 4, 9, 16].map(x => x * 2) |> join}}"), Is.EqualTo("2,8,18,32")); + + Assert.That(context.EvaluateScript("{{['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'].pop()}}"), Is.EqualTo("tomato")); + + Assert.That(context.EvaluateScript("{{['pigs', 'goats', 'sheep'].push('cows')}}"), Is.EqualTo("4")); + + Assert.That(context.EvaluateScript("{{[1, 2, 3, 4].reduce((accumulator, currentValue) => accumulator + currentValue)}}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{[1, 2, 3, 4].reduce((accumulator, currentValue) => accumulator + currentValue, 5)}}"), Is.EqualTo("15")); + + Assert.That(context.EvaluateScript("{{['one', 'two', 'three'].reverse() |> join}}"), Is.EqualTo("three,two,one")); + + Assert.That(context.EvaluateScript("{{[1, 2, 3].shift()}}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{['ant', 'bison', 'camel', 'duck', 'elephant'] |> to => animals}}{{animals.slice(2) |> join}}"), Is.EqualTo("camel,duck,elephant")); + Assert.That(context.EvaluateScript("{{['ant', 'bison', 'camel', 'duck', 'elephant'] |> to => animals}}{{animals.slice(2,4) |> join}}"), Is.EqualTo("camel,duck")); + Assert.That(context.EvaluateScript("{{['ant', 'bison', 'camel', 'duck', 'elephant'] |> to => animals}}{{animals.slice(1,5) |> join}}"), Is.EqualTo("bison,camel,duck,elephant")); + + Assert.That(context.EvaluateScript("{{[1, 2, 3, 4, 5].some(x => x % 2 == 0)}}"), Is.EqualTo("True")); + + Assert.That(context.EvaluateScript("{{['March', 'Jan', 'Feb', 'Dec'].sort() |> join}}"), Is.EqualTo("Dec,Feb,Jan,March")); + Assert.That(context.EvaluateScript("{{[1, 30, 4, 21, 100000].sort() |> join}}"), Is.EqualTo("1,4,21,30,100000")); + + Assert.That(context.EvaluateScript( + "{{['Jan', 'March', 'April', 'June'] |> to => months}}{{months.splice(1,0,['Feb']) |> end}}{{months |> join}}"), + Is.EqualTo("Jan,Feb,March,April,June")); + + Assert.That(context.EvaluateScript("{{[1, 2, 3] |> to => array}}{{array.unshift([4,5])}} : {{array |> join}}"), Is.EqualTo("5 : 4,5,1,2,3")); + + Assert.That(context.EvaluateScript("{{['a', 'b', 'c'].values() |> join}}"), Is.EqualTo("a,b,c")); + } + + [Test] + public void Can_use_forEach_on_dictionaries() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript( + "{{ {a:1,b:2,c:3} |> to => d }}{{ [] |> to => values}}{{d.forEach((key,val) => values.push(val))}}{{values |> join}}"), + Is.EqualTo("1,2,3")); + + } + + [Test] + public void Can_flatMap() + { + var context = new ScriptContext().Init(); + Assert.That(context.Evaluate("{{ flatten([[1,2],[3,4]]) |> return }}"), Is.EqualTo(new[]{ 1, 2, 3, 4 })); + } + + [Test] + public void Can_removeKeyFromDictionary() + { + var context = new ScriptContext().Init(); + var output = context.RenderScript(@"```code|q +sample = {} +sample.myKey1 = 1 +sample.myKey2 = 2 +sample |> remove('myKey1') +sample |> removeKeyFromDictionary('myKey2') +``` +{{ sample.myKey }}".NormalizeNewLines()); + + Assert.That(output, Is.EqualTo("")); + } + + [Test] + public void Can_use_ownProps() + { + var context = new ScriptContext().Init(); + + var output = context.RenderScript(@" +{{#partial test}} +{{ it |> ownProps |> map => it.Key |> jsv }}|{{ it.ownProps().map(x => x.Key).jsv() }} +{{/partial}} +{{ 'test' | partial({ A:1, B:2 }) }}".NormalizeNewLines()); + + output.Print(); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo("[A,B]|[A,B]")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/DslTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/DslTests.cs new file mode 100644 index 00000000000..b7ca2f059fe --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/DslTests.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ProtoBufMethods : ScriptMethods + { + public ReadOnlyMemory<byte> serialize(object target) + { + var ms = new MemoryStream(); + global::ProtoBuf.Serializer.NonGeneric.Serialize(ms, target); + return ms.GetBufferAsMemory(); + } + } + + [DataContract] + public class PersonContract + { + [DataMember(Order = 1)] + public string Name { get; set; } + + [DataMember(Order = 2)] + public int Age { get; set; } + } + + public class DslTests + { + private static ScriptContext CreateContext() => new ScriptContext { + InsertScriptMethods = { + new ProtoBufMethods() + } + }.Init(); + + [Test] + public void Can_use_injected_binary_serializer_with_EvaluateScript() + { + var context = CreateContext(); + + var person = new PersonContract { Name = "Kurt", Age = 27 }; + var result = (ReadOnlyMemory<byte>)context.Evaluate("{{ serialize(target) |> return }}", new Dictionary<string, object> { + ["target"] = person + }); + + var ms = new MemoryStream(result.ToArray()); + var fromScript = (PersonContract)global::ProtoBuf.Serializer.NonGeneric.Deserialize(typeof(PersonContract), ms); + + Assert.That(fromScript.Name, Is.EqualTo(person.Name)); + Assert.That(fromScript.Age, Is.EqualTo(person.Age)); + } + + [Test] + public void Can_use_injected_binary_serializer_via_eval_and_custom_Scope() + { + var context = CreateContext(); + + var person = new PersonContract { Name = "Kurt", Age = 27 }; + var scope = context.CreateScope(new Dictionary<string, object> { + ["target"] = person + }); + var result = (ReadOnlyMemory<byte>)JS.eval("serialize(target)", scope); + + var ms = new MemoryStream(result.ToArray()); + var fromScript = (PersonContract)global::ProtoBuf.Serializer.NonGeneric.Deserialize(typeof(PersonContract), ms); + + Assert.That(fromScript.Name, Is.EqualTo(person.Name)); + Assert.That(fromScript.Age, Is.EqualTo(person.Age)); + } + + [Test] + public void Can_use_injected_binary_serializer_via_eval_and_custom_ScriptScopeContext() + { + var context = CreateContext(); + + var person = new PersonContract { Name = "Kurt", Age = 27 }; + var scope = new ScriptScopeContext(context, new Dictionary<string, object> { + ["target"] = person + }); + + var result = (ReadOnlyMemory<byte>)JS.eval("serialize(target)", scope); + + var ms = new MemoryStream(result.ToArray()); + var fromScript = (PersonContract)global::ProtoBuf.Serializer.NonGeneric.Deserialize(typeof(PersonContract), ms); + + Assert.That(fromScript.Name, Is.EqualTo(person.Name)); + Assert.That(fromScript.Age, Is.EqualTo(person.Age)); + } + + [Test] + public void Can_use_injected_binary_serializer_via_page_result() + { + var context = CreateContext(); + + var person = new PersonContract { Name = "Kurt", Age = 27 }; + + var evalContext = new PageResult(context.OneTimePage("{{ serialize(target) |> return }}")) { + Args = { + ["target"] = person + } + }; + evalContext.RenderToStringAsync().Wait(); + + var result = (ReadOnlyMemory<byte>) evalContext.ReturnValue.Result; + + var ms = new MemoryStream(result.ToArray()); + var fromScript = (PersonContract)global::ProtoBuf.Serializer.NonGeneric.Deserialize(typeof(PersonContract), ms); + + Assert.That(fromScript.Name, Is.EqualTo(person.Name)); + Assert.That(fromScript.Age, Is.EqualTo(person.Age)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ErrorHandlingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ErrorHandlingTests.cs new file mode 100644 index 00000000000..e5bac9ab3c8 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ErrorHandlingTests.cs @@ -0,0 +1,581 @@ +using System; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ErrorHandlingTests + { + [Test] + public void Exceptions_in_filter_bubble_by_default() + { + var context = new ScriptContext().Init(); + + try + { + context.EvaluateScript("{{ 'in filter' |> throw }}"); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.Message, Is.EqualTo("in filter")); + } + } + + [Test] + public void Exceptions_in_filter_bubble_by_default_async() + { + var context = new ScriptContext + { + }.Init(); + + try + { + context.EvaluateScript("{{ 'in filter' |> throwAsync }}"); + } + catch (Exception ex) + { + Assert.That(ex.Message, Is.EqualTo("in filter")); + } + } + + [Test] + public void Can_capture_exception_using_AssignException() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw }} +<var>{{ error.Message }}</var>", out _), + Is.EqualTo("<var>in filter</var>")); + } + + [Test] + public void Can_capture_exception_using_assignError() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw({ assignError: 'myError' }) }} +<var>{{ myError.Message }}</var>", out _), + Is.EqualTo("<var>in filter</var>")); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw({ assignError: 'myError' }) }} +<var>{{ myError.Message }}</var><pre>{{ lastErrorStackTrace }}</pre>", out _), + Does.StartWith("<var>in filter</var><pre> at ")); + } + + [Test] + public void Can_capture_and_suppress_exception_using_catchError() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw({ catchError: 'myError' }) }} +<var>{{ myError.Message }}</var>"), + Is.EqualTo("<var>in filter</var>")); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw({ catchError: 'myError' }) }} +<var>{{ myError.Message }}</var><pre>{{ myErrorStackTrace }}</pre>"), + Does.StartWith("<var>in filter</var><pre> at ")); + } + + [Test] + public void Can_use_conditional_filters_with_filter_errors() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw }}{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw }}{{ lastError |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw }}{{ lastErrorMessage |> format('<h1>FAIL! {0}</h1>') |> raw }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throw }}<h1>{{ lastError |> ifExists |> map: it.Message }}</h1>", out _), + Is.EqualTo("<h1>in filter</h1>")); + + + Assert.That(context.EvaluateScript(@"{{ ifNoError |> select: <h1>SUCCESS!</h1> }}"), + Is.EqualTo("<h1>SUCCESS!</h1>")); + Assert.That(context.EvaluateScript(@"<h1>{{ ifNoError |> show: SUCCESS! }}</h1>"), + Is.EqualTo("<h1>SUCCESS!</h1>")); + Assert.That(context.EvaluateScript(@"{{ '<h1>SUCCESS!</h1>' |> ifNoError |> raw }}"), + Is.EqualTo("<h1>SUCCESS!</h1>")); + Assert.That(context.EvaluateScript(@"{{ lastError | endIfExists |> select: <h1>SUCCESS!</h1> }}"), + Is.EqualTo("<h1>SUCCESS!</h1>")); + Assert.That(context.EvaluateScript(@"<h1>{{ 'SUCCESS!' |> ifNotExists(lastError) }}</h1>"), + Is.EqualTo("<h1>SUCCESS!</h1>")); + } + + [Test] + public void Can_throw_on_conditions() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(true) }}{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(true) }}{{ error |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ true |> ifThrow('in filter') }}{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ true |> ifThrow('in filter') }}{{ error |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(false) }}{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("")); + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(false) }}{{ error |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("")); + Assert.That(context.EvaluateScript(@"{{ false |> ifThrow('in filter') }}{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("")); + Assert.That(context.EvaluateScript(@"{{ false |> ifThrow('in filter') }}{{ error |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("")); + } + + [Test] + public void Can_throw_on_conditions_with_assignError() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(true, { assignError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ true |> ifThrow('in filter', { assignError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(false, { assignError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("")); + Assert.That(context.EvaluateScript(@"{{ false |> ifThrow('in filter', { assignError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}", out _), + Is.EqualTo("")); + } + + [Test] + public void Can_throw_on_conditions_and_suppresses_with_catchError() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(true, { catchError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}"), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + Assert.That(context.EvaluateScript(@"{{ true |> ifThrow('in filter', { catchError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}"), + Is.EqualTo("<h1>FAIL! in filter</h1>")); + + Assert.That(context.EvaluateScript(@"{{ 'in filter' |> throwIf(false, { catchError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}"), + Is.EqualTo("")); + Assert.That(context.EvaluateScript(@"{{ false |> ifThrow('in filter', { catchError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>FAIL! { it.Message }</h1> }}"), + Is.EqualTo("")); + } + + [Test] + public void Can_throw_different_exception_types() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ true |> ifThrowArgumentNullException('p') }}{{ ifError |> select: <h1>{ it |> typeName }! { it.Message }</h1> }}", out _).NormalizeNewLines(), + Does.StartWith("<h1>ArgumentNullException! Value cannot be null.")); + Assert.That(context.EvaluateScript(@"{{ true |> ifThrowArgumentNullException('p', { assignError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>{ it |> typeName }! { it.Message }</h1> }}", out _).NormalizeNewLines(), + Does.StartWith("<h1>ArgumentNullException! Value cannot be null.")); + + Assert.That(context.EvaluateScript(@"{{ true |> ifThrowArgumentException('bad arg', 'p') }}{{ ifError |> select: <h1>{ it |> typeName }! { it.Message }</h1> }}", out _).NormalizeNewLines(), + Does.StartWith("<h1>ArgumentException! bad arg")); + Assert.That(context.EvaluateScript(@"{{ true |> ifThrowArgumentException('bad arg', 'p', { assignError: 'ex' }) }}{{ ex |> ifExists |> select: <h1>{ it |> typeName }! { it.Message }</h1> }}", out _).NormalizeNewLines(), + Does.StartWith("<h1>ArgumentException! bad arg")); + } + + [Test] + public void Does_skipExecutingPageFiltersIfError() + { + var context = new ScriptContext + { + AssignExceptionsTo = "error" + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body> +{{ page }} +</body> +</html>"); + + context.VirtualFiles.WriteFile("page.html", @" +{{ skipExecutingFiltersOnError }} +<h1>Before Error</h1> +{{ 'in filter' |> throw }} +{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }} + +<b>{{ 'never executed' }}</b> + +<h1>After Error</h1> +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@"<html> +<body> + +<h1>Before Error</h1> +<h1>FAIL! in filter</h1> + +<b></b> + +<h1>After Error</h1> + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Does_SkipExecutingPageFiltersIfError_in_Context() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body> +{{ page }} +</body> +</html>"); + + context.VirtualFiles.WriteFile("page.html", @" +<h1>Before Error</h1> +{{ 'in filter' |> throw }} +{{ ifError |> select: <h1>FAIL! { it.Message }</h1> }} + +<b>{{ 'never executed' }}</b> + +<h1>After Error</h1> +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@"<html> +<body> + +<h1>Before Error</h1> +<h1>FAIL! in filter</h1> + +<b></b> + +<h1>After Error</h1> + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Does_render_htmlErrorDebug_in_DebugMode() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + DebugMode = true, + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body> +{{ page }} +</body> +</html>"); + + context.VirtualFiles.WriteFile("page.html", @" +<h1>Before Error</h1> +{{ 'in filter' |> throw }} +{{ htmlError }} + +<b>{{ 'never executed' }}</b> + +<h1>After Error</h1> +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.NormalizeNewLines(), Does.StartWith(@"<html> +<body> + +<h1>Before Error</h1> +<pre class=""alert alert-danger"">Exception: in filter +".NormalizeNewLines())); + } + + [Test] + public void Does_render_htmlErrorMessage_when_not_DebugMode() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + DebugMode = false, + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body> +{{ page }} +</body> +</html>"); + + context.VirtualFiles.WriteFile("page.html", @" +<h1>Before Error</h1> +{{ 'in filter' |> throw }} +{{ htmlError }} + +<b>{{ 'never executed' }}</b> + +<h1>After Error</h1> +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@"<html> +<body> + +<h1>Before Error</h1> +<div class=""alert alert-danger"">in filter</div> + +<b></b> + +<h1>After Error</h1> + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Does_render_htmlErrorDebug_with_StackTraces() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + }.Init(); + + context.VirtualFiles.WriteFile("page.html", @" +<h1>Before Error</h1> +{{ 'in filter' |> throw }} +{{ htmlErrorDebug }} + +<b>{{ 'never executed' }}</b> + +<h1>After Error</h1> +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<h1>Before Error</h1> +<pre class=""alert alert-danger"">Exception: in filter + +StackTrace: + at Expression (String): ""in filter"" + at Page: page.html +</pre> + + +<b></b> + +<h1>After Error</h1>".NormalizeNewLines())); + } + + [Test] + public void Can_continue_executing_filters_with_continueExecutingFiltersOnError() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + }.Init(); + + context.VirtualFiles.WriteFile("page.html", @" +{{ continueExecutingFiltersOnError }} +<h1>Before Error</h1> +{{ 'in filter' |> throw }} +{{ htmlErrorDebug }} + +<b>{{ 'is evaluated' }}</b> + +<h1>After Error</h1> +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<h1>Before Error</h1> +<pre class=""alert alert-danger"">Exception: in filter + +StackTrace: + at Expression (String): ""in filter"" + at Page: page.html +</pre> + + +<b>is evaluated</b> + +<h1>After Error</h1>".NormalizeNewLines())); + } + + [Test] + public void Can_continue_executing_filters_with_continueExecutingFiltersOnError_in_filterError() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("page.html", @" +{{ continueExecutingFiltersOnError }} +{{ 'A' |> to => someVariable }} +{{ someVariable |> toInt |> to => myInt }} +myInt {{ myInt }} +"); + + var page = context.GetPage("page"); + var output = new PageResult(page).Result; + + Assert.That(output.Trim(), Is.EqualTo("myInt")); + } + + [Test] + public void Can_continue_executing_filters_with_catchError() + { + var template = @"{{ 'ex' |> catchError }} +Result = +```code +'h1' |> lower |> to => elemType +elemType |> toInt |> raw +```"; + + var context = new ScriptContext().Init(); + var dynamicPage = context.OneTimePage(template); + var pageResult = new PageResult(dynamicPage); + var output = pageResult.RenderScript(); + Assert.That(output.Trim(), Is.EqualTo("Result =")); + } + + [Test] + public void Calling_ensureAllArgsNotNull_throws_if_any_args_are_null() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + DebugMode = false, + Args = + { + ["arg"] = "value", + ["empty"] = "", + } + }.Init(); + + context.VirtualFiles.WriteFile("page-arg.html", @"{{ { arg } |> ensureAllArgsNotNull |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-empty.html", @"{{ { empty } |> ensureAllArgsNotNull |> select: { it.empty } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-noarg.html", @"{{ { noArg } |> ensureAllArgsNotNull |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-msg.html", @"{{ { noArg } |> ensureAllArgsNotNull({ message: '{0} required' }) |> select: { it.arg } }}{{ htmlError }}"); + + Assert.That(new PageResult(context.GetPage("page-arg")).Result, Is.EqualTo(@"value")); + Assert.That(new PageResult(context.GetPage("page-empty")).Result, Is.EqualTo(@"")); + Assert.That(new PageResult(context.GetPage("page-noarg")).Result.NormalizeNewLines(), + Does.StartWith("<div class=\"alert alert-danger\">Value cannot be null.")); + Assert.That(new PageResult(context.GetPage("page-msg")).Result.NormalizeNewLines(), + Is.EqualTo("<div class=\"alert alert-danger\">noArg required</div>")); + } + + [Test] + public void Calling_ensureAllArgsNotEmpty_throws_if_any_args_are_empty() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + DebugMode = false, + Args = + { + ["arg"] = "value", + ["empty"] = "", + } + }.Init(); + + context.VirtualFiles.WriteFile("page-arg.html", @"{{ { arg } |> ensureAllArgsNotEmpty |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-empty.html", @"{{ { empty } |> ensureAllArgsNotEmpty |> select: { it.empty } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-noarg.html", @"{{ { noArg } |> ensureAllArgsNotEmpty |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-msg.html", @"{{ { noArg } |> ensureAllArgsNotEmpty({ message: '{0} required' }) |> select: { it.arg } }}{{ htmlError }}"); + + Assert.That(new PageResult(context.GetPage("page-arg")).Result, Is.EqualTo(@"value")); + Assert.That(new PageResult(context.GetPage("page-empty")).Result.NormalizeNewLines(), + Does.StartWith("<div class=\"alert alert-danger\">Value cannot be null.")); + Assert.That(new PageResult(context.GetPage("page-noarg")).Result.NormalizeNewLines(), + Does.StartWith("<div class=\"alert alert-danger\">Value cannot be null.")); + Assert.That(new PageResult(context.GetPage("page-msg")).Result.NormalizeNewLines(), + Is.EqualTo("<div class=\"alert alert-danger\">noArg required</div>")); + } + + [Test] + public void Calling_ensureAnyArgsNotNull_throws_if_all_args_are_null() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + DebugMode = false, + Args = + { + ["arg"] = "value", + ["empty"] = "", + } + }.Init(); + + context.VirtualFiles.WriteFile("page-arg.html", @"{{ { arg } |> ensureAnyArgsNotNull |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-empty.html", @"{{ { arg, noArg } |> ensureAnyArgsNotNull |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-noarg.html", @"{{ { noArg } |> ensureAnyArgsNotNull |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-msg.html", @"{{ { noArg, empty } |> ensureAnyArgsNotNull({ message: '{0} required' }) |> select: { it.empty } }}{{ htmlError }}"); + + Assert.That(new PageResult(context.GetPage("page-arg")).Result, Is.EqualTo(@"value")); + Assert.That(new PageResult(context.GetPage("page-empty")).Result, Is.EqualTo(@"value")); + Assert.That(new PageResult(context.GetPage("page-noarg")).Result.NormalizeNewLines(), + Does.StartWith("<div class=\"alert alert-danger\">Value cannot be null")); + Assert.That(new PageResult(context.GetPage("page-msg")).Result.NormalizeNewLines(), + Is.EqualTo("")); + } + + [Test] + public void Calling_ensureAnyArgsNotEmpty_throws_if_all_args_are_empty() + { + var context = new ScriptContext + { + SkipExecutingFiltersIfError = true, + DebugMode = false, + Args = + { + ["arg"] = "value", + ["empty"] = "", + } + }.Init(); + + context.VirtualFiles.WriteFile("page-arg.html", @"{{ { arg } |> ensureAnyArgsNotEmpty |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-empty.html", @"{{ { arg, noArg } |> ensureAnyArgsNotEmpty |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-noarg.html", @"{{ { noArg } |> ensureAnyArgsNotEmpty |> select: { it.arg } }}{{ htmlError }}"); + context.VirtualFiles.WriteFile("page-msg.html", @"{{ { noArg, empty } |> ensureAnyArgsNotEmpty({ message: '{0} required' }) |> select: { it.empty } }}{{ htmlError }}"); + + Assert.That(new PageResult(context.GetPage("page-arg")).Result, Is.EqualTo(@"value")); + Assert.That(new PageResult(context.GetPage("page-empty")).Result, Is.EqualTo(@"value")); + Assert.That(new PageResult(context.GetPage("page-noarg")).Result.NormalizeNewLines(), + Does.StartWith("<div class=\"alert alert-danger\">Value cannot be null.")); + Assert.That(new PageResult(context.GetPage("page-msg")).Result.NormalizeNewLines(), + Is.EqualTo("<div class=\"alert alert-danger\">empty required</div>")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/EvaluateScriptTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/EvaluateScriptTests.cs new file mode 100644 index 00000000000..dc9bc064c53 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/EvaluateScriptTests.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class EvaluateScriptTests + { + [Test] + public void Evaluate_does_return_ReturnValue() + { + var identity = new object(); + var context = new ScriptContext { + Args = { + ["identity"] = identity + } + }.Init(); + + Assert.That(context.Evaluate("{{ identity |> return }}"), Is.EqualTo(identity)); + Assert.That(context.Evaluate("{{ id |> return }}", new ObjectDictionary { + ["id"] = identity, + }), Is.EqualTo(identity)); + + Assert.That(context.Evaluate("{{ 1 + 1 |> return }}"), Is.EqualTo(2)); + Assert.That(context.Evaluate("{{ return(1 + 1) }}"), Is.EqualTo(2)); + } + + [Test] + public async Task Evaluate_does_return_ReturnValue_Async() + { + var identity = new object(); + var context = new ScriptContext { + Args = { + ["identity"] = identity + } + }.Init(); + + Assert.That(await context.EvaluateAsync("{{ identity |> return }}"), Is.EqualTo(identity)); + Assert.That(await context.EvaluateAsync("{{ id |> return }}", new ObjectDictionary { + ["id"] = identity, + }), Is.EqualTo(identity)); + + Assert.That(await context.EvaluateAsync("{{ 1 + 1 |> return }}"), Is.EqualTo(2)); + Assert.That(await context.EvaluateAsync("{{ return(1 + 1) }}"), Is.EqualTo(2)); + } + + [Test] + public void Evaluate_does_throw_ScriptException() + { + var context = new ScriptContext().Init(); + + try + { + context.Evaluate("{{ 'fail' |> throw }} {{ 1 |> return }}"); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + Assert.That(e.Message, Is.EqualTo("fail")); + Assert.That(e.InnerException.Message, Is.EqualTo("fail")); + Assert.That(e.PageStackTrace, Is.Not.Null); + } + + try + { + context.EvaluateScript("{{ 'fail' |> throw }} {{ 1 |> return }}"); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + Assert.That(e.Message, Is.EqualTo("fail")); + Assert.That(e.InnerException.Message, Is.EqualTo("fail")); + Assert.That(e.PageStackTrace, Is.Not.Null); + } + } + + [Test] + public async Task Evaluate_does_throw_ScriptException_Async() + { + var context = new ScriptContext().Init(); + + try + { + await context.EvaluateAsync("{{ 'fail' |> throw }} {{ 1 |> return }}"); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + Assert.That(e.Message, Is.EqualTo("fail")); + Assert.That(e.InnerException.Message, Is.EqualTo("fail")); + Assert.That(e.PageStackTrace, Is.Not.Null); + } + + try + { + await context.EvaluateScriptAsync("{{ 'fail' |> throw }} {{ 1 |> return }}"); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + Assert.That(e.Message, Is.EqualTo("fail")); + Assert.That(e.InnerException.Message, Is.EqualTo("fail")); + Assert.That(e.PageStackTrace, Is.Not.Null); + } + } + + [Test] + public void Evaluate_script_without_return_throws_NotSupportedException() + { + var context = new ScriptContext().Init(); + try + { + Assert.That(context.EvaluateScript("{{1 + 1}}"), Is.EqualTo("2")); + + context.Evaluate("{{ 1 + 1 }}"); + Assert.Fail("Should throw"); + } + catch (NotSupportedException) {} + } + + [Test] + public void Evaluate_does_convert_return_Value() + { + var context = new ScriptContext().Init(); + + Assert.That(context.Evaluate<string>("{{ return(1 + 1) }}"), Is.EqualTo("2")); + Assert.That(context.Evaluate<int>("{{ return(1 + 1) }}"), Is.EqualTo(2)); + Assert.That(context.Evaluate<long>("{{ return(1 + 1) }}"), Is.EqualTo(2)); + Assert.That(context.Evaluate<double>("{{ return(1 + 1) }}"), Is.EqualTo(2)); + Assert.That(context.Evaluate<double>("{{ return('2') }}"), Is.EqualTo(2)); + + Assert.That(context.Evaluate("{{ return({Age:1,Name:'foo'}) }}"), Is.EqualTo(new Dictionary<string, object> { + {"Age", 1}, + {"Name", "foo"}, + })); + + var person = context.Evaluate<Person>("{{ return({Age:1,Name:'foo'}) }}"); + Assert.That(person.Age, Is.EqualTo(1)); + Assert.That(person.Name, Is.EqualTo("foo")); + + Assert.That(context.Evaluate<Dictionary<string, object>>("{{ return(person) }}", new ObjectDictionary { + ["person"] = new Person { Age = 1, Name = "foo" } + }), Is.EqualTo(new Dictionary<string, object> { + {"Age", 1}, + {"Name", "foo"}, + })); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ExpressionTests.cs new file mode 100644 index 00000000000..f390cc91c5a --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ExpressionTests.cs @@ -0,0 +1,91 @@ +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ExpressionTests + { + [Test] + public void Can_assign_list_numbers() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ [1,2,3] |> assignTo: numArray }} +{{ do: assign('numArray[1]', 4) }} +{{ numArray[1] }} +").Trim(), Is.EqualTo("4")); + } + + [Test] + public void Does_not_execute_do_on_null_or_none_existing_value() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ 1 |> assignTo: arg }} +{{ arg |> do: assign('doArg', incr(it)) }} +{{ doArg }} +").Trim(), Is.EqualTo("2")); + + Assert.That(context.EvaluateScript(@" +{{ null |> assignTo: arg }} +{{ arg |> do: assign('doArg', 2) }} +{{ doArg }} +").Trim(), Is.EqualTo("")); + + Assert.That(context.EvaluateScript(@" +{{ noArg |> do: assign('doArg', 2) }} +{{ doArg }} +").Trim(), Is.EqualTo("")); + } + + [Test] + public void Can_assign_array_numbers() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ [1,2,3] |> toArray |> assignTo: numArray }} +{{ do: assign('numArray[1]', 4) }} +{{ numArray[1] }} +").Trim(), Is.EqualTo("4")); + } + + [Test] + public void Can_assign_list_strings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ ['a','b','c'] |> assignTo: stringArray }} +{{ do: assign('stringArray[1]', 'd') }} +{{ stringArray[1] }} +").Trim(), Is.EqualTo("d")); + } + + [Test] + public void Can_assign_array_strings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ ['a','b','c'] |> toArray |> assignTo: stringArray }} +{{ do: assign('stringArray[1]', 'd') }} +{{ stringArray[1] }} +").Trim(), Is.EqualTo("d")); + } + + [Test] + public void Can_assign_dictionary_strings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@" +{{ { a: 'foo', b: 'bar' } |> assignTo: map }} +{{ do: assign('map[`b`]', 'qux') }} +{{ map['b'] }} +").Trim(), Is.EqualTo("qux")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/GithubScriptTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/GithubScriptTests.cs new file mode 100644 index 00000000000..9b1d6369a4b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/GithubScriptTests.cs @@ -0,0 +1,69 @@ +using System.IO; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [Ignore("Integration Tests")] + public class GithubScriptTests + { + public ScriptContext CreateScriptContext() + { + return new ScriptContext { + Plugins = { new GitHubPlugin() }, + ScriptMethods = { new InfoScripts(), new ProtectedScripts(), }, + }; + } + + [Test] + public void Can_write_and_read_gist_files() + { + var context = CreateScriptContext().Init(); + + var output = context.EvaluateScript(@" +```code +githubGateway('GITHUB_GIST_TOKEN'.envVariable()) |> to => gateway + +{{ gateway.githubCreateGist('Hello World Examples', { + 'hello_world_ruby.txt': 'Run `ruby hello_world.rb` to print Hello World', + 'hello_world_python.txt': 'Run `python hello_world.py` to print Hello World', + }) + |> to => newGist }} + +{ ...newGist, Files: null, Owner: null } |> textDump({ caption: 'new gist' }) +newGist.Owner |> textDump({ caption: 'new gist owner' }) +newGist.Files |> toList |> map(x => x.Value.textDump({ caption: x.Key })) |> join('\n') + +gateway.githubGist(newGist.Id) |> to => gist +{ ...gist, Files: null, Owner: null } |> textDump({ caption: 'gist' }) +gist.Files |> toList |> map(x => x.Value.textDump({ caption: x.Key })) |> join('\n') +```"); + + output.Print(); + } + + [Test] + public void Display_Gist() + { + var context = CreateScriptContext().Init(); + context.Args["gistId"] = "4c5d95ec4b2594b4cdd238987fe7a15a"; + + var output = context.EvaluateScript(@" +```code +githubGateway('GITHUB_GIST_TOKEN'.envVariable()) |> to => gateway + +gateway.githubGist(gistId) |> to => gist + +{ ...gist, Files: null, Owner: null } |> textDump({ caption: 'gist' }) + +`### Gist Files` +#each file in gist.Files.Keys + gist.Files[file] |> textDump({ caption: file }) +/each +```"); + + output.Print(); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsArrowFunctionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsArrowFunctionTests.cs new file mode 100644 index 00000000000..ac276be3a3b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsArrowFunctionTests.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [TestFixture] + public class JsArrowFunctionTests + { + [Test] + public void Does_parse_Arrow_Expressions() + { + JsToken token; + + "a => 1".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrowFunctionExpression( + new JsIdentifier("a"), + new JsLiteral(1) + ))); + + "a => a + 1".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrowFunctionExpression( + new JsIdentifier("a"), + new JsBinaryExpression( + new JsIdentifier("a"), + JsAddition.Operator, + new JsLiteral(1) + ) + ))); + + "a=>a+1".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrowFunctionExpression( + new JsIdentifier("a"), + new JsBinaryExpression( + new JsIdentifier("a"), + JsAddition.Operator, + new JsLiteral(1) + ) + ))); + + "(a,b) => a + b".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrowFunctionExpression( + new[] + { + new JsIdentifier("a"), + new JsIdentifier("b"), + }, + new JsBinaryExpression( + new JsIdentifier("a"), + JsAddition.Operator, + new JsIdentifier("b") + ) + ))); + + "fn(a => a + b)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression(new JsIdentifier("fn"), + new JsArrowFunctionExpression( + new[] + { + new JsIdentifier("a"), + }, + new JsBinaryExpression( + new JsIdentifier("a"), + JsAddition.Operator, + new JsIdentifier("b") + ) + )))); + + "fn((a,b) => a + b)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression(new JsIdentifier("fn"), + new JsArrowFunctionExpression( + new[] + { + new JsIdentifier("a"), + new JsIdentifier("b"), + }, + new JsBinaryExpression( + new JsIdentifier("a"), + JsAddition.Operator, + new JsIdentifier("b") + ) + )))); + + "{ k: a => 1 }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsObjectExpression( + new JsProperty( + new JsIdentifier("k"), + new JsArrowFunctionExpression( + new JsIdentifier("a"), + new JsLiteral(1) + ) + )))); + } + + [Test] + public void Does_evaluate_shorthand_Arrow_Expressions() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> map(it => it * it) |> sum }}"), Is.EqualTo("14")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> map(n => n * n) |> sum }}"), Is.EqualTo("14")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> map => it * it |> sum }}"), Is.EqualTo("14")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> where => it % 2 == 1 |> map => it * it |> sum }}"), Is.EqualTo("10")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> all => it > 2 |> lower }}"), Is.EqualTo("false")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> any => it > 2 |> show: Y }}"), Is.EqualTo("Y")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> orderByDesc => it |> join }}"), Is.EqualTo("3,2,1")); + + Assert.That(context.EvaluateScript("{{ [3,2,1] |> orderBy => it |> join }}"), Is.EqualTo("1,2,3")); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> map => it * it |> assignTo => values }}{{ values |> sum }}"), Is.EqualTo("14")); + + Assert.That(context.EvaluateScript("{{ ['A','B','C'] |> map => lower(it) |> map => `${it}` |> join('') }}"), Is.EqualTo("abc")); + + Assert.That(context.EvaluateScript("{{ ['A','B','C'] |> map => lower(it) |> map => `${it}` |> concat }}"), Is.EqualTo("abc")); + } + + [Test] + public void Does_evaluate_let_bindings_Arrow_Expressions() + { + var context = new ScriptContext + { + Args = + { + ["people"] = new[] { new Person("name1", 1), new Person("name2", 2), new Person("name3", 3), } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ [1,2,3] |> let => { a: it * it, b: isOdd(it) } |> select: ({a},{b}), }}"), + Is.EqualTo("(1,True),(4,False),(9,True),")); + + Assert.That(context.EvaluateScript("{{ people |> let => { a: it.Name, b: it.Age * 2 } |> select: ({a},{b}), }}"), + Is.EqualTo("(name1,2),(name2,4),(name3,6),")); + + Assert.That(context.EvaluateScript("{{ people |> let => { it.Name, it.Age } |> select: ({Name},{Age}), }}"), + Is.EqualTo("(name1,1),(name2,2),(name3,3),")); + + Assert.That(context.EvaluateScript("{{ people |> map => { it.Name, it.Age } |> select: ({it.Name},{it.Age}), }}"), + Is.EqualTo("(name1,1),(name2,2),(name3,3),")); + } + + [Test] + public void Does_evaluate_toDictionary_Arrow_Expressions() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@"{{ [{name:'Alice',score:50},{name:'Bob',score:40},{name:'Cathy',score:45}] |> assignTo=>scoreRecords }} +Bob's score: {{ scoreRecords + |> toDictionary => it.name + |> map => it.Bob + |> select: { it.name } = { it.score } +}}"), Is.EqualTo("Bob's score: Bob = 40")); + } + + [Test] + public void Does_evaluate_reduce_Arrow_Expressions() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@"{{ [20, 10, 40, 50, 10, 70, 30] |> assignTo: attemptedWithdrawals }} +{{ attemptedWithdrawals + |> reduce((balance, nextWithdrawal) => ((nextWithdrawal <= balance) ? (balance - nextWithdrawal) : balance), + { initialValue: 100.0, }) + |> select: Ending balance: { it }. }}"), + Is.EqualTo("Ending balance: 20.")); + } + + public class AnagramEqualityComparer : IEqualityComparer<string> + { + public bool Equals(string x, string y) => GetCanonicalString(x) == GetCanonicalString(y); + public int GetHashCode(string obj) => GetCanonicalString(obj).GetHashCode(); + private string GetCanonicalString(string word) + { + var wordChars = word.ToCharArray(); + Array.Sort(wordChars); + return new string(wordChars); + } + } + + [Test] + public void Does_evaluate_groupBy_Arrow_Expressions() + { + var context = new ScriptContext + { + Args = + { + ["anagramComparer"] = new AnagramEqualityComparer() + } + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ ['from ', ' salt', ' earn ', ' last ', ' near ', ' form '] |> assignTo: anagrams }} +{{#each groupBy(anagrams, w => trim(w), { map: x => upper(x), comparer: anagramComparer }) }}{{it |> json}}{{/each}}"), + Is.EqualTo(@"[""FROM "","" FORM ""]["" SALT"","" LAST ""]["" EARN "","" NEAR ""]")); + } + + class MyFilters : ScriptMethods + { + public double pow(double arg1, double arg2) => arg1 / arg2; + } + + [Test] + public void Can_Invoke_Arrow_Expressions() + { + var context = new ScriptContext().Init(); + + var expr = JS.expression("pow(2,2) + pow(4,2)"); + Assert.That(expr.Evaluate(), Is.EqualTo(20)); + + Assert.That(JS.eval("pow(2,2) + pow(4,2)"), Is.EqualTo(20)); + + var scope = JS.CreateScope(args: new Dictionary<string, object> { + ["a"] = 2, + ["b"] = 4, + }); + Assert.That(JS.eval("pow(a,2) + pow(b,2)", scope), Is.EqualTo(20)); + + var customPow = JS.CreateScope(functions: new MyFilters()); + Assert.That(JS.eval("pow(2,2) + pow(4,2)", customPow), Is.EqualTo(3)); + + var arrowExpr = (JsArrowFunctionExpression)JS.expression("(a,b) => pow(a,2) + pow(b,2)"); + + Assert.That(arrowExpr.Invoke(2,4), Is.EqualTo(20)); + + Assert.That(arrowExpr.Invoke(customPow, 2,4), Is.EqualTo(3)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsAssignmentTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsAssignmentTests.cs new file mode 100644 index 00000000000..ef337ab1f9b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsAssignmentTests.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsAssignmentTests + { + [Test] + public void Does_parse_assignment_expressions() + { + JsToken token; + + "a = 1 == 2 ? 3 : 4".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsAssignmentExpression( + new JsIdentifier("a"), + JsAssignment.Operator, + new JsConditionalExpression( + new JsBinaryExpression(new JsLiteral(1), JsEquals.Operator, new JsLiteral(2)), + new JsLiteral(3), + new JsLiteral(4)) + ))); + } + + + [Test] + public void Can_assign_local_Variables() + { + var context = new ScriptContext().Init(); + + var pageResult = new PageResult(context.OneTimePage("{{ var a = 1 }}a == {{a}}")); + var output = pageResult.RenderScript(); + Assert.That(output, Is.EqualTo("a == 1")); + + pageResult = new PageResult(context.OneTimePage("{{ var a = 1, b = 1 + 1 }}b == {{b}}")); + output = pageResult.RenderScript(); + Assert.That(output, Is.EqualTo("b == 2")); + + pageResult = new PageResult(context.OneTimePage("{{ var a = 1 }}:{{ a = 2 }}:a == {{a}}")); + output = pageResult.RenderScript(); + Assert.That(output, Is.EqualTo(":2:a == 2")); + Assert.That(!pageResult.Args.ContainsKey("a")); + } + + [Test] + public void Can_assign_global_Variables() + { + var context = new ScriptContext().Init(); + + var pageResult = new PageResult(context.OneTimePage("a == {{a = 1}}")); + var output = pageResult.RenderScript(); + Assert.That(output, Is.EqualTo("a == 1")); + Assert.That(pageResult.Args["a"], Is.EqualTo(1)); + + pageResult = new PageResult(context.OneTimePage("g == {{global.g = 1}}")); + output = pageResult.RenderScript(); + Assert.That(pageResult.Args["g"], Is.EqualTo(1)); + Assert.That(output, Is.EqualTo("g == 1")); + + pageResult = new PageResult(context.OneTimePage("g == {{global['g'] = 2}}")); + output = pageResult.RenderScript(); + Assert.That(pageResult.Args["g"], Is.EqualTo(2)); + Assert.That(output, Is.EqualTo("g == 2")); + } + + public class GrandNestedPerson + { + public NestedPerson Nested { get; set; } + } + + public class NestedPerson + { + public Person A { get; set; } + } + + [Test] + public void Can_assign_collections_and_pocos() + { + void populateArgs(Dictionary<string, object> args) + { + args["intList"] = new List<int> { 1, 2, 3 }; + args["intArray"] = new[] { 1, 2, 3 }; + args["stringList"] = new List<string> { "a", "b", "c" }; + args["stringArray"] = new [] { "a", "b", "c" }; + args["intMap"] = new Dictionary<string, int> { + ["a"] = 1, + ["b"] = 2, + ["c"] = 3, + }; + args["stringMap"] = new Dictionary<string, string> { + ["a"] = "A", + ["b"] = "B", + ["c"] = "C", + }; + args["person"] = new Person { + Age = 27, + Name = "Kurt", + }; + args["nestedObjectMap"] = new Dictionary<string, object> { + ["person"] = new Person { + Age = 27, + Name = "Kurt", + }, + ["nestedPerson"] = new NestedPerson { + A = new Person + { + Age = 27, + Name = "Kurt", + } + }, + ["grandNestedPerson"] = new GrandNestedPerson + { + Nested = new NestedPerson { + A = new Person + { + Age = 27, + Name = "Kurt", + } + } + } + }; + args["grandNestedPerson"] = new GrandNestedPerson { + Nested = new NestedPerson { + A = new Person { + Age = 27, + Name = "Kurt", + } + } + }; + } + + var context = new ScriptContext(); + populateArgs(context.Args); + context.Init(); + + void assert<T>(string src, string expectedOutput, Func<Dictionary<string,object>, T> actual, T expected) + { + var pageResult = new PageResult(context.OneTimePage(src)); + var output = pageResult.RenderScript(); + Assert.That(output, Is.EqualTo(expectedOutput)); + Assert.That(actual(context.Args), Is.EqualTo(expected)); + + var local = new ScriptContext().Init(); + pageResult = new PageResult(local.OneTimePage(src)); + populateArgs(pageResult.Args); + output = pageResult.RenderScript(); + Assert.That(output, Is.EqualTo(expectedOutput)); + Assert.That(actual(pageResult.Args), Is.EqualTo(expected)); + } + + assert("intList[1] == {{ intList[1] = 4 }}", "intList[1] == 4", + args => ((List<int>)args["intList"])[1], 4); + + assert("intArray[1] == {{ intArray[1] = 4 }}", "intArray[1] == 4", + args => ((int[])args["intArray"])[1], 4); + + assert("stringList[1] == {{ stringList[1] = 'D' }}", "stringList[1] == D", + args => ((List<string>)args["stringList"])[1], "D"); + + assert("stringArray[1] == {{ stringArray[1] = 'D' }}", "stringArray[1] == D", + args => ((string[])args["stringArray"])[1], "D"); + + assert("intMap['b'] == {{ intMap['b'] = 4 }}", "intMap['b'] == 4", + args => ((Dictionary<string, int>)args["intMap"])["b"], 4); + + assert("stringMap['b'] == {{ stringMap['b'] = 'D' }}", "stringMap['b'] == D", + args => ((Dictionary<string, string>)args["stringMap"])["b"], "D"); + + assert("intMap.b == {{ intMap.b = 4 }}", "intMap.b == 4", + args => ((Dictionary<string, int>)args["intMap"])["b"], 4); + + assert("stringMap.b == {{ stringMap.b = 'D' }}", "stringMap.b == D", + args => ((Dictionary<string, string>)args["stringMap"])["b"], "D"); + + assert("person.Age == {{ person.Age = 30 }}", "person.Age == 30", + args => ((Person)args["person"]).Age, 30); + assert("person.Name == {{ person.Name = 'Eddie' }}", "person.Name == Eddie", + args => ((Person)args["person"]).Name, "Eddie"); + + assert("nestedObjectMap['person'].Age == {{ nestedObjectMap['person'].Age = 30 }}", "nestedObjectMap['person'].Age == 30", + args => ((Person)((Dictionary<string,object>)args["nestedObjectMap"])["person"]).Age, 30); + assert("nestedObjectMap['per' + 'son'].Name == {{ nestedObjectMap['per' + 'son'].Name = 'Eddie' }}", "nestedObjectMap['per' + 'son'].Name == Eddie", + args => ((Person)((Dictionary<string,object>)args["nestedObjectMap"])["person"]).Name, "Eddie"); + + assert("nestedObjectMap.person.Age == {{ nestedObjectMap.person.Age = 30 }}", "nestedObjectMap.person.Age == 30", + args => ((Person)((Dictionary<string,object>)args["nestedObjectMap"])["person"]).Age, 30); + assert("nestedObjectMap.person.Name == {{ nestedObjectMap.person.Name = 'Eddie' }}", "nestedObjectMap.person.Name == Eddie", + args => ((Person)((Dictionary<string,object>)args["nestedObjectMap"])["person"]).Name, "Eddie"); + + assert("nestedObjectMap['nestedPerson'].A.Age == {{ nestedObjectMap['nestedPerson'].A.Age = 30 }}", "nestedObjectMap['nestedPerson'].A.Age == 30", + args => ((NestedPerson)((Dictionary<string,object>)args["nestedObjectMap"])["nestedPerson"]).A.Age, 30); + assert("nestedObjectMap['nestedPerson'].A.Name == {{ nestedObjectMap['nestedPerson'].A.Name = 'Eddie' }}", "nestedObjectMap['nestedPerson'].A.Name == Eddie", + args => ((NestedPerson)((Dictionary<string,object>)args["nestedObjectMap"])["nestedPerson"]).A.Name, "Eddie"); + + assert("nestedObjectMap['grandNestedPerson'].Nested.A.Age == {{ nestedObjectMap['grandNestedPerson'].Nested.A.Age = 30 }}", "nestedObjectMap['grandNestedPerson'].Nested.A.Age == 30", + args => ((GrandNestedPerson)((Dictionary<string,object>)args["nestedObjectMap"])["grandNestedPerson"]).Nested.A.Age, 30); + assert("nestedObjectMap['grandNestedPerson'].Nested.A.Name == {{ nestedObjectMap['grandNestedPerson'].Nested.A.Name = 'Eddie' }}", "nestedObjectMap['grandNestedPerson'].Nested.A.Name == Eddie", + args => ((GrandNestedPerson)((Dictionary<string,object>)args["nestedObjectMap"])["grandNestedPerson"]).Nested.A.Name, "Eddie"); + + assert("grandNestedPerson.Nested.A.Age == {{ grandNestedPerson.Nested.A.Age = 30 }}", "grandNestedPerson.Nested.A.Age == 30", + args => ((GrandNestedPerson)args["grandNestedPerson"]).Nested.A.Age, 30); + assert("grandNestedPerson.Nested.A.Name == {{ grandNestedPerson.Nested.A.Name = 'Eddie' }}", "grandNestedPerson.Nested.A.Name == Eddie", + args => ((GrandNestedPerson)args["grandNestedPerson"]).Nested.A.Name, "Eddie"); + + + assert("intList[1.isOdd() ? 2 : 3] == {{ intList[1.isOdd() ? 2 : 3] = 4 }}", "intList[1.isOdd() ? 2 : 3] == 4", + args => ((List<int>)args["intList"])[1+1], 4); + + assert("stringMap[1.isEven() ? 'a' : 'b'] == {{ stringMap[1.isEven() ? 'a' : 'b'] = 'D' }}", "stringMap[1.isEven() ? 'a' : 'b'] == D", + args => ((Dictionary<string, string>)args["stringMap"])["b"], "D"); + } + + [Test] + public void Variable_declarations_truncate_their_whitespace() + { + var context = new ScriptContext().Init(); + + var output = context.RenderScript(@"{{ var a = 1 }} +{{ var b = 2 }} +{{ var c = 3 }} +a + b + c = {{ a + b + c }}"); + + Assert.That(output, Is.EqualTo("a + b + c = 6")); + } + + [Test] + public void Variable_declarations_does_return_an_null_value() + { + var context = new ScriptContext().Init(); + + var output = context.RenderScript(@"{{ isNull(var a = 1) }}:{{a}}"); + + Assert.That(output, Is.EqualTo("True:1")); + } + + [Test] + public void Does_assign_entire_expression() + { + var context = new ScriptContext().Init(); + var output = context.RenderScript(@" +```code|q +var optional = [] +var key = 'a' +key = optional.contains(key) ? `${key}?` : key +``` +{{key}}"); + output.Print(); + Assert.That(output.Trim(), Is.EqualTo("a")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsAstTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsAstTests.cs new file mode 100644 index 00000000000..4f768ab2708 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsAstTests.cs @@ -0,0 +1,133 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsAstTests + { + [Test] + public void Can_use_ToJsAst_to_generate_Esprima_AST() + { + JsToken token = JS.expression("{ key: a.prop == 1 ? b < 2 : c > 3 }"); + +// "{ key: a.prop == 1 ? b < 2 : c > 3 }".ParseJsExpression(out token); + + Dictionary<string, object> ast = token.ToJsAst(); + + ast.ToJson().IndentJson().Print(); + + var expected = new Dictionary<string, object> { + ["type"] = "ObjectExpression", + ["properties"] = new List<object> { + new Dictionary<string, object> { + ["type"] = "Property", + ["key"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "key", + }, + ["computed"] = false, + ["value"] = new Dictionary<string, object> { + ["type"] = "ConditionalExpression", + ["test"] = new Dictionary<string, object> { + ["type"] = "BinaryExpression", + ["operator"] = "==", + ["left"] = new Dictionary<string, object> { + ["type"] = "MemberExpression", + ["computed"] = false, + ["object"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "a", + }, + ["property"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "prop", + } + }, + ["right"] = new Dictionary<string, object> { + ["type"] = "Literal", + ["value"] = 1, + ["raw"] = "1", + }, + }, + ["consequent"] = new Dictionary<string, object> { + ["type"] = "BinaryExpression", + ["operator"] = "<", + ["left"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "b", + }, + ["right"] = new Dictionary<string, object> { + ["type"] = "Literal", + ["value"] = 2, + ["raw"] = "2", + }, + }, + ["alternate"] = new Dictionary<string, object> { + ["type"] = "BinaryExpression", + ["operator"] = ">", + ["left"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "c", + }, + ["right"] = new Dictionary<string, object> { + ["type"] = "Literal", + ["value"] = 3, + ["raw"] = "3", + }, + }, + }, + ["kind"] = "init", + ["method"] = false, + ["shorthand"] = false, + } + } + }; + + "Expected: ".Print(); + expected.ToJson().IndentJson().Print(); + + Assert.That(ast, Is.EqualTo(expected)); + } + + [Test] + public void Does_support_ast_with_null() + { + JsToken token; + + "a > b ? a : null".ParseJsExpression(out token); + + var ast = token.ToJsAst(); + + token.ToJsAstString().Print(); + + var expected = new Dictionary<string, object> { + ["type"] = "ConditionalExpression", + ["test"] = new Dictionary<string, object> { + ["type"] = "BinaryExpression", + ["operator"] = ">", + ["left"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "a", + }, + ["right"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "b", + }, + }, + ["consequent"] = new Dictionary<string, object> { + ["type"] = "Identifier", + ["name"] = "a", + }, + ["alternate"] = new Dictionary<string, object> { + ["type"] = "Literal", + ["value"] = null, + ["raw"] = "null", + }, + }; + + Assert.That(ast, Is.EqualTo(expected)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsLiteralTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsLiteralTests.cs new file mode 100644 index 00000000000..4a1710c40f6 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsLiteralTests.cs @@ -0,0 +1,198 @@ +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsLiteralTests + { + [Test] + public void Can_parse_simple_TemplateLiterals() + { + JsToken token; + + "``".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { new JsTemplateElement("","", tail:true) }))); + + "`a`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { new JsTemplateElement("a","a", tail:true) }))); + + "1.0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(1.0))); + + var hold = ScriptConfig.ParseRealNumber; + ScriptConfig.ParseRealNumber = numLiteral => numLiteral.ParseDecimal(); + + "1.0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(1.0m))); + + ScriptConfig.ParseRealNumber = hold; + + "`a${b}`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("a","a"), + new JsTemplateElement("","", tail:true), + }, + new[] { new JsIdentifier("b") }))); + + "`a ${b} c`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("a ","a "), + new JsTemplateElement(" c"," c", tail:true), + }, + new[] { new JsIdentifier("b") }))); + + "`a ${b + 1} c ${incr(d + 1)}`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("a ","a "), + new JsTemplateElement(" c "," c "), + new JsTemplateElement("","", tail:true) + }, + new JsToken[] { + new JsBinaryExpression( + new JsIdentifier("b"), + JsAddition.Operator, + new JsLiteral(1) + ), + new JsCallExpression( + new JsIdentifier("incr"), + new JsBinaryExpression( + new JsIdentifier("d"), + JsAddition.Operator, + new JsLiteral(1) + ) + ), + }))); + + "`\"\"`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("\"\"", "\"\"", tail:true), + } + ))); + + "`''`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("''", "''", tail:true), + } + ))); + + @"`""#key"".replace(/\\s+/g,'')`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement( + "\"#key\".replace(/\\\\s+/g,'')", + "\"#key\".replace(/\\s+/g,'')", + tail:true), + } + ))); + + "`${a}${b}`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("",""), + new JsTemplateElement("",""), + new JsTemplateElement("","", tail:true), + }, + new[] { new JsIdentifier("a"), new JsIdentifier("b") }))); + + } + + [Test] + public void Can_parse_strings_with_escape_chars() + { + JsToken token; + + @"′\\′".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(@"\\"))); + } + + [Test] + public void Can_parse_TemplateLiterals_with_escape_chars() + { + JsToken token; + + @"`${a}\${b}`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("",""), + new JsTemplateElement(@"\${b}","${b}", tail:true), + }, + new[] { new JsIdentifier("a") }))); + + @"`${a}\\${b}`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("",""), + new JsTemplateElement(@"\\",@"\"), + new JsTemplateElement("","", tail:true), + }, + new[] { new JsIdentifier("a"), new JsIdentifier("b") }))); + + @"`${a}\\\${b}`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { + new JsTemplateElement("",""), + new JsTemplateElement(@"\\\${b}",@"\${b}", tail:true), + }, + new[] { new JsIdentifier("a") }))); + + @"`\\`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { new JsTemplateElement("\\\\","\\", tail:true) }))); + + @"`\\ \n`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral( + new[] { new JsTemplateElement(@"\\ \n","\\ \n", tail:true) }))); + } + + [Test] + public void Can_evaluate_TemplateLiterals_with_escape_chars() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript(@"{{ `\\` }}"), + Is.EqualTo(@"\")); + + Assert.That(context.EvaluateScript(@"{{ `\\ \n` }}"), + Is.EqualTo("\\ \n")); + + Assert.That(context.EvaluateScript(@"{{ `""#key"".replace(/\\s+/g,'')` |> raw }}"), + Is.EqualTo(@"""#key"".replace(/\s+/g,'')")); + } + + [Test] + public void Does_evaluate_TemplateLiteral() + { + var context = new ScriptContext { + Args = { + ["a"] = 1, + ["b"] = 2, + ["c"] = 3, + ["d"] = 4, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{``}}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{`a`}}"), Is.EqualTo("a")); + Assert.That(context.EvaluateScript("{{`a${b}`}}"), Is.EqualTo("a2")); + Assert.That(context.EvaluateScript("{{`a ${b} c`}}"), Is.EqualTo("a 2 c")); + Assert.That(context.EvaluateScript("{{`a ${b + 1} c ${incr(d + 1)}`}}"), Is.EqualTo("a 3 c 6")); + Assert.That(context.EvaluateScript("{{`\n`}}"), Is.EqualTo("\n")); + Assert.That(context.EvaluateScript("{{`a\n${b}`}}"), Is.EqualTo("a\n2")); + Assert.That(context.EvaluateScript("{{`\"\"` |> raw}}"), Is.EqualTo("\"\"")); + Assert.That(context.EvaluateScript("{{`''` |> raw}}"), Is.EqualTo("''")); + Assert.That(context.EvaluateScript("{{`a\"b\"c` |> raw}}"), Is.EqualTo("a\"b\"c")); + Assert.That(context.EvaluateScript("{{`a'b'c` |> raw}}"), Is.EqualTo("a'b'c")); + + Assert.That(context.EvaluateScript("{{`a\"b\"c` |> appendTo: a}}{{ a |> raw }}"), Is.EqualTo("a\"b\"c")); + Assert.That(context.EvaluateScript("{{`${a}\\\\${b}`}}"), Is.EqualTo("1\\2")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsLogicalExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsLogicalExpressionTests.cs new file mode 100644 index 00000000000..fabd7aeb701 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsLogicalExpressionTests.cs @@ -0,0 +1,186 @@ +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsLogicalExpressionTests + { + [Test] + public void Does_parse_logical_expressions() + { + JsToken token; + + "a && b".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsIdentifier("a"), + JsAnd.Operator, + new JsIdentifier("b") + ))); + + "a || b".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsIdentifier("a"), + JsOr.Operator, + new JsIdentifier("b") + ))); + + "a || b && c || d".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsLogicalExpression( + new JsIdentifier("a"), + JsOr.Operator, + new JsLogicalExpression( + new JsIdentifier("b"), + JsAnd.Operator, + new JsIdentifier("c") + ) + ), + JsOr.Operator, + new JsIdentifier("d") + ))); + + "(a || b) && (c || d)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsLogicalExpression( + new JsIdentifier("a"), + JsOr.Operator, + new JsIdentifier("b") + ), + JsAnd.Operator, + new JsLogicalExpression( + new JsIdentifier("c"), + JsOr.Operator, + new JsIdentifier("d") + ) + ) + )); + } + + [Test] + public void Does_parse_logical_expressions_using_keyword_operators() + { + JsToken token; + + "a and b".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsIdentifier("a"), + JsAnd.Operator, + new JsIdentifier("b") + ))); + + "a or b".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsIdentifier("a"), + JsOr.Operator, + new JsIdentifier("b") + ))); + + "a or b and c or d".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsLogicalExpression( + new JsIdentifier("a"), + JsOr.Operator, + new JsLogicalExpression( + new JsIdentifier("b"), + JsAnd.Operator, + new JsIdentifier("c") + ) + ), + JsOr.Operator, + new JsIdentifier("d") + ))); + + "(a or b) and (c or d)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLogicalExpression( + new JsLogicalExpression( + new JsIdentifier("a"), + JsOr.Operator, + new JsIdentifier("b") + ), + JsAnd.Operator, + new JsLogicalExpression( + new JsIdentifier("c"), + JsOr.Operator, + new JsIdentifier("d") + ) + ) + )); + } + + [Test] + public void Does_parse_ConditionalExpression() + { + JsToken token; + + "a ? b : c".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsConditionalExpression( + new JsIdentifier("a"), + new JsIdentifier("b"), + new JsIdentifier("c") + ))); + + "(1 < 2) ? 3 + 4 : -5 + (add(6,a) + 7)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsConditionalExpression( + new JsBinaryExpression( + new JsLiteral(1), + JsLessThan.Operator, + new JsLiteral(2) + ), + new JsBinaryExpression( + new JsLiteral(3), + JsAddition.Operator, + new JsLiteral(4) + ), + new JsBinaryExpression( + new JsUnaryExpression(JsMinus.Operator, new JsLiteral(5)), + JsAddition.Operator, + new JsBinaryExpression( + new JsCallExpression( + new JsIdentifier("add"), + new JsLiteral(6), + new JsIdentifier("a") + ), + JsAddition.Operator, + new JsLiteral(7) + ) + ) + ))); + + "1 + 2 > subtract(3, 4) ? 'YES' : 'NO'".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsConditionalExpression( + new JsBinaryExpression( + new JsBinaryExpression( + new JsLiteral(1), + JsAddition.Operator, + new JsLiteral(2) + ), + JsGreaterThan.Operator, + new JsCallExpression( + new JsIdentifier("subtract"), + new JsLiteral(3), + new JsLiteral(4) + ) + ), + new JsLiteral("YES"), + new JsLiteral("NO") + ))); + } + + [Test] + public void Does_evaluate_ConditionalExpression() + { + var context = new ScriptContext { + Args = { + ["varTrue"] = true, + ["varFalse"] = false, + ["a"] = 1, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ true ? 1 : 0 }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ false ? 1 : 0 }}"), Is.EqualTo("0")); + Assert.That(context.EvaluateScript("{{ (1 < 2) ? 3 + 4 : -5 + (add(6,a) + 7) }}"), Is.EqualTo("7")); + Assert.That(context.EvaluateScript("{{ 1 + 2 > subtract(3, 4) ? 'YES' : 'NO' }}"), Is.EqualTo("YES")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsMemberCallExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsMemberCallExpressionTests.cs new file mode 100644 index 00000000000..c3e01c6f4ca --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsMemberCallExpressionTests.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsMemberCallExpressionTests + { + [Test] + public void Does_parse_member_call_expressions() + { + JsToken token; + + "a.b()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("b") + ) + ))); + + "a[key]()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("key"), + computed:true + ) + ))); + + "a['key']()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsIdentifier("a"), + new JsLiteral("key"), + computed:true + ) + ))); + + "a.b.c[key]()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsMemberExpression( + new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("b") + ), + new JsIdentifier("c") + ), + new JsIdentifier("key"), + computed:true + )))); + + "toDateTime('2001-01-01').Day()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsCallExpression( + new JsIdentifier("toDateTime"), + new JsLiteral("2001-01-01") + ), + new JsIdentifier("Day") + ) + ))); + + "[toDateTime('2001-01-01')][0].Day()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsMemberExpression( + new JsArrayExpression( + new JsCallExpression( + new JsIdentifier("toDateTime"), + new JsLiteral("2001-01-01") + ) + ), + new JsLiteral(0), + computed:true + ), + new JsIdentifier("Day") + ) + ))); + } + + [Test] + public void Does_parse_member_call_expressions_on_literals() + { + JsToken token; + + "1.a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsLiteral(1), + new JsIdentifier("a") + ) + ))); + + "1.2.a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsLiteral(1.2), + new JsIdentifier("a") + ) + ))); + + "'a'.a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsLiteral("a"), + new JsIdentifier("a") + ) + ))); + + "[1].a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsArrayExpression(new JsLiteral(1)), + new JsIdentifier("a") + ) + ))); + + "{k:1}.a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsObjectExpression( + new JsProperty(new JsIdentifier("k"), new JsLiteral(1)) + ), + new JsIdentifier("a") + ) + ))); + + "''.a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsLiteral(""), + new JsIdentifier("a") + ) + ))); + + "[].a()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsArrayExpression(), + new JsIdentifier("a") + ) + ))); + } + + [Test] + public void Does_parse_member_call_expressions_on_literals_chained() + { + JsToken token; + + "1.a().b()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsCallExpression( + new JsMemberExpression( + new JsLiteral(1), + new JsIdentifier("a") + ) + ), + new JsIdentifier("b") + ) + ))); + + "1.2.a().b()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsCallExpression( + new JsMemberExpression( + new JsLiteral(1.2), + new JsIdentifier("a") + ) + ), + new JsIdentifier("b") + ) + ))); + + "'a'.a().b()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsCallExpression( + new JsMemberExpression( + new JsLiteral("a"), + new JsIdentifier("a") + ) + ), + new JsIdentifier("b") + ) + ))); + + "[1].a().b()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsCallExpression( + new JsMemberExpression( + new JsArrayExpression(new JsLiteral(1)), + new JsIdentifier("a") + ) + ), + new JsIdentifier("b") + ) + ))); + + "{k:1}.a().b()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsCallExpression( + new JsMemberExpression( + new JsObjectExpression( + new JsProperty(new JsIdentifier("k"), new JsLiteral(1)) + ), + new JsIdentifier("a") + ) + ), + new JsIdentifier("b") + ) + ))); + } + + [Test] + public void Does_parse_member_call_expressions_with_arrow_expression_args() + { + JsToken token; + + "a.b(x => x * 2)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("b") + ), + new JsArrowFunctionExpression( + new JsIdentifier("x"), + new JsBinaryExpression( + new JsIdentifier("x"), + JsMultiplication.Operator, + new JsLiteral(2) + ) + ) + ))); + } + + public class MyMethods : ScriptMethods + { + public object count(object target) => target == null + ? 0 + : target is string s + ? s.Length + : target is ICollection c + ? c.Count + : target is IEnumerable e + ? e.Cast<object>().Count() + : throw new NotSupportedException($"Cannot count '{target.GetType().Name}'"); + + public List<object> reverse(object target) => target == null + ? new List<object>() + : target is string s + ? s.Reverse().Cast<object>().ToList() + : target is IEnumerable e + ? e.Cast<object>().Reverse().ToList() + : throw new NotSupportedException($"Cannot count '{target.GetType().Name}'"); + + public double square(double target) => target * target; + } + + class TestTarget + { + public string String { get; set; } + + public int Int { get; set; } + public double Double { get; set; } + + public int[] Nums { get; set; } + } + + private static ScriptContext CreateScriptContext() + { + return new ScriptContext { + ScriptMethods = { new MyMethods() }, + Args = { + ["a"] = new TestTarget { + Int = 2, + String = "test", + Nums = new[] { 1,2,3 }, + }, + ["c"] = "count", + ["two"] = 2, + } + }; + } + + [Test] + public void Calling_method_with_no_args_on_members_calls_script_methods() + { + var context = CreateScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ a.String.count() }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ a.String['count']() }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ a.String[c]() }}"), Is.EqualTo("4")); + + Assert.That(context.EvaluateScript("{{ [1,2,3].count() }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ {a:1,b:2}.count() }}"), Is.EqualTo("2")); + + Assert.That(context.EvaluateScript("{{ [1,2,3].reverse().reverse().count() }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ a.Nums.reverse().reverse().count() }}"), Is.EqualTo("3")); + + Assert.That(context.EvaluateScript("{{ 2.square() }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ 2.square().square() }}"), Is.EqualTo("16")); + Assert.That(context.EvaluateScript("{{ two.square() }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ two.square().square() }}"), Is.EqualTo("16")); + + Assert.That(context.EvaluateScript("{{ a.String.count().square() }}"), Is.EqualTo("16")); + } + + [Test] + public void Can_call_methods_with_multiple_args() + { + var context = CreateScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 2.add(2) }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ two.add(two) }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ a.Int.add(two) }}"), Is.EqualTo("4")); + + Assert.That(context.EvaluateScript("{{ 2.add(2).add(2) }}"), Is.EqualTo("6")); + Assert.That(context.EvaluateScript("{{ two.add(two).add(two) }}"), Is.EqualTo("6")); + Assert.That(context.EvaluateScript("{{ a.Int.add(two).add(two) }}"), Is.EqualTo("6")); + Assert.That(context.EvaluateScript("{{ a.Int.add(a.Int.add(two)) }}"), Is.EqualTo("6")); + + Assert.That(context.EvaluateScript("{{ 'fmt {0} {1}'.fmt('a',2.add(2)) }}"), Is.EqualTo("fmt a 4")); + Assert.That(context.EvaluateScript("{{ 'fmt {0} {1} {2}'.fmt('a',2.add(2),a.Int.add(two).add(two)) }}"), Is.EqualTo("fmt a 4 6")); + } + + [Test] + public void Can_call_methods_with_multiple_args_and_scope() + { + var context = CreateScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'foo'.assign(2).add(foo) }}"), Is.EqualTo("4")); + } + + [Test] + public void Can_call_methods_with_spread_args() + { + var context = CreateScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'foo'.assign(...[2]).add(foo) }}"), Is.EqualTo("4")); + Assert.That(context.EvaluateScript("{{ 'fmt {0} {1}'.fmt(...['a',2.add(2)]) }}"), Is.EqualTo("fmt a 4")); + Assert.That(context.EvaluateScript("{{ 'fmt {0} {1} {2}'.fmt(...['a',2.add(2),a.Int.add(two).add(two)]) }}"), Is.EqualTo("fmt a 4 6")); + Assert.That(context.EvaluateScript("{{ 'fmt {0} {1} {2}'.fmt(...range(3)) }}"), Is.EqualTo("fmt 0 1 2")); + Assert.That(context.EvaluateScript("{{ 'fmt {0}'.fmt([...range(3)].count()) }}"), Is.EqualTo("fmt 3")); + } + + [Test] + public void Can_call_methods_with_arrow_expression_args() + { + var context = CreateScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2) |> join }}"), Is.EqualTo("2,4,6")); + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2).count() }}"), Is.EqualTo("3")); + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2).map(x => x.square()) |> join }}"), Is.EqualTo("4,16,36")); + + Assert.That(context.EvaluateScript("{{ a.Int.times().map(x => x + 2) |> join }}"), Is.EqualTo("2,3")); + Assert.That(context.EvaluateScript("{{ 'ABC'.repeat(3).count().divide(3).times().map(x => x + 2) |> join }}"), Is.EqualTo("2,3,4")); + + Assert.That(context.EvaluateScript("{{ 3.times().map(x => x[x.isEven() ? 'decr' : 'incr']()) |> join }}"), Is.EqualTo("-1,2,1")); + } + + [Test] + public void Does_stop_execution() + { + var context = CreateScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2).use('A') }}"), Is.EqualTo("A")); + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2).end().use('A') }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2).end().use('A') }}{{ 1 + 1 }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ a.Nums.map(x => x * 2).return().use('A') }}{{ 1 + 1 }}"), Is.EqualTo("")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsMemberExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsMemberExpressionTests.cs new file mode 100644 index 00000000000..b8b33bcd1bc --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsMemberExpressionTests.cs @@ -0,0 +1,231 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsMemberExpressionTests + { + [Test] + public void Does_parse_member_expressions() + { + JsToken token; + + "a".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsIdentifier("a"))); + "a.b".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("b") + ))); + "a[key]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("key"), + computed:true + ))); + "a['key']".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsIdentifier("a"), + new JsLiteral("key"), + computed:true + ))); + "a.b.c[key]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsMemberExpression( + new JsMemberExpression( + new JsIdentifier("a"), + new JsIdentifier("b") + ), + new JsIdentifier("c") + ), + new JsIdentifier("key"), + computed:true + ))); + + "a[1+1]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsIdentifier("a"), + new JsBinaryExpression( + new JsLiteral(1), + JsAddition.Operator, + new JsLiteral(1) + ), + computed:true + ))); + + "toDateTime('2001-01-01').Day".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsCallExpression( + new JsIdentifier("toDateTime"), + new JsLiteral("2001-01-01") + ), + new JsIdentifier("Day") + ))); + + "[toDateTime('2001-01-01')][0].Day".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsMemberExpression( + new JsMemberExpression( + new JsArrayExpression( + new JsCallExpression( + new JsIdentifier("toDateTime"), + new JsLiteral("2001-01-01") + ) + ), + new JsLiteral(0), + computed:true + ), + new JsIdentifier("Day") + ))); + } + + class A + { + public string Name { get; set; } + public A Prop { get; set; } + public Dictionary<string, object> StringDictionary { get; set; } + public A[] Array { get; set; } + public List<A> List { get; set; } + public IEnumerable<A> Enumerable { get; set; } + public string[] ArrayStrings { get; set; } + public int[] ArrayInts { get; set; } + public List<string> ListStrings { get; set; } + public List<int> ListInts { get; set; } + public Indexer Indexer { get; set; } + public IntIndexer IntIndexer { get; set; } + public StringIndexer StringIndexer { get; set; } + } + + class Indexer + { + public A this[string index] => new A { Name = index }; + } + class IntIndexer + { + public int this[int index] => index; + } + class StringIndexer + { + public string this[string index] => index; + } + + [Test] + public void Does_Evaluate_property_binding_expression() + { + var a = new A { Name = "foo", Prop = new A { Name = "bar", Prop = new A { Name = "qux" }}}; + var context = new ScriptContext { + Args = { + ["a"] = a + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ a.Name }}"), Is.EqualTo("foo")); + Assert.That(context.EvaluateScript("{{ a.Prop.Name }}"), Is.EqualTo("bar")); + Assert.That(context.EvaluateScript("{{ a.Prop.Prop.Name }}"), Is.EqualTo("qux")); + } + + [Test] + public void Does_Evaluate_property_collection_binding_expression() + { + var queue = new Queue<A>(); + queue.Enqueue(new A { Name = "enumerable[0]" }); + + var a = new A { + Prop = new A { Name = "prop" }, + Array = new []{ new A { Name = "array[0]" } }, + List = new List<A> { new A { Name = "list[0]" } }, + ArrayStrings = new[] { "A", "B", "C" }, + ArrayInts = new []{ 1 }, + ListStrings = new[] { "A", "B", "C" }.ToList(), + ListInts = new []{ 1 }.ToList(), + Enumerable = queue, + StringDictionary = new Dictionary<string, object> { + {"key", new A { Name = "StringDictionary[key]" }} + }, + Indexer = new Indexer(), + StringIndexer = new StringIndexer(), + IntIndexer = new IntIndexer(), + }; + var context = new ScriptContext { + Args = { + ["a"] = a, + ["keyName"] = "key", + ["propName"] = "Prop", + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ a.ArrayStrings[0] }}"), Is.EqualTo("A")); + Assert.That(context.EvaluateScript("{{ a.ArrayInts[0] }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ a.ListStrings[0] }}"), Is.EqualTo("A")); + Assert.That(context.EvaluateScript("{{ a.ListInts[0] }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ a.Array[0].Name }}"), Is.EqualTo("array[0]")); + Assert.That(context.EvaluateScript("{{ a.List[0].Name }}"), Is.EqualTo("list[0]")); + + Assert.That(context.EvaluateScript("{{ a.Enumerable[0].Name }}"), Is.EqualTo("enumerable[0]")); + Assert.That(context.EvaluateScript("{{ a.StringDictionary['key'].Name }}"), Is.EqualTo("StringDictionary[key]")); + Assert.That(context.EvaluateScript("{{ a.StringDictionary[keyName].Name }}"), Is.EqualTo("StringDictionary[key]")); + Assert.That(context.EvaluateScript("{{ a.StringDictionary.key.Name }}"), Is.EqualTo("StringDictionary[key]")); + + Assert.That(context.EvaluateScript("{{ a[propName].Name }}"), Is.EqualTo("prop")); + Assert.That(context.EvaluateScript("{{ a['Prop'].Name }}"), Is.EqualTo("prop")); + + Assert.That(context.EvaluateScript("{{ a.Indexer.idx.Name }}"), Is.EqualTo("idx")); + Assert.That(context.EvaluateScript("{{ a.Indexer['idx'].Name }}"), Is.EqualTo("idx")); + + Assert.That(context.EvaluateScript("{{ a.ArrayStrings[1+1] }}"), Is.EqualTo("C")); + Assert.That(context.EvaluateScript("{{ a.ListStrings[1+1] }}"), Is.EqualTo("C")); + Assert.That(context.EvaluateScript("{{ a['Pr' + 'op'].Name }}"), Is.EqualTo("prop")); + } + + [Test] + public void Can_evaluate_MemberExpression_of_Method() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ toDateTime('2001-01-01').Day }}"), Is.EqualTo("1")); + } + + [Test] + public void Can_evaluate_MemberExpression_of_Array() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ [toDateTime('2001-01-01')][0].Day }}"), Is.EqualTo("1")); + } + + [Test] + public void Index_access_to_non_existent_key_returns_null() + { + var a = new A { + StringDictionary = new Dictionary<string, object>() + }; + var context = new ScriptContext { + Args = { + ["a"] = a, + ["keyName"] = "key", + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ a.StringDictionary['notfound'] }}"), Is.EqualTo("")); + } + + [Test] + public void Index_access_to_non_existent_property_throws_ArgumentException() + { + var a = new A { + StringDictionary = new Dictionary<string, object>() + }; + var context = new ScriptContext { + Args = { + ["a"] = a, + ["keyName"] = "key", + } + }.Init(); + + Assert.Throws<ScriptException>(() => + context.EvaluateScript("{{ a.notfound }}")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsSpreadTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsSpreadTests.cs new file mode 100644 index 00000000000..3a21fd281d6 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsSpreadTests.cs @@ -0,0 +1,203 @@ +using System; +using System.Linq; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsSpreadTests + { + [Test] + public void Does_parse_ArrayExpression_with_spread_operator() + { + JsToken token; + + "[...a]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression( + new JsSpreadElement(new JsIdentifier("a")) + ))); + + "[...[1]]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression( + new JsSpreadElement(new JsArrayExpression( + new JsLiteral(1) + )) + ))); + + "[1, ...[2], 3]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression( + new JsLiteral(1), + new JsSpreadElement(new JsArrayExpression( + new JsLiteral(2) + )), + new JsLiteral(3) + ))); + } + + [Test] + public void Does_parse_ObjectExpression_with_spread_operator() + { + JsToken token; + + "{...a}".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsObjectExpression( + new JsProperty(null, new JsSpreadElement(new JsIdentifier("a"))) + ))); + + "{...{b:2}}".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsObjectExpression( + new JsProperty( + null, + new JsSpreadElement( + new JsObjectExpression( + new JsProperty(new JsIdentifier("b"), new JsLiteral(2)) + ) + ) + ) + ))); + + "{a:1, ...{b:2}, c:3}".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsObjectExpression( + new JsProperty(new JsIdentifier("a"), new JsLiteral(1)), + new JsProperty( + null, + new JsSpreadElement( + new JsObjectExpression( + new JsProperty(new JsIdentifier("b"), new JsLiteral(2)) + ) + ) + ), + new JsProperty(new JsIdentifier("c"), new JsLiteral(3)) + ))); + } + + [Test] + public void Does_parse_CallExpression_with_spread_operator() + { + JsToken token; + + "fn(...a)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsIdentifier("fn"), + new JsSpreadElement(new JsIdentifier("a")) + ))); + + "fn(...[1])".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsIdentifier("fn"), + new JsSpreadElement(new JsArrayExpression( + new JsLiteral(1) + )) + ))); + + "fn(1, ...[2], 3)".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsIdentifier("fn"), + new JsLiteral(1), + new JsSpreadElement(new JsArrayExpression( + new JsLiteral(2) + )), + new JsLiteral(3) + ))); + + "fn(...range(3))".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsIdentifier("fn"), + new JsSpreadElement( + new JsCallExpression( + new JsIdentifier("range"), + new JsLiteral(3) + ) + ) + ))); + } + + [Test] + public void Does_evaluate_ArrayExpression_with_spread_operator() + { + var context = new ScriptContext { + Args = { + ["a"] = new[]{ 2, 1 }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ [...a] |> sum }}"), Is.EqualTo("3")); + + Assert.That(context.EvaluateScript("{{ [...[2,1]] |> sum }}"), Is.EqualTo("3")); + + Assert.That(context.EvaluateScript("{{ [1, ...a, 4] |> sum }}"), Is.EqualTo("8")); + } + + [Test] + public void Does_evaluate_ObjectExpression_with_spread_operator() + { + var context = new ScriptContext { + Args = { + ["a"] = new{ b = 2, c = 3 }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ {...a}.b }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ {...{b:2,c:3}}.b }}"), Is.EqualTo("2")); + + Assert.That(context.EvaluateScript("{{ {...a} |> values |> sum }}"), Is.EqualTo("5")); + Assert.That(context.EvaluateScript("{{ {...{b:2,c:3}} |> values |> sum }}"), Is.EqualTo("5")); + + Assert.That(context.EvaluateScript("{{ { a:1, ...a, d:4} |> values |> sum }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ { a:1, ...{b:2,c:3}, d:4} |> values |> sum }}"), Is.EqualTo("10")); + + Assert.That(context.EvaluateScript("{{ { b:4, ...a, c:6} |> values |> sum }}"), Is.EqualTo("8")); + Assert.That(context.EvaluateScript("{{ { b:4, ...{b:2,c:3}, c:6} |> values |> sum }}"), Is.EqualTo("8")); + } + + [Test] + public void Spread_operator_does_cascade_object_properties() + { + var context = new ScriptContext { + Args = { + ["poco"] = new Person("foo", 1), + ["anon"] = new { Name = "bar", Age = 2 }, + ["foo"] = new Person("foo", 3), + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ {...poco}.Age }}"), Is.EqualTo("1")); + + Assert.That(context.EvaluateScript("{{ {...poco, ...anon}.Name }}"), Is.EqualTo("bar")); + Assert.That(context.EvaluateScript("{{ {...poco, ...anon}.Age }}"), Is.EqualTo("2")); + Assert.That(context.EvaluateScript("{{ {...poco, ...foo}.Age }}"), Is.EqualTo("3")); + } + + class MyFilters : ScriptMethods + { + public double Min2(double a, double b) => Math.Min(a, b); + public double Min3(double a, double b, double c) => new[]{ a,b,c }.Min(); + } + + [Test] + public void Does_evaluate_CallExpression_with_spread_operator() + { + var context = new ScriptContext { + Args = { + ["nums2"] = new[]{ 20,10 }, + ["nums3"] = new[]{ 20,10,1 }, + }, + ScriptMethods = { + new MyFilters() + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ Min2(...[20,10]) }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ Min2(...nums2) }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ Min3(...nums3) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> Min3(...[20,10]) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 30 |> Min3(...[20,10]) }}"), Is.EqualTo("10")); + + Assert.That(context.EvaluateScript("{{ Min3(30,...[20,10]) }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ Min3(30,...nums2) }}"), Is.EqualTo("10")); + Assert.That(context.EvaluateScript("{{ Min3(...[20,10],1) }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ Min3(...nums2,1) }}"), Is.EqualTo("1")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsTests.cs new file mode 100644 index 00000000000..2bb8b6dd7a4 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsTests.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsTests + { + public class HasObject + { + public object Value { get; set; } + } + + [Test] + public void Does_deserialize_late_bound_object_with_quotes() + { + var dto = new HasObject { + Value = "<bla fasel=\"hurz\" />" + }; + + var json = JSON.stringify(dto); + json.Print(); + + Assert.That(json, Is.EqualTo("{\"Value\":\"<bla fasel=\\\"hurz\\\" />\"}")); + + var obj = (Dictionary<string,object>)JSON.parse(json); + + Assert.That(obj["Value"], Is.EqualTo(dto.Value)); + + JS.Configure(); + + var fromJson = json.FromJson<HasObject>(); + + JS.UnConfigure(); + + Assert.That(fromJson.Value, Is.EqualTo(dto.Value)); + } + + [Test] + public void Can_parse_json_values() + { + Assert.That(JSON.parseSpan("true".AsSpan()), Is.EqualTo(true)); + Assert.That(JSON.parseSpan("false".AsSpan()), Is.EqualTo(false)); + Assert.That(JSON.parseSpan("1".AsSpan()), Is.EqualTo(1)); + Assert.That(JSON.parseSpan("1.1".AsSpan()), Is.EqualTo(1.1)); + Assert.That(JSON.parseSpan("foo".AsSpan()), Is.EqualTo("foo")); + Assert.That(JSON.parseSpan("null".AsSpan()), Is.EqualTo(null)); + Assert.That(JSON.parseSpan("[1]".AsSpan()), Is.EqualTo(new object[]{ 1 })); + Assert.That(JSON.parseSpan("{\"foo\":1}".AsSpan()), Is.EqualTo(new Dictionary<string,object> { ["foo"] = 1 })); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsonTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsonTests.cs new file mode 100644 index 00000000000..e138c1be886 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/JsonTests.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class JsonTests + { + [Test] + public void Does_escape_strings_in_JSON() + { + var json = @"{""app.settings"":""debug true\nname MyApp\n""}"; + var obj = (Dictionary<string,object>)JSON.parse(json); + + Assert.That(obj["app.settings"], Is.EqualTo("debug true\nname MyApp\n")); + } + + [Test] + public void Can_parse_escaped_json() + { + var json = "{\"content\": \"warn(\\n false,\\n \\\"props in \\\\\\\"\\\" + (route.path) + \\\"\\\\\\\" is a \\\" + (typeof config) + \\\", \\\" +\\n \\\"expecting an object, function or boolean.\\\"\\n );\"}"; + var obj = (Dictionary<string,object>)JSON.parse(json); + Assert.That(obj.ContainsKey("content")); + } + + [Test] + public void Does_throw_on_invalid_number() + { + try + { + JSON.parse(@"{""test"":23.34.3333}"); + Assert.Fail("should throw"); + } + catch (FormatException) {} + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/PageBasedRoutingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/PageBasedRoutingTests.cs new file mode 100644 index 00000000000..6a484dfa972 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/PageBasedRoutingTests.cs @@ -0,0 +1,126 @@ +using System.Collections.Generic; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; +using System.Collections.Generic; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class PageBasedRoutingTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(SharpPageTests), typeof(SharpPagesService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new SharpPagesFeature()); + } + + static readonly Dictionary<string,string> HtmlFiles = new Dictionary<string, string> + { + { "_layout.html", "<html><body>{{ page }}</body></html>" }, + { "_slug/index.html", "_slug/index.html slug: {{slug}}" }, + { "_slug/_category.html", "_slug/_category.html slug: {{slug}}, category: {{category}}" }, + { "comments/_postid/_id.html", "comments/_postid/_id.html postid: {{postid}}, id: {{id}}" }, + { "favorites/index.html", "favorites/index.html" }, + { "login/_provider.html", "login/_provider.html provider: {{provider}}" }, + { "organizations/_slug/index.html", "organizations/_slug/index.html slug: {{slug}}" }, + { "organizations/index.html", "organizations/index.html" }, + { "posts/_id/_postslug.html", "posts/_id/_postslug.html id: {{id}}, postslug: {{postslug}}" }, + { "stacks/index.html", "stacks/index.html" }, + { "stacks/new.html", "stacks/new.html" }, + { "stacks/_slug/index.html", "stacks/_slug/index.html slug: {{slug}}" }, + { "stacks/_slug/edit.html", "stacks/_slug/edit.html slug: {{slug}}" }, + { "tech/index.html", "tech/index.html" }, + { "tech/new.html", "tech/new.html" }, + { "tech/_slug/index.html", "tech/_slug/index.html slug: {{slug}}" }, + { "tech/_slug/edit.html", "tech/_slug/edit.html slug: {{slug}}" }, + { "top/index.html", "top/index.html" }, + { "users/_username.html", "users/_username.html username: {{username}}" }, + { "returnpages/index.html", "returnpages/index.html {{ return }} suffix" }, + { "returnpages/_arg.html", "returnpages/_arg.html {{arg}} {{ return }} suffix" }, + { "returnpages/if.html", "returnpages/if.html {{#if true}}{{ return }}{{/if}} suffix" }, + { "httpresults/index.html", "httpresults/index.html {{ {foo:'bar'} |> return({ format: 'json' }) }} suffix" }, + { "httpresults/explicit.html", "httpresults/explicit.html {{ {response: {foo:'bar'}, format: 'json'} |> httpResult |> return }} suffix" }, + { "httpresults/_arg.html", "httpresults/_arg.html {{ {foo:arg} |> return({ format: 'json' }) }} suffix" }, + { "httpresults/no-response.html", "httpresults/no-response.html {{ httpResult({ format: 'json' }) |> return }} suffix" }, + { "httpresults/redirect.html", "httpresults/redirect.html {{ httpResult({ status:'Found', Location:'/httpresults/redirected' }) |> return }} suffix" }, + { "httpresults/redirect-code.html", "httpresults/redirect.html {{ httpResult({ status:301, Location:'/httpresults/redirected-301' }) |> return }} suffix" }, + }; + + public override List<IVirtualPathProvider> GetVirtualFileSources() + { + var existingProviders = base.GetVirtualFileSources(); + var memFs = new MemoryVirtualFiles(); + + foreach (var entry in HtmlFiles) + { + memFs.AppendFile(entry.Key, entry.Value); + } + + existingProviders.Insert(0, memFs); + return existingProviders; + } + } + + private readonly ServiceStackHost appHost; + public PageBasedRoutingTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + [TestCase("/redis", "<html><body>_slug/index.html slug: redis</body></html>")] + [TestCase("/redis/", "<html><body>_slug/index.html slug: redis</body></html>")] + [TestCase("/redis/clients", "<html><body>_slug/_category.html slug: redis, category: clients</body></html>")] + [TestCase("/comments/1/2", "<html><body>comments/_postid/_id.html postid: 1, id: 2</body></html>")] + [TestCase("/favorites", "<html><body>favorites/index.html</body></html>")] + [TestCase("/login/github", "<html><body>login/_provider.html provider: github</body></html>")] + [TestCase("/organizations/redis", "<html><body>organizations/_slug/index.html slug: redis</body></html>")] + [TestCase("/organizations", "<html><body>organizations/index.html</body></html>")] + [TestCase("/posts/1/the-slug", "<html><body>posts/_id/_postslug.html id: 1, postslug: the-slug</body></html>")] + [TestCase("/stacks", "<html><body>stacks/index.html</body></html>")] + [TestCase("/stacks/new", "<html><body>stacks/new.html</body></html>")] + [TestCase("/stacks/redis", "<html><body>stacks/_slug/index.html slug: redis</body></html>")] + [TestCase("/stacks/redis/edit", "<html><body>stacks/_slug/edit.html slug: redis</body></html>")] + [TestCase("/tech", "<html><body>tech/index.html</body></html>")] + [TestCase("/tech/new", "<html><body>tech/new.html</body></html>")] + [TestCase("/tech/redis", "<html><body>tech/_slug/index.html slug: redis</body></html>")] + [TestCase("/tech/redis/edit", "<html><body>tech/_slug/edit.html slug: redis</body></html>")] + [TestCase("/top", "<html><body>top/index.html</body></html>")] + [TestCase("returnpages", "")] + [TestCase("returnpages/qux", "")] + [TestCase("returnpages/if", "")] + public void Can_use_page_based_routing(string path, string expectedHtml) + { + var html = Config.ListeningOn.CombineWith(path) + .GetStringFromUrl(); + + Assert.That(html, Is.EqualTo(expectedHtml)); + } + + [Test] + [TestCase("/httpresults", "{\"foo\":\"bar\"}")] + [TestCase("/httpresults/explicit", "{\"foo\":\"bar\"}")] + [TestCase("/httpresults/qux", "{\"foo\":\"qux\"}")] + [TestCase("/httpresults/no-response", "")] + [TestCase("/httpresults/redirect", "{\"foo\":\"redirected\"}")] + [TestCase("/httpresults/redirect-code", "{\"foo\":\"redirected-301\"}")] + public void Does_return_custom_result(string path, string expectedJson) + { + var response = Config.ListeningOn.CombineWith(path).GetStringFromUrl( + responseFilter:res => Assert.That(res.MatchesContentType(MimeTypes.Json))); + + Assert.That(response, Is.EqualTo(expectedJson)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ProtectedScriptsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ProtectedScriptsTests.cs new file mode 100644 index 00000000000..eaaaf645ffa --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ProtectedScriptsTests.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [Route("/includeUrl-echo")] + public class IncludeUrlEcho : IReturn<string> {} + + [Route("/includeUrl-model")] + public class IncludeUrlModel + { + public int Id { get; set; } + public string Name { get; set; } + } + + [Route("/includeUrl-models")] + public class IncludeUrlModels : List<IncludeUrlModel> {} + + [Route("/includeUrl-time")] + public class GetCurrentTime : IReturn<string> {} + + public class TemplatePageServices : Service + { + public object Any(IncludeUrlEcho request) => + $"{Request.Verb} {Request.RawUrl}"; + + public object Any(IncludeUrlModel request) => + request; + + public object Any(IncludeUrlModels request) => + request; + + public object Any(GetCurrentTime request) => + DateTime.Now.ToString("o"); + } + + public class ProtectedScriptsTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ProtectedScriptsTests), typeof(TemplatePageServices).Assembly) {} + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + UseCamelCase = false, //normalize with .NET Core + }); + + Plugins.Add(new SharpPagesFeature + { + Args = + { + ["baseUrl"] = Tests.Config.ListeningOn + } + }); + } + + private readonly List<IVirtualPathProvider> virtualFiles = new List<IVirtualPathProvider> { new MemoryVirtualFiles() }; + public override List<IVirtualPathProvider> GetVirtualFileSources() => virtualFiles; + } + + private readonly ServiceStackHost appHost; + public ProtectedScriptsTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_not_include_protected_filters_by_default() + { + var context = new ScriptContext().Init(); + context.VirtualFiles.WriteFile("index.txt", "file contents"); + + Assert.That(new PageResult(context.OneTimePage("{{ 'index.txt' |> includeFile }}")).Result, + Is.EqualTo("")); + + var feature = new SharpPagesFeature().Init(); + feature.VirtualFiles.WriteFile("index.txt", "file contents"); + + Assert.That(new PageResult(context.OneTimePage("{{ 'index.txt' |> includeFile }}")).Result, + Is.EqualTo("")); + } + + [Test] + public void Can_use_protected_includeFiles_in_context_or_PageResult() + { + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() } + }.Init(); + context.VirtualFiles.WriteFile("index.txt", "file contents"); + + Assert.That(new PageResult(context.OneTimePage("{{ 'index.txt' |> includeFile }}")).Result, + Is.EqualTo("file contents")); + } + + [Test] + public void Can_use_transformers_on_block_filter_outputs() + { + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() }, + FilterTransformers = + { + ["markdown"] = MarkdownPageFormat.TransformToHtml + } + }.Init(); + context.VirtualFiles.WriteFile("index.md", "## Markdown Heading"); + + Assert.That(new PageResult(context.OneTimePage("{{ 'index.md' |> includeFile |> markdown }}")).Result.Trim(), + Is.EqualTo("<h2>Markdown Heading</h2>")); + } + + [Test] + public void Can_use_includeUrl() + { + string urlContents; + var context = appHost.GetPlugin<SharpPagesFeature>(); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-echo') |> addQueryString({ id:1, name:'foo'}) |> includeUrl |> htmlencode }}")).Result; + Assert.That(urlContents, Is.EqualTo("GET /includeUrl-echo?id=1&amp;name=foo")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-model') |> addQueryString({ id:1, name:'foo'}) |> includeUrl({ accept: 'application/json' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("{\"Id\":1,\"Name\":\"foo\"}")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-model') |> addQueryString({ id:1, name:'foo'}) |> includeUrl({ dataType: 'json' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("{\"Id\":1,\"Name\":\"foo\"}")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-model') |> includeUrl({ method:'POST', data: { id: 1, name: 'foo' }, accept: 'application/jsv' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("{Id:1,Name:foo}")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-model') |> includeUrl({ method:'POST', data: { id: 1, name: 'foo' }, accept: 'application/json', contentType: 'application/json' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("{\"Id\":1,\"Name\":\"foo\"}")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-model') |> includeUrl({ method:'POST', data: { id: 1, name: 'foo' }, dataType: 'json' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("{\"Id\":1,\"Name\":\"foo\"}")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-model') |> includeUrl({ method:'POST', data: { id: 1, name: 'foo' }, dataType: 'jsv' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("{Id:1,Name:foo}")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-models') |> includeUrl({ method:'POST', data: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }], contentType:'application/json', accept: 'application/jsv' }) }}")).Result; + Assert.That(urlContents, Is.EqualTo("[{Id:1,Name:foo},{Id:2,Name:bar}]")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-models') |> includeUrl({ method:'POST', data: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }], contentType:'application/jsv', accept: 'text/csv' }) }}")).Result.NormalizeNewLines(); + Assert.That(urlContents, Is.EqualTo("Id,Name\n1,foo\n2,bar")); + + urlContents = new PageResult(context.OneTimePage( + "{{ baseUrl |> addPath('includeUrl-models') |> includeUrl({ method:'POST', data: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }], dataType:'csv' }) }}")).Result.NormalizeNewLines(); + Assert.That(urlContents, Is.EqualTo("Id,Name\n1,foo\n2,bar")); + } + + [Test] + public void Filter_includeFile_does_load_modiifed_contents() + { + var context = appHost.GetPlugin<SharpPagesFeature>(); + context.VirtualFiles.WriteFile("page.txt", "Original Content"); + + var includeFilePage = context.OneTimePage("{{ 'page.txt' |> includeFile }}"); + var fileContents = new PageResult(includeFilePage).Result; + Assert.That(fileContents, Is.EqualTo("Original Content")); + + context.VirtualFiles.WriteFile("page.txt", "Modified Content"); + fileContents = new PageResult(includeFilePage).Result; + Assert.That(fileContents, Is.EqualTo("Modified Content")); + } + + [Test] + public void Can_cache_contents_with_includeUrlWithCache_and_includeFileWithCache() + { + var context = appHost.GetPlugin<SharpPagesFeature>(); + context.VirtualFiles.WriteFile("page.txt", "Original Content"); + + var urlWithDefaultCache = context.OneTimePage("{{ baseUrl |> addPath('includeUrl-time') |> includeUrlWithCache }}"); + + var urlContents1 = new PageResult(urlWithDefaultCache).Result; + var urlContents2 = new PageResult(urlWithDefaultCache).Result; + Assert.That(urlContents1, Is.EqualTo(urlContents2)); + + Assert.That(new PageResult(context.OneTimePage("{{ 'page.txt' |> includeFileWithCache }}")).Result, Is.EqualTo("Original Content")); + context.VirtualFiles.WriteFile("page.txt", "Modified Content"); + + var fileWithCachePage = context.OneTimePage("{{ 'page.txt' |> includeFileWithCache({ expiresInSecs: 1 }) }}"); + var urlWithCache1Sec = context.OneTimePage("{{ baseUrl |> addPath('includeUrl-time') |> includeUrlWithCache({ expireInSecs: 1 }) }}"); + + urlContents1 = new PageResult(urlWithCache1Sec).Result; + + Thread.Sleep(TimeSpan.FromMilliseconds(1001)); + + urlContents2 = new PageResult(urlWithCache1Sec).Result; + Assert.That(urlContents1, Is.Not.EqualTo(urlContents2)); + + Assert.That(new PageResult(fileWithCachePage).Result, Is.EqualTo("Modified Content")); + } + + [Test] + public void Can_exclude_individual_filters() + { + var context = new ScriptContext + { + ExcludeFiltersNamed = { "includeUrl" }, + ScriptMethods = { new ProtectedScripts() }, + }.Init(); + + context.VirtualFiles.WriteFile("file.txt", "File Contents"); + + context.VirtualFiles.WriteFile("page.html", @" +includeUrl = {{ baseUrl |> addPath('includeUrl-time') |> includeUrl }} +includeFile = {{ 'file.txt' |> includeFile }} +"); + + Assert.Throws<NotSupportedException>(() => { + var ignore = new PageResult(context.GetPage("page")).Result; }); + } + + [Test] + public void Can_write_and_read_Contents_API() + { + var text = "abcdef"; + var bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() }, + Args = { + [nameof(text)] = text, + [nameof(bytes)] = bytes, + } + }.Init(); + + var textContents = (ReadOnlyMemory<char>) context.Evaluate(@" +{{ vfsMemory |> to => memFs }} +{{ memFs.writeFile('/dir/file.txt', text) }} +{{ memFs.fileContents('/dir/file.txt') |> return }}"); + Assert.That(textContents.Span.SequenceEqual(text.AsSpan())); + + var byteContents = (ReadOnlyMemory<byte>) context.Evaluate(@" +{{ vfsMemory |> to => memFs }} +{{ memFs.writeFile('/dir/file.bin', bytes) }} +{{ memFs.fileContents('/dir/file.bin') |> return }}"); + Assert.That(byteContents.Span.SequenceEqual(bytes)); + } + + #if NETFX + [Test] + public void Does_use_dollar_as_currency_symbol_when_InvariantCulture() + { + var hold = Thread.CurrentThread.CurrentCulture; + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + + var context = new ScriptContext().Init(); + + var output = context.EvaluateScript("{{ 12.345 |> currency }}"); + Assert.That(output, Is.EqualTo("$12.35")); + + Thread.CurrentThread.CurrentCulture = hold; + } + #endif + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryData.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryData.cs new file mode 100644 index 00000000000..f614e639159 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryData.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class Customer + { + public string CustomerId { get; set; } + public string CompanyName { get; set; } + public string Address { get; set; } + public string City { get; set; } + public string Region { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string Phone { get; set; } + public string Fax { get; set; } + public List<Order> Orders { get; set; } + + public override string ToString() => + $"Customer(customerId='{CustomerId}', companyName='{CompanyName}', orders='{Orders.Count}')"; + } + + public class Order + { + public int OrderId { get; set; } + public DateTime OrderDate { get; set; } + public double Total { get; set; } + } + + public class Product + { + public int ProductId { get; set; } + public string ProductName { get; set; } + public string Category { get; set; } + public double UnitPrice { get; set; } + public int UnitsInStock { get; set; } + + public Product() {} + public Product(int productId, string productName, string category, double unitPrice, int unitsInStock) + { + ProductId = productId; + ProductName = productName; + Category = category; + UnitPrice = unitPrice; + UnitsInStock = unitsInStock; + } + } + + public class QueryData + { + public static Product[] Products = + { + new Product(1, "Chai", "Beverages", 18.000, 39), + new Product(2, "Chang", "Beverages", 19.000, 17), + new Product(3, "Aniseed Syrup", "Condiments", 10.000, 13), + new Product(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.000, 53), + new Product(5, "Chef Anton's Gumbo Mix", "Condiments", 21.350, 0), + new Product(6, "Grandma's Boysenberry Spread", "Condiments", 25.000, 120), + new Product(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.000, 15), + new Product(8, "Northwoods Cranberry Sauce", "Condiments", 40.000, 6), + new Product(9, "Mishi Kobe Niku", "Meat/Poultry", 97.000, 29), + new Product(10, "Ikura", "Seafood", 31.000, 31), + new Product(11, "Queso Cabrales", "Dairy Products", 21.000, 22), + new Product(12, "Queso Manchego La Pastora", "Dairy Products", 38.000, 86), + new Product(13, "Konbu", "Seafood", 6.000, 24), + new Product(14, "Tofu", "Produce", 23.250, 35), + new Product(15, "Genen Shouyu", "Condiments", 15.500, 39), + new Product(16, "Pavlova", "Confections", 17.450, 29), + new Product(17, "Alice Mutton", "Meat/Poultry", 39.000, 0), + new Product(18, "Carnarvon Tigers", "Seafood", 62.500, 42), + new Product(19, "Teatime Chocolate Biscuits", "Confections", 9.200, 25), + new Product(20, "Sir Rodney's Marmalade", "Confections", 81.000, 40), + new Product(21, "Sir Rodney's Scones", "Confections", 10.000, 3), + new Product(22, "Gustaf's Kn\u00e4ckebr\u00f6d", "Grains/Cereals", 21.000, 104), + new Product(23, "Tunnbr\u00f6d", "Grains/Cereals", 9.000, 61), + new Product(24, "Guaran\u00e1 Fant\u00e1stica", "Beverages", 4.500, 20), + new Product(25, "NuNuCa Nu\u00df-Nougat-Creme", "Confections", 14.000, 76), + new Product(26, "Gumb\u00e4r Gummib\u00e4rchen", "Confections", 31.230, 15), + new Product(27, "Schoggi Schokolade", "Confections", 43.900, 49), + new Product(28, "R\u00f6ssle Sauerkraut", "Produce", 45.600, 26), + new Product(29, "Th\u00fcringer Rostbratwurst", "Meat/Poultry", 123.790, 0), + new Product(30, "Nord-Ost Matjeshering", "Seafood", 25.890, 10), + new Product(31, "Gorgonzola Telino", "Dairy Products", 12.500, 0), + new Product(32, "Mascarpone Fabioli", "Dairy Products", 32.000, 9), + new Product(33, "Geitost", "Dairy Products", 2.500, 112), + new Product(34, "Sasquatch Ale", "Beverages", 14.000, 111), + new Product(35, "Steeleye Stout", "Beverages", 18.000, 20), + new Product(36, "Inlagd Sill", "Seafood", 19.000, 112), + new Product(37, "Gravad lax", "Seafood", 26.000, 11), + new Product(38, "C\u00f4te de Blaye", "Beverages", 263.500, 17), + new Product(39, "Chartreuse verte", "Beverages", 18.000, 69), + new Product(40, "Boston Crab Meat", "Seafood", 18.400, 123), + new Product(41, "Jack's New England Clam Chowder", "Seafood", 9.650, 85), + new Product(42, "Singaporean Hokkien Fried Mee", "Grains/Cereals", 14.000, 26), + new Product(43, "Ipoh Coffee", "Beverages", 46.000, 17), + new Product(44, "Gula Malacca", "Condiments", 19.450, 27), + new Product(45, "Rogede sild", "Seafood", 9.500, 5), + new Product(46, "Spegesild", "Seafood", 12.000, 95), + new Product(47, "Zaanse koeken", "Confections", 9.500, 36), + new Product(48, "Chocolade", "Confections", 12.750, 15), + new Product(49, "Maxilaku", "Confections", 20.000, 10), + new Product(50, "Valkoinen suklaa", "Confections", 16.250, 65), + new Product(51, "Manjimup Dried Apples", "Produce", 53.000, 20), + new Product(52, "Filo Mix", "Grains/Cereals", 7.000, 38), + new Product(53, "Perth Pasties", "Meat/Poultry", 32.800, 0), + new Product(54, "Tourti\u00e8re", "Meat/Poultry", 7.450, 21), + new Product(55, "P\u00e2t\u00e9 chinois", "Meat/Poultry", 24.000, 115), + new Product(56, "Gnocchi di nonna Alice", "Grains/Cereals", 38.000, 21), + new Product(57, "Ravioli Angelo", "Grains/Cereals", 19.500, 36), + new Product(58, "Escargots de Bourgogne", "Seafood", 13.250, 62), + new Product(59, "Raclette Courdavault", "Dairy Products", 55.000, 79), + new Product(60, "Camembert Pierrot", "Dairy Products", 34.000, 19), + new Product(61, "Sirop d'\u00e9rable", "Condiments", 28.500, 113), + new Product(62, "Tarte au sucre", "Confections", 49.300, 17), + new Product(63, "Vegie-spread", "Condiments", 43.900, 24), + new Product(64, "Wimmers gute Semmelkn\u00f6del", "Grains/Cereals", 33.250, 22), + new Product(65, "Louisiana Fiery Hot Pepper Sauce", "Condiments", 21.050, 76), + new Product(66, "Louisiana Hot Spiced Okra", "Condiments", 17.000, 4), + new Product(67, "Laughing Lumberjack Lager", "Beverages", 14.000, 52), + new Product(68, "Scottish Longbreads", "Confections", 12.500, 6), + new Product(69, "Gudbrandsdalsost", "Dairy Products", 36.000, 26), + new Product(70, "Outback Lager", "Beverages", 15.000, 15), + new Product(71, "Flotemysost", "Dairy Products", 21.500, 26), + new Product(72, "Mozzarella di Giovanni", "Dairy Products", 34.800, 14), + new Product(73, "R\u00f6d Kaviar", "Seafood", 15.000, 101), + new Product(74, "Longlife Tofu", "Produce", 10.000, 4), + new Product(75, "Rh\u00f6nbr\u00e4u Klosterbier", "Beverages", 7.750, 125), + new Product(76, "Lakkalik\u00f6\u00f6ri", "Beverages", 18.000, 57), + new Product(77, "Original Frankfurter gr\u00fcne So\u00dfe", "Condiments", 13.000, 32) + }; + + private static List<Customer> customers; + public static List<Customer> Customers + { + get + { + if (customers != null) + return customers; + + var path = "~/App_Data/customers.json".MapAbsolutePath(); + var json = File.ReadAllText(path); + customers = json.FromJson<List<Customer>>(); + return customers; + } + } + + public static Customer GetCustomer(string id) => Customers.FirstOrDefault(x => x.CustomerId == id); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryExpressionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryExpressionTests.cs new file mode 100644 index 00000000000..0a65b4344f8 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryExpressionTests.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class QueryExpressionTests + { + [Test] + public void Does_parse_basic_QueryExpressions() + { + JsToken expr; + + "1".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsLiteral(1))); + + "1 > 2".ParseJsExpression(out expr); + Assert.That(expr, + Is.EqualTo(new JsBinaryExpression(new JsLiteral(1), JsGreaterThan.Operator, new JsLiteral(2)))); + + "1 > 2 && 3 > 4".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsLogicalExpression( + new JsBinaryExpression(new JsLiteral(1), JsGreaterThan.Operator, new JsLiteral(2)), + JsAnd.Operator, + new JsBinaryExpression(new JsLiteral(3), JsGreaterThan.Operator, new JsLiteral(4)) + ) + )); + + "1 > 2 and 3 > 4".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsLogicalExpression( + new JsBinaryExpression(new JsLiteral(1), JsGreaterThan.Operator, new JsLiteral(2)), + JsAnd.Operator, + new JsBinaryExpression(new JsLiteral(3), JsGreaterThan.Operator, new JsLiteral(4)) + ) + )); + } + + [Test] + public void Does_parse_linq_examples() + { + var it = new JsIdentifier("it"); + + "it < 5".ParseJsExpression(out var expr); + Assert.That(expr, + Is.EqualTo(new JsBinaryExpression(it, JsLessThan.Operator, new JsLiteral(5)))); + + "it.UnitsInStock > 0 and it.UnitPrice > 3".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo( + new JsLogicalExpression( + new JsBinaryExpression( + new JsMemberExpression(new JsIdentifier("it"), new JsIdentifier("UnitsInStock")), + JsGreaterThan.Operator, + new JsLiteral(0) + ), + JsAnd.Operator, + new JsBinaryExpression( + new JsMemberExpression(new JsIdentifier("it"), new JsIdentifier("UnitPrice")), + JsGreaterThan.Operator, + new JsLiteral(3) + ) + ) + )); + } + + [Test] + public void Does_parse_not_unary_expression() + { + var it = new JsIdentifier("it"); + + "!it".ParseJsExpression(out var expr); + Assert.That(expr, + Is.EqualTo(new JsUnaryExpression(JsNot.Operator, it))); + + "!contains(items, it)".ParseJsExpression(out expr); + Assert.That(expr, Is.EqualTo(new JsUnaryExpression(JsNot.Operator, + new JsCallExpression( + new JsIdentifier("contains"), + new JsIdentifier("items"), + new JsIdentifier("it") + )))); + } + + [Test] + public void Can_customize_and_evaluate_custom_AST_expressions() + { + JsToken expr; + + var expected = new JsLogicalExpression( + new JsBinaryExpression(new JsIdentifier("a"), JsGreaterThan.Operator, new JsLiteral(1)), + JsAnd.Operator, + new JsBinaryExpression(new JsIdentifier("b"), JsLessThan.Operator, new JsLiteral(2)) + ); + + expr = JS.expression("a > 1 && b < 2"); + Assert.That(expr, Is.EqualTo(expected)); + Assert.That(expr.Equals(expected)); + + Assert.That(new JsLogicalExpression( + JS.expression("a > 1"), + JsAnd.Operator, + JS.expression("b < 2")), + Is.EqualTo(expected)); + + Assert.That((bool)expr.Evaluate(JS.CreateScope(args:new Dictionary<string, object> { + ["a"] = 2, + ["b"] = 1 + }))); + + Assert.That((bool)expr.Evaluate(JS.CreateScope(args:new Dictionary<string, object> { + ["a"] = 1, + ["b"] = 2 + })), Is.False); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqAlternativeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqAlternativeTests.cs new file mode 100644 index 00000000000..aef9d26e052 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqAlternativeTests.cs @@ -0,0 +1,343 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class QueryFilterAlternativeTests + { + private static ScriptContext CreateContext(Dictionary<string, object> optionalArgs = null) + { + var context = new ScriptContext + { + Args = + { + ["numbers"] = new[] {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}, + ["products"] = QueryData.Products, + ["customers"] = QueryData.Customers, + } + }; + optionalArgs.Each((key, val) => context.Args[key] = val); + return context.Init(); + } + + [Test] + public void linq1_original() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript(@" +Numbers < 5: +{{ numbers |> where('it < 5') |> select('{{ it }}\n') }}").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers < 5: +4 +1 +3 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void linq2_original() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript(@" +Sold out products: +{{ products + |> where('it.UnitsInStock == 0') + |> select('{{ it.productName |> raw }} is sold out!\n') +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +Sold out products: +Chef Anton's Gumbo Mix is sold out! +Alice Mutton is sold out! +Thüringer Rostbratwurst is sold out! +Gorgonzola Telino is sold out! +Perth Pasties is sold out! +".NormalizeNewLines())); + } + + [Test] + public void linq2_original_with_custom_item_binding() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript(@" +Sold out products: +{{ products + |> where('product.UnitsInStock == 0', { it: 'product' }) + |> select('{{ product.productName |> raw }} is sold out!\n', { it: 'product' }) +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +Sold out products: +Chef Anton's Gumbo Mix is sold out! +Alice Mutton is sold out! +Thüringer Rostbratwurst is sold out! +Gorgonzola Telino is sold out! +Perth Pasties is sold out! +".NormalizeNewLines())); + } + + [Test] + public void linq4_selectPartial() + { + var context = CreateContext(new Dictionary<string, object> + { + {ScriptConstants.DefaultDateFormat, "yyyy/MM/dd"} + }); + + context.VirtualFiles.WriteFile("page.html", @"{{ + customers + |> where: it.Region == 'WA' + |> assignTo: waCustomers +}} +Customers from Washington and their orders: +{{ waCustomers |> selectPartial('customer') }}"); + + context.VirtualFiles.WriteFile("customer.html", @"Customer {{ it.CustomerId }} {{ it.CompanyName |> raw }} +{{ it.Orders |> select("" Order {{ it.OrderId }}: {{ it.OrderDate |> dateFormat |> newLine }}"") }}"); + + Assert.That(new PageResult(context.GetPage("page")).Result.NormalizeNewLines(), + Does.StartWith(@" +Customers from Washington and their orders: +Customer LAZYK Lazy K Kountry Store + Order 10482: 1997/03/21 + Order 10545: 1997/05/22 +Customer TRAIH Trail's Head Gourmet Provisioners + Order 10574: 1997/06/19 + Order 10577: 1997/06/23 + Order 10822: 1998/01/08 +".NormalizeNewLines())); + } + + [Test] + public void linq4_selectPartial_nested() + { + var context = CreateContext(new Dictionary<string, object> + { + {ScriptConstants.DefaultDateFormat, "yyyy/MM/dd"} + }); + + context.VirtualFiles.WriteFile("page.html", @"{{ + customers + |> where: it.Region == 'WA' + |> assignTo: waCustomers +}} +Customers from Washington and their orders: +{{ waCustomers |> selectPartial: customer }}"); + + context.VirtualFiles.WriteFile("customer.html", + @"Customer {{ it.CustomerId }} {{ it.CompanyName |> raw }} +{{ it.Orders |> selectPartial: order }}"); + + context.VirtualFiles.WriteFile("order.html", @" Order {{ it.OrderId }}: {{ it.OrderDate |> dateFormat}} +"); + + Assert.That(new PageResult(context.GetPage("page")).Result.NormalizeNewLines(), + Does.StartWith(@" +Customers from Washington and their orders: +Customer LAZYK Lazy K Kountry Store + Order 10482: 1997/03/21 + Order 10545: 1997/05/22 +Customer TRAIH Trail's Head Gourmet Provisioners + Order 10574: 1997/06/19 + Order 10577: 1997/06/23 + Order 10822: 1998/01/08 +".NormalizeNewLines())); + } + + [Test] + public void linq4_selectPartial_nested_with_custom_item_binding() + { + var context = CreateContext(new Dictionary<string, object> + { + {ScriptConstants.DefaultDateFormat, "yyyy/MM/dd"} + }); + + context.VirtualFiles.WriteFile("page.html", @"{{ + customers + |> where: it.Region == 'WA' + |> assignTo: waCustomers +}} +Customers from Washington and their orders: +{{ waCustomers |> selectPartial: customer }}"); + + context.VirtualFiles.WriteFile("customer.html", + @" +<!-- +it: cust +--> + +Customer {{ cust.CustomerId }} {{ cust.CompanyName |> raw }} +{{ cust.Orders |> selectPartial('order', { it: 'order' }) }}"); + + context.VirtualFiles.WriteFile("order.html", + " Order {{ order.OrderId }}: {{ order.OrderDate |> dateFormat}}\n"); + + Assert.That(new PageResult(context.GetPage("page")).Result.NormalizeNewLines(), + Does.StartWith(@" +Customers from Washington and their orders: +Customer LAZYK Lazy K Kountry Store + Order 10482: 1997/03/21 + Order 10545: 1997/05/22 +Customer TRAIH Trail's Head Gourmet Provisioners + Order 10574: 1997/06/19 + Order 10577: 1997/06/23 + Order 10822: 1998/01/08 +".NormalizeNewLines())); + } + + [Test] + public void Linq14_original() + { + var context = CreateContext(new Dictionary<string, object> + { + {"numbersA", new[] {0, 2, 4, 5, 6, 8, 9}}, + {"numbersB", new[] {1, 3, 5, 7, 8}}, + }); + + Assert.That(context.EvaluateScript(@" +Pairs where a < b: +{{ numbersA |> zip(numbersB) + |> where: it[0] < it[1] + |> select: { it[0] } is less than { it[1] }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq14_bindings() + { + var context = CreateContext(new Dictionary<string, object> + { + {"numbersA", new[] {0, 2, 4, 5, 6, 8, 9}}, + {"numbersB", new[] {1, 3, 5, 7, 8}}, + }); + + Assert.That(context.EvaluateScript(@" +Pairs where a < b: +{{ numbersA |> zip(numbersB) + |> let({ a: 'it[0]', b: 'it[1]' }) + |> where: a < b + |> select: { a } is less than { b }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq18_whitespace_test() + { + var context = CreateContext(); + + var template = @" +{{ '1997-01-01' |> assignTo: cutoffDate }} +{{ customers + |> where: it.Region == 'WA' + |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: o.OrderDate >= cutoffDate + |> select: ({ c.CustomerId }, { o.OrderId })\n }} +".NormalizeNewLines(); + Assert.That(context.EvaluateScript(template).NormalizeNewLines(), + + Does.StartWith(@" +(LAZYK, 10482) +(LAZYK, 10545) +(TRAIH, 10574) +".NormalizeNewLines())); + } + + [Test] + public void Linq21_jsv() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript(@" +First 3 orders in WA: +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: c.Region == 'WA' + |> select: { [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +First 3 orders in WA: +[LAZYK,10482,1997-03-21] +[LAZYK,10545,1997-05-22] +[TRAIH,10574,1997-06-19] +".NormalizeNewLines())); + } + + [Test] + public void Linq21_json_with_config() + { + var context = CreateContext(); + + Assert.That(context.EvaluateScript(@" +First 3 orders in WA: +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: c.Region == 'WA' + |> select: { [c.CustomerId, o.OrderId, o.OrderDate] |> json('DateHandler:ISO8601DateOnly') }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +First 3 orders in WA: +[""LAZYK"",10482,""1997-03-21""] +[""LAZYK"",10545,""1997-05-22""] +[""TRAIH"",10574,""1997-06-19""] +".NormalizeNewLines())); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqPipelineOperatorTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqPipelineOperatorTests.cs new file mode 100644 index 00000000000..2782556a6c0 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqPipelineOperatorTests.cs @@ -0,0 +1,2102 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Logging; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class QueryLinqPipelineOperatorTests + { + private static ScriptContext CreateContext() + { + var context = new ScriptContext + { + Args = + { + [ScriptConstants.DefaultDateFormat] = "yyyy/MM/dd", + ["products"] = QueryData.Products, + ["customers"] = QueryData.Customers, + ["comparer"] = new CaseInsensitiveComparer(), + ["anagramComparer"] = new AnagramEqualityComparer(), + } + }; + return context.Init(); + } + + [SetUp] + public void Setup() => context = CreateContext(); + private ScriptContext context; + + [Test] + public void Can_use_pipeline_operator_in_code_blocks() + { + ConsoleLogFactory.Configure(); + Assert.That(context.EvaluateScript(@" +```code +`Numbers < 5:` |> raw +[5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers +numbers |> where => it < 5 |> joinln |> raw +```").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers < 5: +4 +1 +3 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq01() // alternative with clean whitespace sensitive string argument syntax: + { + Assert.That(context.EvaluateScript(@" +Numbers < 5: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> where => it < 5 + |> joinln +}}").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers < 5: +4 +1 +3 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq02() // alternative with clean whitespace sensitive string argument syntax: + { + Assert.That(context.EvaluateScript(@" +Sold out products: +{{ products + |> where => it.UnitsInStock == 0 + |> select: { it.productName |> raw } is sold out!\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Sold out products: +Chef Anton's Gumbo Mix is sold out! +Alice Mutton is sold out! +Thüringer Rostbratwurst is sold out! +Gorgonzola Telino is sold out! +Perth Pasties is sold out! +".NormalizeNewLines())); + } + + [Test] + public void Linq03() + { + Assert.That(context.EvaluateScript(@" +In-stock products that cost more than 3.00: +{{ products + |> where => it.UnitsInStock > 0 and it.UnitPrice > 3 + |> select: { it.productName |> raw } is in stock and costs more than 3.00.\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +In-stock products that cost more than 3.00: +Chai is in stock and costs more than 3.00. +Chang is in stock and costs more than 3.00. +Aniseed Syrup is in stock and costs more than 3.00. +".NormalizeNewLines())); + } + + [Test] + public void Linq04() + { + context.VirtualFiles.WriteFile("customer.html", @" +Customer {{ it.CustomerId }} {{ it.CompanyName |> raw }} +{{ it.Orders |> selectPartial: order }}"); + + context.VirtualFiles.WriteFile("order.html", " Order {{ it.OrderId }}: {{ it.OrderDate |> dateFormat }}\n"); + + Assert.That(context.EvaluateScript(@" +{{ customers + |> where => it.Region == 'WA' + |> to => waCustomers +}} +Customers from Washington and their orders: +{{ waCustomers |> selectPartial: customer }} +").NormalizeNewLines(), + + Does.StartWith(@" +Customers from Washington and their orders: + +Customer LAZYK Lazy K Kountry Store + Order 10482: 1997/03/21 + Order 10545: 1997/05/22 + +Customer TRAIH Trail's Head Gourmet Provisioners + Order 10574: 1997/06/19 + Order 10577: 1997/06/23 + Order 10822: 1998/01/08 +".NormalizeNewLines())); + } + + [Test] + public void Linq05() + { + Assert.That(context.EvaluateScript(@" +Short digits: +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => digits }} +{{ digits + |> where => it.Length < index + |> select: The word {it} is shorter than its value.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Short digits: +The word five is shorter than its value. +The word six is shorter than its value. +The word seven is shorter than its value. +The word eight is shorter than its value. +The word nine is shorter than its value. +".NormalizeNewLines())); + } + + [Test] + public void Linq06() + { + Assert.That(context.EvaluateScript(@" +Numbers + 1: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> select: { it |> incr }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Numbers + 1: +6 +5 +2 +4 +10 +9 +7 +8 +3 +1 +".NormalizeNewLines())); + } + + [Test] + public void Linq07() + { + Assert.That(context.EvaluateScript(@" +Product Names: +{{ products |> select: { it.ProductName |> raw }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Product Names: +Chai +Chang +Aniseed Syrup +Chef Anton's Cajun Seasoning +Chef Anton's Gumbo Mix +".NormalizeNewLines())); + } + + [Test] + public void Linq08() + { + Assert.That(context.EvaluateScript(@" +Number strings: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => strings }} +{{ numbers |> select: { strings[it] }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Number strings: +five +four +one +three +nine +eight +six +seven +two +zero +".NormalizeNewLines())); + } + + [Test] + public void Linq09() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'BlUeBeRrY', 'cHeRry'] |> to => words }} +{{ words |> select: Uppercase: { it |> upper }, Lowercase: { it |> lower }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Uppercase: APPLE, Lowercase: apple +Uppercase: BLUEBERRY, Lowercase: blueberry +Uppercase: CHERRY, Lowercase: cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq10() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => strings }} +{{ numbers |> select: The digit { strings[it] } is { it.isEven() ? 'even' : 'odd' }.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +The digit five is odd. +The digit four is even. +The digit one is odd. +The digit three is odd. +The digit nine is odd. +The digit eight is even. +The digit six is even. +The digit seven is odd. +The digit two is even. +The digit zero is even. +".NormalizeNewLines())); + } + + [Test] + public void Linq11() + { + Assert.That(context.EvaluateScript(@" +Product Info: +{{ products |> select: { it.ProductName |> raw } is in the category { it.Category } and costs { it.UnitPrice |> currency } per unit.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Product Info: +Chai is in the category Beverages and costs $18.00 per unit. +Chang is in the category Beverages and costs $19.00 per unit. +Aniseed Syrup is in the category Condiments and costs $10.00 per unit. +".NormalizeNewLines())); + } + + [Test] + public void Linq12() + { + Assert.That(context.EvaluateScript(@" +Number: In-place? +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> select: { it }: { it |> equals(index) |> lower }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Number: In-place? +5: false +4: false +1: false +3: true +9: false +8: false +6: true +7: true +2: false +0: false +".NormalizeNewLines())); + } + + [Test] + public void Linq13() + { + Assert.That(context.EvaluateScript(@" +Numbers < 5: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => digits }} +{{ numbers + |> where => it < 5 + |> select: { digits[it] }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +Numbers < 5: +four +one +three +two +zero +".NormalizeNewLines())); + } + + [Test] + public void Linq14() + { + Assert.That(context.EvaluateScript(@" +{{ [0, 2, 4, 5, 6, 8, 9] |> to => numbersA }} +{{ [1, 3, 5, 7, 8] |> to => numbersB }} +Pairs where a < b: +{{ numbersA |> zip(numbersB) + |> let({ a: 'it[0]', b: 'it[1]' }) + |> where => a < b + |> select: { a } is less than { b }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq15() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip => it.Orders + |> let => { c: it[0], o: it[1] } + |> where => o.Total < 500 + |> select: ({ c.CustomerId }, { o.OrderId }, { o.Total |> format('0.0#') })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ALFKI, 10702, 330.0) +(ALFKI, 10952, 471.2) +(ANATR, 10308, 88.8) +(ANATR, 10625, 479.75) +".NormalizeNewLines())); + } + + [Test] + public void Linq16() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip => it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where => o.OrderDate >= '1998-01-01' + |> select: ({ c.CustomerId }, { o.OrderId }, { o.OrderDate })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ALFKI, 10835, 1/15/1998 12:00:00 AM) +(ALFKI, 10952, 3/16/1998 12:00:00 AM) +(ALFKI, 11011, 4/9/1998 12:00:00 AM) +(ANATR, 10926, 3/4/1998 12:00:00 AM) +(ANTON, 10856, 1/28/1998 12:00:00 AM) +".NormalizeNewLines())); + } + + [Test] + public void Linq17() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where => o.Total >= 2000 + |> select: ({ c.CustomerId }, { o.OrderId }, { o.Total |> format('0.0#') })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ANTON, 10573, 2082.0) +(AROUT, 10558, 2142.9) +(AROUT, 10953, 4441.25) +(BERGS, 10384, 2222.4) +(BERGS, 10524, 3192.65) +".NormalizeNewLines())); + } + + [Test] + public void Linq18() + { + var template = @" +{{ '1997-01-01' |> to => cutoffDate }} +{{ customers + |> where => it.Region == 'WA' + |> zip => it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where => o.OrderDate >= cutoffDate + |> select: ({ c.CustomerId }, { o.OrderId })\n }} +"; + Assert.That(context.EvaluateScript(template.NormalizeNewLines()).NormalizeNewLines(), + + Does.StartWith(@" +(LAZYK, 10482) +(LAZYK, 10545) +(TRAIH, 10574) +(TRAIH, 10577) +(TRAIH, 10822) +(WHITC, 10469) +(WHITC, 10483) +(WHITC, 10504) +(WHITC, 10596) +(WHITC, 10693) +(WHITC, 10696) +(WHITC, 10723) +(WHITC, 10740) +(WHITC, 10861) +(WHITC, 10904) +(WHITC, 11032) +(WHITC, 11066) +".NormalizeNewLines())); + } + + [Test] + public void Linq19() + { + Assert.That(context.EvaluateScript(@" +{{ customers + |> let({ cust: 'it', custIndex: 'index' }) + |> zip => cust.Orders + |> let({ o: 'it[1]' }) + |> select: Customer #{ custIndex |> incr } has an order with OrderID { o.OrderId }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Customer #1 has an order with OrderID 10643 +Customer #1 has an order with OrderID 10692 +Customer #1 has an order with OrderID 10702 +Customer #1 has an order with OrderID 10835 +Customer #1 has an order with OrderID 10952 +Customer #1 has an order with OrderID 11011 +Customer #2 has an order with OrderID 10308 +Customer #2 has an order with OrderID 10625 +Customer #2 has an order with OrderID 10759 +Customer #2 has an order with OrderID 10926 +".NormalizeNewLines())); + } + + [Test] + public void Linq20() + { + Assert.That(context.EvaluateScript(@" +First 3 numbers: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> take(3) |> select: { it }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +First 3 numbers: +5 +4 +1 +".NormalizeNewLines())); + } + + [Test] + public void Linq21() + { + Assert.That(context.EvaluateScript(@" +First 3 orders in WA: +{{ customers |> zip => it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where => c.Region == 'WA' + |> select: { [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +First 3 orders in WA: +[LAZYK,10482,1997-03-21] +[LAZYK,10545,1997-05-22] +[TRAIH,10574,1997-06-19] +".NormalizeNewLines())); + } + + [Test] + public void Linq22() + { + Assert.That(context.EvaluateScript(@" +All but first 4 numbers: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> skip(4) |> select: { it }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +All but first 4 numbers: +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq23() + { + Assert.That(context.EvaluateScript(@" +All but first 2 orders in WA: +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where => c.Region == 'WA' + |> skip(2) + |> select: { [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +All but first 2 orders in WA: +[TRAIH,10574,1997-06-19] +[TRAIH,10577,1997-06-23] +[TRAIH,10822,1998-01-08] +[WHITC,10269,1996-07-31] +[WHITC,10344,1996-11-01] +[WHITC,10469,1997-03-10] +[WHITC,10483,1997-03-24] +[WHITC,10504,1997-04-11] +[WHITC,10596,1997-07-11] +[WHITC,10693,1997-10-06] +[WHITC,10696,1997-10-08] +[WHITC,10723,1997-10-30] +[WHITC,10740,1997-11-13] +[WHITC,10861,1998-01-30] +[WHITC,10904,1998-02-24] +[WHITC,11032,1998-04-17] +[WHITC,11066,1998-05-01] +".NormalizeNewLines())); + } + + [Test] + public void Linq24() + { + Assert.That(context.EvaluateScript(@" +First numbers less than 6: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> takeWhile => it < 6 + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +First numbers less than 6: +5 +4 +1 +3 +".NormalizeNewLines())); + } + + [Test] + public void Linq25() + { + Assert.That(context.EvaluateScript(@" +First numbers not less than their position: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> takeWhile => it >= index + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +First numbers not less than their position: +5 +4 +".NormalizeNewLines())); + } + + [Test] + public void Linq26() + { + Assert.That(context.EvaluateScript(@" +All elements starting from first element divisible by 3: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> skipWhile => mod(it,3) != 0 + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +All elements starting from first element divisible by 3: +3 +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq27() + { + Assert.That(context.EvaluateScript(@" +All elements starting from first element less than its position: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> skipWhile: it >= index + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +All elements starting from first element less than its position: +1 +3 +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq28() + { + Assert.That(context.EvaluateScript(@" +The sorted list of words: +{{ ['cherry', 'apple', 'blueberry'] |> to => words }} +{{ words + |> orderBy => it + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The sorted list of words: +apple +blueberry +cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq29() + { + Assert.That(context.EvaluateScript(@" +The sorted list of words (by length): +{{ ['cherry', 'apple', 'blueberry'] |> to => words }} +{{ words + |> orderBy => it.Length + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The sorted list of words (by length): +apple +cherry +blueberry +".NormalizeNewLines())); + } + + [Test] + public void Linq30() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> orderBy => it.ProductName + |> select: { it |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +{ProductId:17,ProductName:Alice Mutton,Category:Meat/Poultry,UnitPrice:39,UnitsInStock:0} +{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13} +{ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4,UnitsInStock:123} +{ProductId:60,ProductName:Camembert Pierrot,Category:Dairy Products,UnitPrice:34,UnitsInStock:19} +{ProductId:18,ProductName:Carnarvon Tigers,Category:Seafood,UnitPrice:62.5,UnitsInStock:42} +".NormalizeNewLines())); + } + + [Test] + public void Linq31() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> to => words }} +{{ words + |> orderBy('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +AbAcUs +aPPLE +BlUeBeRrY +bRaNcH +cHeRry +ClOvEr +".NormalizeNewLines())); + } + + [Test] + public void Linq32() + { + Assert.That(context.EvaluateScript(@" +The doubles from highest to lowest: +{{ [1.7, 2.3, 1.9, 4.1, 2.9] |> to => doubles }} +{{ doubles + |> orderByDescending => it + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The doubles from highest to lowest: +4.1 +2.9 +2.3 +1.9 +1.7 +".NormalizeNewLines())); + } + + [Test] + public void Linq33() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> orderByDescending => it.UnitsInStock + |> select: { it |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +{ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75,UnitsInStock:125} +{ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4,UnitsInStock:123} +{ProductId:6,ProductName:Grandma's Boysenberry Spread,Category:Condiments,UnitPrice:25,UnitsInStock:120} +{ProductId:55,ProductName:Pâté chinois,Category:Meat/Poultry,UnitPrice:24,UnitsInStock:115} +{ProductId:61,ProductName:Sirop d'érable,Category:Condiments,UnitPrice:28.5,UnitsInStock:113} +".NormalizeNewLines())); + } + + [Test] + public void Linq34() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> to => words }} +{{ words + |> orderByDescending('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +ClOvEr +cHeRry +bRaNcH +BlUeBeRrY +aPPLE +AbAcUs +".NormalizeNewLines())); + } + + [Test] + public void Linq35() + { + Assert.That(context.EvaluateScript(@" +Sorted digits: +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => digits }} +{{ digits + |> orderBy => it.length + |> thenBy => it + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Sorted digits: +one +six +two +five +four +nine +zero +eight +seven +three +".NormalizeNewLines())); + } + + [Test] + public void Linq36() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> to => words }} +{{ words + |> orderBy => it.length + |> thenBy('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +aPPLE +AbAcUs +bRaNcH +cHeRry +ClOvEr +BlUeBeRrY +".NormalizeNewLines())); + } + + [Test] + public void Linq37() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> orderBy => it.Category + |> thenByDescending => it.UnitPrice + |> select: { it |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17} +{ProductId:43,ProductName:Ipoh Coffee,Category:Beverages,UnitPrice:46,UnitsInStock:17} +{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39} +{ProductId:35,ProductName:Steeleye Stout,Category:Beverages,UnitPrice:18,UnitsInStock:20} +{ProductId:39,ProductName:Chartreuse verte,Category:Beverages,UnitPrice:18,UnitsInStock:69} +{ProductId:76,ProductName:Lakkalikööri,Category:Beverages,UnitPrice:18,UnitsInStock:57} +{ProductId:70,ProductName:Outback Lager,Category:Beverages,UnitPrice:15,UnitsInStock:15} +{ProductId:34,ProductName:Sasquatch Ale,Category:Beverages,UnitPrice:14,UnitsInStock:111} +".NormalizeNewLines())); + } + + [Test] + public void Linq38() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> to => words }} +{{ words + |> orderBy => it.length + |> thenByDescending('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +aPPLE +ClOvEr +cHeRry +bRaNcH +AbAcUs +BlUeBeRrY +".NormalizeNewLines())); + } + + [Test] + public void Linq39() + { + Assert.That(context.EvaluateScript(@" +A backwards list of the digits with a second character of 'i': +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => digits }} +{{ digits + |> where => it[1] == 'i' + |> reverse + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +A backwards list of the digits with a second character of 'i': +nine +eight +six +five +".NormalizeNewLines())); + } + + [Test] + public void Linq40() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> groupBy => mod(it,5) + |> let({ remainder: 'it.Key', numbers: 'it' }) + |> select: Numbers with a remainder of { remainder } when divided by 5:\n{ numbers |> select('{it}\n') } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers with a remainder of 0 when divided by 5: +5 +0 +Numbers with a remainder of 4 when divided by 5: +4 +9 +Numbers with a remainder of 1 when divided by 5: +1 +6 +Numbers with a remainder of 3 when divided by 5: +3 +8 +Numbers with a remainder of 2 when divided by 5: +7 +2 +".NormalizeNewLines())); + } + + [Test] + public void Linq41() + { + Assert.That(context.EvaluateScript(@" +{{ ['blueberry', 'chimpanzee', 'abacus', 'banana', 'apple', 'cheese'] |> to => words }} +{{ words + |> groupBy => it[0] + |> let({ firstLetter: 'it.Key', words: 'it' }) + |> select: Words that start with the letter '{firstLetter}':\n{ words |> select('{it}\n') } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Words that start with the letter 'b': +blueberry +banana +Words that start with the letter 'c': +chimpanzee +cheese +Words that start with the letter 'a': +abacus +apple +".NormalizeNewLines())); + } + + [Test] + public void Linq42() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ category: 'it.Key', products: 'it' }) + |> select: {category}:\n{ products |> select('{it |> jsv}\n') } }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages: +{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39} +{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +{ProductId:24,ProductName:Guaraná Fantástica,Category:Beverages,UnitPrice:4.5,UnitsInStock:20} +{ProductId:34,ProductName:Sasquatch Ale,Category:Beverages,UnitPrice:14,UnitsInStock:111} +{ProductId:35,ProductName:Steeleye Stout,Category:Beverages,UnitPrice:18,UnitsInStock:20} +{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17} +{ProductId:39,ProductName:Chartreuse verte,Category:Beverages,UnitPrice:18,UnitsInStock:69} +{ProductId:43,ProductName:Ipoh Coffee,Category:Beverages,UnitPrice:46,UnitsInStock:17} +{ProductId:67,ProductName:Laughing Lumberjack Lager,Category:Beverages,UnitPrice:14,UnitsInStock:52} +{ProductId:70,ProductName:Outback Lager,Category:Beverages,UnitPrice:15,UnitsInStock:15} +{ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75,UnitsInStock:125} +{ProductId:76,ProductName:Lakkalikööri,Category:Beverages,UnitPrice:18,UnitsInStock:57} +Condiments: +{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13} +{ProductId:4,ProductName:Chef Anton's Cajun Seasoning,Category:Condiments,UnitPrice:22,UnitsInStock:53} +".NormalizeNewLines())); + } + + [Test] + public void Linq43() + { + context.VirtualFiles.WriteFile("month-orders.html", @" +{{ year }} +{{ monthGroups |> scopeVars |> select: { indent }{ month }\n{ 2 |> indents }{ orders |> jsv }\n }}"); + + Assert.That(context.EvaluateScript(@" +{{ customers + |> let({ + companyName: 'it.CompanyName', + yearGroups: ""map ( + groupBy(it.Orders, 'it.OrderDate.Year'), + '{ + year: it.Key, + monthGroups: map ( + groupBy(it, `it.OrderDate.Month`), + `{ month: it.Key, orders: it }` + ) + }' + )"" + }) + |> select: \n# { companyName |> raw }{ yearGroups |> scopeVars |> selectPartial('month-orders') } +}} +").NormalizeNewLines(), + + Does.StartWith(@" +# Alfreds Futterkiste +1997 + 8 + [{OrderId:10643,OrderDate:1997-08-25,Total:814.5}] + 10 + [{OrderId:10692,OrderDate:1997-10-03,Total:878},{OrderId:10702,OrderDate:1997-10-13,Total:330}] + +1998 + 1 + [{OrderId:10835,OrderDate:1998-01-15,Total:845.8}] + 3 + [{OrderId:10952,OrderDate:1998-03-16,Total:471.2}] + 4 + [{OrderId:11011,OrderDate:1998-04-09,Total:933.5}] + +# Ana Trujillo Emparedados y helados +1996 + 9 + [{OrderId:10308,OrderDate:1996-09-18,Total:88.8}] +".NormalizeNewLines())); + } + + [Test] + public void Linq43_alt() + { + context.VirtualFiles.WriteFile("month-orders.html", @" +{{ year }} +{{ monthGroups |> scopeVars |> select: { indent }{ month }\n{ 2 |> indents }{ orders |> jsv }\n }}"); + + Assert.That(context.EvaluateScript(@" +{{ customers + |> map => { + companyName: it.CompanyName, + yearGroups: map ( + groupBy(it.Orders, it => it.OrderDate.Year), + yg => { + year: yg.Key, + monthGroups: map ( + groupBy(yg, o => o.OrderDate.Month), + mg => { month: mg.Key, orders: mg } + ) + } + ) + } + |> select: \n# { it.companyName |> raw }{ it.yearGroups |> scopeVars |> selectPartial('month-orders') } +}} +").NormalizeNewLines(), + + Does.StartWith(@" +# Alfreds Futterkiste +1997 + 8 + [{OrderId:10643,OrderDate:1997-08-25,Total:814.5}] + 10 + [{OrderId:10692,OrderDate:1997-10-03,Total:878},{OrderId:10702,OrderDate:1997-10-13,Total:330}] + +1998 + 1 + [{OrderId:10835,OrderDate:1998-01-15,Total:845.8}] + 3 + [{OrderId:10952,OrderDate:1998-03-16,Total:471.2}] + 4 + [{OrderId:11011,OrderDate:1998-04-09,Total:933.5}] + +# Ana Trujillo Emparedados y helados +1996 + 9 + [{OrderId:10308,OrderDate:1996-09-18,Total:88.8}] +".NormalizeNewLines())); + } + + [Test] + public void Linq44() + { + Assert.That(context.EvaluateScript(@" +{{ ['from ', ' salt', ' earn ', ' last ', ' near ', ' form '] |> to => anagrams }} +{{ anagrams + |> groupBy('trim(it)', { comparer: anagramComparer }) + |> select: { it |> json }\n +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +[""from "","" form ""] +["" salt"","" last ""] +["" earn "","" near ""] +".NormalizeNewLines())); + } + + [Test] + public void Linq45() + { + Assert.That(context.EvaluateScript(@" +{{ ['from ', ' salt', ' earn ', ' last ', ' near ', ' form '] |> to => anagrams }} +{{ anagrams + |> groupBy('trim(it)', { map: 'upper(it)', comparer: anagramComparer }) + |> select: { it |> json }\n +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +[""FROM "","" FORM ""] +["" SALT"","" LAST ""] +["" EARN "","" NEAR ""] +".NormalizeNewLines())); + } + + [Test] + public void Linq46() + { + Assert.That(context.EvaluateScript(@" +Prime factors of 300: +{{ [2, 2, 3, 5, 5] |> to => factorsOf300 }} +{{ factorsOf300 |> distinct |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Prime factors of 300: +2 +3 +5 +".NormalizeNewLines())); + } + + [Test] + public void Linq47() + { + Assert.That(context.EvaluateScript(@" +Category names: +{{ products + |> map => it.Category + |> distinct + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Category names: +Beverages +Condiments +Produce +Meat/Poultry +Seafood +Dairy Products +Confections +Grains/Cereals +".NormalizeNewLines())); + } + + [Test] + public void Linq48() + { + Assert.That(context.EvaluateScript(@" +{{ [ 0, 2, 4, 5, 6, 8, 9 ] |> to => numbersA }} +{{ [ 1, 3, 5, 7, 8 ] |> to => numbersB }} +Unique numbers from both arrays: +{{ numbersA |> union(numbersB) |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Unique numbers from both arrays: +0 +2 +4 +5 +6 +8 +9 +1 +3 +7 +".NormalizeNewLines())); + } + + [Test] + public void Linq49() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> map => it.ProductName[0] + |> to => productFirstChars }} +{{ customers + |> map => it.CompanyName[0] + |> to => customerFirstChars }} +Unique first letters from Product names and Customer names: +{{ productFirstChars + |> union(customerFirstChars) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Unique first letters from Product names and Customer names: +C +A +G +U +N +M +I +Q +K +T +P +S +R +B +J +Z +V +F +E +W +L +O +D +H +".NormalizeNewLines())); + } + + [Test] + public void Linq50() + { + Assert.That(context.EvaluateScript(@" +{{ [ 0, 2, 4, 5, 6, 8, 9 ] |> to => numbersA }} +{{ [ 1, 3, 5, 7, 8 ] |> to => numbersB }} +Common numbers shared by both arrays: +{{ numbersA |> intersect(numbersB) |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Common numbers shared by both arrays: +5 +8 +".NormalizeNewLines())); + } + + [Test] + public void Linq51() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> map => it.ProductName[0] + |> to => productFirstChars }} +{{ customers + |> map => it.CompanyName[0] + |> to => customerFirstChars }} +Common first letters from Product names and Customer names: +{{ productFirstChars + |> intersect(customerFirstChars) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Common first letters from Product names and Customer names: +C +A +G +N +M +I +Q +K +T +P +S +R +B +V +F +E +W +L +O +".NormalizeNewLines())); + } + + [Test] + public void Linq52() + { + Assert.That(context.EvaluateScript(@" +{{ [ 0, 2, 4, 5, 6, 8, 9 ] |> to => numbersA }} +{{ [ 1, 3, 5, 7, 8 ] |> to => numbersB }} +Numbers in first array but not second array: +{{ numbersA |> except(numbersB) |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers in first array but not second array: +0 +2 +4 +6 +9 +".NormalizeNewLines())); + } + + [Test] + public void Linq53() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> map => it.ProductName[0] + |> to => productFirstChars }} +{{ customers + |> map => it.CompanyName[0] + |> to => customerFirstChars }} +First letters from Product names, but not from Customer names: +{{ productFirstChars + |> except(customerFirstChars) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +First letters from Product names, but not from Customer names: +U +J +Z +".NormalizeNewLines())); + } + + [Test] + public void Linq54() + { + Assert.That(context.EvaluateScript(@" +{{ [ 1.7, 2.3, 1.9, 4.1, 2.9 ] |> to => doubles }} +Every other double from highest to lowest: +{{ doubles + |> orderByDescending => it + |> step({ by: 2 }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Every other double from highest to lowest: +4.1 +2.3 +1.7 +".NormalizeNewLines())); + } + + [Test] + public void Linq55() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => words }} +The sorted word list: +{{ words + |> orderBy => it + |> toList + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The sorted word list: +apple +blueberry +cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq56() + { + Assert.That(context.EvaluateScript(@" +{{ [{name:'Alice', score:50}, {name: 'Bob', score:40}, {name:'Cathy', score:45}] |> to => scoreRecords }} +Bob's score: +{{ scoreRecords + |> toDictionary => it.name + |> get('Bob') + |> select: { it['name'] } = { it['score'] } +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +Bob's score: +Bob = 40 +".NormalizeNewLines())); + } + + [Test] + public void Linq57() + { + Assert.That(context.EvaluateScript(@" +{{ [null, 1.0, 'two', 3, 'four', 5, 'six', 7.0] |> to => numbers }} +Numbers stored as doubles: +{{ numbers + |> of({ type: 'Double' }) + |> select: { it |> format('#.0') }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers stored as doubles: +1.0 +7.0 +".NormalizeNewLines())); + } + + [Test] + public void Linq58() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> where => it.ProductId == 12 + |> first + |> select: { it |> jsv } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +{ProductId:12,ProductName:Queso Manchego La Pastora,Category:Dairy Products,UnitPrice:38,UnitsInStock:86} +".NormalizeNewLines())); + } + + [Test] + public void Linq59() + { + Assert.That(context.EvaluateScript(@" +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> to => strings }} +{{ strings + |> first => it[0] == 'o' + |> select: A string starting with 'o': { it } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +A string starting with 'o': one +".NormalizeNewLines())); + } + + [Test] + public void Linq61() + { + Assert.That(context.EvaluateScript(@" +{{ [] |> to => numbers }} +{{ numbers |> first |> otherwise('null') }} +").NormalizeNewLines(), + + Is.EqualTo(@" +null +".NormalizeNewLines())); + } + + [Test] + public void Linq62() + { + Assert.That(context.EvaluateScript(@" +Product 789 exists: {{ products + |> first => it.ProductId == 789 + |> isNotNull }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Product 789 exists: False +".NormalizeNewLines())); + } + + [Test] + public void Linq64() + { + Assert.That(context.EvaluateScript(@" +{{ [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ] |> to => numbers }} +{{ numbers + |> where => it > 5 + |> elementAt(1) + |> select: Second number > 5: { it } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Second number > 5: 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq65() + { + Assert.That(context.EvaluateScript(@" +{{ range(100,50) + |> select: The number {it} is { it.isEven() ? 'even' : 'odd' }.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +The number 100 is even. +The number 101 is odd. +The number 102 is even. +The number 103 is odd. +The number 104 is even. +The number 105 is odd. +The number 106 is even. +The number 107 is odd. +The number 108 is even. +The number 109 is odd. +The number 110 is even. +".NormalizeNewLines())); + } + + [Test] + public void Linq66() + { + Assert.That(context.EvaluateScript(@" +{{ 10 |> itemsOf(7) |> select: {it}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +".NormalizeNewLines())); + } + + [Test] + public void Linq67() + { + Assert.That(context.EvaluateScript(@" +{{ ['believe', 'relief', 'receipt', 'field'] |> to => words }} +{{ words + |> any => contains(it, 'ei') + |> select: There is a word that contains in the list that contains 'ei': { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +There is a word that contains in the list that contains 'ei': true".NormalizeNewLines())); + } + + [Test] + public void Linq69() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> where => any(it, 'it.UnitsInStock == 0') + |> let({ category: 'it.Key', products: 'it' }) + |> select: { category }\n{ products |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Condiments +[{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13},{ProductId:4,ProductName:Chef Anton's Cajun Seasoning,Category:Condiments,UnitPrice:22,UnitsInStock:53} +".NormalizeNewLines())); + } + + [Test] + public void Linq70() + { + Assert.That(context.EvaluateScript(@" +{{ [1, 11, 3, 19, 41, 65, 19] |> to => numbers }} +{{ numbers + |> all => isOdd(it) + |> select: The list contains only odd numbers: { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +The list contains only odd numbers: true".NormalizeNewLines())); + } + + [Test] + public void Linq72() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> where => all(it, 'it.UnitsInStock > 0') + |> let({ category: 'it.Key', products: 'it' }) + |> select: { category }\n{ products |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages +[{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39},{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +".NormalizeNewLines())); + } + + [Test] + public void Linq73() + { + Assert.That(context.EvaluateScript(@" +{{ [2, 2, 3, 5, 5] |> to => factorsOf300 }} +{{ factorsOf300 |> distinct |> count |> select: There are {it} unique factors of 300. }} +").NormalizeNewLines(), + + Does.StartWith(@" +There are 3 unique factors of 300.".NormalizeNewLines())); + } + + [Test] + public void Linq74() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> count => isOdd(it) + |> select: There are {it} odd numbers in the list. }} +").NormalizeNewLines(), + + Does.StartWith(@" +There are 5 odd numbers in the list.".NormalizeNewLines())); + } + + [Test] + public void Linq76() + { + Assert.That(context.EvaluateScript(@" +{{ customers + |> let({ customerId: 'it.CustomerId', ordersCount: 'count(it.Orders)' }) + |> select: {customerId}, {ordersCount}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +ALFKI, 6 +ANATR, 4 +ANTON, 7 +AROUT, 13 +BERGS, 18 +BLAUS, 7 +BLONP, 11 +".NormalizeNewLines())); + } + + [Test] + public void Linq77() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ category: 'it.Key', productCount: 'count(it)' }) + |> select: {category}, {productCount}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages, 12 +Condiments, 12 +Produce, 5 +Meat/Poultry, 6 +Seafood, 12 +Dairy Products, 10 +Confections, 13 +Grains/Cereals, 7 +".NormalizeNewLines())); + } + + [Test] + public void Linq78() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> sum |> select: The sum of the numbers is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The sum of the numbers is 45.".NormalizeNewLines())); + } + + [Test] + public void Linq79() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry'] |> to => words }} +{{ words + |> sum => it.Length + |> select: There are a total of {it} characters in these words. }} +").NormalizeNewLines(), + + Does.StartWith(@" +There are a total of 20 characters in these words.".NormalizeNewLines())); + } + + [Test] + public void Linq80() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ category: 'it.Key', totalUnitsInStock: 'sum(it, `it.UnitsInStock`)' }) + |> select: {category}, {totalUnitsInStock}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages, 559 +Condiments, 507 +Produce, 100 +Meat/Poultry, 165 +Seafood, 701 +Dairy Products, 393 +Confections, 386 +Grains/Cereals, 308 +".NormalizeNewLines())); + } + + [Test] + public void Linq81() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> min |> select: The minimum number is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The minimum number is 0.".NormalizeNewLines())); + } + + [Test] + public void Linq82() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => words }} +{{ words + |> min => it.Length + |> select: The shortest word is {it} characters long. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The shortest word is 5 characters long.".NormalizeNewLines())); + } + + [Test] + public void Linq83() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ category: 'it.Key', cheapestPrice: 'min(it, `it.UnitPrice`)' }) + |> select: {category}, {cheapestPrice}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages, 4.5 +Condiments, 10 +Produce, 10 +Meat/Poultry, 7.45 +Seafood, 6 +Dairy Products, 2.5 +Confections, 9.2 +Grains/Cereals, 7 +".NormalizeNewLines())); + } + + [Test] + public void Linq84() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ + g: 'it', + minPrice: 'min(g, `it.UnitPrice`)', + category: 'g.Key', + cheapestProducts: 'where(g, `it.UnitPrice == minPrice`)' + }) + |> select: { category }\n{ cheapestProducts |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages +[{ProductId:24,ProductName:Guaraná Fantástica,Category:Beverages,UnitPrice:4.5,UnitsInStock:20}] +Condiments +[{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13}] +Produce +[{ProductId:74,ProductName:Longlife Tofu,Category:Produce,UnitPrice:10,UnitsInStock:4}] +Meat/Poultry +[{ProductId:54,ProductName:Tourtière,Category:Meat/Poultry,UnitPrice:7.45,UnitsInStock:21}] +Seafood +[{ProductId:13,ProductName:Konbu,Category:Seafood,UnitPrice:6,UnitsInStock:24}] +Dairy Products +[{ProductId:33,ProductName:Geitost,Category:Dairy Products,UnitPrice:2.5,UnitsInStock:112}] +Confections +[{ProductId:19,ProductName:Teatime Chocolate Biscuits,Category:Confections,UnitPrice:9.2,UnitsInStock:25}] +Grains/Cereals +[{ProductId:52,ProductName:Filo Mix,Category:Grains/Cereals,UnitPrice:7,UnitsInStock:38}] +".NormalizeNewLines())); + } + + [Test] + public void Linq85() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> max |> select: The maximum number is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The maximum number is 9.".NormalizeNewLines())); + } + + [Test] + public void Linq86() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => words }} +{{ words + |> max => it.Length + |> select: The longest word is {it} characters long. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The longest word is 9 characters long.".NormalizeNewLines())); + } + + [Test] + public void Linq87() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ category: 'it.Key', mostExpensivePrice: 'max(it, `it.UnitPrice`)' }) + |> select: Category: {category}, MaximumPrice: {mostExpensivePrice}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Category: Beverages, MaximumPrice: 263.5 +Category: Condiments, MaximumPrice: 43.9 +Category: Produce, MaximumPrice: 53 +Category: Meat/Poultry, MaximumPrice: 123.79 +Category: Seafood, MaximumPrice: 62.5 +Category: Dairy Products, MaximumPrice: 55 +Category: Confections, MaximumPrice: 81 +Category: Grains/Cereals, MaximumPrice: 38 +".NormalizeNewLines())); + } + + [Test] + public void Linq88() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ + g: 'it', + maxPrice: 'max(g, `it.UnitPrice`)', + category: 'g.Key', + mostExpensiveProducts: 'where(g, `it.UnitPrice == maxPrice`)' + }) + |> select: { category }\n{ mostExpensiveProducts |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages +[{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17}] +Condiments +[{ProductId:63,ProductName:Vegie-spread,Category:Condiments,UnitPrice:43.9,UnitsInStock:24}] +Produce +[{ProductId:51,ProductName:Manjimup Dried Apples,Category:Produce,UnitPrice:53,UnitsInStock:20}] +Meat/Poultry +[{ProductId:29,ProductName:Thüringer Rostbratwurst,Category:Meat/Poultry,UnitPrice:123.79,UnitsInStock:0}] +Seafood +[{ProductId:18,ProductName:Carnarvon Tigers,Category:Seafood,UnitPrice:62.5,UnitsInStock:42}] +Dairy Products +[{ProductId:59,ProductName:Raclette Courdavault,Category:Dairy Products,UnitPrice:55,UnitsInStock:79}] +Confections +[{ProductId:20,ProductName:Sir Rodney's Marmalade,Category:Confections,UnitPrice:81,UnitsInStock:40}] +Grains/Cereals +[{ProductId:56,ProductName:Gnocchi di nonna Alice,Category:Grains/Cereals,UnitPrice:38,UnitsInStock:21}] +".NormalizeNewLines())); + } + + [Test] + public void Linq89() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers |> average |> select: The average number is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The average number is 4.5.".NormalizeNewLines())); + } + + [Test] + public void Linq90() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => words }} +{{ words + |> average => it.Length + |> select: The average word length is {it} characters. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The average word length is 6.6666666666666".NormalizeNewLines())); + } + + [Test] + public void Linq91() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy => it.Category + |> let({ category: 'it.Key', averagePrice: 'average(it, `it.UnitPrice`)' }) + |> select: Category: {category}, AveragePrice: {averagePrice}\n }} +").NormalizeNewLines() + .Replace("37.979166666666664","37.9791666666667") //.NET Core 3.1 + .Replace("54.00666666666667","54.0066666666667"), + + Does.StartWith(@" +Category: Beverages, AveragePrice: 37.9791666666667 +Category: Condiments, AveragePrice: 23.0625 +Category: Produce, AveragePrice: 32.37 +Category: Meat/Poultry, AveragePrice: 54.0066666666667 +Category: Seafood, AveragePrice: 20.6825 +Category: Dairy Products, AveragePrice: 28.73 +Category: Confections, AveragePrice: 25.16 +Category: Grains/Cereals, AveragePrice: 20.25 +".NormalizeNewLines())); + } + + [Test] + public void Linq92() + { + Assert.That(context.EvaluateScript(@" +{{ [1.7, 2.3, 1.9, 4.1, 2.9] |> to => doubles }} +{{ doubles + |> reduce((accumulator,it) => accumulator * it,1) + |> select: Total product of all numbers: { it |> format('#.####') }. }} +").NormalizeNewLines() + .Replace("37.979166666666664","37.9791666666667") //.NET Core 3.1 + .Replace("54.00666666666667","54.0066666666667"), + + Does.StartWith(@" +Total product of all numbers: 88.3308".NormalizeNewLines())); + } + + [Test] + public void Linq93() + { + Assert.That(context.EvaluateScript(@" +{{ [20, 10, 40, 50, 10, 70, 30] |> to => attemptedWithdrawals }} +{{ attemptedWithdrawals + |> reduce((balance, nextWithdrawal) => ((nextWithdrawal <= balance) ? (balance - nextWithdrawal) : balance), + { initialValue: 100.0, }) + |> select: Ending balance: { it }. }} +").NormalizeNewLines(), + + Does.StartWith(@" +Ending balance: 20".NormalizeNewLines())); + } + + [Test] + public void Linq94() + { + Assert.That(context.EvaluateScript(@" +{{ [0, 2, 4, 5, 6, 8, 9] |> to => numbersA }} +{{ [1, 3, 5, 7, 8] |> to => numbersB }} +All numbers from both arrays: +{{ numbersA |> concat(numbersB) |> select: {it}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +All numbers from both arrays: +0 +2 +4 +5 +6 +8 +9 +1 +3 +5 +7 +8 +".NormalizeNewLines())); + } + + [Test] + public void Linq95() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> map('it.CompanyName') |> to => customerNames }} +{{ products |> map('it.ProductName') |> to => productNames }} +Customer and product names: +{{ customerNames |> concat(productNames) |> select: { it |> raw }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Customer and product names: +Alfreds Futterkiste +Ana Trujillo Emparedados y helados +Antonio Moreno Taquería +Around the Horn +Berglunds snabbköp +Blauer See Delikatessen +".NormalizeNewLines())); + } + + [Test] + public void Linq96() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => wordsA }} +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => wordsB }} +{{ wordsA |> equivalentTo(wordsB) |> select: The sequences match: { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +The sequences match: true".NormalizeNewLines())); + } + + [Test] + public void linq97() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> to => wordsA }} +{{ [ 'apple', 'blueberry', 'cherry' ] |> to => wordsB }} +{{ wordsA |> equivalentTo(wordsB) |> select: The sequences match: { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +The sequences match: false".NormalizeNewLines())); + } + + [Test] + public void Linq99() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ 0 |> to => i }} +{{ numbers |> let({ i: 'incr(i)' }) |> select: v = {index |> incr}, i = {i}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +v = 1, i = 1 +v = 2, i = 2 +v = 3, i = 3 +v = 4, i = 4 +v = 5, i = 5 +v = 6, i = 6 +v = 7, i = 7 +v = 8, i = 8 +v = 9, i = 9 +v = 10, i = 10 +".NormalizeNewLines())); + } + + [Test] + public void Linq100() + { + // lowNumbers is assigned the result not a reusable query + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> where: it <= 3 + |> to => lowNumbers }} +First run numbers <= 3: +{{ lowNumbers |> select: {it}\n }} +{{ 10 |> times |> do: assign('numbers[index]', -numbers[index]) }} +Second run numbers <= 3: +{{ lowNumbers |> select: {it}\n }} +Contents of numbers: +{{ numbers |> select: {it}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +First run numbers <= 3: +1 +3 +2 +0 + +Second run numbers <= 3: +1 +3 +2 +0 + +Contents of numbers: +-5 +-4 +-1 +-3 +-9 +-8 +-6 +-7 +-2 +0 +".NormalizeNewLines())); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqTests.cs new file mode 100644 index 00000000000..eeb5f742d7b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryLinqTests.cs @@ -0,0 +1,2112 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class AnagramEqualityComparer : IEqualityComparer<string>, IEqualityComparer<object> + { + public bool Equals(string x, string y) => GetCanonicalString(x) == GetCanonicalString(y); + public int GetHashCode(string obj) => GetCanonicalString(obj).GetHashCode(); + private string GetCanonicalString(string word) + { + var wordChars = word.ToCharArray(); + Array.Sort(wordChars); + return new string(wordChars); + } + + public bool Equals(object x, object y) => Equals((string) x, (string) y); + + public int GetHashCode(object obj) => GetHashCode((string)obj); + } + + public class QueryFilterTests + { + private static ScriptContext CreateContext() + { + var context = new ScriptContext + { + Args = + { + [ScriptConstants.DefaultDateFormat] = "yyyy/MM/dd", + ["products"] = QueryData.Products, + ["customers"] = QueryData.Customers, + ["comparer"] = new CaseInsensitiveComparer(), + ["anagramComparer"] = new AnagramEqualityComparer(), + } + }; + return context.Init(); + } + + [SetUp] + public void Setup() => context = CreateContext(); + private ScriptContext context; + + [Test] + public void Linq01() // alternative with clean whitespace sensitive string argument syntax: + { + Assert.That(context.EvaluateScript(@" +Numbers < 5: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> where: it < 5 + |> select: { it }\n +}}").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers < 5: +4 +1 +3 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq02() // alternative with clean whitespace sensitive string argument syntax: + { + Assert.That(context.EvaluateScript(@" +Sold out products: +{{ products + |> where: it.UnitsInStock == 0 + |> select: { it.productName |> raw } is sold out!\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Sold out products: +Chef Anton's Gumbo Mix is sold out! +Alice Mutton is sold out! +Thüringer Rostbratwurst is sold out! +Gorgonzola Telino is sold out! +Perth Pasties is sold out! +".NormalizeNewLines())); + } + + [Test] + public void Linq03() + { + Assert.That(context.EvaluateScript(@" +In-stock products that cost more than 3.00: +{{ products + |> where: it.UnitsInStock > 0 and it.UnitPrice > 3 + |> select: { it.productName |> raw } is in stock and costs more than 3.00.\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +In-stock products that cost more than 3.00: +Chai is in stock and costs more than 3.00. +Chang is in stock and costs more than 3.00. +Aniseed Syrup is in stock and costs more than 3.00. +".NormalizeNewLines())); + } + + [Test] + public void Linq04() + { + context.VirtualFiles.WriteFile("customer.html", @" +Customer {{ it.CustomerId }} {{ it.CompanyName |> raw }} +{{ it.Orders |> selectPartial: order }}"); + + context.VirtualFiles.WriteFile("order.html", " Order {{ it.OrderId }}: {{ it.OrderDate |> dateFormat }}\n"); + + Assert.That(context.EvaluateScript(@" +{{ customers + |> where: it.Region == 'WA' + |> assignTo: waCustomers +}} +Customers from Washington and their orders: +{{ waCustomers |> selectPartial: customer }} +").NormalizeNewLines(), + + Does.StartWith(@" +Customers from Washington and their orders: + +Customer LAZYK Lazy K Kountry Store + Order 10482: 1997/03/21 + Order 10545: 1997/05/22 + +Customer TRAIH Trail's Head Gourmet Provisioners + Order 10574: 1997/06/19 + Order 10577: 1997/06/23 + Order 10822: 1998/01/08 +".NormalizeNewLines())); + } + + [Test] + public void Linq05() + { + Assert.That(context.EvaluateScript(@" +Short digits: +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: digits }} +{{ digits + |> where: it.Length < index + |> select: The word {it} is shorter than its value.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Short digits: +The word five is shorter than its value. +The word six is shorter than its value. +The word seven is shorter than its value. +The word eight is shorter than its value. +The word nine is shorter than its value. +".NormalizeNewLines())); + } + + [Test] + public void Linq06() + { + Assert.That(context.EvaluateScript(@" +Numbers + 1: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> select: { it |> incr }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Numbers + 1: +6 +5 +2 +4 +10 +9 +7 +8 +3 +1 +".NormalizeNewLines())); + } + + [Test] + public void Linq07() + { + Assert.That(context.EvaluateScript(@" +Product Names: +{{ products |> select: { it.ProductName |> raw }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Product Names: +Chai +Chang +Aniseed Syrup +Chef Anton's Cajun Seasoning +Chef Anton's Gumbo Mix +".NormalizeNewLines())); + } + + [Test] + public void Linq08() + { + Assert.That(context.EvaluateScript(@" +Number strings: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: strings }} +{{ numbers |> select: { strings[it] }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Number strings: +five +four +one +three +nine +eight +six +seven +two +zero +".NormalizeNewLines())); + } + + [Test] + public void Linq09() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'BlUeBeRrY', 'cHeRry'] |> assignTo: words }} +{{ words |> select: Uppercase: { it |> upper }, Lowercase: { it |> lower }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Uppercase: APPLE, Lowercase: apple +Uppercase: BLUEBERRY, Lowercase: blueberry +Uppercase: CHERRY, Lowercase: cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq10() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: strings }} +{{ numbers |> select: The digit { strings[it] } is { it.isEven() ? 'even' : 'odd' }.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +The digit five is odd. +The digit four is even. +The digit one is odd. +The digit three is odd. +The digit nine is odd. +The digit eight is even. +The digit six is even. +The digit seven is odd. +The digit two is even. +The digit zero is even. +".NormalizeNewLines())); + } + + [Test] + public void Linq11() + { + Assert.That(context.EvaluateScript(@" +Product Info: +{{ products |> select: { it.ProductName |> raw } is in the category { it.Category } and costs { it.UnitPrice |> currency } per unit.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Product Info: +Chai is in the category Beverages and costs $18.00 per unit. +Chang is in the category Beverages and costs $19.00 per unit. +Aniseed Syrup is in the category Condiments and costs $10.00 per unit. +".NormalizeNewLines())); + } + + [Test] + public void Linq12() + { + Assert.That(context.EvaluateScript(@" +Number: In-place? +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> select: { it }: { it |> equals(index) |> lower }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Number: In-place? +5: false +4: false +1: false +3: true +9: false +8: false +6: true +7: true +2: false +0: false +".NormalizeNewLines())); + } + + [Test] + public void Linq13() + { + Assert.That(context.EvaluateScript(@" +Numbers < 5: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: digits }} +{{ numbers + |> where: it < 5 + |> select: { digits[it] }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +Numbers < 5: +four +one +three +two +zero +".NormalizeNewLines())); + } + + [Test] + public void Linq14() + { + Assert.That(context.EvaluateScript(@" +{{ [0, 2, 4, 5, 6, 8, 9] |> assignTo: numbersA }} +{{ [1, 3, 5, 7, 8] |> assignTo: numbersB }} +Pairs where a < b: +{{ numbersA |> zip(numbersB) + |> let({ a: 'it[0]', b: 'it[1]' }) + |> where: a < b + |> select: { a } is less than { b }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq15() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip => it.Orders + |> let => { c: it[0], o: it[1] } + |> where => o.Total < 500 + |> select: ({ c.CustomerId }, { o.OrderId }, { o.Total |> format('0.0#') })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ALFKI, 10702, 330.0) +(ALFKI, 10952, 471.2) +(ANATR, 10308, 88.8) +(ANATR, 10625, 479.75) +".NormalizeNewLines())); + } + + [Test] + public void Linq15_literal() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: o.Total < 500 + |> select: ({ c.CustomerId }, { o.OrderId }, { o.Total |> format('0.0#') })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ALFKI, 10702, 330.0) +(ALFKI, 10952, 471.2) +(ANATR, 10308, 88.8) +(ANATR, 10625, 479.75) +".NormalizeNewLines())); + } + + [Test] + public void Linq16() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: o.OrderDate >= '1998-01-01' + |> select: ({ c.CustomerId }, { o.OrderId }, { o.OrderDate })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ALFKI, 10835, 1/15/1998 12:00:00 AM) +(ALFKI, 10952, 3/16/1998 12:00:00 AM) +(ALFKI, 11011, 4/9/1998 12:00:00 AM) +(ANATR, 10926, 3/4/1998 12:00:00 AM) +(ANTON, 10856, 1/28/1998 12:00:00 AM) +".NormalizeNewLines())); + } + + [Test] + public void Linq17() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: o.Total >= 2000 + |> select: ({ c.CustomerId }, { o.OrderId }, { o.Total |> format('0.0#') })\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +(ANTON, 10573, 2082.0) +(AROUT, 10558, 2142.9) +(AROUT, 10953, 4441.25) +(BERGS, 10384, 2222.4) +(BERGS, 10524, 3192.65) +".NormalizeNewLines())); + } + + [Test] + public void Linq18() + { + var template = @" +{{ '1997-01-01' |> assignTo: cutoffDate }} +{{ customers + |> where: it.Region == 'WA' + |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: o.OrderDate >= cutoffDate + |> select: ({ c.CustomerId }, { o.OrderId })\n }} +"; + Assert.That(context.EvaluateScript(template.NormalizeNewLines()).NormalizeNewLines(), + + Does.StartWith(@" +(LAZYK, 10482) +(LAZYK, 10545) +(TRAIH, 10574) +(TRAIH, 10577) +(TRAIH, 10822) +(WHITC, 10469) +(WHITC, 10483) +(WHITC, 10504) +(WHITC, 10596) +(WHITC, 10693) +(WHITC, 10696) +(WHITC, 10723) +(WHITC, 10740) +(WHITC, 10861) +(WHITC, 10904) +(WHITC, 11032) +(WHITC, 11066) +".NormalizeNewLines())); + } + + [Test] + public void Linq19() + { + Assert.That(context.EvaluateScript(@" +{{ customers + |> let({ cust: 'it', custIndex: 'index' }) + |> zip: cust.Orders + |> let({ o: 'it[1]' }) + |> select: Customer #{ custIndex |> incr } has an order with OrderID { o.OrderId }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Customer #1 has an order with OrderID 10643 +Customer #1 has an order with OrderID 10692 +Customer #1 has an order with OrderID 10702 +Customer #1 has an order with OrderID 10835 +Customer #1 has an order with OrderID 10952 +Customer #1 has an order with OrderID 11011 +Customer #2 has an order with OrderID 10308 +Customer #2 has an order with OrderID 10625 +Customer #2 has an order with OrderID 10759 +Customer #2 has an order with OrderID 10926 +".NormalizeNewLines())); + } + + [Test] + public void Linq20() + { + Assert.That(context.EvaluateScript(@" +First 3 numbers: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> take(3) |> select: { it }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +First 3 numbers: +5 +4 +1 +".NormalizeNewLines())); + } + + [Test] + public void Linq21() + { + Assert.That(context.EvaluateScript(@" +First 3 orders in WA: +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: c.Region == 'WA' + |> select: { [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +First 3 orders in WA: +[LAZYK,10482,1997-03-21] +[LAZYK,10545,1997-05-22] +[TRAIH,10574,1997-06-19] +".NormalizeNewLines())); + } + + [Test] + public void Linq22() + { + Assert.That(context.EvaluateScript(@" +All but first 4 numbers: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> skip(4) |> select: { it }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +All but first 4 numbers: +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq23() + { + Assert.That(context.EvaluateScript(@" +All but first 2 orders in WA: +{{ customers |> zip: it.Orders + |> let({ c: 'it[0]', o: 'it[1]' }) + |> where: c.Region == 'WA' + |> skip(2) + |> select: { [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }\n +}} +").NormalizeNewLines(), + + Does.StartWith(@" +All but first 2 orders in WA: +[TRAIH,10574,1997-06-19] +[TRAIH,10577,1997-06-23] +[TRAIH,10822,1998-01-08] +[WHITC,10269,1996-07-31] +[WHITC,10344,1996-11-01] +[WHITC,10469,1997-03-10] +[WHITC,10483,1997-03-24] +[WHITC,10504,1997-04-11] +[WHITC,10596,1997-07-11] +[WHITC,10693,1997-10-06] +[WHITC,10696,1997-10-08] +[WHITC,10723,1997-10-30] +[WHITC,10740,1997-11-13] +[WHITC,10861,1998-01-30] +[WHITC,10904,1998-02-24] +[WHITC,11032,1998-04-17] +[WHITC,11066,1998-05-01] +".NormalizeNewLines())); + } + + [Test] + public void Linq24() + { + Assert.That(context.EvaluateScript(@" +First numbers less than 6: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> to => numbers }} +{{ numbers + |> takeWhile: it < 6 + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +First numbers less than 6: +5 +4 +1 +3 +".NormalizeNewLines())); + } + + [Test] + public void Linq25() + { + Assert.That(context.EvaluateScript(@" +First numbers not less than their position: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> takeWhile: it >= index + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +First numbers not less than their position: +5 +4 +".NormalizeNewLines())); + } + + [Test] + public void Linq26() + { + Assert.That(context.EvaluateScript(@" +All elements starting from first element divisible by 3: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> skipWhile: mod(it,3) != 0 + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +All elements starting from first element divisible by 3: +3 +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq27() + { + Assert.That(context.EvaluateScript(@" +All elements starting from first element less than its position: +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> skipWhile: it >= index + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +All elements starting from first element less than its position: +1 +3 +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq28() + { + Assert.That(context.EvaluateScript(@" +The sorted list of words: +{{ ['cherry', 'apple', 'blueberry'] |> assignTo: words }} +{{ words + |> orderBy: it + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The sorted list of words: +apple +blueberry +cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq29() + { + Assert.That(context.EvaluateScript(@" +The sorted list of words (by length): +{{ ['cherry', 'apple', 'blueberry'] |> assignTo: words }} +{{ words + |> orderBy: it.Length + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The sorted list of words (by length): +apple +cherry +blueberry +".NormalizeNewLines())); + } + + [Test] + public void Linq30() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> orderBy: it.ProductName + |> select: { it |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +{ProductId:17,ProductName:Alice Mutton,Category:Meat/Poultry,UnitPrice:39,UnitsInStock:0} +{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13} +{ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4,UnitsInStock:123} +{ProductId:60,ProductName:Camembert Pierrot,Category:Dairy Products,UnitPrice:34,UnitsInStock:19} +{ProductId:18,ProductName:Carnarvon Tigers,Category:Seafood,UnitPrice:62.5,UnitsInStock:42} +".NormalizeNewLines())); + } + + [Test] + public void Linq31() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> assignTo: words }} +{{ words + |> orderBy('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +AbAcUs +aPPLE +BlUeBeRrY +bRaNcH +cHeRry +ClOvEr +".NormalizeNewLines())); + } + + [Test] + public void Linq32() + { + Assert.That(context.EvaluateScript(@" +The doubles from highest to lowest: +{{ [1.7, 2.3, 1.9, 4.1, 2.9] |> assignTo: doubles }} +{{ doubles + |> orderByDescending: it + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The doubles from highest to lowest: +4.1 +2.9 +2.3 +1.9 +1.7 +".NormalizeNewLines())); + } + + [Test] + public void Linq33() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> orderByDescending: it.UnitsInStock + |> select: { it |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +{ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75,UnitsInStock:125} +{ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4,UnitsInStock:123} +{ProductId:6,ProductName:Grandma's Boysenberry Spread,Category:Condiments,UnitPrice:25,UnitsInStock:120} +{ProductId:55,ProductName:Pâté chinois,Category:Meat/Poultry,UnitPrice:24,UnitsInStock:115} +{ProductId:61,ProductName:Sirop d'érable,Category:Condiments,UnitPrice:28.5,UnitsInStock:113} +".NormalizeNewLines())); + } + + [Test] + public void Linq34() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> assignTo: words }} +{{ words + |> orderByDescending('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +ClOvEr +cHeRry +bRaNcH +BlUeBeRrY +aPPLE +AbAcUs +".NormalizeNewLines())); + } + + [Test] + public void Linq35() + { + Assert.That(context.EvaluateScript(@" +Sorted digits: +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: digits }} +{{ digits + |> orderBy: it.length + |> thenBy: it + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Sorted digits: +one +six +two +five +four +nine +zero +eight +seven +three +".NormalizeNewLines())); + } + + [Test] + public void Linq36() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> assignTo: words }} +{{ words + |> orderBy: it.length + |> thenBy('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +aPPLE +AbAcUs +bRaNcH +cHeRry +ClOvEr +BlUeBeRrY +".NormalizeNewLines())); + } + + [Test] + public void Linq37() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> orderBy: it.Category + |> thenByDescending: it.UnitPrice + |> select: { it |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17} +{ProductId:43,ProductName:Ipoh Coffee,Category:Beverages,UnitPrice:46,UnitsInStock:17} +{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39} +{ProductId:35,ProductName:Steeleye Stout,Category:Beverages,UnitPrice:18,UnitsInStock:20} +{ProductId:39,ProductName:Chartreuse verte,Category:Beverages,UnitPrice:18,UnitsInStock:69} +{ProductId:76,ProductName:Lakkalikööri,Category:Beverages,UnitPrice:18,UnitsInStock:57} +{ProductId:70,ProductName:Outback Lager,Category:Beverages,UnitPrice:15,UnitsInStock:15} +{ProductId:34,ProductName:Sasquatch Ale,Category:Beverages,UnitPrice:14,UnitsInStock:111} +".NormalizeNewLines())); + } + + [Test] + public void Linq38() + { + Assert.That(context.EvaluateScript(@" +{{ ['aPPLE', 'AbAcUs', 'bRaNcH', 'BlUeBeRrY', 'ClOvEr', 'cHeRry'] |> assignTo: words }} +{{ words + |> orderBy: it.length + |> thenByDescending('it', { comparer }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +aPPLE +ClOvEr +cHeRry +bRaNcH +AbAcUs +BlUeBeRrY +".NormalizeNewLines())); + } + + [Test] + public void Linq39() + { + Assert.That(context.EvaluateScript(@" +A backwards list of the digits with a second character of 'i': +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: digits }} +{{ digits + |> where: it[1] == 'i' + |> reverse + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +A backwards list of the digits with a second character of 'i': +nine +eight +six +five +".NormalizeNewLines())); + } + + [Test] + public void Linq40() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> groupBy: mod(it,5) + |> let({ remainder: 'it.Key', numbers: 'it' }) + |> select: Numbers with a remainder of { remainder } when divided by 5:\n{ numbers |> select('{it}\n') } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers with a remainder of 0 when divided by 5: +5 +0 +Numbers with a remainder of 4 when divided by 5: +4 +9 +Numbers with a remainder of 1 when divided by 5: +1 +6 +Numbers with a remainder of 3 when divided by 5: +3 +8 +Numbers with a remainder of 2 when divided by 5: +7 +2 +".NormalizeNewLines())); + } + + [Test] + public void Linq41() + { + Assert.That(context.EvaluateScript(@" +{{ ['blueberry', 'chimpanzee', 'abacus', 'banana', 'apple', 'cheese'] |> assignTo: words }} +{{ words + |> groupBy: it[0] + |> let({ firstLetter: 'it.Key', words: 'it' }) + |> select: Words that start with the letter '{firstLetter}':\n{ words |> select('{it}\n') } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Words that start with the letter 'b': +blueberry +banana +Words that start with the letter 'c': +chimpanzee +cheese +Words that start with the letter 'a': +abacus +apple +".NormalizeNewLines())); + } + + [Test] + public void Linq42() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ category: 'it.Key', products: 'it' }) + |> select: {category}:\n{ products |> select('{it |> jsv}\n') } }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages: +{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39} +{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +{ProductId:24,ProductName:Guaraná Fantástica,Category:Beverages,UnitPrice:4.5,UnitsInStock:20} +{ProductId:34,ProductName:Sasquatch Ale,Category:Beverages,UnitPrice:14,UnitsInStock:111} +{ProductId:35,ProductName:Steeleye Stout,Category:Beverages,UnitPrice:18,UnitsInStock:20} +{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17} +{ProductId:39,ProductName:Chartreuse verte,Category:Beverages,UnitPrice:18,UnitsInStock:69} +{ProductId:43,ProductName:Ipoh Coffee,Category:Beverages,UnitPrice:46,UnitsInStock:17} +{ProductId:67,ProductName:Laughing Lumberjack Lager,Category:Beverages,UnitPrice:14,UnitsInStock:52} +{ProductId:70,ProductName:Outback Lager,Category:Beverages,UnitPrice:15,UnitsInStock:15} +{ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75,UnitsInStock:125} +{ProductId:76,ProductName:Lakkalikööri,Category:Beverages,UnitPrice:18,UnitsInStock:57} +Condiments: +{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13} +{ProductId:4,ProductName:Chef Anton's Cajun Seasoning,Category:Condiments,UnitPrice:22,UnitsInStock:53} +".NormalizeNewLines())); + } + + [Test] + public void Linq43() + { + context.VirtualFiles.WriteFile("month-orders.html", @" +{{ year }} +{{ monthGroups |> scopeVars |> select: { indent }{ month }\n{ 2 |> indents }{ orders |> jsv }\n }}"); + + Assert.That(context.EvaluateScript(@" +{{ customers + |> let({ + companyName: 'it.CompanyName', + yearGroups: ""map ( + groupBy(it.Orders, 'it.OrderDate.Year'), + '{ + year: it.Key, + monthGroups: map ( + groupBy(it, `it.OrderDate.Month`), + `{ month: it.Key, orders: it }` + ) + }' + )"" + }) + |> select: \n# { companyName |> raw }{ yearGroups |> scopeVars |> selectPartial('month-orders') } +}} +").NormalizeNewLines(), + + Does.StartWith(@" +# Alfreds Futterkiste +1997 + 8 + [{OrderId:10643,OrderDate:1997-08-25,Total:814.5}] + 10 + [{OrderId:10692,OrderDate:1997-10-03,Total:878},{OrderId:10702,OrderDate:1997-10-13,Total:330}] + +1998 + 1 + [{OrderId:10835,OrderDate:1998-01-15,Total:845.8}] + 3 + [{OrderId:10952,OrderDate:1998-03-16,Total:471.2}] + 4 + [{OrderId:11011,OrderDate:1998-04-09,Total:933.5}] + +# Ana Trujillo Emparedados y helados +1996 + 9 + [{OrderId:10308,OrderDate:1996-09-18,Total:88.8}] +".NormalizeNewLines())); + } + + [Test] + public void Linq43_alt() + { + context.VirtualFiles.WriteFile("month-orders.html", @" +{{ year }} +{{ monthGroups |> scopeVars |> select: { indent }{ month }\n{ 2 |> indents }{ orders |> jsv }\n }}"); + + Assert.That(context.EvaluateScript(@" +{{ customers + |> map => { + companyName: it.CompanyName, + yearGroups: map ( + groupBy(it.Orders, it => it.OrderDate.Year), + yg => { + year: yg.Key, + monthGroups: map ( + groupBy(yg, o => o.OrderDate.Month), + mg => { month: mg.Key, orders: mg } + ) + } + ) + } + |> select: \n# { it.companyName |> raw }{ it.yearGroups |> scopeVars |> selectPartial('month-orders') } +}} +").NormalizeNewLines(), + + Does.StartWith(@" +# Alfreds Futterkiste +1997 + 8 + [{OrderId:10643,OrderDate:1997-08-25,Total:814.5}] + 10 + [{OrderId:10692,OrderDate:1997-10-03,Total:878},{OrderId:10702,OrderDate:1997-10-13,Total:330}] + +1998 + 1 + [{OrderId:10835,OrderDate:1998-01-15,Total:845.8}] + 3 + [{OrderId:10952,OrderDate:1998-03-16,Total:471.2}] + 4 + [{OrderId:11011,OrderDate:1998-04-09,Total:933.5}] + +# Ana Trujillo Emparedados y helados +1996 + 9 + [{OrderId:10308,OrderDate:1996-09-18,Total:88.8}] +".NormalizeNewLines())); + } + + [Test] + public void Linq44() + { + Assert.That(context.EvaluateScript(@" +{{ ['from ', ' salt', ' earn ', ' last ', ' near ', ' form '] |> assignTo: anagrams }} +{{ anagrams + |> groupBy('trim(it)', { comparer: anagramComparer }) + |> select: { it |> json }\n +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +[""from "","" form ""] +["" salt"","" last ""] +["" earn "","" near ""] +".NormalizeNewLines())); + } + + [Test] + public void Linq45() + { + Assert.That(context.EvaluateScript(@" +{{ ['from ', ' salt', ' earn ', ' last ', ' near ', ' form '] |> assignTo: anagrams }} +{{ anagrams + |> groupBy('trim(it)', { map: 'upper(it)', comparer: anagramComparer }) + |> select: { it |> json }\n +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +[""FROM "","" FORM ""] +["" SALT"","" LAST ""] +["" EARN "","" NEAR ""] +".NormalizeNewLines())); + } + + [Test] + public void Linq46() + { + Assert.That(context.EvaluateScript(@" +Prime factors of 300: +{{ [2, 2, 3, 5, 5] |> assignTo: factorsOf300 }} +{{ factorsOf300 |> distinct |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Prime factors of 300: +2 +3 +5 +".NormalizeNewLines())); + } + + [Test] + public void Linq47() + { + Assert.That(context.EvaluateScript(@" +Category names: +{{ products + |> map: it.Category + |> distinct + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Category names: +Beverages +Condiments +Produce +Meat/Poultry +Seafood +Dairy Products +Confections +Grains/Cereals +".NormalizeNewLines())); + } + + [Test] + public void Linq48() + { + Assert.That(context.EvaluateScript(@" +{{ [ 0, 2, 4, 5, 6, 8, 9 ] |> assignTo: numbersA }} +{{ [ 1, 3, 5, 7, 8 ] |> assignTo: numbersB }} +Unique numbers from both arrays: +{{ numbersA |> union(numbersB) |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Unique numbers from both arrays: +0 +2 +4 +5 +6 +8 +9 +1 +3 +7 +".NormalizeNewLines())); + } + + [Test] + public void Linq49() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> map: it.ProductName[0] + |> assignTo: productFirstChars }} +{{ customers + |> map: it.CompanyName[0] + |> assignTo: customerFirstChars }} +Unique first letters from Product names and Customer names: +{{ productFirstChars + |> union(customerFirstChars) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Unique first letters from Product names and Customer names: +C +A +G +U +N +M +I +Q +K +T +P +S +R +B +J +Z +V +F +E +W +L +O +D +H +".NormalizeNewLines())); + } + + [Test] + public void Linq50() + { + Assert.That(context.EvaluateScript(@" +{{ [ 0, 2, 4, 5, 6, 8, 9 ] |> assignTo: numbersA }} +{{ [ 1, 3, 5, 7, 8 ] |> assignTo: numbersB }} +Common numbers shared by both arrays: +{{ numbersA |> intersect(numbersB) |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Common numbers shared by both arrays: +5 +8 +".NormalizeNewLines())); + } + + [Test] + public void Linq51() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> map: it.ProductName[0] + |> assignTo: productFirstChars }} +{{ customers + |> map: it.CompanyName[0] + |> assignTo: customerFirstChars }} +Common first letters from Product names and Customer names: +{{ productFirstChars + |> intersect(customerFirstChars) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Common first letters from Product names and Customer names: +C +A +G +N +M +I +Q +K +T +P +S +R +B +V +F +E +W +L +O +".NormalizeNewLines())); + } + + [Test] + public void Linq52() + { + Assert.That(context.EvaluateScript(@" +{{ [ 0, 2, 4, 5, 6, 8, 9 ] |> assignTo: numbersA }} +{{ [ 1, 3, 5, 7, 8 ] |> assignTo: numbersB }} +Numbers in first array but not second array: +{{ numbersA |> except(numbersB) |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers in first array but not second array: +0 +2 +4 +6 +9 +".NormalizeNewLines())); + } + + [Test] + public void Linq53() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> map: it.ProductName[0] + |> assignTo: productFirstChars }} +{{ customers + |> map: it.CompanyName[0] + |> assignTo: customerFirstChars }} +First letters from Product names, but not from Customer names: +{{ productFirstChars + |> except(customerFirstChars) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +First letters from Product names, but not from Customer names: +U +J +Z +".NormalizeNewLines())); + } + + [Test] + public void Linq54() + { + Assert.That(context.EvaluateScript(@" +{{ [ 1.7, 2.3, 1.9, 4.1, 2.9 ] |> assignTo: doubles }} +Every other double from highest to lowest: +{{ doubles + |> orderByDescending: it + |> step({ by: 2 }) + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Every other double from highest to lowest: +4.1 +2.3 +1.7 +".NormalizeNewLines())); + } + + [Test] + public void Linq55() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: words }} +The sorted word list: +{{ words + |> orderBy: it + |> toList + |> select: { it }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +The sorted word list: +apple +blueberry +cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq56() + { + Assert.That(context.EvaluateScript(@" +{{ [{name:'Alice', score:50}, {name: 'Bob', score:40}, {name:'Cathy', score:45}] |> assignTo: scoreRecords }} +Bob's score: +{{ scoreRecords + |> toDictionary: it.name + |> get: Bob + |> select: { it['name'] } = { it['score'] } +}} +").NormalizeNewLines(), + + Is.EqualTo(@" +Bob's score: +Bob = 40 +".NormalizeNewLines())); + } + + [Test] + public void Linq57() + { + Assert.That(context.EvaluateScript(@" +{{ [null, 1.0, 'two', 3, 'four', 5, 'six', 7.0] |> assignTo: numbers }} +Numbers stored as doubles: +{{ numbers + |> of({ type: 'Double' }) + |> select: { it |> format('#.0') }\n }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Numbers stored as doubles: +1.0 +7.0 +".NormalizeNewLines())); + } + + [Test] + public void Linq58() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> where: it.ProductId == 12 + |> first + |> select: { it |> jsv } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +{ProductId:12,ProductName:Queso Manchego La Pastora,Category:Dairy Products,UnitPrice:38,UnitsInStock:86} +".NormalizeNewLines())); + } + + [Test] + public void Linq59() + { + Assert.That(context.EvaluateScript(@" +{{ ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] |> assignTo: strings }} +{{ strings + |> first: it[0] == 'o' + |> select: A string starting with 'o': { it } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +A string starting with 'o': one +".NormalizeNewLines())); + } + + [Test] + public void Linq61() + { + Assert.That(context.EvaluateScript(@" +{{ [] |> assignTo: numbers }} +{{ numbers |> first |> otherwise('null') }} +").NormalizeNewLines(), + + Is.EqualTo(@" +null +".NormalizeNewLines())); + } + + [Test] + public void Linq62() + { + Assert.That(context.EvaluateScript(@" +Product 789 exists: {{ products + |> first: it.ProductId == 789 + |> isNotNull }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Product 789 exists: False +".NormalizeNewLines())); + } + + [Test] + public void Linq64() + { + Assert.That(context.EvaluateScript(@" +{{ [ 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 ] |> assignTo: numbers }} +{{ numbers + |> where: it > 5 + |> elementAt(1) + |> select: Second number > 5: { it } }} +").NormalizeNewLines(), + + Is.EqualTo(@" +Second number > 5: 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq65() + { + Assert.That(context.EvaluateScript(@" +{{ range(100,50) + |> select: The number {it} is { it.isEven() ? 'even' : 'odd' }.\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +The number 100 is even. +The number 101 is odd. +The number 102 is even. +The number 103 is odd. +The number 104 is even. +The number 105 is odd. +The number 106 is even. +The number 107 is odd. +The number 108 is even. +The number 109 is odd. +The number 110 is even. +".NormalizeNewLines())); + } + + [Test] + public void Linq66() + { + Assert.That(context.EvaluateScript(@" +{{ 10 |> itemsOf(7) |> select: {it}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +".NormalizeNewLines())); + } + + [Test] + public void Linq67() + { + Assert.That(context.EvaluateScript(@" +{{ ['believe', 'relief', 'receipt', 'field'] |> assignTo: words }} +{{ words + |> any: contains(it, 'ei') + |> select: There is a word that contains in the list that contains 'ei': { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +There is a word that contains in the list that contains 'ei': true".NormalizeNewLines())); + } + + [Test] + public void Linq69() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> where: any(it, 'it.UnitsInStock == 0') + |> let({ category: 'it.Key', products: 'it' }) + |> select: { category }\n{ products |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Condiments +[{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13},{ProductId:4,ProductName:Chef Anton's Cajun Seasoning,Category:Condiments,UnitPrice:22,UnitsInStock:53} +".NormalizeNewLines())); + } + + [Test] + public void Linq70() + { + Assert.That(context.EvaluateScript(@" +{{ [1, 11, 3, 19, 41, 65, 19] |> assignTo: numbers }} +{{ numbers + |> all: isOdd(it) + |> select: The list contains only odd numbers: { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +The list contains only odd numbers: true".NormalizeNewLines())); + } + + [Test] + public void Linq72() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> where: all(it, 'it.UnitsInStock > 0') + |> let({ category: 'it.Key', products: 'it' }) + |> select: { category }\n{ products |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages +[{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39},{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +".NormalizeNewLines())); + } + + [Test] + public void Linq73() + { + Assert.That(context.EvaluateScript(@" +{{ [2, 2, 3, 5, 5] |> assignTo: factorsOf300 }} +{{ factorsOf300 |> distinct |> count |> select: There are {it} unique factors of 300. }} +").NormalizeNewLines(), + + Does.StartWith(@" +There are 3 unique factors of 300.".NormalizeNewLines())); + } + + [Test] + public void Linq74() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> count: isOdd(it) + |> select: There are {it} odd numbers in the list. }} +").NormalizeNewLines(), + + Does.StartWith(@" +There are 5 odd numbers in the list.".NormalizeNewLines())); + } + + [Test] + public void Linq76() + { + Assert.That(context.EvaluateScript(@" +{{ customers + |> let({ customerId: 'it.CustomerId', ordersCount: 'count(it.Orders)' }) + |> select: {customerId}, {ordersCount}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +ALFKI, 6 +ANATR, 4 +ANTON, 7 +AROUT, 13 +BERGS, 18 +BLAUS, 7 +BLONP, 11 +".NormalizeNewLines())); + } + + [Test] + public void Linq77() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ category: 'it.Key', productCount: 'count(it)' }) + |> select: {category}, {productCount}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages, 12 +Condiments, 12 +Produce, 5 +Meat/Poultry, 6 +Seafood, 12 +Dairy Products, 10 +Confections, 13 +Grains/Cereals, 7 +".NormalizeNewLines())); + } + + [Test] + public void Linq78() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> sum |> select: The sum of the numbers is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The sum of the numbers is 45.".NormalizeNewLines())); + } + + [Test] + public void Linq79() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry'] |> assignTo: words }} +{{ words + |> sum: it.Length + |> select: There are a total of {it} characters in these words. }} +").NormalizeNewLines(), + + Does.StartWith(@" +There are a total of 20 characters in these words.".NormalizeNewLines())); + } + + [Test] + public void Linq80() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ category: 'it.Key', totalUnitsInStock: 'sum(it, `it.UnitsInStock`)' }) + |> select: {category}, {totalUnitsInStock}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages, 559 +Condiments, 507 +Produce, 100 +Meat/Poultry, 165 +Seafood, 701 +Dairy Products, 393 +Confections, 386 +Grains/Cereals, 308 +".NormalizeNewLines())); + } + + [Test] + public void Linq81() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> min |> select: The minimum number is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The minimum number is 0.".NormalizeNewLines())); + } + + [Test] + public void Linq82() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: words }} +{{ words + |> min: it.Length + |> select: The shortest word is {it} characters long. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The shortest word is 5 characters long.".NormalizeNewLines())); + } + + [Test] + public void Linq83() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ category: 'it.Key', cheapestPrice: 'min(it, `it.UnitPrice`)' }) + |> select: {category}, {cheapestPrice}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages, 4.5 +Condiments, 10 +Produce, 10 +Meat/Poultry, 7.45 +Seafood, 6 +Dairy Products, 2.5 +Confections, 9.2 +Grains/Cereals, 7 +".NormalizeNewLines())); + } + + [Test] + public void Linq84() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ + g: 'it', + minPrice: 'min(g, `it.UnitPrice`)', + category: 'g.Key', + cheapestProducts: 'where(g, `it.UnitPrice == minPrice`)' + }) + |> select: { category }\n{ cheapestProducts |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages +[{ProductId:24,ProductName:Guaraná Fantástica,Category:Beverages,UnitPrice:4.5,UnitsInStock:20}] +Condiments +[{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13}] +Produce +[{ProductId:74,ProductName:Longlife Tofu,Category:Produce,UnitPrice:10,UnitsInStock:4}] +Meat/Poultry +[{ProductId:54,ProductName:Tourtière,Category:Meat/Poultry,UnitPrice:7.45,UnitsInStock:21}] +Seafood +[{ProductId:13,ProductName:Konbu,Category:Seafood,UnitPrice:6,UnitsInStock:24}] +Dairy Products +[{ProductId:33,ProductName:Geitost,Category:Dairy Products,UnitPrice:2.5,UnitsInStock:112}] +Confections +[{ProductId:19,ProductName:Teatime Chocolate Biscuits,Category:Confections,UnitPrice:9.2,UnitsInStock:25}] +Grains/Cereals +[{ProductId:52,ProductName:Filo Mix,Category:Grains/Cereals,UnitPrice:7,UnitsInStock:38}] +".NormalizeNewLines())); + } + + [Test] + public void Linq85() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> max |> select: The maximum number is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The maximum number is 9.".NormalizeNewLines())); + } + + [Test] + public void Linq86() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: words }} +{{ words + |> max: it.Length + |> select: The longest word is {it} characters long. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The longest word is 9 characters long.".NormalizeNewLines())); + } + + [Test] + public void Linq87() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ category: 'it.Key', mostExpensivePrice: 'max(it, `it.UnitPrice`)' }) + |> select: Category: {category}, MaximumPrice: {mostExpensivePrice}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Category: Beverages, MaximumPrice: 263.5 +Category: Condiments, MaximumPrice: 43.9 +Category: Produce, MaximumPrice: 53 +Category: Meat/Poultry, MaximumPrice: 123.79 +Category: Seafood, MaximumPrice: 62.5 +Category: Dairy Products, MaximumPrice: 55 +Category: Confections, MaximumPrice: 81 +Category: Grains/Cereals, MaximumPrice: 38 +".NormalizeNewLines())); + } + + [Test] + public void Linq88() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ + g: 'it', + maxPrice: 'max(g, `it.UnitPrice`)', + category: 'g.Key', + mostExpensiveProducts: 'where(g, `it.UnitPrice == maxPrice`)' + }) + |> select: { category }\n{ mostExpensiveProducts |> jsv }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Beverages +[{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17}] +Condiments +[{ProductId:63,ProductName:Vegie-spread,Category:Condiments,UnitPrice:43.9,UnitsInStock:24}] +Produce +[{ProductId:51,ProductName:Manjimup Dried Apples,Category:Produce,UnitPrice:53,UnitsInStock:20}] +Meat/Poultry +[{ProductId:29,ProductName:Thüringer Rostbratwurst,Category:Meat/Poultry,UnitPrice:123.79,UnitsInStock:0}] +Seafood +[{ProductId:18,ProductName:Carnarvon Tigers,Category:Seafood,UnitPrice:62.5,UnitsInStock:42}] +Dairy Products +[{ProductId:59,ProductName:Raclette Courdavault,Category:Dairy Products,UnitPrice:55,UnitsInStock:79}] +Confections +[{ProductId:20,ProductName:Sir Rodney's Marmalade,Category:Confections,UnitPrice:81,UnitsInStock:40}] +Grains/Cereals +[{ProductId:56,ProductName:Gnocchi di nonna Alice,Category:Grains/Cereals,UnitPrice:38,UnitsInStock:21}] +".NormalizeNewLines())); + } + + [Test] + public void Linq89() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers |> average |> select: The average number is {it}. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The average number is 4.5.".NormalizeNewLines())); + } + + [Test] + public void Linq90() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: words }} +{{ words + |> average: it.Length + |> select: The average word length is {it} characters. }} +").NormalizeNewLines(), + + Does.StartWith(@" +The average word length is 6.6666666666666".NormalizeNewLines())); + } + + [Test] + public void Linq91() + { + Assert.That(context.EvaluateScript(@" +{{ products + |> groupBy: it.Category + |> let({ category: 'it.Key', averagePrice: 'average(it, `it.UnitPrice`)' }) + |> select: Category: {category}, AveragePrice: {averagePrice}\n }} +").NormalizeNewLines() + .Replace("37.979166666666664","37.9791666666667") //.NET Core 3.1 + .Replace("54.00666666666667","54.0066666666667"), + + Does.StartWith(@" +Category: Beverages, AveragePrice: 37.9791666666667 +Category: Condiments, AveragePrice: 23.0625 +Category: Produce, AveragePrice: 32.37 +Category: Meat/Poultry, AveragePrice: 54.0066666666667 +Category: Seafood, AveragePrice: 20.6825 +Category: Dairy Products, AveragePrice: 28.73 +Category: Confections, AveragePrice: 25.16 +Category: Grains/Cereals, AveragePrice: 20.25 +".NormalizeNewLines())); + } + + [Test] + public void Linq92() + { + Assert.That(context.EvaluateScript(@" +{{ [1.7, 2.3, 1.9, 4.1, 2.9] |> assignTo: doubles }} +{{ doubles + |> reduce((accumulator,it) => accumulator * it,1) + |> select: Total product of all numbers: { it |> format('#.####') }. }} +").NormalizeNewLines(), + + Does.StartWith(@" +Total product of all numbers: 88.3308".NormalizeNewLines())); + } + + [Test] + public void Linq93() + { + Assert.That(context.EvaluateScript(@" +{{ [20, 10, 40, 50, 10, 70, 30] |> assignTo: attemptedWithdrawals }} +{{ attemptedWithdrawals + |> reduce((balance, nextWithdrawal) => ((nextWithdrawal <= balance) ? (balance - nextWithdrawal) : balance), + { initialValue: 100.0, }) + |> select: Ending balance: { it }. }} +").NormalizeNewLines(), + + Does.StartWith(@" +Ending balance: 20".NormalizeNewLines())); + } + + [Test] + public void Linq94() + { + Assert.That(context.EvaluateScript(@" +{{ [0, 2, 4, 5, 6, 8, 9] |> assignTo: numbersA }} +{{ [1, 3, 5, 7, 8] |> assignTo: numbersB }} +All numbers from both arrays: +{{ numbersA |> concat(numbersB) |> select: {it}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +All numbers from both arrays: +0 +2 +4 +5 +6 +8 +9 +1 +3 +5 +7 +8 +".NormalizeNewLines())); + } + + [Test] + public void Linq95() + { + Assert.That(context.EvaluateScript(@" +{{ customers |> map('it.CompanyName') |> assignTo: customerNames }} +{{ products |> map('it.ProductName') |> assignTo: productNames }} +Customer and product names: +{{ customerNames |> concat(productNames) |> select: { it |> raw }\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +Customer and product names: +Alfreds Futterkiste +Ana Trujillo Emparedados y helados +Antonio Moreno Taquería +Around the Horn +Berglunds snabbköp +Blauer See Delikatessen +".NormalizeNewLines())); + } + + [Test] + public void Linq96() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: wordsA }} +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: wordsB }} +{{ wordsA |> equivalentTo(wordsB) |> select: The sequences match: { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +The sequences match: true".NormalizeNewLines())); + } + + [Test] + public void linq97() + { + Assert.That(context.EvaluateScript(@" +{{ [ 'cherry', 'apple', 'blueberry' ] |> assignTo: wordsA }} +{{ [ 'apple', 'blueberry', 'cherry' ] |> assignTo: wordsB }} +{{ wordsA |> equivalentTo(wordsB) |> select: The sequences match: { it |> lower } }} +").NormalizeNewLines(), + + Does.StartWith(@" +The sequences match: false".NormalizeNewLines())); + } + + [Test] + public void Linq99() + { + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ 0 |> assignTo: i }} +{{ numbers |> let({ i: 'incr(i)' }) |> select: v = {index |> incr}, i = {i}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +v = 1, i = 1 +v = 2, i = 2 +v = 3, i = 3 +v = 4, i = 4 +v = 5, i = 5 +v = 6, i = 6 +v = 7, i = 7 +v = 8, i = 8 +v = 9, i = 9 +v = 10, i = 10 +".NormalizeNewLines())); + } + + [Test] + public void Linq100() + { + // lowNumbers is assigned the result not a reusable query + Assert.That(context.EvaluateScript(@" +{{ [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] |> assignTo: numbers }} +{{ numbers + |> where: it <= 3 + |> assignTo: lowNumbers }} +First run numbers <= 3: +{{ lowNumbers |> select: {it}\n }} +{{ 10 |> times |> do: assign('numbers[index]', -numbers[index]) }} +Second run numbers <= 3: +{{ lowNumbers |> select: {it}\n }} +Contents of numbers: +{{ numbers |> select: {it}\n }} +").NormalizeNewLines(), + + Does.StartWith(@" +First run numbers <= 3: +1 +3 +2 +0 + +Second run numbers <= 3: +1 +3 +2 +0 + +Contents of numbers: +-5 +-4 +-1 +-3 +-9 +-8 +-6 +-7 +-2 +0 +".NormalizeNewLines())); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryTests.cs new file mode 100644 index 00000000000..1e760cfa6b3 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/QueryTests.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class QueryTests + { + [Test] + public void Take_does_limit_KVP_Objects() + { + var context = new ScriptContext { + Args = { + ["items"] = new List<KeyValuePair<string, object>> { + new("A", 1), + new("B", 2), + new("C", 3), + } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ items | textDump }}").NormalizeNewLines(), Is.EqualTo(@"||| +|-|-| +| A | 1 | +| B | 2 | +| C | 3 |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ items | take(2) | textDump }}").NormalizeNewLines(), Is.EqualTo(@"||| +|-|-| +| A | 1 | +| B | 2 |".NormalizeNewLines())); + } + + [Test] + public void Take_does_limit_KVP_longs() + { + var context = new ScriptContext { + Args = { + ["items"] = new List<KeyValuePair<string, long>> { + new("A", 1), + new("B", 2), + new("C", 3), + } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ items | textDump }}").NormalizeNewLines(), Is.EqualTo(@"||| +|-|-| +| A | 1 | +| B | 2 | +| C | 3 |".NormalizeNewLines())); + + Assert.That(context.EvaluateScript("{{ items | take(2) | textDump }}").NormalizeNewLines(), Is.EqualTo(@"||| +|-|-| +| A | 1 | +| B | 2 |".NormalizeNewLines())); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/RedisScriptsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/RedisScriptsTests.cs new file mode 100644 index 00000000000..bd2fb600a34 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/RedisScriptsTests.cs @@ -0,0 +1,29 @@ +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Redis; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class RedisScriptsTests + { + [Test] + public void Can_pass_filter_by_argument_to_partial() + { + var context = new ScriptContext + { + ScriptMethods = + { + new RedisScripts { RedisManager = new RedisManagerPool() }, + } + }.Init(); + + context.VirtualFiles.WriteFile("page-argument.html", "{{ 'partial-argument' |> partial({ redis: redisConnection }) }}"); + context.VirtualFiles.WriteFile("partial-argument.html", "{{ redis.host }}, {{ redis.port }}"); + + var output = new PageResult(context.GetPage("page-argument")).Result; + + Assert.That(output, Is.EqualTo("localhost, 6379")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptAssembliesTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptAssembliesTests.cs new file mode 100644 index 00000000000..b6b0c00c7b3 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptAssembliesTests.cs @@ -0,0 +1,683 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using Funq; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class Ints + { + public Ints(int a, int b) + { + A = a; + B = b; + } + public int A { get; set; } + public int B { get; set; } + public int C { get; set; } + public int D { get; set; } + public int GetTotal() => A + B + C + D; + + public int AddA(int a) => A += a; + + public string GenericMethod<T>() => typeof(T).Name + " " + GetTotal(); + + public string GenericMethod<T>(T value) => typeof(T).Name + $" {value} " + GetTotal(); + } + + public class Adder + { + public string String { get; set; } + public double Double { get; set; } + + public Adder(string str) => String = str; + public Adder(double num) => Double = num; + + public string Add(string str) => String += str; + public double Add(double num) => Double += num; + + public override string ToString() => String != null ? $"string: {String}" : $"double: {Double}"; + } + + public class StaticLog + { + static StringBuilder sb = new StringBuilder(); + + public static void Log(string message) => sb.Append(message); + + public static void Log<T>(string message) => sb.Append(typeof(T).Name + " " + message); + + public static string AllLogs() => sb.ToString(); + + public static void Clear() => sb.Clear(); + + public static string Prop { get; } = "StaticLog.Prop"; + public static string Field = "StaticLog.Field"; + public const string Const = "StaticLog.Const"; + + public string InstanceProp { get; } = "StaticLog.InstanceProp"; + public string InstanceField = "StaticLog.InstanceField"; + + public class Inner1 + { + public static string Prop1 { get; } = "StaticLog.Inner1.Prop1"; + public static string Field1 = "StaticLog.Inner1.Field1"; + public const string Const1 = "StaticLog.Inner1.Const1"; + + public string InstanceProp1 { get; } = "StaticLog.Inner1.InstanceProp1"; + public string InstanceField1 = "StaticLog.Inner1.InstanceField1"; + + public static class Inner2 + { + public static string Prop2 { get; } = "StaticLog.Inner1.Inner2.Prop2"; + public static string Field2 = "StaticLog.Inner1.Inner2.Field2"; + public const string Const2 = "StaticLog.Inner1.Inner2.Const2"; + } + } + } + + public class GenericStaticLog<T> + { + static StringBuilder sb = new StringBuilder(); + + public static void Log(string message) => sb.Append(typeof(T).Name + " " + message); + + public static void Log<T2>(string message) => sb.Append(typeof(T).Name + " " + typeof(T2).Name + " " + message); + + public static string AllLogs() => sb.ToString(); + + public static void Clear() => sb.Clear(); + } + + public class InstanceLog + { + private readonly string prefix; + public InstanceLog(string prefix) => this.prefix = prefix; + + StringBuilder sb = new StringBuilder(); + + public void Log(string message) => sb.Append(prefix + " " + message); + + public void Log<T2>(string message) => sb.Append(prefix + " " + typeof(T2).Name + " " + message); + + public string AllLogs() => sb.ToString(); + + public void Clear() => sb.Clear(); + } + + internal class InternalType + { + public InternalType() { } + public InternalType(int num) {} + } + + public interface ICursor + { + string AProp { get; set; } + string AMethod(int arg); + } + public class Cursor : ICursor + { + public string AProp { get; set; } + public string BProp { get; set; } + public string AMethod(int arg) => $"AMethod: {arg}"; + public string BMethod(int arg) => $"BMethod: {arg}"; + } + + public class ContentResolver + { + public ICursor Query( + Uri uri, + string[] projection, + string selection, + string[] selectionArgs, + string sortOrder) + { + return new Cursor(); + } + } + + public class ScriptAssembliesTests + { + private static ScriptContext CreateContext() => + new ScriptContext { + ScriptMethods = { + new ProtectedScripts() + }, + ScriptTypes = { + typeof(DynamicInt), + } + }; + + private static ScriptContext CreateContext(Action<ScriptContext> fn) + { + var context = CreateContext(); + fn(context); + return context; + } + + [Test] + public void Does_not_allow_Types_by_default() + { + Assert.Throws<ScriptException>(() => + new ScriptContext().Init().EvaluateScript("{{ 'int'.typeof().Name }}")); + + var context = CreateContext().Init(); + var result = context.EvaluateScript("{{ 'DynamicInt'.typeof().Name }}"); + + Assert.That(result, Is.EqualTo(nameof(DynamicInt))); + + result = context.EvaluateScript("{{ 'ServiceStack.WebHost.Endpoints.Tests.ScriptTests.Ints'.typeof().Name }}"); + Assert.That(result, Is.Empty); + + context = CreateContext(c => c.AllowScriptingOfAllTypes = true).Init(); + result = context.EvaluateScript("{{ 'ServiceStack.WebHost.Endpoints.Tests.ScriptTests.Ints'.typeof().Name }}"); + Assert.That(result, Is.EqualTo(nameof(Ints))); + } + + [Test] + public void Does_not_allow_creating_instances_of_public_types() + { + var context = CreateContext(c => { + c.ScriptTypes.Add(typeof(InternalType)); + }).Init(); + + try + { + context.Evaluate("{{ 'InternalType'.new() |> return }}"); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + Assert.That(e.InnerException.GetType(), Is.EqualTo(typeof(NotSupportedException))); + } + + try + { + context.Evaluate("{{ 'InternalType'.new(1) |> return }}"); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + Assert.That(e.InnerException.GetType(), Is.EqualTo(typeof(NotSupportedException))); + } + + context = CreateContext(c => { + c.ScriptTypes.Add(typeof(InternalType)); + c.AllowScriptingOfAllTypes = true; + }).Init(); + + var result = context.Evaluate("{{ 'InternalType'.new() |> return }}"); + Assert.That(result.GetType(), Is.EqualTo(typeof(InternalType))); + + result = context.Evaluate("{{ 'InternalType'.new(1) |> return }}"); + Assert.That(result.GetType(), Is.EqualTo(typeof(InternalType))); + } + + [Test] + public void typeof_returns_correct_types() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add("System"); + c.ScriptNamespaces.Add("System.Collections.Generic"); + c.ScriptNamespaces.Add(typeof(StaticLog).Namespace); + }).Init(); + + Assert.That(context.Evaluate<Type>("{{ typeof('int') |> return}}"), Is.EqualTo(typeof(int))); + Assert.That(context.Evaluate<Type>("{{ typeof('Int32') |> return}}"), Is.EqualTo(typeof(Int32))); + Assert.That(context.Evaluate<Type>("{{ typeof('List<>') |> return}}"), Is.EqualTo(typeof(List<>))); + Assert.That(context.Evaluate<Type>("{{ typeof('Dictionary<,>') |> return}}"), Is.EqualTo(typeof(Dictionary<,>))); + Assert.That(context.Evaluate<Type>("{{ typeof('List<string>') |> return}}"), Is.EqualTo(typeof(List<string>))); + Assert.That(context.Evaluate<Type>("{{ typeof('Dictionary<string,int>') |> return}}"), Is.EqualTo(typeof(Dictionary<string,int>))); + Assert.That(context.Evaluate<Type>("{{ typeof('Dictionary<String,Int32>') |> return}}"), Is.EqualTo(typeof(Dictionary<string,int>))); + Assert.That(context.Evaluate<Type>("{{ typeof('Dictionary<String,ServiceStack.WebHost.Endpoints.Tests.ScriptTests.Ints>') |> return}}"), Is.EqualTo(typeof(Dictionary<string,Ints>))); + + Assert.That(context.Evaluate<Type>("{{ typeof('StaticLog+Inner1') |> return}}"), Is.EqualTo(typeof(StaticLog.Inner1))); + Assert.That(context.Evaluate<Type>("{{ typeof('StaticLog+Inner1+Inner2') |> return}}"), Is.EqualTo(typeof(StaticLog.Inner1.Inner2))); + Assert.That(context.Evaluate<Type>("{{ typeof('StaticLog.Inner1') |> return}}"), Is.EqualTo(typeof(StaticLog.Inner1))); + Assert.That(context.Evaluate<Type>("{{ typeof('StaticLog.Inner1.Inner2') |> return}}"), Is.EqualTo(typeof(StaticLog.Inner1.Inner2))); + + Assert.That(context.Evaluate<Type>("{{ typeof('string[]') |> return}}"), Is.EqualTo(typeof(string[]))); + Assert.That(context.Evaluate<Type>("{{ typeof('List<string>[]') |> return}}"), Is.EqualTo(typeof(List<string>[]))); + Assert.That(context.Evaluate<Type>("{{ typeof('Dictionary<String, System.Int32>[]') |> return}}"), Is.EqualTo(typeof(Dictionary<String, System.Int32>[]))); + } + + [Test] + public void Can_create_Type_from_registered_Script_Assembly() + { + var context = CreateContext().Init(); + + var result = context.EvaluateScript( + @"{{ 'DynamicInt'.new() |> to => d }}{{ d.call('add', [1, 2]) }}"); + Assert.That(result, Is.EqualTo("3")); + + result = context.EvaluateScript( + @"{{ 'DynamicInt'.new() |> to => d }}{{ d.call('add', [3, 4]) }}"); + Assert.That(result, Is.EqualTo("7")); + + result = context.EvaluateScript( + @"{{ 'ServiceStack.DynamicInt'.new() |> to => d }}{{ d.call('add', [5, 6]) }}"); + Assert.That(result, Is.EqualTo("11")); + + result = context.EvaluateScript( + @"{{ typeof('DynamicInt').createInstance() |> to => d }}{{ d.call('add', [3, 4]) }}"); + Assert.That(result, Is.EqualTo("7")); + } + + [Test] + public void Cant_create_instances_from_ambiguous_constructors() + { + var context = CreateContext(c => c.ScriptTypes.Add(typeof(Adder))).Init(); + + object result = null; + + try + { + result = context.Evaluate("{{ 'Adder'.new([1]) }}"); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException.GetType(), Is.EqualTo(typeof(NotSupportedException))); + } + + result = context.Evaluate("{{ 'Adder'.new([1.toString()]) |> to => o }}{{ o.String |> return }}"); + Assert.That(result, Is.EqualTo("1")); + + result = context.Evaluate("{{ 'Adder'.new([1.toDouble()]) |> to => o }}{{ o.Double |> return }}"); + Assert.That(result, Is.EqualTo(1.0d)); + + result = context.Evaluate("{{ Constructor('Adder(string)')(1) |> to => o }}{{ o.String |> return }}"); + Assert.That(result, Is.EqualTo("1")); + + result = context.Evaluate("{{ Constructor('Adder(double)')(1) |> to => o }}{{ o.Double |> return }}"); + Assert.That(result, Is.EqualTo(1.0d)); + } + + [Test] + public void Can_call_ambiguous_methods() + { + var context = CreateContext(c => c.ScriptTypes.Add(typeof(Adder))).Init(); + + object result = null; + + try + { + result = context.Evaluate("{{ 'Adder'.new(['1']) |> to => o }}{{ o.call('Add',[1]) }}{{ o.String |> return }}"); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException.GetType(), Is.EqualTo(typeof(NotSupportedException))); + } + + result = context.Evaluate("{{ 'Adder'.new(['1']) |> to => o }}{{ o.call('Add',['1']) }}{{ o.String |> return }}"); + Assert.That(result, Is.EqualTo("11")); + + result = context.Evaluate("{{ 'Adder'.new([1.0]) |> to => o }}{{ o.call('Add',[1.0]) }}{{ o.Double |> return }}"); + Assert.That(result, Is.EqualTo(2.0d)); + + result = context.Evaluate("{{ Constructor('Adder(string)')(1) |> to => o }}{{ Function('Adder.Add(string)') |> to => adder }}{{ o.adder(1) |> return }}"); + Assert.That(result, Is.EqualTo("11")); + + result = context.Evaluate("{{ Constructor('Adder(double)')(1) |> to => o }}{{ Function('Adder.Add(double)') |> to => adder }}{{ o.adder(1) |> return }}"); + Assert.That(result, Is.EqualTo(2.0d)); + } + + [Test] + public void Can_create_Type_from_registered_Script_Assembly_from_Constructor_ObjectActivator() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add("System"); + }).Init(); + + var result = context.Evaluate<object>( + @"{{ Constructor('DynamicInt()') |> to => ctor }}{{ ctor() |> return }}"); + Assert.That(result.GetType(), Is.EqualTo(typeof(DynamicInt))); + + result = context.Evaluate<object>( + @"{{ Constructor('DynamicInt()')() |> return }}"); + Assert.That(result.GetType(), Is.EqualTo(typeof(DynamicInt))); + + result = context.Evaluate<object>( + @"{{ Constructor('DateTime(int,int,int)')(2001,1,1) |> return }}"); + Assert.That(result, Is.EqualTo(new DateTime(2001,1,1))); + + result = context.Evaluate<object>( + @"{{ Constructor('DateTime(int,int,int)') |> to => newDate }}{{ newDate(2001,1,1) |> return }}"); + Assert.That(result, Is.EqualTo(new DateTime(2001,1,1))); + + result = context.Evaluate<object>( + @"{{ Constructor('DateTime(int,int,int)') |> to => newDate }}{{ 2001.newDate(1,1) |> return }}"); + Assert.That(result, Is.EqualTo(new DateTime(2001,1,1))); + + result = context.Evaluate<object>( + @"{{ Constructor('Tuple<string,int>(System.String,System.Int32)') |> to => tuple }}{{ tuple('A',1) |> to => pair }}{{ `${pair.Item1}=${pair.Item2}` |> return }}"); + Assert.That(result, Is.EqualTo("A=1")); + + result = context.Evaluate<object>( + @"{{ Constructor('System.Collections.Generic.KeyValuePair<string,int>(System.String,System.Int32)')('A',1) |> to => kvp }}{{ `${kvp.Key}=${kvp.Value}` |> return }}"); + Assert.That(result, Is.EqualTo("A=1")); + + result = context.Evaluate<object>( + @"{{ Constructor('System.Collections.Generic.KeyValuePair<char,double>(char,double)')('A',1) |> to => kvp }}{{ `${kvp.Key}=${kvp.Value}` |> return }}"); + Assert.That(result, Is.EqualTo("A=1")); + } + + [Test] + public void Can_call_generic_methods() + { + var context = CreateContext(c => c.ScriptAssemblies.Add(typeof(Ints).Assembly)).Init(); + + var result = context.Evaluate<string>( + "{{ 'Ints'.new([1,2]).call('GenericMethod<string>') |> return }}"); + Assert.That(result, Is.EqualTo("String 3")); + + result = context.Evaluate<string>( + "{{ 'Ints'.new([1,2]).call('GenericMethod<string>',['arg']) |> return }}"); + Assert.That(result, Is.EqualTo("String arg 3")); + + result = context.Evaluate<string>( + "{{ typeof('Ints').createInstance([1,2]).call('GenericMethod<string>',['arg']) |> return }}"); + Assert.That(result, Is.EqualTo("String arg 3")); + } + + [Test] + public void Can_create_type_with_constructor_arguments() + { + var context = CreateContext(c => c.ScriptAssemblies.Add(typeof(Ints).Assembly)).Init(); + + var result = context.Evaluate<int>( + "{{ 'Ints'.new([1,2]).call('GetTotal') |> return }}"); + Assert.That(result, Is.EqualTo(3)); + + result = context.Evaluate<int>( + "{{ typeof('Ints').createInstance([1,2]).call('GetTotal') |> return }}"); + Assert.That(result, Is.EqualTo(3)); + + result = context.Evaluate<int>( + "{{ 'Ints'.new([1,2]).set({ C:3, D:4.0 }).call('GetTotal') |> return }}"); + Assert.That(result, Is.EqualTo(10)); + + result = context.Evaluate<int>( + "{{ 'Ints'.new([1,2]).set({ C:3 }).set({ D:4.0 }).call('GetTotal') |> return }}"); + Assert.That(result, Is.EqualTo(10)); + + result = context.Evaluate<int>( + "{{ Constructor('Ints(int,int)')(1,2).set({ C:3, D:4 }).call('GetTotal') |> return }}"); + Assert.That(result, Is.EqualTo(10)); + + result = context.Evaluate<int>( + "{{ Function('Ints.GetTotal') |> to => total}}" + + "{{ Constructor('Ints(int,int)') |> to => tuple}}" + + "{{ tuple(1,2).set({ C:3, D:4 }).total() |> return }}"); + Assert.That(result, Is.EqualTo(10)); + } + + [Test] + public void Can_create_generic_type_with_constructor_arguments() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add(typeof(KeyValuePair<,>).Namespace); + }).Init(); + + var result = context.EvaluateScript( + "{{ 'KeyValuePair<string,int>'.new(['A',1]) |> to => kvp }}{{ kvp.Key }}={{ kvp.Value }}"); + Assert.That(result, Is.EqualTo("A=1")); + + result = context.EvaluateScript( + "{{ typeof('KeyValuePair<string,int>').createInstance(['A',1]) |> to => kvp }}{{ kvp.Key }}={{ kvp.Value }}"); + Assert.That(result, Is.EqualTo("A=1")); + } + + [Test] + public void Can_create_Type_from_Loaded_Assembly() + { + var context = CreateContext(c => c.AllowScriptingOfAllTypes = true).Init(); + + var result = context.Evaluate( + "{{ 'ServiceStack.WebHost.Endpoints.Tests.ScriptTests.Ints'.new() |> return}}"); + Assert.That(result as Ints, Is.Not.Null); + } + + [Test] + public void Script_Types_Use_Case() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add(typeof(DateTime).Namespace); + c.ScriptNamespaces.Add(typeof(Adder).Namespace); + }).Init(); + //var url = new Uri(); + + object result = null; + result = context.Evaluate("{{ 'Uri'.new(['http://host.org']) |> return }}"); + Assert.That(result, Is.EqualTo(new Uri("http://host.org"))); + result = context.Evaluate("{{ Constructor('Uri(string)')('http://host.org') |> return }}"); + Assert.That(result, Is.EqualTo(new Uri("http://host.org"))); + result = context.Evaluate("{{ Constructor('Uri(string)') |> to => url }}{{ url('http://host.org') |> return }}"); + Assert.That(result, Is.EqualTo(new Uri("http://host.org"))); + result = context.Evaluate("{{ Constructor('Uri(string)') |> to => url }}{{ 'http://host.org'.url() |> return }}"); + Assert.That(result, Is.EqualTo(new Uri("http://host.org"))); + result = context.Evaluate("{{ Constructor('Uri(string)') |> to => url }}{{ 'http://host.org' |> url |> return }}"); + Assert.That(result, Is.EqualTo(new Uri("http://host.org"))); + + result = context.Evaluate("{{ 'DateTime'.new() |> return }}"); + Assert.That(result.GetType(), Is.EqualTo(typeof(DateTime))); + + result = context.Evaluate("{{ Constructor('Adder(double)') |> to => doubleAdder }}{{ doubleAdder(1) |> return }}"); + Assert.That(((Adder) result).Double, Is.EqualTo(1.0d)); + result = context.Evaluate("{{ Constructor('Adder(double)') |> to => doubleAdder }}{{ 1.doubleAdder() |> return }}"); + Assert.That(((Adder) result).Double, Is.EqualTo(1.0d)); + result = context.Evaluate("{{ Constructor('Adder(double)') |> to => doubleAdder }}{{ 1 |> doubleAdder |> return }}"); + Assert.That(((Adder) result).Double, Is.EqualTo(1.0d)); + + result = context.Evaluate("{{ 'Ints'.new([1,2]) |> to => o }}{{ o.call('GenericMethod<int>') |> return }}"); + Assert.That((string) result, Is.EqualTo("Int32 3")); + result = context.Evaluate("{{ 'Ints'.new([1,2]) |> to => o }}{{ o.call('GenericMethod<int>',[1]) |> return }}"); + Assert.That((string) result, Is.EqualTo("Int32 1 3")); + } + + [Test] + public void Can_create_Function_for_static_Methods() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add(typeof(Console).Namespace); + c.ScriptNamespaces.Add(typeof(StaticLog).Namespace); + }).Init(); + + string result = null; + + result = context.EvaluateScript(@"{{ Function('Console.WriteLine(string)') |> to => writeln }} + {{ writeln('static method') }} + {{ 'ext method'.writeln() }}"); + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Clear')() }} + {{ Function('StaticLog.Log') |> to => log }} + {{ log('arg.') }} + {{ 'ext.'.log() }} + {{ Function('StaticLog.AllLogs') |> to => allLogs }}{{ allLogs() |> return }}"); + Assert.That(result, Is.EqualTo("arg.ext.")); + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Clear')() }} + {{ Function('StaticLog.Log<int>') |> to => log }} + {{ log('arg.') }} + {{ 'ext.'.log() }} + {{ Function('StaticLog.AllLogs') |> to => allLogs }}{{ allLogs() |> return }}"); + Assert.That(result, Is.EqualTo("Int32 arg.Int32 ext.")); + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Clear')() }} + {{ Function('StaticLog.Log')('iife') }} + {{ Function('StaticLog.AllLogs')() |> return }}"); + Assert.That(result, Is.EqualTo("iife")); + } + + [Test] + public void Can_create_Function_for_generic_type_static_Methods() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add(typeof(GenericStaticLog<>).Namespace); + }).Init(); + + string result = null; + + result = context.Evaluate<string>(@"{{ Function('GenericStaticLog<string>.Clear()')() }} + {{ Function('GenericStaticLog<string>.Log(string)') |> to => log }} + {{ log('arg.') }} + {{ 'ext.'.log() }} + {{ Function('GenericStaticLog<string>.AllLogs') |> to => allLogs }}{{ allLogs() |> return }}"); + Assert.That(result, Is.EqualTo("String arg.String ext.")); + + result = context.Evaluate<string>(@"{{ Function('GenericStaticLog<string>.Clear()')() }} + {{ Function('GenericStaticLog<string>.Log(string)')('iife') }} + {{ Function('GenericStaticLog<string>.AllLogs')() |> return }}"); + Assert.That(result, Is.EqualTo("String iife")); + + result = context.Evaluate<string>(@"{{ Function('GenericStaticLog<string>.Clear()')() }} + {{ Function('GenericStaticLog<string>.Log<int>') |> to => log }} + {{ Function('GenericStaticLog<string>.Log<int>(string)') |> to => log }} + {{ log('arg.') }} + {{ 'ext.'.log() }} + {{ Function('GenericStaticLog<string>.AllLogs') |> to => allLogs }}{{ allLogs() |> return }}"); + Assert.That(result, Is.EqualTo("String Int32 arg.String Int32 ext.")); + } + + [Test] + public void Can_create_Function_for_instance_methods() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add(typeof(InstanceLog).Namespace); + }).Init(); + + string result = null; + + result = context.Evaluate<string>(@"{{ 'InstanceLog'.new(['instance']) |> to => o }} + {{ Function('InstanceLog.Log') |> to => log }} + {{ o.log('arg.') }} + {{ log(o,'param.') }} + {{ Function('InstanceLog.AllLogs') |> to => allLogs }}{{ o.allLogs() |> return }}"); + Assert.That(result, Is.EqualTo("instance arg.instance param.")); + + result = context.Evaluate<string>(@"{{ Function('InstanceLog.Log<int>') |> to => log }} + {{ 'InstanceLog'.new(['instance']) |> to => o }} + {{ o.log('arg.') }} + {{ log(o,'param.') }} + {{ Function('InstanceLog.AllLogs') |> to => allLogs }}{{ o.allLogs() |> return }}"); + Assert.That(result, Is.EqualTo("instance Int32 arg.instance Int32 param.")); + } + + [Test] + public void Can_get_inner_class_properties() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add(typeof(StaticLog).Namespace); + }).Init(); + + string result = null; + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Prop')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Prop")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Field')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Field")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Const')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Const")); + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.Prop1')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.Prop1")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.Field1')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.Field1")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.Const1')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.Const1")); + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.Inner2.Prop2')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.Inner2.Prop2")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.Inner2.Field2')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.Inner2.Field2")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.Inner2.Const2')() |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.Inner2.Const2")); + + context.Args["o"] = new StaticLog(); + context.Args["o1"] = new StaticLog.Inner1(); + result = context.Evaluate<string>(@"{{ Function('StaticLog.InstanceProp')(o) |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.InstanceProp")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.InstanceField')(o) |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.InstanceField")); + + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.InstanceProp1')(o1) |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.InstanceProp1")); + result = context.Evaluate<string>(@"{{ Function('StaticLog.Inner1.InstanceField1')(o1) |> return }}"); + Assert.That(result, Is.EqualTo("StaticLog.Inner1.InstanceField1")); + } + + [Test] + public void Can_call_ContentResolver_Query_on_instance() + { + var context = CreateContext(c => { + c.AllowScriptingOfAllTypes = true; + c.ScriptNamespaces.Add("System"); + c.ScriptNamespaces.Add(typeof(ContentResolver).Namespace); + }).Init(); + + var result = context.Evaluate(@"{{ F('ContentResolver.Query(Uri,string[],string,string[],string)') |> to => Query }} + {{ MainActivity.Query('http://host.org',['A'],'B',['C'],'D') |> return }}", + new Dictionary<string, object> { + ["MainActivity"] = new ContentResolver() + }); + + Assert.That(result is ICursor); + } + + [Test] + public void Can_Call_registered_IOC_Dependency() + { + var context = CreateContext(c => { + c.ScriptTypes.Add(typeof(InstanceLog)); + }).Init(); + context.Container.AddTransient(() => new InstanceLog("ioc")); + + string result = null; + + result = context.Evaluate<string>(@"{{ resolve('InstanceLog') |> to => o }} + {{ Function('InstanceLog.Log') |> to => log }} + {{ o.log('arg') }} + {{ Function('InstanceLog.AllLogs') |> to => allLogs }}{{ o.allLogs() |> return }}".NormalizeNewLines()); + + Assert.That(result, Is.EqualTo("ioc arg")); + } + + [Test] + public void Can_call_resolve_interface_from_registered_Dependency() + { + var context = CreateContext(c => { + c.ScriptNamespaces.Add(typeof(ICursor).Namespace); + c.AllowScriptingOfAllTypes = true; + }); + context.Container.AddTransient<ICursor>(() => new Cursor()); + context.Init(); + + var output = context.EvaluateCode("'ICursor'.typeof().Name |> return"); + Assert.That(output, Is.EqualTo(nameof(ICursor))); + + output = context.EvaluateCode<List<string>>("resolve('ICursor').methods() |> return"); + Assert.That(output, Is.EqualTo(new[]{ "AMethod", "BMethod"})); + + output = context.EvaluateCode<string>("F('ICursor.AMethod')(resolve('ICursor'), 1) |> return"); + Assert.That(output, Is.EqualTo("AMethod: 1")); + + output = context.EvaluateCode<string>("F('Cursor.BMethod')(resolve('ICursor'), 2) |> return"); + Assert.That(output, Is.EqualTo("BMethod: 2")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptBlockHtmlTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptBlockHtmlTests.cs new file mode 100644 index 00000000000..030b81f2a87 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptBlockHtmlTests.cs @@ -0,0 +1,178 @@ +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptBlockHtmlTests + { + [Test] + public void Does_evaluate_void_img_html_block() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{#img {alt:'image',src:'image.png'} }}{{/img}}"), + Is.EqualTo("<img alt=\"image\" src=\"image.png\">")); + } + + [Test] + public void Does_evaluate_ul_html_block() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new int[]{1, 2, 3}, + ["letters"] = new[]{ "A", "B", "C" }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#ul}}{{/ul}}").RemoveNewLines(), Is.EqualTo("<ul></ul>")); + + Assert.That(context.EvaluateScript("{{#ul {class:'nav'} }} <li>item</li> {{/ul}}").RemoveNewLines(), + Is.EqualTo(@"<ul class=""nav""> <li>item</li> </ul>")); + + Assert.That(context.EvaluateScript("{{#ul {each:letters, class:'nav', id:'menu'} }}<li>{{it}}</li>{{/ul}}").RemoveNewLines(), + Is.EqualTo(@"<ul class=""nav"" id=""menu""><li>A</li><li>B</li><li>C</li></ul>")); + + Assert.That(context.EvaluateScript("{{#ul {each:numbers, it:'num'} }}<li>{{num}}</li>{{/ul}}").RemoveNewLines(), + Is.EqualTo(@"<ul><li>1</li><li>2</li><li>3</li></ul>")); + + Assert.That(context.EvaluateScript("{{#ul {each:none} }}<li>{{it}}</li>{{/ul}}").RemoveNewLines(), Is.EqualTo(@"")); + + Assert.That(context.EvaluateScript("{{#ul {each:none} }}<li>{{it}}</li>{{else}}no items{{/ul}}").RemoveNewLines(), + Is.EqualTo(@"no items")); + } + + private static ScriptContext CreateContext() + { + var context = new ScriptContext { + Args = { + ["items"] = new[] {new Person("foo", 1), new Person("bar", 2), new Person("baz", 3)}, + ["id"] = "menu", + ["disclaimerAccepted"] = false, + ["hasAccess"] = true, + ["highlight"] = "baz", + ["digits"] = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }, + } + }.Init(); + return context; + } + + [Test] + public void Does_evaluate_ul_with_nested_html_blocks() + { + var context = CreateContext(); + + var template = @" +{{#ul {each:items, class:['nav', !disclaimerAccepted?'blur':''], id:`ul-${id}`} }} + {{#li {class: {alt:isOdd(index), active:Name==highlight} }} + {{Name}} + {{/li}} +{{else}} + <div>no items</div> +{{/ul}}"; + + var result = context.EvaluateScript(template); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<ul class=""nav blur"" id=""ul-menu""> + <li> + foo + </li> + <li class=""alt""> + bar + </li> + <li class=""active""> + baz + </li> +</ul>".NormalizeNewLines())); + + var withoutHtmlBlock = @" +{{#if !isEmpty(items)}} +<ul{{ ['nav', !disclaimerAccepted?'blur':''] |> htmlClass }} id=""ul-{{id}}""> +{{#each items}} + <li{{ {alt:isOdd(index), active:Name==highlight} |> htmlClass }}> + {{Name}} + </li> +{{/each}} +</ul> +{{else}} + <div>no items</div> +{{/if}}"; + + var withoutBlockResult = context.EvaluateScript(withoutHtmlBlock); + + Assert.That(withoutBlockResult.RemoveNewLines(), Is.EqualTo(result.RemoveNewLines())); + } + + [Test] + public void Does_evaluate_if_and_where_in_html_blocks() + { + var context = CreateContext(); + + var template = @" +{{#ul {if:hasAccess, each:items, where:'Age >= 2', class:['nav', !disclaimerAccepted?'blur':''], id:`ul-${id}`} }} + {{#li {class: {alt:isOdd(index), active:Name==highlight} }} + {{Name}} + {{/li}} +{{else}} + <div>no items</div> +{{/ul}}"; + + var result = context.EvaluateScript(template); + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<ul class=""nav blur"" id=""ul-menu""> + <li> + bar + </li> + <li class=""alt active""> + baz + </li> +</ul>".NormalizeNewLines())); + + var withoutHtmlBlock = @" +{{ items |> where: it.Age >= 2 + |> assignTo: items }} +{{#if !isEmpty(items)}} +{{#if hasAccess}} +<ul{{ ['nav', !disclaimerAccepted?'blur':''] |> htmlClass }} id=""ul-{{id}}""> +{{#each items}} + <li{{ {alt:isOdd(index), active:Name==highlight} |> htmlClass }}> + {{Name}} + </li> +{{/each}} +</ul> +{{/if}} + {{else}} + <div>no items</div> + {{/if}}".NormalizeNewLines(); + + var withoutBlockResult = context.EvaluateScript(withoutHtmlBlock); + withoutBlockResult.Print(); + Assert.That(withoutBlockResult.RemoveNewLines(), Is.EqualTo(result.RemoveNewLines())); + + result = context.EvaluateScript(template.Replace("hasAccess","!hasAccess")); + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@"")); + } + + [Test] + public void Does_evaluate_where_expression_on_strings() + { + var context = CreateContext(); + + var template = @" +{{#each d in digits where d.Length < index}} +The word {{d}} is shorter than its value. +{{/each}}"; + + var result = context.EvaluateScript(template); + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +The word five is shorter than its value. +The word six is shorter than its value. +The word seven is shorter than its value. +The word eight is shorter than its value. +The word nine is shorter than its value.".NormalizeNewLines())); + } + + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptBlockTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptBlockTests.cs new file mode 100644 index 00000000000..50dc3613db9 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptBlockTests.cs @@ -0,0 +1,1142 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptBlockTests + { + [Test] + public void Does_parse_template_with_Block_Statement() + { + var fragments = ScriptTemplateUtils.ParseTemplate("BEFORE {{#bold}} Hi, {{name}}! {{/bold}} AFTER"); + + Assert.That(fragments.Count, Is.EqualTo(3)); + Assert.That(((PageStringFragment)fragments[0]).Value.ToString(), Is.EqualTo("BEFORE ")); + + var statement = fragments[1] as PageBlockFragment; + Assert.That(statement, Is.Not.Null); + Assert.That(statement.Name, Is.EqualTo("bold")); + Assert.That(statement.Argument.ToString(), Is.EqualTo("")); + + Assert.That(((PageStringFragment)statement.Body[0]).Value.ToString(), Is.EqualTo(" Hi, ")); + Assert.That(((PageVariableFragment)statement.Body[1]).Binding, Is.EqualTo("name")); + Assert.That(((PageStringFragment)statement.Body[2]).Value.ToString(), Is.EqualTo("! ")); + + Assert.That(((PageStringFragment)fragments[2]).Value.ToString(), Is.EqualTo(" AFTER")); + } + + [Test] + public void Does_parse_template_with_if_else_statement() + { + var fragments = ScriptTemplateUtils.ParseTemplate("BEFORE {{#if a < b}}YES{{else}}NO{{/if}} AFTER"); + + Assert.That(fragments.Count, Is.EqualTo(3)); + Assert.That(((PageStringFragment)fragments[0]).Value.ToString(), Is.EqualTo("BEFORE ")); + + var statement = fragments[1] as PageBlockFragment; + Assert.That(statement, Is.Not.Null); + Assert.That(statement.Name, Is.EqualTo("if")); + Assert.That(statement.Argument.ToString(), Is.EqualTo("a < b")); + Assert.That(((PageStringFragment)statement.Body[0]).Value.ToString(), Is.EqualTo("YES")); + + Assert.That(statement.ElseBlocks[0].Argument.ToString(), Is.EqualTo("")); + Assert.That(((PageStringFragment)statement.ElseBlocks[0].Body[0]).Value.ToString(), Is.EqualTo("NO")); + + Assert.That(((PageStringFragment)fragments[2]).Value.ToString(), Is.EqualTo(" AFTER")); + } + + [Test] + public void Does_parse_template_with_if_and_else_if_statement() + { + var fragments = ScriptTemplateUtils.ParseTemplate("BEFORE {{#if a < b}}YES{{else if c < d}}NO{{else}}MAYBE{{/if}} AFTER"); + + Assert.That(fragments.Count, Is.EqualTo(3)); + Assert.That(((PageStringFragment)fragments[0]).Value.ToString(), Is.EqualTo("BEFORE ")); + + var statement = fragments[1] as PageBlockFragment; + Assert.That(statement, Is.Not.Null); + Assert.That(statement.Name, Is.EqualTo("if")); + Assert.That(statement.Argument.ToString(), Is.EqualTo("a < b")); + Assert.That(((PageStringFragment)statement.Body[0]).Value.ToString(), Is.EqualTo("YES")); + + Assert.That(statement.ElseBlocks[0].Argument.ToString(), Is.EqualTo("if c < d")); + Assert.That(((PageStringFragment)statement.ElseBlocks[0].Body[0]).Value.ToString(), Is.EqualTo("NO")); + + Assert.That(statement.ElseBlocks[1].Argument.ToString(), Is.EqualTo("")); + Assert.That(((PageStringFragment)statement.ElseBlocks[1].Body[0]).Value.ToString(), Is.EqualTo("MAYBE")); + + Assert.That(((PageStringFragment)fragments[2]).Value.ToString(), Is.EqualTo(" AFTER")); + } + + [Test] + public void Does_parse_template_with_nested_Block_Statement() + { + var fragments = ScriptTemplateUtils.ParseTemplate("BEFORE {{#bold}} Hi, {{#bold}}{{name}}{{/bold}}! {{/bold}} AFTER"); + + Assert.That(fragments.Count, Is.EqualTo(3)); + Assert.That(((PageStringFragment)fragments[0]).Value.ToString(), Is.EqualTo("BEFORE ")); + + var statement = fragments[1] as PageBlockFragment; + Assert.That(statement, Is.Not.Null); + Assert.That(statement.Name, Is.EqualTo("bold")); + Assert.That(statement.Argument.ToString(), Is.EqualTo("")); + + Assert.That(((PageStringFragment)statement.Body[0]).Value.ToString(), Is.EqualTo(" Hi, ")); + + var nested = (PageBlockFragment) statement.Body[1]; + Assert.That(nested.Name, Is.EqualTo("bold")); + Assert.That(((PageVariableFragment)nested.Body[0]).Binding, Is.EqualTo("name")); + + Assert.That(((PageStringFragment)statement.Body[2]).Value.ToString(), Is.EqualTo("! ")); + + Assert.That(((PageStringFragment)fragments[2]).Value.ToString(), Is.EqualTo(" AFTER")); + } + + [Test] + public void Does_parse_Raw_block_body_as_string() + { + var fragments = ScriptTemplateUtils.ParseTemplate("BEFORE {{#raw}} Hi, {{ {{ name }} }} {{/raw}} AFTER"); + + Assert.That(fragments.Count, Is.EqualTo(3)); + Assert.That(((PageStringFragment)fragments[0]).Value.ToString(), Is.EqualTo("BEFORE ")); + + var statement = fragments[1] as PageBlockFragment; + Assert.That(statement, Is.Not.Null); + Assert.That(statement.Name, Is.EqualTo("raw")); + Assert.That(statement.Argument.ToString(), Is.EqualTo("")); + Assert.That(statement.Body.Length, Is.EqualTo(1)); + + Assert.That(((PageStringFragment)statement.Body[0]).Value.ToString(), Is.EqualTo(" Hi, {{ {{ name }} }} ")); + + Assert.That(((PageStringFragment)fragments[2]).Value.ToString(), Is.EqualTo(" AFTER")); + } + + [Test] + public void Does_evaluate_Raw_block_body_as_string() + { + var context = new ScriptContext { + Plugins = { new MarkdownScriptPlugin() } + }.Init(); + + Assert.That(context.EvaluateScript("BEFORE {{#raw}} Hi, {{ {{ name }} }} {{/raw}} AFTER"), + Is.EqualTo("BEFORE Hi, {{ {{ name }} }} AFTER")); + + Assert.That(context.EvaluateScript("BEFORE {{#raw md}}# Heading{{/raw}} AFTER {{ md |> markdown }}").NormalizeNewLines(), + Is.EqualTo("BEFORE AFTER <h1>Heading</h1>")); + } + + [Test] + public void Does_evaluate_Markdown_block_body_as_string() + { + var context = new ScriptContext { + Plugins = { new MarkdownScriptPlugin() } + }.Init(); + + Assert.That(context.EvaluateScript("BEFORE {{#markdown}}# Heading{{/markdown}} AFTER").RemoveNewLines(), + Is.EqualTo("BEFORE <h1>Heading</h1> AFTER")); + + Assert.That(context.EvaluateScript("BEFORE {{#markdown md}}# Heading{{/markdown}} AFTER {{ md }}").NormalizeNewLines(), + Is.EqualTo("BEFORE AFTER <h1>Heading</h1>")); + } + + [Test] + public void Does_evaluate_Raw_block_body_and_appendTo_string() + { + var context = new ScriptContext { + Plugins = { new MarkdownScriptPlugin() } + }.Init(); + + Assert.That(context.EvaluateScript("BEFORE {{#raw appendTo md}}# Heading{{/raw}}{{#raw appendTo md}} Appended{{/raw}} AFTER {{ md |> markdown }}").NormalizeNewLines(), + Is.EqualTo("BEFORE AFTER <h1>Heading Appended</h1>")); + } + + public class ScriptBoldBlock : ScriptBlock + { + public override string Name => "bold"; + + public override async Task WriteAsync(ScriptScopeContext scope, PageBlockFragment block, CancellationToken token) + { + await scope.OutputStream.WriteAsync("<b>", token); + await WriteBodyAsync(scope, block, token); + await scope.OutputStream.WriteAsync("</b>", token); + } + } + + [Test] + public void Does_evaluate_custom_Block_Statement() + { + var context = new ScriptContext { + ScriptBlocks = { new ScriptBoldBlock() }, + Args = { + ["name"] = "World" + } + }.Init(); + + var result = context.EvaluateScript("BEFORE {{#bold}} Hi, {{name}}! {{/bold}} AFTER"); + Assert.That(result, Is.EqualTo("BEFORE <b> Hi, World! </b> AFTER")); + } + + [Test] + public void Does_evaluate_template_with_nested_Block_Statement() + { + var context = new ScriptContext { + ScriptBlocks = { new ScriptBoldBlock() }, + Args = { + ["name"] = "World" + } + }.Init(); + + var result = context.EvaluateScript("BEFORE {{#bold}} Hi, {{#bold}}{{name}}{{/bold}}! {{/bold}} AFTER"); + Assert.That(result, Is.EqualTo("BEFORE <b> Hi, <b>World</b>! </b> AFTER")); + + var template = "BEFORE {{#bold}} Hi, {{#if a == null}}{{#bold}}{{name}}{{/bold}}{{else}}{{a}}{{/if}}! {{/bold}} AFTER"; + + result = context.EvaluateScript(template); + Assert.That(result, Is.EqualTo("BEFORE <b> Hi, <b>World</b>! </b> AFTER")); + + context.Args["a"] = "foo"; + result = context.EvaluateScript(template); + Assert.That(result, Is.EqualTo("BEFORE <b> Hi, foo! </b> AFTER")); + } + + [Test] + public void Does_evaluate_template_with_if_else_statement() + { + var context = new ScriptContext { + Args = { + ["a"] = 1, + ["b"] = 2, + } + }.Init(); + + var template = "BEFORE {{#if a < b}}YES{{else}}NO{{/if}} AFTER"; + + Assert.That(context.EvaluateScript(template), Is.EqualTo("BEFORE YES AFTER")); + + context.Args["a"] = 3; + Assert.That(context.EvaluateScript(template), Is.EqualTo("BEFORE NO AFTER")); + } + + [Test] + public void Does_evaluate_template_with_if_and_else_if_statement() + { + var context = new ScriptContext { + Args = { + ["a"] = 1, + ["b"] = 2, + ["c"] = 3, + ["d"] = 4 + } + }.Init(); + + var template = "BEFORE {{#if a < b}}YES{{else if c < d}}NO{{else}}MAYBE{{/if}} AFTER"; + + Assert.That(context.EvaluateScript(template), Is.EqualTo("BEFORE YES AFTER")); + + context.Args["a"] = 3; + Assert.That(context.EvaluateScript(template), Is.EqualTo("BEFORE NO AFTER")); + + context.Args["c"] = 5; + Assert.That(context.EvaluateScript(template), Is.EqualTo("BEFORE MAYBE AFTER")); + } + + [Test] + public void Does_evaluate_template_containing_with_block() + { + var context = new ScriptContext { + Args = { + ["person"] = new Person { Name = "poco", Age = 27 }, + ["personMap"] = new Dictionary<string, object> { + ["name"] = "map", + ["age"] = 27, + } + } + }.Init(); + + Assert.That(context.EvaluateScript("Person {{#with person}}{{Name}} is {{Age}} years old{{/with}}"), + Is.EqualTo("Person poco is 27 years old")); + + Assert.That(context.EvaluateScript("Person {{#with personMap}}{{name}} is {{age}} years old{{/with}}"), + Is.EqualTo("Person map is 27 years old")); + + Assert.That(context.EvaluateScript("Person {{#with {name:'inline',age:27} }}{{name}} is {{age}} years old{{/with}}"), + Is.EqualTo("Person inline is 27 years old")); + } + + [Test] + public void Does_evaluate_template_containing_with_and_else_block() + { + var context = new ScriptContext { + Args = { + ["person"] = null, + ["personMap"] = new Dictionary<string, object> { + ["name"] = "map", + ["age"] = 27, + } + } + }.Init(); + + Assert.That(context.EvaluateScript("Person {{#with person}}{{Name}} is {{Age}} years old{{else}}does not exist{{/with}}"), + Is.EqualTo("Person does not exist")); + Assert.That(context.EvaluateScript("Person {{#with null}}{{Name}} is {{Age}} years old{{else}}does not exist{{/with}}"), + Is.EqualTo("Person does not exist")); + Assert.That(context.EvaluateScript("Person {{#with person}}{{Name}} is {{Age}} years old{{else if personMap != null}}map does exist{{else}}does not exist{{/with}}"), + Is.EqualTo("Person map does exist")); + } + + public class ScriptSimpleEachBlock : ScriptBlock + { + public override string Name => "each"; + + public override async Task WriteAsync( + ScriptScopeContext scope, PageBlockFragment block, CancellationToken token) + { + var collection = (IEnumerable) block.Argument.GetJsExpressionAndEvaluate(scope, + ifNone: () => throw new NotSupportedException("'each' block does not have a valid expression")); + + var index = 0; + if (collection != null) + { + foreach (var element in collection) + { + var scopeArgs = element.ToObjectDictionary(); + scopeArgs["it"] = element; + scopeArgs[nameof(index)] = index++; + + var itemScope = scope.ScopeWithParams(scopeArgs); + await WriteBodyAsync(itemScope, block, token); + } + } + + if (index == 0) + { + await WriteElseAsync(scope, block.ElseBlocks, token); + } + } + } + + [Test] + public void Does_evaluate_template_with_simple_each_blocks() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new[]{ 1, 2, 3 }, + ["letters"] = new[]{ "A", "B", "C" }, + ["empty"] = new int[]{}, + }, + ScriptBlocks = { + new ScriptSimpleEachBlock(), + new IfScriptBlock(), + } + } + .RemovePlugins(x => x is DefaultScriptBlocks) + .Init(); + + Assert.That(context.EvaluateScript("{{#each numbers}}{{it}} {{/each}}"), Is.EqualTo("1 2 3 ")); + + Assert.That(context.EvaluateScript("{{#each letters}}{{it}} {{/each}}"), Is.EqualTo("A B C ")); + + Assert.That(context.EvaluateScript("{{#each numbers}}{{#if isNumber(it)}}number {{it}} {{else}}letter {{it}} {{/if}}{{/each}}"), + Is.EqualTo("number 1 number 2 number 3 ")); + + Assert.That(context.EvaluateScript("{{#each letters}}{{#if isNumber(it)}}number {{it}} {{else}}letter {{it}} {{/if}}{{/each}}"), + Is.EqualTo("letter A letter B letter C ")); + + Assert.That(context.EvaluateScript("{{#each empty}}{{it}}{{else}}none{{/each}}"), Is.EqualTo("none")); + } + + [Test] + public void Does_evaluate_template_with_each_blocks() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new[]{ 1, 2, 3 }, + ["letters"] = new[]{ "A", "B", "C" }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each numbers}}{{it}} {{/each}}"), Is.EqualTo("1 2 3 ")); + + Assert.That(context.EvaluateScript("{{#each letters}}{{it}} {{/each}}"), Is.EqualTo("A B C ")); + + Assert.That(context.EvaluateScript("{{#each numbers}}{{#if isNumber(it)}}number {{it}} {{else}}letter {{it}} {{/if}}{{/each}}"), + Is.EqualTo("number 1 number 2 number 3 ")); + + Assert.That(context.EvaluateScript("{{#each letters}}{{#if isNumber(it)}}number {{it}} {{else}}letter {{it}} {{/if}}{{/each}}"), + Is.EqualTo("letter A letter B letter C ")); + } + + [Test] + public void Does_evaluate_template_with_each_else_blocks() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new int[]{}, + ["letters"] = new[]{ "A", "B", "C" }, + ["people"] = new[]{ new Person("name1", 1),new Person("name2", 2),new Person("name3", 3) }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each numbers}}{{it}} {{else}}no numbers{{/each}}"), + Is.EqualTo("no numbers")); + Assert.That(context.EvaluateScript("{{#each numbers}}{{it}} {{else if !isEmpty(letters)}}has letters{{else}}no numbers{{/each}}"), + Is.EqualTo("has letters")); + Assert.That(context.EvaluateScript("{{#each numbers}}{{it}} {{else if !isEmpty([])}}has letters{{else}}no numbers{{/each}}"), + Is.EqualTo("no numbers")); + } + + [Test] + public void Does_evaluate_template_with_each_where_blocks() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new[]{ 1, 2, 3, 4, 5, }, + ["letters"] = new[]{ "A", "B", "C", "D", "E" }, + ["people"] = new[]{ new Person("name1", 1),new Person("name2", 2),new Person("name3", 3) }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each numbers where isOdd(it)}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 1, #1 3, #2 5, ")); + Assert.That(context.EvaluateScript("{{#each num in numbers where isOdd(num)}}#{{index}} {{num}}, {{/each}}"), + Is.EqualTo("#0 1, #1 3, #2 5, ")); + Assert.That(context.EvaluateScript("{{#each people where Name == 'name2' and Age == 2 }}#{{index}} {{Name}}, {{Age}}{{/each}}"), + Is.EqualTo("#0 name2, 2")); + Assert.That(context.EvaluateScript("{{#each p in people where p.Name == 'name2' }}#{{index}} {{p.Name}}, {{p.Age}}{{/each}}"), + Is.EqualTo("#0 name2, 2")); + } + + [Test] + public void Does_evaluate_template_with_each_blocks_containing_LINQ_expressions() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new[]{ 4, 5, 1, 3, 2, }, + ["letters"] = new[]{ "C", "D", "B", "E", "A" }, + ["people"] = new[]{ new Person("name3", 3),new Person("name2", 4),new Person("name1", 5),new Person("name5", 1),new Person("name4", 2) }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each numbers orderby it descending}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 5, #1 4, #2 3, #3 2, #4 1, ")); + Assert.That(context.EvaluateScript("{{#each numbers where isOdd(it) orderby it descending}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 5, #1 3, #2 1, ")); + Assert.That(context.EvaluateScript("{{#each numbers orderby it}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 1, #1 2, #2 3, #3 4, #4 5, ")); + Assert.That(context.EvaluateScript("{{#each numbers where isOdd(it) orderby it}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 1, #1 3, #2 5, ")); + Assert.That(context.EvaluateScript("{{#each n in numbers orderby n}}#{{index}} {{n}}, {{/each}}"), + Is.EqualTo("#0 1, #1 2, #2 3, #3 4, #4 5, ")); + Assert.That(context.EvaluateScript("{{#each n in numbers where isOdd(n) orderby n}}#{{index}} {{n}}, {{/each}}"), + Is.EqualTo("#0 1, #1 3, #2 5, ")); + Assert.That(context.EvaluateScript("{{#each numbers where it % 2 == 1 orderby it skip 1}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 3, #1 5, ")); + Assert.That(context.EvaluateScript("{{#each numbers where it % 2 == 1 orderby it take 2}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 1, #1 3, ")); + Assert.That(context.EvaluateScript("{{#each numbers where it % 2 == 1 orderby it skip 1 take 1}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 3, ")); + + Assert.That(context.EvaluateScript("{{#each letters orderby it}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 A, #1 B, #2 C, #3 D, #4 E, ")); + Assert.That(context.EvaluateScript("{{#each letters where it > 'A' orderby it skip 1 take 2}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 C, #1 D, ")); + Assert.That(context.EvaluateScript("{{#each letters where index > 0 orderby it skip 1 take 2}}#{{index}} {{it}}, {{/each}}"), + Is.EqualTo("#0 B, #1 D, ")); + + Assert.That(context.EvaluateScript("{{#each people where Name > 'name2' orderby Age take 2}}#{{index}} {{Name}}, {{Age}} {{/each}}"), + Is.EqualTo("#0 name5, 1 #1 name4, 2 ")); + Assert.That(context.EvaluateScript("{{#each p in people where p.Name > 'name2' orderby p.Age take 2}}#{{index}} {{p.Name}}, {{p.Age}} {{/each}}"), + Is.EqualTo("#0 name5, 1 #1 name4, 2 ")); + Assert.That(context.EvaluateScript("{{#each p in people where p.Name > 'name2' orderby p.Age descending skip 1 take 2}}#{{index}} {{p.Name}}, {{p.Age}} {{/each}}"), + Is.EqualTo("#0 name4, 2 #1 name5, 1 ")); + } + + [Test] + public void Template_each_blocks_without_in_explodes_ref_type_arguments_into_scope() + { + var context = new ScriptContext { + Args = { + ["people"] = new[]{ new Person("name1", 1),new Person("name2", 2),new Person("name3", 3) }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each people}}({{Name}},{{Age}}) {{/each}}"), + Is.EqualTo("(name1,1) (name2,2) (name3,3) ")); + } + + [Test] + public void Does_evaluate_template_with_each_in_blocks() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new[]{ 1, 2, 3 }, + ["letters"] = new[]{ "A", "B", "C" }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each num in numbers}}{{num}} {{/each}}"), Is.EqualTo("1 2 3 ")); + Assert.That(context.EvaluateScript("{{#each num in [1,2,3] }}{{num}} {{/each}}"), Is.EqualTo("1 2 3 ")); + + Assert.That(context.EvaluateScript("{{#each c in letters}}{{c}} {{/each}}"), Is.EqualTo("A B C ")); + Assert.That(context.EvaluateScript("{{#each c in ['A','B','C'] }}{{c}} {{/each}}"), Is.EqualTo("A B C ")); + + Assert.That(context.EvaluateScript("{{#each num in numbers}}{{#if isNumber(num)}}number {{num}} {{else}}letter {{num}} {{/if}}{{/each}}"), + Is.EqualTo("number 1 number 2 number 3 ")); + + Assert.That(context.EvaluateScript("{{#each c in letters}}{{#if isNumber(c)}}number {{c}} {{else}}letter {{c}} {{/if}}{{/each}}"), + Is.EqualTo("letter A letter B letter C ")); + } + + [Test] + public void Does_export_scope_args_of_all_KeyValuePairs() + { + var context = new ScriptContext { + Args = { + ["numbers"] = new Dictionary<string,int> { ["a"] = 1, ["b"] = 2, ["c"] = 3}, + ["letters"] = new Dictionary<string,string> { ["a"] = "A", ["b"] = "B", ["c"] = "C"}, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each numbers}}{{Key}}={{Value}} {{/each}}"), + Is.EqualTo("a=1 b=2 c=3 ")); + Assert.That(context.EvaluateScript("{{#each {a:1,b:2,c:3} }}{{Key}}={{Value}} {{/each}}"), + Is.EqualTo("a=1 b=2 c=3 ")); + Assert.That(context.EvaluateScript("{{#each letters}}{{Key}}={{Value}} {{/each}}"), + Is.EqualTo("a=A b=B c=C ")); + } + + [Test] + public void Does_export_Key_name_of_all_KeyValuePairs() + { + var context = new ScriptContext { + Args = { + ["posts"] = new List<Dictionary<string, object>> { + new Dictionary<string, object> { + ["title"] = "title1", + ["content"] = "content1", + }, + new Dictionary<string, object> { + ["title"] = "title2", + ["content"] = "content2", + } + }, + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#each posts}}{{title}}={{content}}, {{/each}}"), + Is.EqualTo("title1=content1, title2=content2, ")); + + context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript( + "{{ { title:'title1', content:'content1' } |> addTo: posts}}" + + "{{ { title:'title2', content:'content2' } |> addTo: posts}}" + + "{{#each posts}}{{title}}={{content}}, {{/each}}"), + Is.EqualTo("title1=content1, title2=content2, ")); + } + + [Test] + public void Does_evaluate_template_with_partial_block() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +{{ 'from layout' |> assignTo: layoutArg }} +I am a Layout with page +{{ page }}"); + + context.VirtualFiles.WriteFile("page.html", @" +{{#partial my_partial}} +I am a partial called with the scoped argument <b>{{ arg }}</b> +Who can also access other arguments in scope <b>{{ layoutArg }}</b> +{{/partial}} + +I am a Page with a partial +{{ 'my_partial' |> partial({ arg: 'from page' }) }}".TrimStart()); + + var pageResult = new PageResult(context.GetPage("page")); + + var result = pageResult.Result; + + result.Print(); + + Assert.That(result.Trim(), Is.EqualTo(@"I am a Layout with page + +I am a Page with a partial +I am a partial called with the scoped argument <b>from page</b> +Who can also access other arguments in scope <b>from layout</b>")); + } + + [Test] + public void Does_evaluate_template_with_partial_block_and_args() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +{{ 'from layout' |> assignTo: layoutArg }} +I am a Layout with page +{{ page }}"); + + context.VirtualFiles.WriteFile("page.html", @" +{{#partial my_partial {partialArg: 'from partial'} }} +I am a partial called with the scoped argument <b>{{ arg }}</b> and <b>{{ partialArg }}</b> +Who can also access other arguments in scope <b>{{ layoutArg }}</b> +{{/partial}} + +{{ 'from page' |> assignTo: partialArg }} +I am a Page with a partial +{{ 'my_partial' |> partial({ arg: 'from page' }) }} +partialArg in page scope is <b>{{ partialArg }}</b>".TrimStart()); + + var pageResult = new PageResult(context.GetPage("page")); + + var result = pageResult.Result; + + result.Print(); + + Assert.That(result.Trim(), Is.EqualTo(@"I am a Layout with page + +I am a Page with a partial +I am a partial called with the scoped argument <b>from page</b> and <b>from partial</b> +Who can also access other arguments in scope <b>from layout</b> + +partialArg in page scope is <b>from page</b>")); + } + + [Test] + public void Can_use_partial_to_evaluate_Markdown() + { + var context = new ScriptContext { + Plugins = { new MarkdownScriptPlugin() } + }.Init(); + + var result = context.EvaluateScript(@" +{{#partial content}} + - List Item +{{/partial}} + +<h1>Heading</h1> + +{{ 'content' |> partial |> markdown }} + +<footer>2000</footer>"); + + Assert.That(result.RemoveNewLines(), Is.EqualTo(@" +<h1>Heading</h1> +<ul><li>List Item</li></ul> +<footer>2000</footer>".RemoveNewLines())); + + } + + [Test] + public void Does_evaluate_template_with_noop_block() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("Remove {{#noop}} from{{/noop}}view"), Is.EqualTo("Remove view")); + } + + public class AsyncResultsFilter : ScriptMethods + { + public Task<object> asyncInts(ScriptScopeContext scope) + { + return ((object)new object[]{1, 2, 3}).InTask(); + } + + public Task<object> asyncDictionary(ScriptScopeContext scope) + { + return ((object)new Dictionary<string, object> { {"foo", 1}, {"bar", 2} }).InTask(); + } + + public Task<object> asyncResult(object result) => result.InTask(); + + public Task<object> asyncTrue() => ((object) true).InTask(); + + public Task<object> asyncFalse() => ((object) false).InTask(); + + public Task<object> asyncPerson() => ((object) new Person("foo",1)).InTask(); + } + + [Test] + public void Does_evaluate_async_results_in_blocks() + { + var context = new ScriptContext { + ScriptMethods = { new AsyncResultsFilter() }, + }.Init(); + + Assert.That(context.EvaluateScript("{{#each asyncInts}}{{it}} {{/each}}"), Is.EqualTo("1 2 3 ")); + Assert.That(context.EvaluateScript("{{#each asyncResult([1,2,3])}}{{it}} {{/each}}"), Is.EqualTo("1 2 3 ")); + Assert.That(context.EvaluateScript("{{#each asyncDictionary}}({{Key}},{{Value}}) {{/each}}"), + Is.EqualTo("(foo,1) (bar,2) ")); + + Assert.That(context.EvaluateScript("{{#each []}}{{else if asyncTrue}}does async{{else}}no async{{/each}}"), + Is.EqualTo("does async")); + + Assert.That(context.EvaluateScript("{{#if asyncTrue}}does async{{else}}no async{{/if}}"), + Is.EqualTo("does async")); + + Assert.That(context.EvaluateScript("{{#if asyncFalse}}no async{{else}}does async{{/if}}"), + Is.EqualTo("does async")); + + Assert.That(context.EvaluateScript("{{#with asyncPerson}}({{Name}},{{Age}}) {{/with}}"), + Is.EqualTo("(foo,1) ")); + } + + [Test] + public void Can_capture_output_with_capture_block() + { + var context = new ScriptContext { + Args = { + ["nums"] = new[]{1,2,3} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#capture output}}{{#each nums}} {{it}}{{/each}}{{/capture}}BEFORE{{output}} AFTER"), + Is.EqualTo("BEFORE 1 2 3 AFTER")); + + Assert.That(context.EvaluateScript("{{#capture output {nums:[4,5,6] }}{{#each nums}} {{it}}{{/each}}{{/capture}}BEFORE{{output}} AFTER"), + Is.EqualTo("BEFORE 4 5 6 AFTER")); + } + + [Test] + public void Can_capture_and_appendTo_output_with_capture_block() + { + var context = new ScriptContext { + Args = { + ["nums"] = new[]{1,2,3} + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#capture appendTo output}} INIT{{/capture}}{{#capture appendTo output}}{{#each nums}} {{it}}{{/each}}{{/capture}}BEFORE{{output}} AFTER"), + Is.EqualTo("BEFORE INIT 1 2 3 AFTER")); + + Assert.That(context.EvaluateScript("{{#capture appendTo output}} INIT{{/capture}}{{#capture appendTo output {nums:[4,5,6] }}{{#each nums}} {{it}}{{/each}}{{/capture}}BEFORE{{output}} AFTER"), + Is.EqualTo("BEFORE INIT 4 5 6 AFTER")); + } + + [Test] + public void Does_evaluate_partial_in_existing_Context() + { + var context = new ScriptContext { + Args = { + ["income"] = 1000 + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#partial p {expenses:100} }} {{income ?? 2000}} - {{expenses}} {{/partial}}{{ 'p' |> partial}}"), + Is.EqualTo(" 1000 - 100 ")); + } + + [Test] + public void Does_evaluate_eval_block_in_new_Context_by_default() + { + var context = new ScriptContext { + ScriptBlocks = { new EvalScriptBlock() }, + Args = { + ["income"] = 1000, + ["incomeExpr"] = "{{income ?? 2000}}", + ["expenseExpr"] = "{{expenses}}", + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#eval {expenses:100} }} {{incomeExpr}} - {{expenses}} {{/eval}}"), + Is.EqualTo(" 2000 - 100 ")); + + Assert.That(context.EvaluateScript("{{ ` ${incomeExpr} - ${expenseExpr} ` |> evalTemplate({expenses:100}) }}"), + Is.EqualTo(" 2000 - 100 ")); + } + + [Test] + public void Does_evaluate_eval_block_in_existing_Context_with_use_context() + { + var context = new ScriptContext { + ScriptBlocks = { new EvalScriptBlock() }, + Args = { + ["income"] = 1000, + ["incomeExpr"] = "{{income ?? 2000}}", + ["expenseExpr"] = "{{expenses}}", + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#eval {use:{context:true},expenses:100} }} {{incomeExpr}} - {{expenses}} {{/eval}}"), + Is.EqualTo(" 1000 - 100 ")); + + Assert.That(context.EvaluateScript("{{ ` ${incomeExpr} - ${expenseExpr} ` |> evalTemplate({use:{context:true},expenses:100}) }}"), + Is.EqualTo(" 1000 - 100 ")); + } + + [Test] + public void Can_include_plugins_into_new_eval_context() + { + var context = new ScriptContext { + ScriptBlocks = { new EvalScriptBlock() }, + Plugins = { new MarkdownScriptPlugin() }, + Args = { + ["evalContent"] = "{{#markdown}}# Heading{{/markdown}}", + } + }.Init(); + + Assert.Throws<ScriptException>(() => + context.EvaluateScript("{{#eval}}{{evalContent}}{{/eval}}")); + Assert.Throws<ScriptException>(() => + context.EvaluateScript("{{ evalContent |> evalTemplate}}")); + + Assert.That(context.EvaluateScript("{{#eval {use:{plugins:'MarkdownScriptPlugin'} }}{{evalContent}}{{/eval}}"), + Is.EqualTo("<h1>Heading</h1>\n")); + + Assert.That(context.EvaluateScript("{{ evalContent |> evalTemplate({use:{plugins:'MarkdownScriptPlugin'}}) |> raw }}"), + Is.EqualTo("<h1>Heading</h1>\n")); + } + + [Test] + public void Can_include_filter_into_new_eval_context() + { + var context = new ScriptContext { + ScriptBlocks = { new EvalScriptBlock() }, + ScriptMethods = { new InfoScripts() }, + Args = { + ["evalContent"] = "{{envServerUserAgent}}", + } + }.Init(); + + Assert.That(context.EvaluateScript("{{#eval}}{{evalContent}}{{/eval}}"), + Does.Not.Contain("ServiceStack")); + Assert.That(context.EvaluateScript("{{ evalContent |> evalTemplate}}"), + Does.Not.Contain("ServiceStack")); + + Assert.That(context.EvaluateScript("{{#eval {use:{filters:'InfoScripts'}}{{evalContent}}{{/eval}}"), + Does.Contain("ServiceStack")); + + Assert.That(context.EvaluateScript("{{ evalContent |> evalTemplate({use:{filters:'InfoScripts'}}) }}"), + Does.Contain("ServiceStack")); + } + + [Test] + public void Can_eval_dynamic_content() + { + var context = new ScriptContext { + ScriptBlocks = { new EvalScriptBlock() }, + Args = { + ["templates"] = new List<string> { + "1. {{income ?? 1000}} - {{expenses}}", + "2. {{income ?? 2000}} - {{expenses}}", + "3. {{income ?? 3000}} - {{expenses}}", + } + } + }.Init(); + + var result = context.EvaluateScript(@"{{#each templates}}{{index}} =>{{#eval {expenses: 100 * index} }} {{it}} {{/eval}}|> {{/each}}"); + Assert.That(result, Is.EqualTo("0 => 1. 1000 - 0 |> 1 => 2. 2000 - 100 |> 2 => 3. 3000 - 200 |> ")); + + result = context.EvaluateScript(@"{{#each templates}}{{index}} =>{{ ` ${it} ` |> evalTemplate({expenses: 100 * index}) }}|> {{/each}}"); + Assert.That(result, Is.EqualTo("0 => 1. 1000 - 0 |> 1 => 2. 2000 - 100 |> 2 => 3. 3000 - 200 |> ")); + } + + [Test] + public void Can_use_minifyjs_script_block() + { + var context = new ScriptContext { + Plugins = { new ServiceStackScriptBlocks() }, + DebugMode = false, + }.Init(); + + var output = context.EvaluateScript("{{#minifyjs}}{{/minifyjs}} {{#minifyjs}} \n{{/minifyjs}}"); + Assert.That(output.Trim(), Is.EqualTo("")); + + output = context.EvaluateScript("{{#minifyjs}}var a = 1; var b = 2;{{/minifyjs}}"); + Assert.That(output.Trim(), Is.EqualTo("var a=1;var b=2;")); + + output = context.EvaluateScript("{{#minifyjs appendTo scripts}}var a = 1; var b = 2;{{/minifyjs}} |> {{#minifyjs appendTo scripts}}function fn ( a ) { }{{/minifyjs}} |> {{scripts}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("|> |> \nvar a=1;var b=2;\nfunction fn(a){}")); + } + + [Test] + public void Can_use_minifycss_script_block() + { + var context = new ScriptContext { + Plugins = { new ServiceStackScriptBlocks() }, + DebugMode = false, + }.Init(); + + var output = context.EvaluateScript("{{#minifycss}} a { width: 1px; } b { height: 1px; } {{/minifycss}}"); + Assert.That(output.Trim(), Is.EqualTo("a{width:1px}b{height:1px}")); + + output = context.EvaluateScript("{{#minifycss appendTo css}} a { width: 1px; } {{/minifycss}} |> {{#minifycss appendTo css}} b { height: 1px; } {{/minifycss}} |> {{css}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("|> |> a{width:1px} b{height:1px}")); + } + + [Test] + public void Can_use_minifyhtml_script_block() + { + var context = new ScriptContext { + Plugins = { new ServiceStackScriptBlocks() }, + DebugMode = false, + }.Init(); + + var output = context.EvaluateScript("{{#minifyhtml}} <h1 > Title </h1> <p > Content </p> {{/minifyhtml}}"); + Assert.That(output.Trim(), Is.EqualTo("<h1> Title </h1> <p> Content </p>")); + + output = context.EvaluateScript("{{#minifyhtml appendTo html}} <h1 > Title </h1> {{/minifyhtml}} |> {{#minifyhtml appendTo html}} <p > Content </p> {{/minifyhtml}} |> {{html |> raw}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("|> |> <h1> Title </h1><p> Content </p>")); + } + + [Test] + public void Can_use_minifyjs_script_block_with_cache() + { + // all js/css/html has same base impl/behavior + + var context = new ScriptContext { + Plugins = { new ServiceStackScriptBlocks() }, + DebugMode = false, + }.Init(); + + var js = "var a = 1; var b = 2;"; + var minified = "var a=1;var b=2;"; + + var output = context.EvaluateScript("{{#minifyjs}}" + js + "{{/minifyjs}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(minified)); + + Assert.That(context.Cache["minifyjs:" + js].ToString().NormalizeNewLines(), Is.EqualTo(minified)); + output = context.EvaluateScript("{{#minifyjs}}" + js + "{{/minifyjs}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(minified)); + + context.Cache.Clear(); + + var js2 = "function fn ( a ) { }"; + var minified2 = "function fn(a){}"; + + output = context.EvaluateScript("{{#minifyjs appendTo scripts}}" + js + "{{/minifyjs}} |> {{#minifyjs appendTo scripts}}" + js2 + "{{/minifyjs}} |> {{scripts}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo($"|> |> \n{minified}\n{minified2}")); + + Assert.That(context.Cache["minifyjs:" + js].ToString().NormalizeNewLines(), Is.EqualTo(minified)); + Assert.That(context.Cache["minifyjs:" + js2].ToString().NormalizeNewLines(), Is.EqualTo(minified2)); + + output = context.EvaluateScript("{{#minifyjs appendTo scripts}}" + js + "{{/minifyjs}} |> {{#minifyjs appendTo scripts}}" + js2 + "{{/minifyjs}} |> {{scripts}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo($"|> |> \n{minified}\n{minified2}")); + } + + [Test] + public void Does_not_minify_or_cache_in_DebugMode() + { + // all js/css/html has same base impl/behavior + + var context = new ScriptContext { + Plugins = { new ServiceStackScriptBlocks() }, + DebugMode = true, + }.Init(); + + var js = "var a = 1; var b = 2;"; + + var output = context.EvaluateScript("{{#minifyjs}}" + js + "{{/minifyjs}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(js)); + + Assert.That(context.Cache.ContainsKey("minifyjs::" + js), Is.False); + output = context.EvaluateScript("{{#minifyjs}}" + js + "{{/minifyjs}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(js)); + } + + [Test] + public void Does_parse_keyvalues() + { + var context = new ScriptContext().Init(); + + var result = context.Evaluate(@" + {{#keyvalues dict}} + Apples 2 + Oranges 3 + {{/keyvalues}}{{dict|return}}"); + + Assert.That(result, Is.EquivalentTo(new Dictionary<string, string> { + {"Apples","2"}, + {"Oranges","3"}, + })); + } + + [Test] + public void Does_parse_keyvalues_with_delimiter() + { + var context = new ScriptContext().Init(); + + var result = context.Evaluate(@" + {{#keyvalues dict ':'}} + Grape Fruit: 2 + Rock Melon: 3 + {{/keyvalues}}{{dict|return}}"); + + Assert.That(result, Is.EquivalentTo(new Dictionary<string, string> { + {"Grape Fruit","2"}, + {"Rock Melon","3"}, + })); + } + + [Test] + public void Does_parse_keyvalues_in_code_blocks() + { + var context = new ScriptContext().Init(); + + var result = context.Evaluate(@" +```code +#keyvalues dict ':' + Apples: 2 + Oranges: 3 + Grape Fruit: 2 + Rock Melon: 3 +/keyvalues +dict |> return +```"); + + Assert.That(result, Is.EquivalentTo(new Dictionary<string, string> { + {"Apples","2"}, + {"Oranges","3"}, + {"Grape Fruit","2"}, + {"Rock Melon","3"}, + })); + } + + [Test] + public void Does_parse_keyvalues_in_code_blocks_with_code_preprocessor() + { + var context = new ScriptContext { + Preprocessors = { ScriptPreprocessors.TransformCodeBlocks } + }.Init(); + + var result = context.Evaluate(@" +```code +#keyvalues dict ':' + * Apples: 2 + * Oranges: 3 + * Grape Fruit: 2 + * Rock Melon: 3 +/keyvalues +dict |> return +```"); + + Assert.That(result, Is.EquivalentTo(new Dictionary<string, string> { + {"Apples","2"}, + {"Oranges","3"}, + {"Grape Fruit","2"}, + {"Rock Melon","3"}, + })); + } + + [Test] + public void Does_parse_csv() + { + var context = new ScriptContext().Init(); + + var result = context.Evaluate(@" + {{#csv list}} + Apples,2,2 + Oranges,3,3 + Grape Fruit,2,2 + Rock Melon,3,3 + {{/csv}}{{list|return}}"); + + Assert.That(result, Is.EquivalentTo(new List<List<string>> { + new List<string> { "Apples", "2", "2" }, + new List<string> { "Oranges", "3", "3" }, + new List<string> { "Grape Fruit", "2", "2" }, + new List<string> { "Rock Melon", "3", "3" }, + })); + } + + [Test] + public void Can_use_while_block() + { + var context = new ScriptContext().Init(); + + var result = context.EvaluateScript(@" +```code +3 |> to => times +#while times > 0 + times + times - 1 |> to => times +/while +```"); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo("3\n2\n1")); + + result = context.EvaluateScript(@" +```code +0 |> to => times +#while times > 0 + times + times - 1 |> to => times +else + `times == 0` +/while +```"); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo("times == 0")); + } + + [Test] + public void Can_use_while_block_single_new_line() + { + var context = new ScriptContext().Init(); + + var result = context.EvaluateScript(@" +```code +3 |> to => times +#while times > 0 + times + times - 1 |> to => times +/while +```".Replace("\r","")); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo("3\n2\n1")); + + result = context.EvaluateScript(@" +```code +0 |> to => times +#while times > 0 + times + times - 1 |> to => times +else + `times == 0` +/while +```".Replace("\r","")); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo("times == 0")); + } + + [Test] + public void Can_use_while_block_with_code_preprocessor() + { + var context = new ScriptContext { + Preprocessors = { ScriptPreprocessors.TransformCodeBlocks } + }.Init(); + + var result = context.EvaluateScript(@" +```code +3 |> to => times +#while times > 0 + times + times - 1 |> to => times +/while +```"); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo("3\n2\n1")); + + result = context.EvaluateScript(@" +```code +0 |> to => times +#while times > 0 + times + times - 1 |> to => times +else + `times == 0` +/while +```"); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo("times == 0")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptCodeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptCodeTests.cs new file mode 100644 index 00000000000..3fe18e415e8 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptCodeTests.cs @@ -0,0 +1,1149 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Logging; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptCodeTests + { + static ScriptCodeTests() => LogManager.LogFactory = new ConsoleLogFactory(); + + [OneTimeTearDown] + public void OneTimeTearDown() => LogManager.LogFactory = null; + + [Test] + public void Can_parse_single_and_multi_line_code_statements() + { + var context = new ScriptContext().Init(); + + JsStatement[] ParseCode(string str) + { + var statements = context.ParseCode(str).Statements; + return statements; + } + + JsStatement[] expr; + expr = new[] { + new JsExpressionStatement(new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, + new JsLiteral(2))), + new JsExpressionStatement(new JsBinaryExpression(new JsLiteral(3), JsMultiplication.Operator, + new JsLiteral(4))), + }; + + Assert.That(ParseCode("1 + 2\n3 * 4"), Is.EqualTo(expr)); + Assert.That(ParseCode("1 + 2\n{{ 3 * 4 }}"), Is.EqualTo(expr)); + Assert.That(ParseCode("1 + 2\n {{ 3 * 4 }} "), Is.EqualTo(expr)); + Assert.That(ParseCode("1 + 2\n \n {{ \n 3 * 4 \n }} \n "), Is.EqualTo(expr)); + + expr = new List<JsStatement>(expr) { + new JsExpressionStatement(new JsBinaryExpression(new JsLiteral(5), JsDivision.Operator, + new JsLiteral(6))), + }.ToArray(); + + Assert.That(ParseCode("1 + 2\n \n {{ \n 3 * 4 \n }} \n 5 / 6"), Is.EqualTo(expr)); + Assert.That(ParseCode("1 + 2\n \n {{ \n 3 * 4 \n }} \n {{ 5 / 6 }} "), Is.EqualTo(expr)); + Assert.That(ParseCode("1 + 2\n \n {{ \n 3 * 4 \n }} \n {{ \n 5 / 6 \n }} \n "), Is.EqualTo(expr)); + Assert.That(ParseCode("1 + 2\n \n {{ \n 3\n*\n4 \n }} \n {{ \n 5 \n / \n 6 \n }} \n "), + Is.EqualTo(expr)); + + expr = new[] { + new JsExpressionStatement(new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, + new JsLiteral(2))), + new JsExpressionStatement(new JsLiteral("\n3\n*\n4\n")), + new JsExpressionStatement(new JsLiteral(" 5 \n / \n 6 ")), + }; + Assert.That(ParseCode("1 + 2\n \n {{ \n '\n3\n*\n4\n' \n }} \n {{ \n ' 5 \n / \n 6 ' \n }} \n "), + Is.EqualTo(expr)); + + expr = new[] { + new JsExpressionStatement(new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, + new JsLiteral(2))), + new JsExpressionStatement(new JsTemplateLiteral("\n3\n*\n4\n")), + new JsExpressionStatement(new JsTemplateLiteral(" 5 \n / \n 6 ")), + }; + Assert.That(ParseCode("1 + 2\n \n {{ \n `\n3\n*\n4\n` \n }} \n {{ \n ` 5 \n / \n 6 ` \n }} \n "), + Is.EqualTo(expr)); + + expr = new[] { + new JsExpressionStatement( + new JsConditionalExpression( + new JsBinaryExpression(new JsIdentifier("a"), JsGreaterThan.Operator, new JsLiteral(2)), + new JsConditionalExpression( + new JsCallExpression(new JsMemberExpression(new JsIdentifier("a"), new JsIdentifier("isOdd"))), + new JsLiteral("a > 2 and odd"), + new JsLiteral("a > 2 and even") + ), + new JsConditionalExpression( + new JsCallExpression(new JsMemberExpression(new JsIdentifier("a"), new JsIdentifier("isOdd"))), + new JsLiteral("a <= 2 and odd"), + new JsLiteral("a <= 2 and even") + ) + ) + ), + }; + + Assert.That(ParseCode(@"{{ (a > 2 + ? (a.isOdd() ? 'a > 2 and odd' : 'a > 2 and even') + : (a.isOdd() ? 'a <= 2 and odd' : 'a <= 2 and even')) }}"), Is.EqualTo(expr)); + + Assert.That(ParseCode(@" {{ +(a > 2 + ? +(a.isOdd() ? 'a > 2 and odd' : 'a > 2 and even') + : +(a.isOdd() ? 'a <= 2 and odd' : 'a <= 2 and even')) +}} +"), Is.EqualTo(expr)); + } + + [Test] + public void Can_parse_filter_expressions() + { + var context = new ScriptContext().Init(); + + JsStatement[] ParseCode(string str) + { + var statements = context.ParseCode(str).Statements; + return statements; + } + + + JsStatement[] expr; + + expr = new[] { + new JsFilterExpressionStatement("1 |> add(2)", new JsLiteral(1), + new JsCallExpression(new JsIdentifier("add"), new JsLiteral(2))), + }; + + Assert.That(ParseCode("1 |> add(2)"), Is.EqualTo(expr)); + Assert.That(ParseCode("{{ 1 |> add(2) }}"), Is.EqualTo(expr)); + Assert.That(ParseCode(" \n {{ \n 1 |> add(2) \n }} \n "), Is.EqualTo(expr)); + + expr = new[] { + new JsFilterExpressionStatement("1 \n |> \n add(2)", new JsLiteral(1), + new JsCallExpression(new JsIdentifier("add"), new JsLiteral(2))), + }; + + Assert.That(ParseCode("{{ \n 1 \n |> \n add(2) \n }}"), Is.EqualTo(expr)); + } + + [Test] + public void Can_parse_multiple_statements_delimited_by_semicolons() + { + var context = new ScriptContext().Init(); + + JsStatement[] ParseCode(string str) + { + var statements = context.ParseCode(str).Statements; + return statements; + } + + var expr = new JsStatement[] { + new JsExpressionStatement( + new JsAssignmentExpression(new JsIdentifier("a"), JsAssignment.Operator, new JsLiteral(1))), + new JsFilterExpressionStatement("a |> add(2)", new JsIdentifier("a"), + new JsCallExpression(new JsIdentifier("add"), new JsLiteral(2))), + new JsExpressionStatement( + new JsVariableDeclaration(JsVariableDeclarationKind.Var, new [] { + new JsDeclaration(new JsIdentifier("b"), new JsLiteral(3)), + new JsDeclaration(new JsIdentifier("d"), new JsLiteral(4)) + })), + new JsFilterExpressionStatement("d |> sub(b)", new JsIdentifier("d"), + new JsCallExpression(new JsIdentifier("sub"), new JsIdentifier("b"))), + }; + + var result = ParseCode("a = 1; a |> add(2); var b = 3, d=4; d |> sub(b)"); + Assert.That(result, Is.EqualTo(expr)); + } + + [Test] + public void Can_parse_code_statements_with_blocks() + { + var context = new ScriptContext().Init(); + + JsStatement[] ParseCode(string str) + { + var statements = context.ParseCode(str).Statements; + return statements; + } + + JsStatement[] expr; + expr = new[] { + new JsPageBlockFragmentStatement( + new PageBlockFragment("1", "if", "true", + new JsBlockStatement(new JsExpressionStatement(new JsLiteral(1))) + ) + ) + }; + + Assert.That(ParseCode("#if true\n1\n/if"), Is.EqualTo(expr)); + Assert.That(ParseCode(" #if true \n 1 \n /if "), Is.EqualTo(expr)); + Assert.That(ParseCode(" \n #if true \n \n 1 \n \n /if \n "), Is.EqualTo(expr)); + + expr = new[] { + new JsPageBlockFragmentStatement(new PageBlockFragment("1", "if", "true", + new JsBlockStatement( + new JsPageBlockFragmentStatement( + new PageBlockFragment("1", "if", "a > b", + new JsBlockStatement(new JsExpressionStatement(new JsLiteral(1))) + ) + ) + ) + )) + }; + Assert.That(ParseCode("#if true\n#if a > b\n1\n/if\n/if"), Is.EqualTo(expr)); + Assert.That(ParseCode("#if true \n \n #if a > b \n \n 1 \n \n /if \n \n /if \n \n "), Is.EqualTo(expr)); + + expr = new[] { + new JsPageBlockFragmentStatement(new PageBlockFragment("1", "if", "true", + new JsBlockStatement( + new JsPageBlockFragmentStatement( + new PageBlockFragment("1", "if", "a > b", + new JsBlockStatement(new JsExpressionStatement(new JsLiteral(1))), + new List<PageElseBlock> { + new PageElseBlock("", new JsBlockStatement(new JsExpressionStatement(new JsLiteral(2)))) + } + ) + ) + ), + new List<PageElseBlock> { + new PageElseBlock("", new JsBlockStatement(new JsExpressionStatement(new JsLiteral("3")))) + } + )) + }; + + Assert.That(ParseCode("#if true\n#if a > b\n1\nelse\n2\n/if\nelse\n'3'\n/if"), Is.EqualTo(expr)); + Assert.That(ParseCode("#if true \n \n #if a > b \n \n 1 \n \n else \n \n 2 \n \n /if \n \n else \n \n '3' \n \n /if \n \n "), Is.EqualTo(expr)); + + expr = new[] { + new JsPageBlockFragmentStatement(new PageBlockFragment("", "if", "a > 1", + new JsBlockStatement( + new JsExpressionStatement(new JsLiteral("a > 1")) + ), + new List<PageElseBlock> { + new PageElseBlock("", + new JsBlockStatement( + new JsExpressionStatement(new JsLiteral("a <= 1")) + ) + ) + } + )) + }; + + // Tests \r\n on Windows + Assert.That(ParseCode(@" +#if a > 1 +'a > 1' +else +'a <= 1' +/if +"), Is.EqualTo(expr)); + } + + [Test] + public void Can_parse_verbatim_blocks() + { + var context = new ScriptContext().Init(); + + JsStatement[] ParseCode(string str) + { + var statements = context.ParseCode(str).Statements; + return statements; + } + + JsStatement[] expr; + expr = new[] { + new JsPageBlockFragmentStatement( + new PageBlockFragment("", "raw", "", + new List<PageFragment> { new PageStringFragment("1\n2") } + ) + ) + }; + Assert.That(ParseCode("#raw\n1\n2\n/raw"), Is.EqualTo(expr)); + Assert.That(ParseCode(" \n #raw\n1\n2\n/raw \n "), Is.EqualTo(expr)); + + expr = new[] { + new JsPageBlockFragmentStatement( + new PageBlockFragment("", "raw", "", + new List<PageFragment> { new PageStringFragment(" \n 1\n2 \n ") } + ) + ) + }; + Assert.That(ParseCode("#raw \n \n 1\n2 \n \n /raw"), Is.EqualTo(expr)); + Assert.That(ParseCode(" \n #raw \n \n 1\n2 \n \n /raw \n "), Is.EqualTo(expr)); + + expr = new[] { + new JsPageBlockFragmentStatement( + new PageBlockFragment("", "raw", "a > b", + new List<PageFragment> { new PageStringFragment(" \n 1\n2 \n ") } + ) + ) + }; + Assert.That(ParseCode("#raw a > b\n \n 1\n2 \n \n /raw"), Is.EqualTo(expr)); + Assert.That(ParseCode(" \n #raw a > b \n \n 1\n2 \n \n /raw \n "), Is.EqualTo(expr)); + } + + [Test] + public void Can_Evaluate_code() + { + var context = new ScriptContext().Init(); + + string result = null; + string code = null; + var expected = @"1 <= 2 and odd +2 <= 2 and even +3 > 2 and odd +4 > 2 and even +5 > 2 and odd +".Replace("\r\n","\n"); + + code = @" +#if a > 1 + `${a} > 1` +else + `${a} <= 1` +/if +"; + result = context.RenderCode(code, new Dictionary<string, object> { ["a"] = 2 }); + Assert.That(result.Trim(), Is.EqualTo("2 &gt; 1")); + + code = @" +#if a > 1 + `${a} > 1` |> raw +else + `${a} <= 1` |> raw +/if +"; + + result = context.RenderCode(code, new Dictionary<string, object> { ["a"] = 1 }); + Assert.That(result.Trim(), Is.EqualTo("1 <= 1")); + + code = @" +range(5) |> map => it + 1 |> to => nums +#each a in nums + #if a > 2 + #if a.isOdd() + `${a} > 2 and odd` |> raw + else + `${a} > 2 and even` |> raw + /if + else + #if a.isOdd() + `${a} <= 2 and odd` |> raw + else + `${a} <= 2 and even` |> raw + /if + /if +/each +"; + + result = context.RenderCode(code); + Assert.That(result, Is.EqualTo(expected)); + + code = @" +#function testValue(a) + #if a > 2 + #if a.isOdd() + `${a} > 2 and odd` |> return + else + `${a} > 2 and even` |> return + /if + else + #if a.isOdd() + `${a} <= 2 and odd` |> return + else + `${a} <= 2 and even` |> return + /if + /if +/function + +range(5) |> map => it + 1 |> to => nums +#each nums + it.testValue() |> raw +/each +"; + + result = context.RenderCode(code); + Assert.That(result, Is.EqualTo(expected)); + + code = @" +#function testValue(a) + return (a > 2 ? (a.isOdd() ? `${a} > 2 and odd` : `${a} > 2 and even`) : (a.isOdd() ? `${a} <= 2 and odd` : `${a} <= 2 and even`)) +/function + +range(5) |> map => it + 1 |> to => nums +#each nums + it.testValue() |> raw +/each +"; + + result = context.RenderCode(code); + Assert.That(result, Is.EqualTo(expected)); + + code = @" +#function testValue(a) + {{ return (a > 2 + ? (a.isOdd() ? `${a} > 2 and odd` : `${a} > 2 and even`) + : (a.isOdd() ? `${a} <= 2 and odd` : `${a} <= 2 and even`)) }} +/function + +range(5) |> map => it + 1 |> to => nums +#each nums + it.testValue() |> raw +/each +"; + + result = context.RenderCode(code); + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void Can_evaluate_template_code_in_code_blocks() + { + var context = new ScriptContext().Init(); + + string result = null; + string code = null; + + result = context.RenderCode(@" +{{#if a > 1}} + {{a}} > 1 +{{else}} + {{a}} <= 1 +{{/if}} +", new Dictionary<string, object> { ["a"] = 1 }); + Assert.That(result.Trim(), Is.EqualTo("1 <= 1")); + + result = context.RenderCode(@" + {{#if a > 1}} + {{a}} > 1 + {{else}} + {{a}} <= 1 + {{/if}}", new Dictionary<string, object> { ["a"] = 1 }); + Assert.That(result.Trim(), Is.EqualTo("1 <= 1")); + + result = context.RenderCode(@" +{{#if a > 1}} + {{a}} > 1 +{{else}} + {{a}} <= 1 +{{/if}} + +#if a.isOdd() + ` and is odd` +else + ` and is even` +/if +", new Dictionary<string, object> { ["a"] = 1 }); + Assert.That(result.NormalizeNewLines(), Is.EqualTo("1 <= 1\n and is odd")); + } + + [Test] + public void Can_evaluate_Template_only_blocks_in_code_blocks() + { + var context = new ScriptContext { + Plugins = { new MarkdownScriptPlugin() } + }.Init(); + + var output = context.RenderCode(@" +#capture out +{{#each range(3)}} + - {{it + 1}} +{{/each}} +/capture +out +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" + - 1 + - 2 + - 3".NormalizeNewLines())); + } + + [Test] + public void Can_execute_existing_Script_Blocks_in_Code_Statements_in_Template_Syntax() + { + var context = new ScriptContext { + DebugMode = true, + Plugins = { + new MarkdownScriptPlugin(), + } + }.Init(); + + string output = null; + object result = null; + + output = context.RenderCode(@" + {{#noop}} + {{#each range(3)}} + - {{it + 1}} + {{/each}} + {{/noop}} + "); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@"")); + + output = context.RenderCode(@" +{{#each range(3)}} + - {{it + 1}} +{{/each}}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" + - 1 + - 2 + - 3".NormalizeNewLines())); + + + output = context.RenderCode(@" +* comment * + +{{#capture text}} +## Title +{{/capture}} + +{{#capture appendTo text}} +{{#each range(3)}} + - {{it + 1}} +{{/each}} +{{/capture}} + +text |> markdown +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<h2>Title</h2> +<ul> +<li>1</li> +<li>2</li> +<li>3</li> +</ul>".NormalizeNewLines())); + + result = context.EvaluateCode(@" + {{#keyvalues dict ':'}} + Apples: 2 + Oranges: 3 + Grape Fruit: 2 + Rock Melon: 3 + {{/keyvalues}} + dict |> return + "); + + Assert.That(result, Is.EquivalentTo(new Dictionary<string, string> { + {"Apples","2"}, + {"Oranges","3"}, + {"Grape Fruit","2"}, + {"Rock Melon","3"}, + })); + + result = context.EvaluateCode(@" + {{#csv list}} + Apples,2,2 + Oranges,3,3 + Grape Fruit,2,2 + Rock Melon,3,3 + {{/csv}} + list |> return"); + + Assert.That(result, Is.EquivalentTo(new List<List<string>> { + new List<string> { "Apples", "2", "2" }, + new List<string> { "Oranges", "3", "3" }, + new List<string> { "Grape Fruit", "2", "2" }, + new List<string> { "Rock Melon", "3", "3" }, + })); + + output = context.RenderCode(@" +{{#ul {if:hasAccess, each:items, where:'Age >= 2', class:['nav', !disclaimerAccepted?'blur':''], id:`ul-${id}`} }} + {{#li {class: {alt:isOdd(index), active:Name==highlight} }} + {{Name}} + {{/li}} +{{else}} + <div>no items</div> +{{/ul}}", new Dictionary<string, object> { + ["items"] = new[] {new Person("foo", 1), new Person("bar", 2), new Person("baz", 3)}, + ["id"] = "menu", + ["disclaimerAccepted"] = false, + ["hasAccess"] = true, + ["highlight"] = "baz", + ["digits"] = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }, + }); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<ul class=""nav blur"" id=""ul-menu""> + <li> + bar + </li> + <li class=""alt active""> + baz + </li> +</ul>".NormalizeNewLines())); + + + output = context.RenderCode(@" +{{#partial content}} + - List Item +{{/partial}} + +'<h1>Title</h1>' |> raw +'content' |> partial |> markdown"); + + Assert.That(output.RemoveNewLines(), Is.EqualTo(@"<h1>Title</h1><ul><li>List Item</li></ul>".RemoveNewLines())); + + output = context.RenderCode(@" +{{#raw content}} +{{ - List Item }} +{{/raw}} + +'# Title' +'{{ - List Item }}'"); + + Assert.That(output.RemoveNewLines(), Is.EqualTo(@"# Title{{ - List Item }}".RemoveNewLines())); + + + output = context.RenderCode(@" +3 |> to => times +{{#while times > 0}} +{{times}} time{{times == 1 ? '' : 's'}} +{{times - 1 |> to => times}} +{{/while}} +"); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo("3 times\n2 times\n1 time")); + + Assert.That(context.RenderCode(@"'Person ' +{{#with person}} +{{Name}} is {{Age}} years old +{{/with}}".NormalizeNewLines(), + new Dictionary<string, object> { + ["person"] = new Person { Name = "poco", Age = 27 }, + }), + Is.EqualTo("Person \npoco is 27 years old\n")); + } + + [Test] + public void Can_execute_existing_Script_Blocks_in_Code_Statements_in_Code_Syntax() + { + var context = new ScriptContext { + DebugMode = true, + Plugins = { + new MarkdownScriptPlugin(), + } + }.Init(); + + string code = null; + string output = null; + object result = null; + + code = @" + #noop + #each range(3) + ` - ${it + 1}` + /each + /noop + "; + Assert.That(context.RenderCode(code).NormalizeNewLines(), Is.EqualTo(@"")); + Assert.That(context.RenderCode(code.Trim()).NormalizeNewLines(), Is.EqualTo(@"")); + + code = @" + #each range(3) + ` - ${it + 1}` + /each"; + Assert.That(context.RenderCode(code).NormalizeNewLines(), Is.EqualTo("- 1\n - 2\n - 3")); + Assert.That(context.RenderCode(code.Trim()).NormalizeNewLines(), Is.EqualTo("- 1\n - 2\n - 3")); + + // Capture requires Template Syntax + + code = @" + #keyvalues dict ':' + Apples: 2 + Oranges: 3 + Grape Fruit: 2 + Rock Melon: 3 + /keyvalues + dict |> return + "; + + result = context.EvaluateCode(code); + Assert.That(result, Is.EquivalentTo(new List<KeyValuePair<string, string>> { + new("Apples","2"), + new("Oranges","3"), + new("Grape Fruit","2"), + new("Rock Melon","3"), + })); + Assert.That(context.EvaluateCode(code.Trim()), Is.EquivalentTo((List<KeyValuePair<string, string>>)result)); + + code = @" + #csv list + Apples,2,2 + Oranges,3,3 + Grape Fruit,2,2 + Rock Melon,3,3 + /csv + list |> return"; + result = context.EvaluateCode(code); + Assert.That(result, Is.EquivalentTo(new List<List<string>> { + new() { "Apples", "2", "2" }, + new() { "Oranges", "3", "3" }, + new() { "Grape Fruit", "2", "2" }, + new() { "Rock Melon", "3", "3" }, + })); + Assert.That(context.EvaluateCode(code.Trim()), Is.EquivalentTo((List<List<string>>)result)); + + // HTML Scripts requires Template Syntax + + // Partial requires Template Syntax + + code = @" +#raw content +{{ - List Item }} +/raw + +'# Title' +'{{ - List Item }}'"; + + Assert.That(context.RenderCode(code).RemoveNewLines(), Is.EqualTo(@"# Title{{ - List Item }}".RemoveNewLines())); + Assert.That(context.RenderCode(code.Trim()).RemoveNewLines(), Is.EqualTo(@"# Title{{ - List Item }}".RemoveNewLines())); + + + code = @" + 3 |> to => times + #while times > 0 + `${times} time${times == 1 ? '' : 's'}` + times - 1 |> to => times + /while"; + + Assert.That(context.RenderCode(code).NormalizeNewLines(), Is.EqualTo("3 times\n2 times\n1 time")); + Assert.That(context.RenderCode(code.Trim()).NormalizeNewLines(), Is.EqualTo("3 times\n2 times\n1 time")); + + code = @"'Person ' + #with person + `${Name} is ${Age} years old` + /with"; +; + Assert.That(context.RenderCode(code, + new Dictionary<string, object> { + ["person"] = new Person {Name = "poco", Age = 27}, + }), + Is.EqualTo("Person \npoco is 27 years old\n")); + Assert.That(context.RenderCode(code.Trim(), + new Dictionary<string, object> { + ["person"] = new Person {Name = "poco", Age = 27}, + }), + Is.EqualTo("Person \npoco is 27 years old\n")); + } + + [Test] + public void Can_execute_existing_Script_Blocks_in_Code_Statements_in_Code_Syntax_only_LF() + { + var context = new ScriptContext { + DebugMode = true, + Plugins = { + new MarkdownScriptPlugin(), + } + }.Init(); + + string code = null; + string output = null; + object result = null; + + code = @" + #noop + #each range(3) + ` - ${it + 1}` + /each + /noop + "; + output = context.RenderCode(code.Replace("\r","")); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@"")); + output = context.RenderCode(code.Trim().Replace("\r","")); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@"")); + + code = @" + #each range(3) + ` - ${it + 1}` + /each".Replace("\r", ""); + Assert.That(context.RenderCode(code).NormalizeNewLines(), Is.EqualTo("- 1\n - 2\n - 3")); + Assert.That(context.RenderCode(code.Trim()).NormalizeNewLines(), Is.EqualTo("- 1\n - 2\n - 3")); + + // Capture requires Template Syntax + + code = @" + #keyvalues dict ':' + Apples: 2 + Oranges: 3 + Grape Fruit: 2 + Rock Melon: 3 + /keyvalues + dict |> return + ".Replace("\r", ""); + var expectedKeyValues = new Dictionary<string, string> { + {"Apples", "2"}, + {"Oranges", "3"}, + {"Grape Fruit", "2"}, + {"Rock Melon", "3"}, + }; + Assert.That(context.EvaluateCode(code), Is.EquivalentTo(expectedKeyValues)); + Assert.That(context.EvaluateCode(code.Trim()), Is.EquivalentTo(expectedKeyValues)); + + result = context.EvaluateCode(@" + #csv list + Apples,2,2 + Oranges,3,3 + Grape Fruit,2,2 + Rock Melon,3,3 + /csv + list |> return".Replace("\r","")); + + Assert.That(result, Is.EquivalentTo(new List<List<string>> { + new List<string> { "Apples", "2", "2" }, + new List<string> { "Oranges", "3", "3" }, + new List<string> { "Grape Fruit", "2", "2" }, + new List<string> { "Rock Melon", "3", "3" }, + })); + + // HTML Scripts requires Template Syntax + + // Partial requires Template Syntax + + code = @" +#raw content +{{ - List Item }} +/raw + +'# Title' +'{{ - List Item }}'".Replace("\r", ""); + Assert.That(context.RenderCode(code).RemoveNewLines(), Is.EqualTo(@"# Title{{ - List Item }}".RemoveNewLines())); + Assert.That(context.RenderCode(code.Trim()).RemoveNewLines(), Is.EqualTo(@"# Title{{ - List Item }}".RemoveNewLines())); + + + code = @" + 3 |> to => times + #while times > 0 + `${times} time${times == 1 ? '' : 's'}` + times - 1 |> to => times + /while".Replace("\r", ""); + Assert.That(context.RenderCode(code).NormalizeNewLines(), Is.EqualTo("3 times\n2 times\n1 time")); + Assert.That(context.RenderCode(code.Trim()).NormalizeNewLines(), Is.EqualTo("3 times\n2 times\n1 time")); + + code = @" + 'Person ' + #with person + `${Name} is ${Age} years old` + /with + ".Replace("\r", ""); + + Assert.That(context.RenderCode(code, + new Dictionary<string, object> { + ["person"] = new Person { Name = "poco", Age = 27 }, + }).NormalizeNewLines(), + Is.EqualTo("Person \npoco is 27 years old")); + Assert.That(context.RenderCode(code.Trim(), + new Dictionary<string, object> { + ["person"] = new Person { Name = "poco", Age = 27 }, + }).NormalizeNewLines(), + Is.EqualTo("Person \npoco is 27 years old")); + } + + [Test] + public void Can_use_multi_line_comments_in_code_statements() + { + var context = new ScriptContext().Init(); + + var output = context.RenderCode(@" +`some` + +{{* this is + a multi-line + comment *}} + +`text`"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("some\ntext")); + + output = context.RenderCode(@" +`some` + + {{* + this is + a multi-line + comment + *}} + +`text`"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("some\ntext")); + + output = context.RenderCode(@" +`some` + + {{* + this is + a {{ multi-line }} +{{ comment }} }} + *}} + +`text`"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("some\ntext")); + + output = context.RenderCode(@" + `some` + {{* this is a single-line comment *}} + `text`"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("some\ntext")); + } + + [Test] + public void Can_execute_code_statements_quietly() + { + var context = new ScriptContext().Init(); + + string template (string block) => "```" + block + @" + 3 |> to => times + #while times > 0 + `${times} time${times == 1 ? '' : 's'}` + times - 1 |> to => times + /while + ``` +remaining={{times}}"; + + Assert.That(context.EvaluateScript(template("code")).NormalizeNewLines(), + Is.EqualTo("3 times\n2 times\n1 time\nremaining=0")); + + Assert.That(context.EvaluateScript(template("code|quiet")).NormalizeNewLines(), + Is.EqualTo("remaining=0")); + Assert.That(context.EvaluateScript(template("code|q")).NormalizeNewLines(), + Is.EqualTo("remaining=0")); + Assert.That(context.EvaluateScript(template("code|mute")).NormalizeNewLines(), + Is.EqualTo("remaining=0")); + } + + void AssertFizzBuzzOutput(string output) + { + Assert.That(output.NormalizeNewLines(), Does.StartWith(@" +1 +2 +Fizz +4 +Buzz +Fizz +7 +8 +Fizz +Buzz +11 +Fizz +13 +14 +FizzBuzz".NormalizeNewLines())); + } + + [Test] + public void Can_eval_FizzBuzz_Script() + { + var context = new ScriptContext().Init(); + + string src = @" +{{#each range(1,100)}} +{{#if it % 3 == 0 && it % 5 == 0}} +FizzBuzz +{{else if it % 3 == 0}} +Fizz +{{else if it % 5 == 0}} +Buzz +{{else}} +{{it}} +{{/if}} +{{/each}} +"; + var output = context.RenderScript(src); + AssertFizzBuzzOutput(output); + } + + [Test] + public void Can_eval_FizzBuzz_Code() + { + var context = new ScriptContext().Init(); + + string src = @" +#each range(1,100) + #if it % 3 == 0 && it % 5 == 0 + 'FizzBuzz' + else if it % 3 == 0 + 'Fizz' + else if it % 5 == 0 + 'Buzz' + else + it + /if +/each +"; + var output = context.RenderCode(src); + AssertFizzBuzzOutput(output); + + src = @" +#function fizzbuzz(it) + #if it % 3 == 0 && it % 5 == 0 + 'FizzBuzz' |> return + else if it % 3 == 0 + 'Fizz' |> return + else if it % 5 == 0 + 'Buzz' |> return + else + it |> return + /if +/function + +#each range(1,100) + fizzbuzz(it) +/each +"; + + output = context.RenderCode(src); + AssertFizzBuzzOutput(output); + } + + [Test] + public void Can_eval_FizzBuzz_Lisp() + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language } + }.Init(); + + string src = @" +(doseq (i (range 1 100)) + (println + (cond ((and (zero? (mod i 3)) (zero? (mod i 5))) ""FizzBuzz"") + ((zero? (mod i 3)) ""Fizz"") + ((zero? (mod i 5)) ""Buzz"") + (t i)) + ))"; + var output = context.RenderLisp(src); + AssertFizzBuzzOutput(output); + + src = @" +(defn fizzbuzz [i] + (cond ((and (zero? (mod i 3)) (zero? (mod i 5))) ""FizzBuzz"") + ((zero? (mod i 3)) ""Fizz"") + ((zero? (mod i 5)) ""Buzz"") + (t i))) + +(dorun println (map fizzbuzz (range 1 100))) +"; + + output = context.RenderLisp(src); + AssertFizzBuzzOutput(output); + } + + [Test] + public void Can_eval_FizzBuzz_combined() + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language }, + Plugins = { + new MarkdownScriptPlugin() + } + }.Init(); + + string src = @" +{{#defn fizzbuzz [i] }} + (cond ((and (zero? (mod i 3)) (zero? (mod i 5))) ""FizzBuzz"") + ((zero? (mod i 3)) ""Fizz"") + ((zero? (mod i 5)) ""Buzz"") + (t i)) +{{/defn}} + +{{#capture md}} +## FizzBuzz: +{{#each range(1,100) }} + - {{ fizzbuzz(it) }} +{{/each}} +{{/capture}} + +{{ md |> markdown }} +"; + + var output = context.RenderScript(src); + Assert.That(output.NormalizeNewLines(), Does.StartWith(@" +<h2>FizzBuzz:</h2> +<ul> +<li>1</li> +<li>2</li> +<li>Fizz</li> +<li>4</li> +<li>Buzz</li> +<li>Fizz</li> +<li>7</li> +<li>8</li> +<li>Fizz</li> +<li>Buzz</li> +<li>11</li> +<li>Fizz</li> +<li>13</li> +<li>14</li> +<li>FizzBuzz</li>".NormalizeNewLines())); + } + + const string TemplateMix = @" +Template: +{{#each range(1,15) }} +{{#if it % 3 == 0 && it % 5 == 0}} + FizzBuzz +{{else if it % 3 == 0}} + Fizz +{{else if it % 5 == 0}} + Buzz +{{else}} + {{it}} +{{/if}} +{{/each}} + +Code: +```code +#each range(1,15) + #if it % 3 == 0 && it % 5 == 0 + ""FizzBuzz"" + else if it % 3 == 0 + ""Fizz"" + else if it % 5 == 0 + ""Buzz"" + else + it + /if +/each +``` + +Lisp: +```lisp +(defn fizzbuzz [i] + (cond ((and (zero? (mod i 3)) (zero? (mod i 5))) ""FizzBuzz"") + ((zero? (mod i 3)) ""Fizz"") + ((zero? (mod i 5)) ""Buzz"") + (t i))) + +(dorun println (map fizzbuzz (range 1 15))) +``` +"; + [Test] + public void Can_use_multiple_code_blocks() + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language } + }; + + context.VirtualFiles.WriteFile("page.html", "{{#raw template}}\n" + + TemplateMix + + @"{{/raw}} + {{template}}"); + context.Init(); + + var output = context.RenderScript(TemplateMix); + Assert.That(output.NormalizeNewLines(), Does.Contain(@"Lisp: +1 +2 +Fizz".NormalizeNewLines())); + + var pageResult = new PageResult(context.GetPage("page")); + output = pageResult.RenderScript(); + Assert.That(output, Does.Contain("#each range(1,15)")); + Assert.That(output, Does.Contain("(defn fizzbuzz [i]")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptDelegateTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptDelegateTests.cs new file mode 100644 index 00000000000..4045e0dd89d --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptDelegateTests.cs @@ -0,0 +1,271 @@ +using System; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ClassTypeName + { + private readonly string fullTypeName; + public ClassTypeName(object instance) + { + fullTypeName = ProtectedScripts.Instance.typeQualifiedName(instance.GetType()); + } + + public override string ToString() => fullTypeName; + } + + + public class ScriptDelegateTests + { + static string Hi() => "static fn"; + + [Test] + public void Can_call_delegates_as_function() + { + var context = new ScriptContext().Init(); + + var result = context.EvaluateScript("{{ fn() }}", new ObjectDictionary { + ["fn"] = (Func<string>) Hi + }); + + Assert.That(result, Is.EqualTo("static fn")); + + Func<string> hi = () => "instance fn"; + + result = context.EvaluateScript("{{ fn() }}", new ObjectDictionary { + ["fn"] = hi + }); + + Assert.That(result, Is.EqualTo("instance fn")); + } + + [Test] + public void Can_call_delegates_with_args_as_function() + { + Func<int, int, int> add = (a, b) => a + b; + + var context = new ScriptContext { + Args = { + ["fn"] = add + } + }.Init(); + + var result = context.EvaluateScript("{{ fn(1,2) }}"); + + Assert.That(result, Is.EqualTo("3")); + + result = context.EvaluateScript("{{ 1.fn(2) }}"); + + Assert.That(result, Is.EqualTo("3")); + } + + [Test] + public void Can_call_delegates_with_args_as_ext_methods() + { + var context = new ScriptContext().Init(); + + Func<int, int, int> add = (a, b) => a + b; + + var result = context.EvaluateScript("{{ 1.fn(2) }}", new ObjectDictionary { + ["fn"] = add + }); + + Assert.That(result, Is.EqualTo("3")); + } + + [Test] + public void Can_use_function_block_to_create_delegate_and_invoke_it() + { + var context = new ScriptContext().Init(); + + var result = context.EvaluateScript("{{#function hi}}'hello' |> return{{/function}}{{ hi() }}"); + + Assert.That(result, Is.EqualTo("hello")); + } + + [Test] + public void Can_use_function_block_to_create_delegate_with_multiple_args_and_invoke_it() + { + var context = new ScriptContext().Init(); + + var result = context.Evaluate(@" + {{#function calc(a,b) }} + a * b |> to => c + a + b + c |> return + {{/function}} + {{ calc(1,2) |> return }}"); + + Assert.That(result, Is.EqualTo(5)); + + result = context.Evaluate(@" + {{#function calc(a,b) }} + a * b |> to => c + a + b + c |> return + {{/function}} + {{ 1.calc(2) |> return }}"); + + Assert.That(result, Is.EqualTo(5)); + } + + [Test] + public void Can_use_function_block_to_create_delegate_with_multiple_args_and_invoke_it_LISP() + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language }, + }.Init(); + + var result = context.Evaluate(@" + {{#defn calc [a, b] }} + (let ( (c (* a b)) ) + (+ a b c) + ) + {{/defn}} + {{ calc(3,4) }} + {{ calc(1,2) |> return }}"); + + Assert.That(result, Is.EqualTo(5)); + + result = context.Evaluate(@" + {{#defn calc [a, b] }} + (let ( (c (* a b)) ) + (+ a b c) + ) + {{/defn}} + {{ calc(3,4) }} + {{ calc(1,2) |> return }}"); + + Assert.That(result, Is.EqualTo(5)); + + result = context.Evaluate(@" + {{#defn fib [n] }} + (if (<= n 1) + n + (+ (fib (- n 1)) + (fib (- n 2)) )) + {{/defn}} + {{ 10.fib() |> return }}"); + + Assert.That(result, Is.EqualTo(55)); + } + + [Test] + public void Does_not_Exceed_MaxStackDepth() + { + var context = new ScriptContext().Init(); + + string template(int depth) => @" + {{#function fib(num) }} + #if num <= 1 + return(num) + /if + return (fib(num-1) + fib(num-2)) + {{/function}} + {{ fib(" + depth + ") |> return }}"; + + var result = context.Evaluate<int>(template(10)); + + Assert.That(result, Is.EqualTo(55)); + + Assert.That(context.MaxStackDepth, Is.EqualTo(25)); + + result = context.Evaluate<int>(template(context.MaxStackDepth - 1)); + + Assert.That(result, Is.EqualTo(46368)); + + try + { + result = context.Evaluate<int>(template(context.MaxStackDepth + 1)); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + e.GetType().Name.Print(); + e.Message.Print(); + if (!(e.InnerException is StackOverflowException)) + throw; + } + } + + static string staticTypeName(object o) => ProtectedScripts.Instance.typeQualifiedName(o.GetType()); + + [Test] + public void Can_call_Delegates_in_filter_expression() + { + Func<object, string> typeName = o => + ProtectedScripts.Instance.typeQualifiedName(o.GetType()); + + var context = new ScriptContext { + Args = { + ["fn"] = typeName, + ["staticfn"] = (Func<object, string>) staticTypeName, + }, + ScriptMethods = { new ProtectedScripts() }, + AllowScriptingOfAllTypes = true + }.Init(); + + + string result = null; + result = context.Evaluate<string>(@" + {{#function info(o) }} + o |> getType |> typeQualifiedName |> return + {{/function}} + {{ 'System.Text.StringBuilder'.new() |> info |> return }}"); + Assert.That(result, Is.EqualTo("System.Text.StringBuilder")); + + result = context.Evaluate<string>( + "{{ 'System.Text.StringBuilder'.new() |> fn |> return }}"); + Assert.That(result, Is.EqualTo("System.Text.StringBuilder")); + + result = context.Evaluate<string>( + "{{ 'System.Text.StringBuilder'.new() |> staticfn |> return }}"); + Assert.That(result, Is.EqualTo("System.Text.StringBuilder")); + + result = context.Evaluate<string>( + @" + {{ Constructor('ServiceStack.WebHost.Endpoints.Tests.ScriptTests.ClassTypeName(string)') |> to => ctorfn }} + {{ 'System.Text.StringBuilder'.new() |> ctorfn |> toString |> return }}"); + Assert.That(result, Is.EqualTo("System.Text.StringBuilder")); + } + + public class CustomMethods : ScriptMethods + { + public static int Counter = 0; + public string chooseColor(ScriptScopeContext scope) => chooseColor(scope, "#ffffff"); + public string chooseColor(ScriptScopeContext scope, string defaultColor) + { + Counter++; + return defaultColor; + } + } + + [Test] + public async Task Only_call_EvaluateCode_method_once() + { + CustomMethods.Counter = 0; + var context = new ScriptContext { + ScriptMethods = { new CustomMethods() }, + }.Init(); + + var fn = ScriptCodeUtils.EnsureReturn("chooseColor(`#336699`)"); + var ret = await context.EvaluateCodeAsync(fn); + Assert.That(ret, Is.EqualTo("#336699")); + Assert.That(CustomMethods.Counter, Is.EqualTo(1)); + + CustomMethods.Counter = 0; + fn = ScriptCodeUtils.EnsureReturn("chooseColor"); + ret = await context.EvaluateCodeAsync(fn); + Assert.That(ret, Is.EqualTo("#ffffff")); + Assert.That(CustomMethods.Counter, Is.EqualTo(1)); + + CustomMethods.Counter = 0; + fn = ScriptCodeUtils.EnsureReturn("chooseColor()"); + ret = await context.EvaluateCodeAsync(fn); + Assert.That(ret, Is.EqualTo("#ffffff")); + Assert.That(CustomMethods.Counter, Is.EqualTo(1)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptHtmlFilterTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptHtmlFilterTests.cs new file mode 100644 index 00000000000..29ae3f6c2f6 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptHtmlFilterTests.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptHtmlFilterTests + { + [Test] + public void Can_call_htmlList_with_empty_arg() + { + var context = new ScriptContext + { + Args = + { + ["arg"] = new List<Dictionary<string,object>> + { + new Dictionary<string, object>{ { "a", 1 } } + }, + ["emptyArg"] = new List<Dictionary<string,object>>() + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ arg |> htmlList }}"), + Is.EqualTo("<table class=\"table\"><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>")); + + Assert.That(context.EvaluateScript("{{ arg |> htmlList() }}"), + Is.EqualTo("<table class=\"table\"><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>")); + + Assert.That(context.EvaluateScript("{{ arg |> htmlList({}) }}"), + Is.EqualTo("<table class=\"table\"><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>")); + + Assert.That(context.EvaluateScript("{{ arg |> htmlList({ }) }}"), + Is.EqualTo("<table class=\"table\"><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>")); + + Assert.That(context.EvaluateScript("{{ emptyArg |> htmlList }}"), Is.EqualTo("")); + + Assert.That(context.EvaluateScript("{{ emptyArg |> htmlList({ captionIfEmpty: 'no rows' }) }}"), + Is.EqualTo("<table class=\"table\"><caption>no rows</caption></table>")); + } + + [Test] + public void Can_render_simple_table() + { + var context = new ScriptContext + { + Args = + { + ["rockstars"] = new List<Dictionary<string,object>> + { + new Dictionary<string, object>{ {"FirstName", "Kurt" }, { "Age", 27 } }, + new Dictionary<string, object>{ {"FirstName", "Jimi" }, { "Age", 27 } }, + } + } + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ rockstars |> htmlDump({ className: ""table table-striped"", caption: ""Rockstars"" }) }}"), + Is.EqualTo(@"<table class=""table table-striped""><caption>Rockstars</caption><thead><tr><th>First Name</th><th>Age</th></tr></thead><tbody><tr><td>Kurt</td><td>27</td></tr><tr><td>Jimi</td><td>27</td></tr></tbody></table>")); + + Assert.That(context.EvaluateScript(@"{{ [] |> htmlDump({ captionIfEmpty: ""No Rocksars""}) }}"), + Is.EqualTo("<table class=\"table\"><caption>No Rocksars</caption></table>")); + } + + [Test] + public void Can_render_complex_object_graph_with_htmldump() + { + var context = new ScriptContext + { + Args = + { + ["customers"] = QueryData.Customers, + ["htmlOptions"] = new Dictionary<string, object> + { + { "className", "table" }, + { "childClass", "table-striped" }, + { "childDepth", 3 }, + } + } + }.Init(); + + "<div id=htmldump>".Print(); + + "<h3>3x Customers:</h3>".Print(); + context.EvaluateScript("{{ customers |> take(3) |> htmlDump(htmlOptions) }}").Print(); + + "<h3>Customer:</h3>".Print(); + context.EvaluateScript("{{ customers |> first |> htmlDump(htmlOptions) }}").Print(); + + "<h3>Orders:</h3>".Print(); + context.EvaluateScript("{{ customers |> first |> property('Orders') |> htmlDump(htmlOptions) }}").Print(); + + "<h3>Order:</h3>".Print(); + context.EvaluateScript("{{ customers |> first |> property('Orders') |> get(0) |> htmlDump(htmlOptions) }}").Print(); + + "<h3>Order Date:</h3>".Print(); + context.EvaluateScript("{{ customers |> first |> property('Orders') |> get(0) |> property('OrderDate') |> htmlDump(htmlOptions) }}").Print(); + + "</div>".Print(); + } + + [Test] + public void Can_execute_custom_html_tags_with_primary_content_usage() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'http://example.org' |> htmlLink }}"), Is.EqualTo("<a href=\"http://example.org\">http://example.org</a>")); + Assert.That(context.EvaluateScript("{{ 'http://example.org' |> htmlLink({ text:'link' }) }}"), Is.EqualTo("<a href=\"http://example.org\">link</a>")); + Assert.That(context.EvaluateScript("{{ 'logo.png' |> htmlImage }}"), Is.EqualTo("<img src=\"logo.png\">")); + Assert.That(context.EvaluateScript("{{ 'logo.png' |> htmlImage({ alt:'alt text' }) }}"), Is.EqualTo("<img alt=\"alt text\" src=\"logo.png\">")); + } + + [Test] + public void Can_execute_htmlTag_filters() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ '<h1>title</h1>' |> htmlA({ href:'#' }) }}"), Is.EqualTo("<a href=\"#\"><h1>title</h1></a>")); + Assert.That(context.EvaluateScript("{{ { src:'logo.png', alt:'alt text' } |> htmlImg }}"), Is.EqualTo("<img alt=\"alt text\" src=\"logo.png\">")); + } + + [Test] + public void htmlTag_filters_does_convert_reserved_js_keywords() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ '<h1>title</h1>' |> htmlA({ href:'#', className:'cls' }) }}"), Is.EqualTo("<a class=\"cls\" href=\"#\"><h1>title</h1></a>")); + Assert.That(context.EvaluateScript("{{ { src:'logo.png', alt:'alt text', className:'cls' } |> htmlImg }}"), Is.EqualTo("<img alt=\"alt text\" class=\"cls\" src=\"logo.png\">")); + Assert.That(context.EvaluateScript("{{ 'text' |> htmlLabel({ htmlFor:'id' }) }}"), Is.EqualTo("<label for=\"id\">text</label>")); + } + + [Test] + public void Can_send_text_content_to_html_tags_primarily_used_with_text() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ 'text' |> htmlEm }}"), Is.EqualTo("<em>text</em>")); + Assert.That(context.EvaluateScript("{{ 'text' |> htmlB }}"), Is.EqualTo("<b>text</b>")); + Assert.That(context.EvaluateScript("{{ 'text' |> htmlB({ class:'cls' }) }}"), Is.EqualTo("<b class=\"cls\">text</b>")); + Assert.That(context.EvaluateScript("{{ 'text' |> htmlOption }}"), Is.EqualTo("<option>text</option>")); + Assert.That(context.EvaluateScript("{{ 'text' |> htmlOption({ value:'val' }) }}"), Is.EqualTo("<option value=\"val\">text</option>")); + + Assert.That(context.EvaluateScript("{{ ['A','B','C'] |> map('htmlOption(it)') |> join('') |> htmlSelect({ name:'sel' }) }}"), + Is.EqualTo("<select name=\"sel\"><option>A</option><option>B</option><option>C</option></select>")); + } + + [Test] + public void Can_generate_html_with_bindings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ ['A','B','C'] |> map('htmlOption(it, { value: it })') |> join('') |> htmlSelect({ name:'sel' }) }}"), + Is.EqualTo("<select name=\"sel\"><option value=\"A\">A</option><option value=\"B\">B</option><option value=\"C\">C</option></select>")); + + Assert.That(context.EvaluateScript("{{ ['A','B','C'] |> map('htmlOption(it, { value: it })') |> join('') |> htmlSelect({ name:'sel' }) }}"), + Is.EqualTo("<select name=\"sel\"><option value=\"A\">A</option><option value=\"B\">B</option><option value=\"C\">C</option></select>")); + } + + [Test] + public void Does_generate_class_list_with_htmlClass() + { + var context = new ScriptContext { + Args = { + ["index"] = 1, + ["name"] = "foo", + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ {alt:isOdd(index), active:'foo'==name } |> htmlClass }}"), + Is.EqualTo(" class=\"alt active\"")); + Assert.That(context.EvaluateScript("{{ {alt:isEven(index), active:'bar'==name } |> htmlClass }}"), + Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ [isOdd(index) ? 'odd': 'even', 'foo'==name ? 'active' : ''] |> htmlClass }}"), + Is.EqualTo(" class=\"odd active\"")); + Assert.That(context.EvaluateScript("{{ [isOdd(index+1) ? 'odd': 'even', 'bar'==name ? 'active' : ''] |> htmlClass }}"), + Is.EqualTo(" class=\"even\"")); + + Assert.That(context.EvaluateScript("{{ 'hide' |> if(!disclaimerAccepted) |> htmlClass }}"), + Is.EqualTo(" class=\"hide\"")); + } + + [Test] + public void HtmlAttrs_with_bool_only_emits_name() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("<option {{ {selected:true,test:'val'} |> htmlAttrs }}>"), + Is.EqualTo("<option selected test=\"val\">")); + + Assert.That(context.EvaluateScript("<option {{ {selected:false,test:'val'} |> htmlAttrs }}>"), + Is.EqualTo("<option test=\"val\">")); + } + + [Test] + public void Does_htmlDump_singleRow() + { + var context = new ScriptContext { + Args = { + ["rows"] = new List<Dictionary<string, object>> { + new Dictionary<string, object> { + ["Id"] = 1, + ["Name"] = "foo", + ["None"] = DBNull.Value, + } + } + } + }.Init(); + + var output = context.EvaluateScript("{{ rows |> htmlDump }}"); +// output.Print(); + Assert.That(output, Does.Contain( + "<tr><th>Id</th><td>1</td></tr><tr><th>Name</th><td>foo</td></tr><tr><th>None</th><td></td></tr>")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLangTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLangTests.cs new file mode 100644 index 00000000000..c74d86b3ea1 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLangTests.cs @@ -0,0 +1,42 @@ +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptLangTests + { + [Test] + public void Ignores_lang_blocks_that_are_not_languages() + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language } + }.Init(); + + string render(string s) => context.RenderScript(s).NormalizeNewLines(); + + Assert.That(render(@" +```code +`test` +``` +{|lisp (+ 1 2) |} +"), Is.EqualTo(@" +test +3 +".NormalizeNewLines())); + + Assert.That(render(@" +```<lang> +test +``` +{|<lang> |} +"), Is.EqualTo(@" +```<lang> +test +``` +{|<lang> |} +".NormalizeNewLines())); + + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispApiTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispApiTests.cs new file mode 100644 index 00000000000..402f9d1a959 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispApiTests.cs @@ -0,0 +1,570 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.IO; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptLispApiTests + { + private static ScriptContext CreateContext() + { + var context = new ScriptContext { + ScriptLanguages = {ScriptLisp.Language}, + Args = { + ["nums3"] = new[] {0, 1, 2}, + ["nums10"] = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,}, + } + }; + return context.Init(); + } + + [SetUp] + public void Setup() => context = CreateContext(); + + private ScriptContext context; + + string render(string lisp) => context.RenderLisp(lisp).NormalizeNewLines(); + void print(string lisp) => render(lisp).Print(); + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + [Test] + public void LISP_fn_shorthand() + { + Assert.That(eval(@"(#(1+ %) 2)"), Is.EqualTo(3)); + Assert.That(eval(@"(#(+ %1 %2) 2 3)"), Is.EqualTo(5)); + } + + [Test] + public void LISP_even() + { + Assert.That(eval(@"(even? 2)"), Is.True); + Assert.That(eval(@"(even? 1)"), Is.Null); + } + + [Test] + public void LISP_odd() + { + Assert.That(eval(@"(odd? 2)"), Is.Null); + Assert.That(eval(@"(odd? 1)"), Is.True); + } + + [Test] + public void LISP_empty() + { + Assert.That(eval(@"(empty? nil)"), Is.True); + Assert.That(eval(@"(empty? ())"), Is.True); + Assert.That(eval(@"(empty? [])"), Is.True); + Assert.That(eval(@"(empty? (to-list []))"), Is.True); + + Assert.That(eval(@"(empty? '(1))"), Is.False); + Assert.That(eval(@"(empty? [1])"), Is.False); + Assert.That(eval(@"(empty? (to-list [1]))"), Is.False); + } + + [Test] + public void LISP_mapcan() + { + Assert.That(eval(@"(mapcan (lambda (x) (and (number? x) (list x))) '(a 1 b c 3 4 d 5))"), + Is.EqualTo(new[] {1, 3, 4, 5})); + } + + [Test] + public void LISP_range() + { + Assert.That(eval(@"(range 5)"), Is.EqualTo(new[] {0, 1, 2, 3, 4})); + Assert.That(eval(@"(range 10 15)"), Is.EqualTo(new[] {10, 11, 12, 13, 14})); + } + + [Test] //filter only works with cons cells + public void LISP_filter() + { + Assert.That(eval(@"(filter #(<= % 3) [5 4 1 3 9 8 6 7 2 0])"), Is.EqualTo(new[] { 1, 3, 2, 0 })); + Assert.That(eval(@"(filter #(<= % 3) [-5 -4 -1 -3 -9 -8 -6 -7 -2 -0])"), Is.EqualTo(new[] { -5, -4, -1, -3, -9, -8, -6, -7, -2, 0 })); + Assert.That(eval(@"(filter #(<= % 3) (to-cons (map #(- %) [5 4 1 3 9 8 6 7 2 0])))"), Is.EqualTo(new[] { -5, -4, -1, -3, -9, -8, -6, -7, -2, 0 })); + Assert.That(eval(@"(filter even? (range 10))"), Is.EqualTo(new[] {0, 2, 4, 6, 8})); + } + + [Test] + public void LISP_filter_index() + { + Assert.That(eval(@" +(setq digits [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) +(filter-index (fn [x i] (> i (length x))) digits)"), + Is.EqualTo(new[] { "five", "six", "seven", "eight", "nine", })); + } + + [Test] //filter works with both IEnumerable + Cells + public void LISP_where() + { + Assert.That(eval(@"(where #(<= % 3) [5 4 1 3 9 8 6 7 2 0])"), Is.EqualTo(new[] { 1, 3, 2, 0 })); + Assert.That(eval(@"(where #(<= % 3) [-5 -4 -1 -3 -9 -8 -6 -7 -2 -0])"), Is.EqualTo(new[] { -5, -4, -1, -3, -9, -8, -6, -7, -2, 0 })); + Assert.That(eval(@"(where #(<= % 3) (to-cons (map #(- %) [5 4 1 3 9 8 6 7 2 0])))"), Is.EqualTo(new[] { -5, -4, -1, -3, -9, -8, -6, -7, -2, 0 })); + Assert.That(eval(@"(where even? (range 10))"), Is.EqualTo(new[] {0, 2, 4, 6, 8})); + } + + [Test] + public void LISP_where_index() + { + Assert.That(eval(@" +(setq digits [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) +(where-index (fn [x i] (> i (length x))) digits)"), + Is.EqualTo(new[] { "five", "six", "seven", "eight", "nine", })); + } + + [Test] + public void LISP_add() + { + Assert.That(eval(@"(+ 1)"), Is.EqualTo(1)); + Assert.That(eval(@"(+ 1 2 3 4)"), Is.EqualTo(10)); + } + + [Test] + public void LISP_multiply() + { + Assert.That(eval(@"(* 1)"), Is.EqualTo(1)); + Assert.That(eval(@"(* 1 2 3 4)"), Is.EqualTo(24)); + } + + [Test] + public void LISP_subtract_minus() + { + Assert.That(eval(@"(- 10 1 2 3 4)"), Is.EqualTo(0)); + Assert.That(eval(@"(- 10)"), Is.EqualTo(-10)); + Assert.That(eval(@"-10"), Is.EqualTo(-10)); + } + + [Test] + public void LISP_divide() + { + Assert.That(eval(@"(/ 6 2)"), Is.EqualTo(3)); + Assert.That(eval(@"(/ 5 2)"), Is.EqualTo(2)); + Assert.That(eval(@"(/ 5.0 2)"), Is.EqualTo(2.5)); + Assert.That(eval(@"(/ 5 2.0)"), Is.EqualTo(2.5)); + Assert.That(eval(@"(/ 5.0 2.0)"), Is.EqualTo(2.5)); + Assert.That(eval(@"(/ 4.0)"), Is.EqualTo(0.25)); + Assert.That(eval(@"(/ 4)"), Is.EqualTo(0)); + Assert.That(eval(@"(/ 25 3 2)"), Is.EqualTo(4)); + Assert.That(eval(@"(/ -17 6)"), Is.EqualTo(-2)); + } + + [Test] + public void LISP_reduce() + { + Assert.That(eval(@"(reduce + [1 2 3])"), Is.EqualTo(6)); + Assert.That(eval(@"(reduce + (to-list [1 2 3]))"), Is.EqualTo(6)); + Assert.That(eval(@"(reduce * [2 3 4])"), Is.EqualTo(24)); + Assert.That(eval(@"(reduce * (to-list [2 3 4]))"), Is.EqualTo(24)); + Assert.That(eval(@"(reduce - [10 1 2 3])"), Is.EqualTo(4)); + Assert.That(eval(@"(reduce - (to-list [10 1 2 3]))"), Is.EqualTo(4)); + Assert.That(eval(@"(reduce / [10 1 2])"), Is.EqualTo(5)); + Assert.That(eval(@"(reduce / (to-list [10 1 2]))"), Is.EqualTo(5)); + } + + [Test] + public void LISP_doseq() + { + Assert.That(render(@"(doseq (x nums3) (println x))"), Is.EqualTo("0\n1\n2")); + } + + [Test] + public void LISP_map_literals() + { + var expected = new Dictionary<string, object> { + {"a", 1}, + {"b", 2}, + {"c", 3}, + }; + Assert.That(eval("(new-map '(a 1) '(b 2) '(c 3) )"), Is.EqualTo(expected)); + Assert.That(eval("{ :a 1 :b 2 :c 3 }"), Is.EqualTo(expected)); + Assert.That(eval("{ :a 1, :b 2, :c 3 }"), Is.EqualTo(expected)); + + Assert.That(eval("{ :a 1 :b { :b1 10 :b2 20 } :c 3 }"), Is.EqualTo(new Dictionary<string, object> { + {"a", 1}, + {"b", new Dictionary<string, object> { + {"b1", 10}, + {"b2", 20}, + }}, + {"c", 3}, + })); + } + + [Test] + public void Lisp_data_list() + { + Assert.That(eval(@"(sum [1 2 3 4])"), Is.EqualTo(10)); + Assert.That(eval(@"(sum [1, 2, 3, 4])"), Is.EqualTo(10)); + } + + [Test] + public void LISP_do() //https://clojuredocs.org/clojure.core/dorun + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language } + }.Init(); + + Assert.That(context.EvaluateLisp(@"(return (do))"), Is.Null); + Assert.That(context.EvaluateLisp(@"(return (do ()))"), Is.Null); + Assert.That(context.EvaluateLisp(@"(return (do (+ 1 1) (+ 2 2) ))"), Is.EqualTo(4)); + Assert.That(context.EvaluateLisp(@"(return (do (+ 1 1) (+ 2 2) nil ))"), Is.Null); + } + + [Test] + public void LISP_can_clojure_fn_data_list_args() + { + Assert.That(render(@"(defn f [] 0)(f)"), Is.EqualTo("0")); + Assert.That(render(@"(defn f [a] a)(f 1)"), Is.EqualTo("1")); + Assert.That(render(@"(defn f [a b] (+ a b))(f 1 2)"), Is.EqualTo("3")); + Assert.That(render(@"(defn f [a b c] (+ a b c))(f 1 2 3)"), Is.EqualTo("6")); + Assert.That(render(@"((fn [a b c] (+ a b c)) 1 2 3)"), Is.EqualTo("6")); + } + + [Test] + public void LISP_can_call_xml_ContextBlockFilter() + { + var obj = eval(@"(/xml { :a 1 } )"); + Assert.That(obj, Does.Contain("<Key>a</Key>")); + } + + [Test] + public void LISP_test_void_variable() + { + Assert.That(eval(@"(if (bound? id) 1 -1)"), Is.EqualTo(-1)); + Assert.That(eval(@"(setq id 2)(if (bound? id) 1 -1)"), Is.EqualTo(1)); + + Assert.That(eval(@"(if (bound? id id2) 1 -1)"), Is.EqualTo(-1)); + Assert.That(eval(@"(setq id 2)(if (bound? id id2) 1 -1)"), Is.EqualTo(-1)); + Assert.That(eval(@"(setq id 2)(setq id2 3)(if (bound? id id2) 1 -1)"), Is.EqualTo(1)); + } + + [Test] + public void LISP_butlast() + { + Assert.That(eval(@"(butlast [1 2 3 4])"), Is.EqualTo(new[]{ 1, 2, 3 })); + Assert.That(eval(@"(butlast (to-list [1 2 3 4]))"), Is.EqualTo(new[]{ 1, 2, 3 })); + } + + [Test] + public void LISP_reverse() + { + Assert.That(eval(@"(reverse [1 2 3 4])"), Is.EqualTo(new[]{ 4, 3, 2, 1 })); + Assert.That(eval(@"(reverse (to-list [1 2 3 4]))"), Is.EqualTo(new[]{ 4, 3, 2, 1 })); + } + + [Test] + public void LISP_first() + { + Assert.That(eval(@"(first [10 20 30])"), Is.EqualTo(10)); + Assert.That(eval(@"(first (to-list [10 20 30]))"), Is.EqualTo(10)); + Assert.That(eval(@"(1st [10 20 30])"), Is.EqualTo(10)); + } + + [Test] + public void LISP_second() + { + Assert.That(eval(@"(second [10 20 30])"), Is.EqualTo(20)); + Assert.That(eval(@"(second (to-list [10 20 30]))"), Is.EqualTo(20)); + Assert.That(eval(@"(second [10])"), Is.Null); + Assert.That(eval(@"(second (to-list [10]))"), Is.Null); + Assert.That(eval(@"(2nd [10 20 30])"), Is.EqualTo(20)); + } + + [Test] + public void LISP_third() + { + Assert.That(eval(@"(third [10 20 30])"), Is.EqualTo(30)); + Assert.That(eval(@"(third (to-list [10 20 30]))"), Is.EqualTo(30)); + Assert.That(eval(@"(third [10])"), Is.Null); + Assert.That(eval(@"(third (to-list [10]))"), Is.Null); + Assert.That(eval(@"(3rd [10 20 30])"), Is.EqualTo(30)); + } + + [Test] + public void LISP_rest() + { + Assert.That(eval(@"(rest [10 20 30])"), Is.EqualTo(new[]{ 20, 30 })); + Assert.That(eval(@"(rest (to-list [10 20 30]))"), Is.EqualTo(new[]{ 20, 30 })); + Assert.That(eval(@"(rest [10])"), Is.Null); + Assert.That(eval(@"(rest (to-list [10]))"), Is.Null); + Assert.That(eval(@"(next [10 20 30])"), Is.EqualTo(new[]{ 20, 30 })); + } + + [Test] + public void LISP_flatten() + { + Assert.That(eval(@"(flatten [1 2 3])"), Is.EqualTo(new[]{ 1, 2, 3 })); + Assert.That(eval(@"(flatten (to-list [1 2 3]))"), Is.EqualTo(new[]{ 1, 2, 3 })); + Assert.That(eval(@"(flatten [1 2 [3 4] 5 [6 [7 [8 9]]]])"), Is.EqualTo(new[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 })); + Assert.That(eval(@"(flatten (to-list [1 2 [3 4] 5 [6 [7 [8 9]]]]))"), Is.EqualTo(new[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 })); + + object reval(string s) => eval(s.Replace("'", "\"")); + Assert.That(reval(@"(flatten ['A' 'B' 'C'])"), Is.EqualTo(new[]{ "A", "B", "C" })); + Assert.That(reval(@"(flatten (to-list ['A' 'B' 'C']))"), Is.EqualTo(new[]{ "A", "B", "C" })); + Assert.That(reval(@"(flatten ['A' 'B' ['C' 'D'] 'E' ['F' ['G' ['H' 'I']]]])"), Is.EqualTo(new[]{ "A", "B", "C", "D", "E", "F", "G", "H", "I" })); + Assert.That(reval(@"(flatten (to-list ['A' 'B' ['C' 'D'] 'E' ['F' ['G' ['H' 'I']]]]))"), Is.EqualTo(new[]{ "A", "B", "C", "D", "E", "F", "G", "H", "I" })); + } + + [Test] + public void LISP_min() + { + Assert.That(eval(@"(min 10 20)"), Is.EqualTo(10)); + Assert.That(eval(@"(min 30 10 20)"), Is.EqualTo(10)); + Assert.That(eval(@"(apply min [5 4 3 9 8 6 7 2])"), Is.EqualTo(2)); + Assert.That(eval(@"(apply min (to-list [5 4 3 9 8 6 7 2]))"), Is.EqualTo(2)); + } + + [Test] + public void LISP_max() + { + Assert.That(eval(@"(max 10 20)"), Is.EqualTo(20)); + Assert.That(eval(@"(max 30 10 20)"), Is.EqualTo(30)); + Assert.That(eval(@"(apply max [5 4 3 9 8 6 7 2])"), Is.EqualTo(9)); + Assert.That(eval(@"(apply max (to-list [5 4 3 9 8 6 7 2]))"), Is.EqualTo(9)); + } + + [Test] + public void LISP_index() + { + Assert.That(eval(@"(:0 ""i"")"), Is.EqualTo('i')); + Assert.That(eval(@"(nth ""i"" 0)"), Is.EqualTo('i')); + } + + [Test] + public void Can_access_page_vars() + { + Assert.That(context.EvaluateLisp(@"<!-- +id 1 +--> + +(return (let () + (if (bound? id) 1 -1) + +))"), Is.EqualTo(1)); + + } + + [Test] + public void Can_access_page_vars_with_line_comment_prefix() + { + Assert.That(context.EvaluateLisp(@";<!-- +; id 1 +;--> + +(return (let () + (if (bound? id) 1 -1) + +))"), Is.EqualTo(1)); + + } + + [Test] + public void LISP_string_format() + { + Assert.That(render(@"(/fmt ""{0} + {1} = {2}"" 1 2 (+ 1 2))"), + Is.EqualTo("1 + 2 = 3")); + } + + [Test] + public void LISP_Instanceof_tests() + { + var context = LoadLispContext(c => c.AllowScriptingOfAllTypes = true); + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + Assert.That(eval("(instance? 'IEnumerable [1])"), Is.True); + Assert.That(eval("(instance? \"IEnumerable\" [1])"), Is.True); + Assert.That(eval("(instance? 'System.Collections.IEnumerable [1])"), Is.True); + Assert.That(eval("(instance? 'IEnumerable 1)"), Is.Null); + } + + [Test] + public void Can_access_db() + { + var context = new ScriptContext { + ScriptLanguages = { ScriptLisp.Language }, + ScriptMethods = { + new DbScriptsAsync() + } + }; + context.Container.AddSingleton<IDbConnectionFactory>(() => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + context.Init(); + + using (var db = context.Container.Resolve<IDbConnectionFactory>().Open()) + { + db.CreateTable<Person>(); + + db.InsertAll(new [] { + new Person("A", 1), + new Person("B", 2), + }); + } + + var result = context.EvaluateLisp( + @"(return (map (fn [p] (:Name p)) (/dbSelect ""select Name, Age from Person"")))"); + Assert.That(result, Is.EqualTo(new[] { "A", "B" })); + } + + private static ScriptContext LoadLispContext(Action<ScriptContext> fn=null) + { + var context = new ScriptContext { + ScriptLanguages = {ScriptLisp.Language}, + ScriptMethods = {new ProtectedScripts()}, + ScriptNamespaces = { // same as SharpPagesFeature + "System", + "System.Collections", + "System.Collections.Generic", + "ServiceStack", + } + }; + fn?.Invoke(context); + return context.Init();; + } + + [Test] + public void Can_load_scripts() + { + var context = LoadLispContext(); + + context.VirtualFiles.WriteFile("lib1.l", "(defn lib-calc [a b] (+ a b))"); + context.VirtualFiles.WriteFile("/dir/lib2.l", "(defn lib-calc [a b] (* a b))"); + + object result; + + result = context.EvaluateLisp(@"(load 'lib1)(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(9)); + + result = context.EvaluateLisp(@"(load ""lib1.l"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(9)); + + result = context.EvaluateLisp(@"(load ""/dir/lib2.l"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(20)); + result = context.EvaluateLisp(@"(load 'lib1)(load ""/dir/lib2.l"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(20)); + + // https://gist.github.com/gistlyn/2f14d629ba1852ee55865607f1fa2c3e + } + +// [Test] // skip integration test + public void Can_load_scripts_from_gist_and_url() + { +// Lisp.AllowLoadingRemoteScripts = false; // uncomment to prevent loading remote scripts + + var context = LoadLispContext(); + + LoadLispTests(context); + LoadLispTests(context); // load twice to check it's using cached downloaded assets + } + +// [Test] + public void Can_load_parse_rss_and_evaluate_rss_feed() + { + var context = LoadLispContext(c => { + //c.AllowScriptingOfAllTypes = true; + c.ScriptTypes.Add(typeof(List<>)); + c.ScriptTypes.Add(typeof(ObjectDictionary)); + c.ScriptTypes.Add(typeof(XDocument)); + c.ScriptTypes.Add(typeof(XLinqExtensions)); + }); + + var result = context.EvaluateLisp(@"(load ""index:parse-rss"")(return (parse-rss (/urlContents ""https://news.ycombinator.com/rss"")))"); + result.PrintDump(); + } + + private static void LoadLispTests(ScriptContext context) + { + object result; + + result = context.EvaluateLisp(@"(load ""gist:2f14d629ba1852ee55865607f1fa2c3e/lib1.l"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(9)); + + // imports all gist files and overwrites symbols where last symbol wins + result = context.EvaluateLisp(@"(load ""gist:2f14d629ba1852ee55865607f1fa2c3e"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(20)); + + result = context.EvaluateLisp( + @"(load ""https://gist.githubusercontent.com/gistlyn/2f14d629ba1852ee55865607f1fa2c3e/raw/95cbc5d071d9db3a96866c1a583056dd87ab5f69/lib1.l"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(9)); + + // import single file from index.md + result = context.EvaluateLisp(@"(load ""index:lib-calc/lib1.l"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(9)); + + // imports all gist files and overwrites symbols where last symbol wins + result = context.EvaluateLisp(@"(load ""index:lib-calc"")(return (lib-calc 4 5))"); + Assert.That(result, Is.EqualTo(20)); + } + +// [Test] + public void Can_load_src() + { + object result; + + var context = LoadLispContext(); + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + result = eval(@"(load-src ""gist:2f14d629ba1852ee55865607f1fa2c3e/lib1.l"")"); + result.ToString().Print(); + + // imports all gist files and overwrites symbols where last symbol wins + result = eval(@"(load-src ""gist:2f14d629ba1852ee55865607f1fa2c3e"")"); + result.ToString().Print(); + + result = eval(@"(load-src ""https://gist.githubusercontent.com/gistlyn/2f14d629ba1852ee55865607f1fa2c3e/raw/95cbc5d071d9db3a96866c1a583056dd87ab5f69/lib1.l"")"); + result.ToString().Print(); + + // import single file from index.md + result = eval(@"(load-src ""index:lib-calc/lib1.l"")"); + result.ToString().Print(); + + // imports all gist files and overwrites symbols where last symbol wins + result = eval(@"(load-src ""index:lib-calc"")"); + result.ToString().Print(); + + result = eval(@"(load-src ""index:parse-rss"")"); + result.ToString().Print(); + } + } + +/* If LISP integration tests are needed in future + public class ScriptListAppHostTests + { + private ServiceStackHost appHost; + + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ScriptListAppHostTests), typeof(ScriptListAppHostTests).Assembly) { } + public override void Configure(Container container) + { + Plugins.Add(new SharpPagesFeature { + ScriptLanguages = { ScriptLisp.Language }, + }); + } + } + + public ScriptListAppHostTests() + { + appHost = new AppHost().Init(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + string render(string lisp) => appHost.GetPlugin<SharpPagesFeature>().RenderLisp(lisp).NormalizeNewLines(); + object eval(string lisp) => appHost.GetPlugin<SharpPagesFeature>().EvaluateLisp($"(return {lisp})"); + +// [Test] + public void Can_call_urlContents() + { + var output = render(@"(/urlContents ""https://api.github.com/repos/ServiceStack/ServiceStack"" { :userAgent ""#Script"" } )"); + output.Print(); + } + } +*/ +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispLinqTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispLinqTests.cs new file mode 100644 index 00000000000..a17acb3ccaf --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispLinqTests.cs @@ -0,0 +1,2701 @@ +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptLispLinqTests + { + private static ScriptContext CreateContext() + { + var context = new ScriptContext + { + ScriptLanguages = { ScriptLisp.Language }, + AllowScriptingOfAllTypes = true, + ScriptNamespaces = { + "System", + typeof(CaseInsensitiveComparer).Namespace, //System.Collections + typeof(AnagramEqualityComparer).Namespace, + }, + ScriptMethods = { + new ProtectedScripts(), + }, + Args = + { + [ScriptConstants.DefaultDateFormat] = "yyyy/MM/dd", + ["products"] = QueryData.Products, + ["customers"] = QueryData.Customers, + ["comparer"] = new CaseInsensitiveComparer(), + ["anagramComparer"] = new AnagramEqualityComparer(), + } + }; + Lisp.Set("products-list", Lisp.ToCons(QueryData.Products)); + Lisp.Set("customers-list", Lisp.ToCons(QueryData.Customers)); + return context.Init(); + } + + [SetUp] + public void Setup() => context = CreateContext(); + private ScriptContext context; + + string render(string lisp) => context.RenderLisp(lisp).NormalizeNewLines(); + + void print(string lisp) + { + "expr: ".Print(); + Lisp.Parse(lisp).Each(x => Lisp.Str(x).Print()); + "result: ".Print(); + eval(lisp).PrintDump(); + } + + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp} ))"); + + [Test] + public void Linq01() + { + Assert.That(render(@" +(defn linq01 [] + (setq numbers [5 4 1 3 9 8 6 7 2 0]) + (let ((low-numbers (where #(< % 5) numbers))) + (println ""Numbers < 5:"") + (doseq (n low-numbers) + (println n)))) +(linq01)"), + + Is.EqualTo(@" +Numbers < 5: +4 +1 +3 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq02() + { + Assert.That(render(@" +(defn linq02 [] + (let ( (sold-out-products + (where #(= 0 (.UnitsInStock %)) products-list)) ) + (println ""Sold out products:"") + (doseq (p sold-out-products) + (println (.ProductName p) "" is sold out"") ) + )) +(linq02)"), + + Is.EqualTo(@" +Sold out products: +Chef Anton's Gumbo Mix is sold out +Alice Mutton is sold out +Thüringer Rostbratwurst is sold out +Gorgonzola Telino is sold out +Perth Pasties is sold out +".NormalizeNewLines())); + } + + [Test] + public void Linq03() + { + Assert.That(render(@" +(defn linq03 [] + (let ( (expensive-in-stock-products + (where #(and + (> (.UnitsInStock %) 0) + (> (.UnitPrice %) 3)) + products-list) + )) + (println ""In-stock products that cost more than 3.00:"") + (doseq (p expensive-in-stock-products) + (println (.ProductName p) "" is in stock and costs more than 3.00"")))) + +(linq03)"), + + Does.StartWith(@" +In-stock products that cost more than 3.00: +Chai is in stock and costs more than 3.00 +Chang is in stock and costs more than 3.00 +Aniseed Syrup is in stock and costs more than 3.00 +Chef Anton's Cajun Seasoning is in stock and costs more than 3.00 +Grandma's Boysenberry Spread is in stock and costs more than 3.00 +".NormalizeNewLines())); + } + + [Test] + public void Linq04() + { + Assert.That(render(@" +(defn linq04 [] + (let ( (wa-customers (where #(= (.Region %) ""WA"") customers-list)) ) + (println ""Customers from Washington and their orders:"") + (doseq (c wa-customers) + (println ""Customer "" (.CustomerId c) "": "" (.CompanyName c) "": "") + (doseq (o (.Orders c)) + (println "" Order "" (.OrderId o) "": "" (.OrderDate o)) ) + ))) +(linq04)"), + + Does.StartWith(@" +Customers from Washington and their orders: +Customer LAZYK: Lazy K Kountry Store: + Order 10482: 3/21/1997 12:00:00 AM + Order 10545: 5/22/1997 12:00:00 AM +Customer TRAIH: Trail's Head Gourmet Provisioners: + Order 10574: 6/19/1997 12:00:00 AM + Order 10577: 6/23/1997 12:00:00 AM + Order 10822: 1/8/1998 12:00:00 AM +".NormalizeNewLines())); + } + + [Test] + public void Linq05() + { + Assert.That(render(@" +(defn linq05 [] + (let ( (digits [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) + (short-digits) ) + (setq short-digits (where-index (fn [x i] (> i (length x))) digits) ) + (println ""Short digits:"") + (doseq (d short-digits) + (println ""The word "" d "" is shorter than its value"")) + )) +(linq05)"), + + Does.StartWith(@" +Short digits: +The word five is shorter than its value +The word six is shorter than its value +The word seven is shorter than its value +The word eight is shorter than its value +The word nine is shorter than its value +".NormalizeNewLines())); + } + + [Test] + public void Linq06() + { + Assert.That(render(@" +(defn linq06 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) (nums-plus-one) ) + (setq nums-plus-one (map inc numbers)) + (println ""Numbers + 1:"") + (doseq (n nums-plus-one) (println n)))) +(linq06)"), + + Does.StartWith(@" +Numbers + 1: +6 +5 +2 +4 +10 +9 +7 +8 +3 +1 +".NormalizeNewLines())); + } + + [Test] + public void Linq07() + { + Assert.That(render(@" +(defn linq07 [] + (let ( (product-names (map .ProductName products-list)) ) + (println ""Product Names:"") + (doseq (x product-names) (println x)))) +(linq07)"), + + Does.StartWith(@" +Product Names: +Chai +Chang +Aniseed Syrup +Chef Anton's Cajun Seasoning +Chef Anton's Gumbo Mix +".NormalizeNewLines())); + } + + [Test] + public void Linq08() + { + Assert.That(render(@" +(defn linq08 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (strings [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) + (text-nums) ) + (setq text-nums (map #(nth strings %) numbers)) + (println ""Number strings:"") + (doseq (n text-nums) (println n)) + )) +(linq08)"), + + Does.StartWith(@" +Number strings: +five +four +one +three +nine +eight +six +seven +two +zero +".NormalizeNewLines())); + } + + [Test] + public void Linq09() + { + Assert.That(render(@" +(defn linq09 [] + (let ( (words [""aPPLE"" ""BlUeBeRrY"" ""cHeRry""]) + (upper-lower-words) ) + (setq upper-lower-words + (map (fn [w] { :lower (lower-case w) :upper (upper-case w) } ) words) ) + (doseq (ul upper-lower-words) + (println ""Uppercase: "" (:upper ul) "", Lowercase: "" (:lower ul))) + )) +(linq09)"), + + Does.StartWith(@" +Uppercase: APPLE, Lowercase: apple +Uppercase: BLUEBERRY, Lowercase: blueberry +Uppercase: CHERRY, Lowercase: cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq10() + { + Assert.That(render(@" +(defn linq10 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (strings [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) + (digit-odd-evens) ) + (setq digit-odd-evens + (map (fn [n] { :digit (nth strings n) :even (even? n) } ) numbers)) + (doseq (d digit-odd-evens) + (println ""The digit "" (:digit d) "" is "" (if (:even d) ""even"" ""odd""))) + )) +(linq10)"), + + Does.StartWith(@" +The digit five is odd +The digit four is even +The digit one is odd +The digit three is odd +The digit nine is odd +The digit eight is even +The digit six is even +The digit seven is odd +The digit two is even +The digit zero is even +".NormalizeNewLines())); + } + + [Test] + public void Linq09_classic_lisp() + { + Assert.That(render(@" +(defn linq09 [] + (let ( (words [""aPPLE"" ""BlUeBeRrY"" ""cHeRry""]) + (upper-lower-words) ) + (setq upper-lower-words + (map (fn [w] `( (lower ,(lower-case w)) (upper ,(upper-case w)) )) words) ) + (doseq (ul upper-lower-words) + (println ""Uppercase: "" (assoc-value 'upper ul) "", Lowercase: "" (assoc-value 'lower ul))) + )) +(linq09)"), + + Does.StartWith(@" +Uppercase: APPLE, Lowercase: apple +Uppercase: BLUEBERRY, Lowercase: blueberry +Uppercase: CHERRY, Lowercase: cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq11() + { + Assert.That(render(@" +(defn linq11 [] + (let ( (product-infos + (map (fn [x] { + :ProductName (.ProductName x) + :Category (.Category x) + :Price (.UnitPrice x) + }) + products-list)) ) + (println ""Product Info:"") + (doseq (p product-infos) + (println (:ProductName p) "" is in the category "" (:Category p) "" and costs "" (:Price p)) ) + )) +(linq11)"), + + Does.StartWith(@" +Product Info: +Chai is in the category Beverages and costs 18 +Chang is in the category Beverages and costs 19 +Aniseed Syrup is in the category Condiments and costs 10 +Chef Anton's Cajun Seasoning is in the category Condiments and costs 22 +Chef Anton's Gumbo Mix is in the category Condiments and costs 21.35 +".NormalizeNewLines())); + } + + [Test] + public void Linq11_expanded_form() + { + Assert.That(render(@" +(defn linq11 [] + (let ( (product-infos + (map (fn [x] (new-map + (list ""ProductName"" (.ProductName x)) + (list ""Category"" (.Category x)) + (list ""Price"" (.UnitPrice x)) + )) + products-list)) ) + (println ""Product Info:"") + (doseq (p product-infos) + (println (:ProductName p) "" is in the category "" (:Category p) "" and costs "" (:Price p))) + )) +(linq11)"), + + Does.StartWith(@" +Product Info: +Chai is in the category Beverages and costs 18 +Chang is in the category Beverages and costs 19 +Aniseed Syrup is in the category Condiments and costs 10 +Chef Anton's Cajun Seasoning is in the category Condiments and costs 22 +Chef Anton's Gumbo Mix is in the category Condiments and costs 21.35 +".NormalizeNewLines())); + } + + [Test] + public void Linq11_classic_lisp() + { + Assert.That(render(@" +(defn linq11 [] + (let ( (product-infos + (map (fn [p] `( + (ProductName ,(.ProductName p)) + (Category ,(.Category p)) + (Price ,(.UnitPrice p)) + )) + products-list)) ) + (println ""Product Info:"") + (doseq (p product-infos) + (println (assoc-value 'ProductName p) "" is in the category "" (assoc-value 'Category p) + "" and costs "" (assoc-value 'Price p))) + )) +(linq11)"), + + Does.StartWith(@" +Product Info: +Chai is in the category Beverages and costs 18 +Chang is in the category Beverages and costs 19 +Aniseed Syrup is in the category Condiments and costs 10 +Chef Anton's Cajun Seasoning is in the category Condiments and costs 22 +Chef Anton's Gumbo Mix is in the category Condiments and costs 21.35 +".NormalizeNewLines())); + } + + [Test] + public void Linq12() + { + Assert.That(render(@" +(defn linq12 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (i 0) (nums-in-place) ) + (setq nums-in-place (map (fn [n] { :num n :in-place (= n (f++ i)) }) numbers)) + (println ""Number: In-place?"") + (doseq (n nums-in-place) + (println (:num n) "": "" (if (:in-place n) 'true 'false)) ) + )) +(linq12)"), + + Does.StartWith(@" +Number: In-place? +5: false +4: false +1: false +3: true +9: false +8: false +6: true +7: true +2: false +0: false +".NormalizeNewLines())); + } + + [Test] + public void Linq13() + { + Assert.That(render(@" +(defn linq13 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (digits [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) ) + (println ""Numbers < 5:"") + (joinln (map #(nth digits %) (where #(< % 5) numbers))) + )) +(linq13)"), + + Does.StartWith(@" +Numbers < 5: +four +one +three +two +zero +".NormalizeNewLines())); + } + + [Test] + public void Linq14() + { + Assert.That(render(@" +(defn linq14 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) + (pairs) ) + (setq pairs (where #(< (:a %) (:b %)) + (zip (fn [a b] { :a a, :b b }) numbers-a numbers-b))) + (println ""Pairs where a < b:"") + (doseq (pair pairs) + (println (:a pair) "" is less than "" (:b pair))) + )) +(linq14)"), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq14_zip_where() + { + Assert.That(render(@" +(defn linq14 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) + (pairs) ) + (setq pairs + (zip-where #(< %1 %2) #(it { :a %1, :b %2 }) numbers-a numbers-b)) + (println ""Pairs where a < b:"") + (doseq (pair pairs) + (println (:a pair) "" is less than "" (:b pair))) + )) +(linq14)"), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq14_doseq() + { + Assert.That(render(@" +(defn linq14 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) + (pairs) ) + (doseq (a numbers-a) + (doseq (b numbers-b) + (if (< a b) (push { :a a, :b b } pairs)))) + (println ""Pairs where a < b:"") + (doseq (pair (nreverse pairs)) + (println (:a pair) "" is less than "" (:b pair))) + )) +(linq14)"), + + Does.StartWith(@" +Pairs where a < b: +0 is less than 1 +0 is less than 3 +0 is less than 5 +0 is less than 7 +0 is less than 8 +2 is less than 3 +2 is less than 5 +2 is less than 7 +2 is less than 8 +4 is less than 5 +4 is less than 7 +4 is less than 8 +5 is less than 7 +5 is less than 8 +6 is less than 7 +6 is less than 8 +".NormalizeNewLines())); + } + + [Test] + public void Linq15() + { + Assert.That(render(@" +(defn linq15 [] + (let ( (orders (flatmap (fn [c] + (map (fn [o] { + :customer-id (.CustomerId c) + :order-id (.OrderId o) + :total (.Total o) + }) (where #(< (.Total %) 500) (.Orders c)) )) + customers-list)) ) + (doseq (o orders) (dump-inline o)) + )) +(linq15)"), + + Does.StartWith(@" +{customer-id:ALFKI,order-id:10702,total:330} +{customer-id:ALFKI,order-id:10952,total:471.2} +{customer-id:ANATR,order-id:10308,total:88.8} +{customer-id:ANATR,order-id:10625,total:479.75} +{customer-id:ANATR,order-id:10759,total:320} +{customer-id:ANTON,order-id:10365,total:403.2} +{customer-id:ANTON,order-id:10682,total:375.5} +{customer-id:AROUT,order-id:10355,total:480} +{customer-id:AROUT,order-id:10453,total:407.7} +{customer-id:AROUT,order-id:10741,total:228} +".NormalizeNewLines())); + } + + [Test] + public void Linq16() + { + Assert.That(render(@" +(defn linq16 [] + (let ( + (orders (flatmap (fn [c] + (map-where #(> (.OrderDate %) (DateTime. 1998 1 1)) + #(it { + :customer-id (.CustomerId c) + :order-id (.OrderId %) + :order-date (.OrderDate %) + }) (.Orders c) ) + ) customers-list) )) + (doseq (o orders) (dump-inline o)) + )) +(linq16)"), + + Does.StartWith(@" +{customer-id:ALFKI,order-id:10835,order-date:1998-01-15} +{customer-id:ALFKI,order-id:10952,order-date:1998-03-16} +{customer-id:ALFKI,order-id:11011,order-date:1998-04-09} +{customer-id:ANATR,order-id:10926,order-date:1998-03-04} +{customer-id:ANTON,order-id:10856,order-date:1998-01-28} +".NormalizeNewLines())); + } + + [Test] + public void Linq17() + { + Assert.That(render(@" +(defn linq17 [] + (let ( + (orders (flatmap (fn [c] + (map-where #(>= (:total %) 2000) + #(it { + :customer-id (.CustomerId c) + :order-id (.OrderId %) + :total (.Total %) + }) (.Orders c) ) + ) customers-list) )) + (doseq (o orders) (dump-inline o)) + )) +(linq17)"), + + Does.StartWith(@" +{customer-id:ANTON,order-id:10573,total:2082} +{customer-id:AROUT,order-id:10558,total:2142.9} +{customer-id:AROUT,order-id:10953,total:4441.25} +{customer-id:BERGS,order-id:10384,total:2222.4} +{customer-id:BERGS,order-id:10524,total:3192.65} +".NormalizeNewLines())); + } + + [Test] + public void Linq18() + { + Assert.That(render(@" +(defn linq18 [] + (let ( (cutoff-date (DateTime. 1997 1 1)) + (orders) ) + (setq orders (flatmap (fn [c] + (map-where #(>= (.OrderDate %) cutoff-date) + #(it { + :customer-id (.CustomerId c) + :order-id (.OrderId %) + }) (.Orders c) ) + ) (where #(= (.Region %) ""WA"") customers-list) ) ) + (doseq (o orders) (dump-inline o)) + )) +(linq18)"), + + Does.StartWith(@" +{customer-id:LAZYK,order-id:10482} +{customer-id:LAZYK,order-id:10545} +{customer-id:TRAIH,order-id:10574} +{customer-id:TRAIH,order-id:10577} +{customer-id:TRAIH,order-id:10822} +{customer-id:WHITC,order-id:10469} +{customer-id:WHITC,order-id:10483} +{customer-id:WHITC,order-id:10504} +{customer-id:WHITC,order-id:10596} +{customer-id:WHITC,order-id:10693} +{customer-id:WHITC,order-id:10696} +{customer-id:WHITC,order-id:10723} +{customer-id:WHITC,order-id:10740} +{customer-id:WHITC,order-id:10861} +{customer-id:WHITC,order-id:10904} +{customer-id:WHITC,order-id:11032} +{customer-id:WHITC,order-id:11066} +".NormalizeNewLines())); + } + + [Test] + public void Linq19() + { + Assert.That(render(@" +(defn linq19 [] + (let ( (customer-orders + (map + #(str ""Customer #"" (:i %) "" has an order with OrderID "" (.OrderId (:o %))) + (flatten (map-index (fn (c i) (map #(it { :o % :i (1+ i) }) (.Orders c))) customers-list)) + )) ) + (doseq (x customer-orders) (println x)) + )) +(linq19)"), + + Does.StartWith(@" +Customer #1 has an order with OrderID 10643 +Customer #1 has an order with OrderID 10692 +Customer #1 has an order with OrderID 10702 +Customer #1 has an order with OrderID 10835 +Customer #1 has an order with OrderID 10952 +Customer #1 has an order with OrderID 11011 +Customer #2 has an order with OrderID 10308 +Customer #2 has an order with OrderID 10625 +Customer #2 has an order with OrderID 10759 +Customer #2 has an order with OrderID 10926 +".NormalizeNewLines())); + } + + [Test] + public void Linq20() + { + Assert.That(render(@" +(defn linq20 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (first-3-numbers) ) + (setq first-3-numbers (take 3 numbers)) + (println ""First 3 numbers:"") + (doseq (n first-3-numbers) (println n)) + )) +(linq20)"), + + Does.StartWith(@" +First 3 numbers: +5 +4 +1 +".NormalizeNewLines())); + } + + [Test] + public void Linq21() + { + Assert.That(render(@" +(defn linq21 [] + (let ( (first-3-wa-orders) ) + (setq first-3-wa-orders + (take 3 + (flatmap (fn [c] + (map #(it { + :customer-id (.CustomerId c) + :order-id (.OrderId %) + :order-date (.OrderDate %) }) + (.Orders c) )) + (where #(= (.Region %) ""WA"") customers-list) )) ) + (println ""First 3 orders in WA:"") + (doseq (x first-3-wa-orders) (dump-inline x)) + )) +(linq21)"), + + Does.StartWith(@" +First 3 orders in WA: +{customer-id:LAZYK,order-id:10482,order-date:1997-03-21} +{customer-id:LAZYK,order-id:10545,order-date:1997-05-22} +{customer-id:TRAIH,order-id:10574,order-date:1997-06-19} +".NormalizeNewLines())); + } + + [Test] + public void Linq22() + { + Assert.That(render(@" +(defn linq22 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (all-but-first-4-numbers) ) + (setq all-but-first-4-numbers (skip 4 numbers)) + (println ""All but first 4 numbers:"") + (doseq (n all-but-first-4-numbers) (println n)) + )) +(linq22)"), + + Does.StartWith(@" +All but first 4 numbers: +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq23() + { + Assert.That(render(@" +(defn linq23 [] + (let ( (all-but-first-2-orders + (skip 2 + (flatmap (fn [c] + (map #(it { + :customer-id (.CustomerId c) + :order-id (.OrderId %) + :order-date (.OrderDate %) }) + (.Orders c) )) + (where #(= (.Region %) ""WA"") customers-list) )) )) + (println ""All but first 2 orders in WA:"") + (doseq (o all-but-first-2-orders) (dump-inline o)) + )) +(linq23)"), + + Does.StartWith(@" +All but first 2 orders in WA: +{customer-id:TRAIH,order-id:10574,order-date:1997-06-19} +{customer-id:TRAIH,order-id:10577,order-date:1997-06-23} +{customer-id:TRAIH,order-id:10822,order-date:1998-01-08} +{customer-id:WHITC,order-id:10269,order-date:1996-07-31} +{customer-id:WHITC,order-id:10344,order-date:1996-11-01} +{customer-id:WHITC,order-id:10469,order-date:1997-03-10} +{customer-id:WHITC,order-id:10483,order-date:1997-03-24} +{customer-id:WHITC,order-id:10504,order-date:1997-04-11} +{customer-id:WHITC,order-id:10596,order-date:1997-07-11} +{customer-id:WHITC,order-id:10693,order-date:1997-10-06} +{customer-id:WHITC,order-id:10696,order-date:1997-10-08} +{customer-id:WHITC,order-id:10723,order-date:1997-10-30} +{customer-id:WHITC,order-id:10740,order-date:1997-11-13} +{customer-id:WHITC,order-id:10861,order-date:1998-01-30} +{customer-id:WHITC,order-id:10904,order-date:1998-02-24} +{customer-id:WHITC,order-id:11032,order-date:1998-04-17} +{customer-id:WHITC,order-id:11066,order-date:1998-05-01} +".NormalizeNewLines())); + } + + [Test] + public void Linq24() + { + Assert.That(render(@" +(defn linq24 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (first-numbers-less-than-6) ) + (setq first-numbers-less-than-6 (take-while #(< % 6) numbers)) + (println ""First numbers less than 6:"") + (doseq (n first-numbers-less-than-6) (println n)) + )) +(linq24)"), + + Does.StartWith(@" +First numbers less than 6: +5 +4 +1 +3 +".NormalizeNewLines())); + } + + [Test] + public void Linq25() + { + Assert.That(render(@" +(defn linq25 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0] ) + (i 0) (first-small-numbers) ) + (setq first-small-numbers (take-while #(>= % (f++ i)) numbers) ) + (println ""First numbers not less than their position:"") + (doseq (n first-small-numbers) (println n)) + )) +(linq25)"), + + Does.StartWith(@" +First numbers not less than their position: +5 +4 +".NormalizeNewLines())); + } + + [Test] + public void Linq26() + { + Assert.That(render(@" +(defn linq26 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (all-but-first-3-numbers) ) + (setq all-but-first-3-numbers (skip-while #(not= (mod % 3) 0) numbers)) + (println ""All elements starting from first element divisible by 3:"") + (doseq (n all-but-first-3-numbers) (println n)) + )) +(linq26)"), + + Does.StartWith(@" +All elements starting from first element divisible by 3: +3 +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq27() + { + Assert.That(render(@" +(defn linq27 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (i 0) (later-numbers) ) + (setq later-numbers (skip-while #(>= % (f++ i)) numbers)) + (println ""All elements starting from first element less than its position:"") + (doseq (n later-numbers) (println n)) + )) +(linq27)"), + + Does.StartWith(@" +All elements starting from first element less than its position: +1 +3 +9 +8 +6 +7 +2 +0 +".NormalizeNewLines())); + } + + [Test] + public void Linq28() + { + Assert.That(render(@" +(defn linq28 [] + (let ( (words [""cherry"" ""apple"" ""blueberry""]) + (sorted-words) ) + (setq sorted-words (sort words)) + (println ""The sorted list of words:"") + (doseq (w sorted-words) (println w)) + )) +(linq28)"), + + Does.StartWith(@" +The sorted list of words: +apple +blueberry +cherry +".NormalizeNewLines())); + } + + [Test] + public void Linq29() + { + Assert.That(render(@" +(defn linq29 [] + (let ( (words [""cherry"" ""apple"" ""blueberry""]) + (sorted-words) ) + (setq sorted-words (sort-by count words)) + (println ""The sorted list of words (by length):"") + (doseq (w sorted-words) (println w)) + )) +(linq29)"), + + Does.StartWith(@" +The sorted list of words (by length): +apple +cherry +blueberry +".NormalizeNewLines())); + } + + [Test] + public void Linq30() + { + Assert.That(render(@" +(defn linq30 [] + (let ( (sorted-products (sort-by .ProductName products-list)) ) + (doseq (p sorted-products) (dump-inline p)) + )) +(linq30)"), + + Does.StartWith(@" +{ProductId:17,ProductName:Alice Mutton,Category:Meat/Poultry,UnitPrice:39,UnitsInStock:0} +{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13} +{ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4,UnitsInStock:123} +{ProductId:60,ProductName:Camembert Pierrot,Category:Dairy Products,UnitPrice:34,UnitsInStock:19} +{ProductId:18,ProductName:Carnarvon Tigers,Category:Seafood,UnitPrice:62.5,UnitsInStock:42} +".NormalizeNewLines()).Or.StartsWith(@" +{UnitsInStock:0,ProductName:Alice Mutton,UnitPrice:39,Category:Meat/Poultry,ProductId:17} +{UnitsInStock:13,ProductName:Aniseed Syrup,UnitPrice:10,Category:Condiments,ProductId:3} +{UnitsInStock:123,ProductName:Boston Crab Meat,UnitPrice:18.4,Category:Seafood,ProductId:40} +{UnitsInStock:19,ProductName:Camembert Pierrot,UnitPrice:34,Category:Dairy Products,ProductId:60} +{UnitsInStock:42,ProductName:Carnarvon Tigers,UnitPrice:62.5,Category:Seafood,ProductId:18} +".NormalizeNewLines())); // different ordering in .NET Core + } + + [Test] + public void Linq31() + { + Assert.That(render(@" +(defn linq31 [] + (let ( (words [""aPPLE"" ""AbAcUs"" ""bRaNcH"" ""BlUeBeRrY"" ""ClOvEr"" ""cHeRry""]) + (sorted-words) ) + (setq sorted-words (sort-by it (CaseInsensitiveComparer.) words)) + (doseq (w sorted-words) (println w)) + )) +(linq31)"), + + Does.StartWith(@" +AbAcUs +aPPLE +BlUeBeRrY +bRaNcH +cHeRry +ClOvEr +".NormalizeNewLines())); + } + + [Test] + public void Linq32() + { + Assert.That(render(@" +(defn linq32 [] + (let ( (dbls [1.7 2.3 1.9 4.1 2.9]) + (sorted-doubles) ) + (setq sorted-doubles (reverse (sort dbls))) + (println ""The doubles from highest to lowest:"") + (doseq (d sorted-doubles) (println d)) + )) +(linq32)"), + + Does.StartWith(@" +The doubles from highest to lowest: +4.1 +2.9 +2.3 +1.9 +1.7 +".NormalizeNewLines())); + } + + [Test] + public void linq33() + { + Assert.That(render(@" +(defn linq33 [] + (let ( (sorted-products (reverse (sort-by .UnitsInStock products-list))) ) + (doseq (p sorted-products) (dump-inline p)) + )) +(linq33)"), + + Does.StartWith(@" +{ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75,UnitsInStock:125} +{ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4,UnitsInStock:123} +{ProductId:6,ProductName:Grandma's Boysenberry Spread,Category:Condiments,UnitPrice:25,UnitsInStock:120} +{ProductId:55,ProductName:Pâté chinois,Category:Meat/Poultry,UnitPrice:24,UnitsInStock:115} +{ProductId:61,ProductName:Sirop d'érable,Category:Condiments,UnitPrice:28.5,UnitsInStock:113} +".NormalizeNewLines()).Or.StartsWith(@" +{UnitsInStock:125,ProductName:Rhönbräu Klosterbier,UnitPrice:7.75,Category:Beverages,ProductId:75} +{UnitsInStock:123,ProductName:Boston Crab Meat,UnitPrice:18.4,Category:Seafood,ProductId:40} +{UnitsInStock:120,ProductName:Grandma's Boysenberry Spread,UnitPrice:25,Category:Condiments,ProductId:6} +{UnitsInStock:115,ProductName:Pâté chinois,UnitPrice:24,Category:Meat/Poultry,ProductId:55} +{UnitsInStock:113,ProductName:Sirop d'érable,UnitPrice:28.5,Category:Condiments,ProductId:61} +".NormalizeNewLines()).Or.StartsWith(@" +{UnitsInStock:125,ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75} +{UnitsInStock:123,ProductId:40,ProductName:Boston Crab Meat,Category:Seafood,UnitPrice:18.4} +{UnitsInStock:120,ProductId:6,ProductName:Grandma's Boysenberry Spread,Category:Condiments,UnitPrice:25} +{UnitsInStock:115,ProductId:55,ProductName:Pâté chinois,Category:Meat/Poultry,UnitPrice:24} +{UnitsInStock:113,ProductId:61,ProductName:Sirop d'érable,Category:Condiments,UnitPrice:28.5} +".NormalizeNewLines())); + } + + [Test] + public void linq34() + { + Assert.That(render(@" +(defn linq34 [] + (let ( (words [""aPPLE"" ""AbAcUs"" ""bRaNcH"" ""BlUeBeRrY"" ""ClOvEr"" ""cHeRry""]) + (sorted-words) ) + (setq sorted-words (order-by [{ :comparer (CaseInsensitiveComparer.) :desc true }] words)) + (doseq (w sorted-words) (println w)) + )) +(linq34)"), + + Does.StartWith(@" +ClOvEr +cHeRry +bRaNcH +BlUeBeRrY +aPPLE +AbAcUs +".NormalizeNewLines())); + } + + [Test] + public void linq35() + { + Assert.That(render(@" +(defn linq35 [] + (let ( (digits [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) + (i 0) (sorted-digits) ) + (setq sorted-digits (order-by [#(count %) it] digits )) + (println ""Sorted digits:"") + (doseq (d sorted-digits) (println d)) + )) +(linq35)"), + + Does.StartWith(@" +Sorted digits: +one +six +two +five +four +nine +zero +eight +seven +three +".NormalizeNewLines())); + } + + [Test] + public void linq36() + { + Assert.That(render(@" +(defn linq36 [] + (let ( (words [""aPPLE"" ""AbAcUs"" ""bRaNcH"" ""BlUeBeRrY"" ""ClOvEr"" ""cHeRry""]) + (sorted-words) ) + (setq sorted-words (order-by [#(count %) { :comparer (CaseInsensitiveComparer.) }] words)) + (doseq (w sorted-words) (println w)) + )) +(linq36)"), + + Does.StartWith(@" +aPPLE +AbAcUs +bRaNcH +cHeRry +ClOvEr +BlUeBeRrY +".NormalizeNewLines())); + } + + [Test] + public void linq37() + { + Assert.That(render(@" +(defn linq37 [] + (let ( (sorted-products (order-by [ #(.Category %) { :key #(.UnitPrice %) :desc true } ] products-list)) ) + (doseq (p sorted-products) (dump-inline p)) + )) +(linq37)"), + + Does.StartWith(@" +{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17} +{ProductId:43,ProductName:Ipoh Coffee,Category:Beverages,UnitPrice:46,UnitsInStock:17} +{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17} +{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39} +{ProductId:35,ProductName:Steeleye Stout,Category:Beverages,UnitPrice:18,UnitsInStock:20} +{ProductId:39,ProductName:Chartreuse verte,Category:Beverages,UnitPrice:18,UnitsInStock:69} +{ProductId:76,ProductName:Lakkalikööri,Category:Beverages,UnitPrice:18,UnitsInStock:57} +{ProductId:70,ProductName:Outback Lager,Category:Beverages,UnitPrice:15,UnitsInStock:15} +{ProductId:34,ProductName:Sasquatch Ale,Category:Beverages,UnitPrice:14,UnitsInStock:111} +".NormalizeNewLines()).Or.StartsWith(@" +{UnitsInStock:17,ProductName:Côte de Blaye,UnitPrice:263.5,Category:Beverages,ProductId:38} +{UnitsInStock:17,ProductName:Ipoh Coffee,UnitPrice:46,Category:Beverages,ProductId:43} +{UnitsInStock:17,ProductName:Chang,UnitPrice:19,Category:Beverages,ProductId:2} +{UnitsInStock:39,ProductName:Chai,UnitPrice:18,Category:Beverages,ProductId:1} +{UnitsInStock:20,ProductName:Steeleye Stout,UnitPrice:18,Category:Beverages,ProductId:35} +{UnitsInStock:69,ProductName:Chartreuse verte,UnitPrice:18,Category:Beverages,ProductId:39} +{UnitsInStock:57,ProductName:Lakkalikööri,UnitPrice:18,Category:Beverages,ProductId:76} +{UnitsInStock:15,ProductName:Outback Lager,UnitPrice:15,Category:Beverages,ProductId:70} +{UnitsInStock:111,ProductName:Sasquatch Ale,UnitPrice:14,Category:Beverages,ProductId:34} +".NormalizeNewLines())); // different ordering in .NET Core + } + + [Test] + public void linq38() + { + Assert.That(render(@" +(defn linq38 [] + (let ( (words [""aPPLE"" ""AbAcUs"" ""bRaNcH"" ""BlUeBeRrY"" ""ClOvEr"" ""cHeRry""]) + (sorted-words) ) + + (setq sorted-words (order-by [ #(count %) { :comparer (CaseInsensitiveComparer.) :desc true } ] words)) + (doseq (w sorted-words) (println w)) + )) +(linq38)"), + + Does.StartWith(@" +aPPLE +ClOvEr +cHeRry +bRaNcH +AbAcUs +BlUeBeRrY +".NormalizeNewLines())); + } + + [Test] + public void linq39() + { + Assert.That(render(@" +(defn linq39 [] + (let ( (digits [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) + (sorted-digits) ) + (setq sorted-digits (reverse (where #(= (:1 %) (:0 ""i"")) digits)) ) + (println ""A backwards list of the digits with a second character of 'i':"") + (doseq (d sorted-digits) (println d)) + )) +(linq39)"), + + Does.StartWith(@" +A backwards list of the digits with a second character of 'i': +nine +eight +six +five +".NormalizeNewLines())); + } + + [Test] + public void linq40() + { + Assert.That(render(@" +(defn linq40 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (number-groups) ) + (setq number-groups + (map (fn [g] { :remainder (.Key g) :numbers g }) (group-by #(mod % 5) numbers))) + (doseq (g number-groups) + (println ""Numbers with a remainder of "" (:remainder g) "" when divided by 5:"") + (doseq (n (:numbers g)) (println n))) + )) +(linq40)"), + + Does.StartWith(@" +Numbers with a remainder of 0 when divided by 5: +5 +0 +Numbers with a remainder of 4 when divided by 5: +4 +9 +Numbers with a remainder of 1 when divided by 5: +1 +6 +Numbers with a remainder of 3 when divided by 5: +3 +8 +Numbers with a remainder of 2 when divided by 5: +7 +2 +".NormalizeNewLines())); + } + + [Test] + public void linq41() + { + Assert.That(render(@" +(defn linq41 [] + (let ( (words [""blueberry"" ""chimpanzee"" ""abacus"" ""banana"" ""apple"" ""cheese""]) + (word-groups) ) + (setq word-groups + (map (fn [g] {:first-letter (.Key g) :words g}) (group-by #(nth % 0) words) )) + (doseq (g word-groups) + (println ""Words that start with the letter: "" (:first-letter g)) + (doseq (w (:words g)) (println w))) + )) +(linq41)"), + + Does.StartWith(@" +Words that start with the letter: b +blueberry +banana +Words that start with the letter: c +chimpanzee +cheese +Words that start with the letter: a +abacus +apple +".NormalizeNewLines())); + } + + [Test] + public void linq42() + { + Assert.That(render(@" +(defn linq42 [] + (let ( (order-groups + (map (fn [g] {:category (.Key g), :products g}) (group-by :category products-list))) ) + (doseq (x order-groups) (dump-inline x)) + )) +(linq42)"), + + Does.StartWith(@" +{category:Beverages,products:[{ProductId:1,ProductName:Chai,Category:Beverages,UnitPrice:18,UnitsInStock:39},{ProductId:2,ProductName:Chang,Category:Beverages,UnitPrice:19,UnitsInStock:17},{ProductId:24,ProductName:Guaraná Fantástica,Category:Beverages,UnitPrice:4.5,UnitsInStock:20},{ProductId:34,ProductName:Sasquatch Ale,Category:Beverages,UnitPrice:14,UnitsInStock:111},{ProductId:35,ProductName:Steeleye Stout,Category:Beverages,UnitPrice:18,UnitsInStock:20},{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17},{ProductId:39,ProductName:Chartreuse verte,Category:Beverages,UnitPrice:18,UnitsInStock:69},{ProductId:43,ProductName:Ipoh Coffee,Category:Beverages,UnitPrice:46,UnitsInStock:17},{ProductId:67,ProductName:Laughing Lumberjack Lager,Category:Beverages,UnitPrice:14,UnitsInStock:52},{ProductId:70,ProductName:Outback Lager,Category:Beverages,UnitPrice:15,UnitsInStock:15},{ProductId:75,ProductName:Rhönbräu Klosterbier,Category:Beverages,UnitPrice:7.75,UnitsInStock:125},{ProductId:76,ProductName:Lakkalikööri,Category:Beverages,UnitPrice:18,UnitsInStock:57}]} +".NormalizeNewLines()).Or.StartsWith(@" +{category:Beverages,products:[{UnitsInStock:39,ProductName:Chai,UnitPrice:18,Category:Beverages,ProductId:1},{UnitsInStock:17,ProductName:Chang,UnitPrice:19,Category:Beverages,ProductId:2},{UnitsInStock:20,ProductName:Guaraná Fantástica,UnitPrice:4.5,Category:Beverages,ProductId:24},{UnitsInStock:111,ProductName:Sasquatch Ale,UnitPrice:14,Category:Beverages,ProductId:34},{UnitsInStock:20,ProductName:Steeleye Stout,UnitPrice:18,Category:Beverages,ProductId:35},{UnitsInStock:17,ProductName:Côte de Blaye,UnitPrice:263.5,Category:Beverages,ProductId:38},{UnitsInStock:69,ProductName:Chartreuse verte,UnitPrice:18,Category:Beverages,ProductId:39},{UnitsInStock:17,ProductName:Ipoh Coffee,UnitPrice:46,Category:Beverages,ProductId:43},{UnitsInStock:52,ProductName:Laughing Lumberjack Lager,UnitPrice:14,Category:Beverages,ProductId:67},{UnitsInStock:15,ProductName:Outback Lager,UnitPrice:15,Category:Beverages,ProductId:70},{UnitsInStock:125,ProductName:Rhönbräu Klosterbier,UnitPrice:7.75,Category:Beverages,ProductId:75},{UnitsInStock:57,ProductName:Lakkalikööri,UnitPrice:18,Category:Beverages,ProductId:76}]} +".NormalizeNewLines())); // different ordering in .NET Core + } + + [Test] + public void linq43() + { + Assert.That(render(@" +(defn linq43 [] + (let ( (customer-order-groups + (map (fn [c] { + :company-name (.CompanyName c) + :year-groups (map (fn [yg] { + :year (.Key yg) + :month-groups (map (fn [mg] { + :month (.Key mg) + :orders mg + }) (group-by #(.Month (.OrderDate %)) yg)) + }) (group-by (fn [o] (.Year (.OrderDate o))) (.Orders c))) + }) customers-list)) ) + (dump customer-order-groups) + )) +(linq43)"), + + Does.StartWith(@" +[ + { + company-name: Alfreds Futterkiste, + year-groups: + [ + { + year: 1997, + month-groups: + [ + { + month: 8, + orders: + [ + { + OrderId: 10643, + OrderDate: 1997-08-25, + Total: 814.5 + } + ] + }, + { + month: 10, + orders: + [ + { + OrderId: 10692, + OrderDate: 1997-10-03, + Total: 878 + }, + { + OrderId: 10702, + OrderDate: 1997-10-13, + Total: 330 + } + ] + } + ] + }, + { + year: 1998, + month-groups: + [ + { + month: 1, + orders: + [ + { + OrderId: 10835, + OrderDate: 1998-01-15, + Total: 845.8 + } + ] + }, + { + month: 3, + orders: + [ + { + OrderId: 10952, + OrderDate: 1998-03-16, + Total: 471.2 + } + ] + }, + { + month: 4, + orders: + [ + { + OrderId: 11011, + OrderDate: 1998-04-09, + Total: 933.5 + } + ] + } + ] + } + ] + }, +".NormalizeNewLines())); + } + + [Test] + public void linq44() + { + Assert.That(render(@" +(defn linq44 [] + (let ( (anagrams [""from "" "" salt"" "" earn "" "" last "" "" near "" "" form ""]) + (order-groups) ) + (setq order-groups (group-by .Trim { :comparer (AnagramEqualityComparer.) } anagrams)) + (doseq (x order-groups) (dump-inline x)) + )) +(linq44)"), + + Does.StartWith(@" +[from , form ] +[ salt, last ] +[ earn , near ] +".NormalizeNewLines())); + } + + [Test] + public void linq44_inline() + { + Assert.That(render(@" +(defn linq44 [] + (let ( (anagrams [""from "" "" salt"" "" earn "" "" last "" "" near "" "" form ""]) + (order-groups) ) + (setq order-groups (group-by #((/C ""String(char[])"") (sort (.ToCharArray (.Trim %)))) anagrams)) + (doseq (x order-groups) (dump-inline x)) + )) +(linq44)"), + + Does.StartWith(@" +[from , form ] +[ salt, last ] +[ earn , near ] +".NormalizeNewLines())); + } + + [Test] + public void linq45() + { + Assert.That(render(@" +(defn linq45 [] + (let ( (anagrams [""from "" "" salt"" "" earn "" "" last "" "" near "" "" form ""]) + (order-groups) ) + (setq order-groups (group-by .Trim { :comparer (AnagramEqualityComparer.) :map upper-case } anagrams)) + (doseq (x order-groups) (dump-inline x)) + )) +(linq45)"), + + Does.StartWith(@" +[FROM , FORM ] +[ SALT, LAST ] +[ EARN , NEAR ] +".NormalizeNewLines())); + } + + [Test] + public void linq46() + { + Assert.That(render(@" +(defn linq46 [] + (let ( (factors-of-300 [2, 2, 3, 5, 5]) + (unique-factors) ) + (setq unique-factors (/distinct factors-of-300)) + (println ""Prime factors of 300:"") + (doseq (n unique-factors) (println n)) + )) +(linq46)"), + + Does.StartWith(@" +Prime factors of 300: +2 +3 +5 +".NormalizeNewLines())); + } + + [Test] + public void linq47() + { + Assert.That(render(@" +(defn linq47 [] + (let ( (category-names (/distinct (map .Category products-list))) ) + (println ""Category names:"") + (doseq (c category-names) (println c)) + )) +(linq47)"), + + Does.StartWith(@" +Category names: +Beverages +Condiments +Produce +Meat/Poultry +Seafood +Dairy Products +Confections +Grains/Cereals +".NormalizeNewLines())); + } + + [Test] + public void linq48() + { + Assert.That(render(@" +(defn linq48 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) + (unique-numbers) ) + + (setq unique-numbers (/union numbers-a numbers-b)) + (println ""Unique numbers from both arrays:"") + (doseq (n unique-numbers) (println n)) + )) +(linq48)"), + + Does.StartWith(@" +Unique numbers from both arrays: +0 +2 +4 +5 +6 +8 +9 +1 +3 +7 +".NormalizeNewLines())); + } + + [Test] + public void linq49() + { + Assert.That(render(@" +(defn linq49 [] + (let ( (product-first-chars (map #(nth (.ProductName %) 0) products-list)) + (customer-first-chars (map #(nth (.CompanyName %) 0) customers-list)) + (unique-first-chars) ) + + (setq unique-first-chars (/union product-first-chars customer-first-chars)) + (println ""Unique first letters from Product names and Customer names:"") + (doseq (x unique-first-chars) (println x)) + )) +(linq49)"), + + Does.StartWith(@" +Unique first letters from Product names and Customer names: +C +A +G +U +N +M +I +Q +K +T +P +S +R +B +J +Z +V +F +E +W +L +O +D +H +".NormalizeNewLines())); + } + + [Test] + public void linq50() + { + Assert.That(render(@" +(defn linq50 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) ) + (setq common-numbers (intersect numbers-a numbers-b)) + (println ""Common numbers shared by both arrays:"") + (doseq (n common-numbers) (println n)) + )) +(linq50)"), + + Does.StartWith(@" +Common numbers shared by both arrays: +5 +8 +".NormalizeNewLines())); + } + + [Test] + public void linq51() + { + Assert.That(render(@" +(defn linq51 [] + (let ( (product-first-chars (map #(nth (.ProductName %) 0) products-list)) + (customer-first-chars (map #(nth (.CompanyName %) 0) customers-list)) + (common-first-chars) ) + (setq common-first-chars (intersect product-first-chars customer-first-chars)) + (println ""Common first letters from Product names and Customer names:"") + (doseq (x common-first-chars) (println x)) + )) +(linq51)"), + + Does.StartWith(@" +Common first letters from Product names and Customer names: +C +A +G +N +M +I +Q +K +T +P +S +R +B +V +F +E +W +L +O +".NormalizeNewLines())); + } + + [Test] + public void linq52() + { + Assert.That(render(@" +(defn linq52 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) + (a-only-numbers) ) + (setq a-only-numbers (/except numbers-a numbers-b)) + (println ""Numbers in first array but not second array:"") + (doseq (n a-only-numbers) (println n)) + )) +(linq52)"), + + Does.StartWith(@" +Numbers in first array but not second array: +0 +2 +4 +6 +9 +".NormalizeNewLines())); + } + + [Test] + public void linq53() + { + Assert.That(render(@" +(defn linq53 [] + (let ( (product-first-chars (map #(nth (.ProductName %) 0) products-list)) + (customer-first-chars (map #(nth (.CompanyName %) 0) customers-list)) + (product-only-first-chars) ) + + (setq product-only-first-chars (/except product-first-chars customer-first-chars)) + (println ""First letters from Product names, but not from Customer names:"") + (doseq (x product-only-first-chars) (println x)) + )) +(linq53)"), + + Does.StartWith(@" +First letters from Product names, but not from Customer names: +U +J +Z +".NormalizeNewLines())); + } + + [Test] + public void linq54() + { + Assert.That(render(@" +(defn linq54 [] + (let ( (dbls [1.7 2.3 1.9 4.1 2.9]) + (sorted-doubles) ) + (setq sorted-doubles (reverse (sort dbls))) + (println ""Every other double from highest to lowest:"") + (doseq (d (/step sorted-doubles { :by 2 })) (println d)) + )) +(linq54)"), + + Does.StartWith(@" +Every other double from highest to lowest: +4.1 +2.3 +1.7 +".NormalizeNewLines())); + } + + [Test] + public void linq55() + { + Assert.That(render(@" +(defn linq55 [] + (let ( (words [""cherry"" ""apple"" ""blueberry""]) + (sorted-words) ) + (setq sorted-words (to-list (sort words))) + (println ""The sorted word list:"") + (doseq (w sorted-words) (println w)) + )) +(linq55)"), + + Does.StartWith(@" +The sorted word list: +apple +blueberry +cherry +".NormalizeNewLines())); + } + + [Test] + public void linq56() + { + Assert.That(render(@" +(defn linq56 [] + (let ( (sorted-records [{:name ""Alice"", :score 50} + {:name ""Bob"", :score 40} + {:name ""Cathy"", :score 45}]) + (sorted-records-dict) ) + (setq sorted-records-dict (to-dictionary :name sorted-records)) + (println ""Bob's score: "" (:score (:""Bob"" sorted-records-dict))) + )) +(linq56)"), + + Does.StartWith(@" +Bob's score: 40 +".NormalizeNewLines())); + } + + [Test] + public void linq57() + { + Assert.That(render(@" +(defn linq57 [] + (let ( (numbers [nil 1.0 ""two"" 3 ""four"" 5 ""six"" 7.0]) + (dbls) ) + (setq dbls (/of numbers { :type ""Double"" })) + (println ""Numbers stored as doubles:"") + (doseq (d dbls) (println d)) + )) +(linq57)"), + + Does.StartWith(@" +Numbers stored as doubles: +1 +7 +".NormalizeNewLines())); + } + + [Test] + public void linq58() + { + Assert.That(render(@" +(defn linq58 [] + (let ( (product-12 (first (where #(= (.ProductId %) 12) products-list)) ) ) + (dump-inline product-12) + )) +(linq58)"), + + Does.StartWith(@" +{ProductId:12,ProductName:Queso Manchego La Pastora,Category:Dairy Products,UnitPrice:38,UnitsInStock:86} +".NormalizeNewLines()).Or.StartsWith(@" +{UnitsInStock:86,ProductName:Queso Manchego La Pastora,UnitPrice:38,Category:Dairy Products,ProductId:12} +".NormalizeNewLines())); // different ordering in .NET Core + } + + [Test] + public void linq59() + { + Assert.That(render(@" +(defn linq59 [] + (let ( (strings [""zero"" ""one"" ""two"" ""three"" ""four"" ""five"" ""six"" ""seven"" ""eight"" ""nine""]) + (starts-with-o) ) + (setq starts-with-o (first (where #(/startsWith % ""o"") strings))) + (println ""A string starting with 'o': "" starts-with-o) + )) +(linq59)"), + + Does.StartWith(@" +A string starting with 'o': one +".NormalizeNewLines())); + } + + [Test] + public void linq61() + { + Assert.That(render(@" +(defn linq61 [] + (let ( (numbers []) (first-num-or-default) ) + (setq first-num-or-default (or (first numbers) 0)) + (println first-num-or-default) + )) +(linq61)"), + + Does.StartWith(@" +0 +".NormalizeNewLines())); + } + + [Test] + public void linq62() + { + Assert.That(render(@" +(defn linq62 [] + (let ( (product-789 (first (where #(= (.ProductId %) 789) products-list) )) ) + (println ""Product 789 exists: "" (not= product-789 nil)) + )) +(linq62)"), + + Does.StartWith(@" +Product 789 exists: False +".NormalizeNewLines())); + } + + [Test] + public void linq64() + { + Assert.That(render(@" +(defn linq64 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) (fourth-low-num) ) + (setq fourth-low-num (nth (where #(> % 5) numbers) 1)) + (println ""Second number > 5: "" fourth-low-num) + )) +(linq64)"), + + Does.StartWith(@" +Second number > 5: 8 +".NormalizeNewLines())); + } + + [Test] + public void linq65() + { + Assert.That(render(@" +(defn linq65 [] + (let ( (numbers (map (fn [n] { + :number n + :odd-even (if (odd? n) ""odd"" ""even"") + }) (range 100 151))) ) + (doseq (n numbers) + (println ""The number "" (:number n) "" is "" (:odd-even n))) + )) +(linq65)"), + + Does.StartWith(@" +The number 100 is even +The number 101 is odd +The number 102 is even +The number 103 is odd +The number 104 is even +The number 105 is odd +The number 106 is even +The number 107 is odd +The number 108 is even +The number 109 is odd +The number 110 is even +".NormalizeNewLines())); + } + + [Test] + public void linq66() + { + Assert.That(render(@" +(defn linq66 [] + (let ( (numbers (/repeat 7 10)) ) + (doseq (n numbers) (println n)))) +(linq66)"), + + Does.StartWith(@" +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +".NormalizeNewLines())); + } + + [Test] + public void linq67() + { + Assert.That(render(@" +(defn linq67 [] + (let ( (words [""believe"" ""relief"" ""receipt"" ""field""]) + (i-after-e) ) + (setq i-after-e (any? #(.Contains % ""ie"") words)) + (println ""There is a word that contains in the list that contains 'ei': "" i-after-e) + )) +(linq67)"), + + Does.StartWith(@" +There is a word that contains in the list that contains 'ei': True +".NormalizeNewLines())); + } + + [Test] + public void linq69() + { + Assert.That(render(@" +(defn linq69 [] + (let ( (product-groups + (map #(it { :category (.Key %), :products % }) + (where #(any? (fn [p] (= (.UnitsInStock p) 0)) %) + (group-by .Category products-list)))) ) + (dump product-groups) + )) +(linq69)"), + + Does.StartWith(@"[ + { + category: Condiments, + products: + [ + { + ProductId: 3, + ProductName: Aniseed Syrup, + Category: Condiments, + UnitPrice: 10, + UnitsInStock: 13 + }, + { + ProductId: 4, + ProductName: Chef Anton's Cajun Seasoning, + Category: Condiments, + UnitPrice: 22, + UnitsInStock: 53 + }, + { + ProductId: 5, + ProductName: Chef Anton's Gumbo Mix, + Category: Condiments, + UnitPrice: 21.35, + UnitsInStock: 0 + }, +".NormalizeNewLines()).Or.StartsWith(@"[ + { + category: Condiments, + products: + [ + { + UnitsInStock: 13, + ProductName: Aniseed Syrup, + UnitPrice: 10, + Category: Condiments, + ProductId: 3 + },".NormalizeNewLines())); + } + + [Test] + public void linq70() + { + Assert.That(render(@" +(defn linq70 [] + (let ( (numbers [1 11 3 19 41 65 19]) + (only-odd) ) + (setq only-odd (all? odd? numbers)) + (println ""The list contains only odd numbers: "" only-odd) + )) +(linq70)"), + + Does.StartWith(@" +The list contains only odd numbers: True +".NormalizeNewLines())); + } + + [Test] + public void linq72() + { + Assert.That(render(@" +(defn linq72 [] + (let ( (product-groups + (map #(it { :category (.Key %), :products % }) + (where #(all? (fn [p] (> (.UnitsInStock p) 0)) %) + (group-by .Category products-list)))) ) + (dump product-groups) + )) +(linq72)"), + + Does.StartWith(@"[ + { + category: Beverages, + products: + [ + { + ProductId: 1, + ProductName: Chai, + Category: Beverages, + UnitPrice: 18, + UnitsInStock: 39 + }, + { + ProductId: 2, + ProductName: Chang, + Category: Beverages, + UnitPrice: 19, + UnitsInStock: 17 + }, + { + ProductId: 24, + ProductName: Guaraná Fantástica, + Category: Beverages, + UnitPrice: 4.5, + UnitsInStock: 20 + }, +".NormalizeNewLines()).Or.StartsWith(@"[ + { + category: Beverages, + products: + [ + { + UnitsInStock: 39, + ProductName: Chai, + UnitPrice: 18, + Category: Beverages, + ProductId: 1 + },".NormalizeNewLines())); + } + + [Test] + public void linq73() + { + Assert.That(render(@" +(defn linq73 [] + (let ( (factors-of-300 [2 2 3 5 5]) + (unique-factors) ) + (setq unique-factors (count (/distinct factors-of-300))) + (println ""There are "" unique-factors "" unique factors of 300."") + )) +(linq73)"), + + Does.StartWith(@" +There are 3 unique factors of 300. +".NormalizeNewLines())); + } + + [Test] + public void linq74() + { + Assert.That(render(@" +(defn linq74 [] + (let ( (numbers [4 5 1 3 9 0 6 7 2 0]) + (odd-numbers) ) + (setq odd-numbers (count (where odd? numbers)) ) + (println ""There are "" odd-numbers "" odd numbers in the list."") + )) +(linq74)"), + + Does.StartWith(@" +There are 5 odd numbers in the list. +".NormalizeNewLines())); + } + + [Test] + public void linq76() + { + Assert.That(render(@" +(defn linq76 [] + (let ( (order-counts + (map #(it { + :customer-id (.CustomerId %) + :order-count (count (.Orders %)) + }) customers-list)) ) + (doseq (x order-counts) (dump-inline x)) +)) +(linq76)"), + + Does.StartWith(@" +{customer-id:ALFKI,order-count:6} +{customer-id:ANATR,order-count:4} +{customer-id:ANTON,order-count:7} +{customer-id:AROUT,order-count:13} +{customer-id:BERGS,order-count:18} +{customer-id:BLAUS,order-count:7} +{customer-id:BLONP,order-count:11} +".NormalizeNewLines())); + } + + [Test] + public void linq77() + { + Assert.That(render(@" +(defn linq77 [] + (let ( (category-counts + (map #(it { + :category (.Key %) + :product-count (count %) + }) + (group-by .Category products-list))) ) + (doseq (x category-counts) (dump-inline x)) + )) +(linq77)"), + + Does.StartWith(@" +{category:Beverages,product-count:12} +{category:Condiments,product-count:12} +{category:Produce,product-count:5} +{category:Meat/Poultry,product-count:6} +{category:Seafood,product-count:12} +{category:Dairy Products,product-count:10} +{category:Confections,product-count:13} +{category:Grains/Cereals,product-count:7} +".NormalizeNewLines())); + } + + [Test] + public void linq78() + { + Assert.That(render(@" +(defn linq78 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) ) + (setq num-sum (reduce + numbers)) + (println ""The sum of the numbers is "" num-sum) + )) +(linq78)"), + + Does.StartWith(@" +The sum of the numbers is 45 +".NormalizeNewLines())); + } + + [Test] + public void linq79() + { + Assert.That(render(@" +(defn linq79 [] + (let ( (words [""cherry"", ""apple"", ""blueberry""]) + (total-chars) ) + (setq total-chars (reduce + (map count words))) + (println ""There are a total of "" total-chars "" characters in these words."") + )) +(linq79)"), + + Does.StartWith(@" +There are a total of 20 characters in these words. +".NormalizeNewLines())); + } + + [Test] + public void linq80() + { + Assert.That(render(@" +(defn linq80 [] + (let ( (categories + (map #(it { + :category (.Key %) + :total-units-in-stock (sum (map .UnitsInStock %)) + }) + (group-by .Category products-list))) ) + (doseq (x categories) (dump-inline x)) + )) +(linq80)"), + + Does.StartWith(@" +{category:Beverages,total-units-in-stock:559} +{category:Condiments,total-units-in-stock:507} +{category:Produce,total-units-in-stock:100} +{category:Meat/Poultry,total-units-in-stock:165} +{category:Seafood,total-units-in-stock:701} +{category:Dairy Products,total-units-in-stock:393} +{category:Confections,total-units-in-stock:386} +{category:Grains/Cereals,total-units-in-stock:308} +".NormalizeNewLines())); + } + + [Test] + public void linq81() + { + Assert.That(render(@" +(defn linq81 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (min-num) ) + (setq min-num (apply min numbers)) + (println ""The minimum number is "" min-num) + )) +(linq81)"), + + Does.StartWith(@" +The minimum number is 0 +".NormalizeNewLines())); + } + + [Test] + public void linq82() + { + Assert.That(render(@" +(defn linq82 [] + (let ( (words [""cherry"", ""apple"", ""blueberry""]) + (shortest-word) ) + (setq shortest-word (apply min (map count words))) + (println ""The shortest word is "" shortest-word "" characters long."") + )) +(linq82)"), + + Does.StartWith(@" +The shortest word is 5 characters long. +".NormalizeNewLines())); + } + + [Test] + public void linq83() + { + Assert.That(render(@" +(defn linq83 [] + (let ( (categories + (map #(it { + :category (.Key %) + :cheapest-price (apply min (map .UnitPrice %)) + }) + (group-by .Category products-list))) ) + (doseq (x categories) (dump-inline x)) + )) +(linq83)"), + + Does.StartWith(@" +{category:Beverages,cheapest-price:4.5} +{category:Condiments,cheapest-price:10} +{category:Produce,cheapest-price:10} +{category:Meat/Poultry,cheapest-price:7.45} +{category:Seafood,cheapest-price:6} +{category:Dairy Products,cheapest-price:2.5} +{category:Confections,cheapest-price:9.2} +{category:Grains/Cereals,cheapest-price:7} +".NormalizeNewLines())); + } + + [Test] + public void linq84() + { + Assert.That(render(@" +(defn linq84 [] + (let ( (categories + (map (fn [g] ( + let ( (min-price (apply min (map .UnitPrice g))) ) + { + :category (.Key g) + :cheapest-products (where #(= (.UnitPrice %) min-price) g) + })) + (group-by .Category products-list))) ) + (doseq (x categories) (dump-inline x)) + )) +(linq84)"), + + Does.StartWith(@" +{category:Beverages,cheapest-products:[{ProductId:24,ProductName:Guaraná Fantástica,Category:Beverages,UnitPrice:4.5,UnitsInStock:20}]} +{category:Condiments,cheapest-products:[{ProductId:3,ProductName:Aniseed Syrup,Category:Condiments,UnitPrice:10,UnitsInStock:13}]} +{category:Produce,cheapest-products:[{ProductId:74,ProductName:Longlife Tofu,Category:Produce,UnitPrice:10,UnitsInStock:4}]} +{category:Meat/Poultry,cheapest-products:[{ProductId:54,ProductName:Tourtière,Category:Meat/Poultry,UnitPrice:7.45,UnitsInStock:21}]} +{category:Seafood,cheapest-products:[{ProductId:13,ProductName:Konbu,Category:Seafood,UnitPrice:6,UnitsInStock:24}]} +{category:Dairy Products,cheapest-products:[{ProductId:33,ProductName:Geitost,Category:Dairy Products,UnitPrice:2.5,UnitsInStock:112}]} +{category:Confections,cheapest-products:[{ProductId:19,ProductName:Teatime Chocolate Biscuits,Category:Confections,UnitPrice:9.2,UnitsInStock:25}]} +{category:Grains/Cereals,cheapest-products:[{ProductId:52,ProductName:Filo Mix,Category:Grains/Cereals,UnitPrice:7,UnitsInStock:38}]} +".NormalizeNewLines()).Or.StartsWith(@" +{category:Beverages,cheapest-products:[{UnitsInStock:20,ProductName:Guaraná Fantástica,UnitPrice:4.5,Category:Beverages,ProductId:24}]} +{category:Condiments,cheapest-products:[{UnitsInStock:13,ProductName:Aniseed Syrup,UnitPrice:10,Category:Condiments,ProductId:3}]} +{category:Produce,cheapest-products:[{UnitsInStock:4,ProductName:Longlife Tofu,UnitPrice:10,Category:Produce,ProductId:74}]} +{category:Meat/Poultry,cheapest-products:[{UnitsInStock:21,ProductName:Tourtière,UnitPrice:7.45,Category:Meat/Poultry,ProductId:54}]} +{category:Seafood,cheapest-products:[{UnitsInStock:24,ProductName:Konbu,UnitPrice:6,Category:Seafood,ProductId:13}]} +{category:Dairy Products,cheapest-products:[{UnitsInStock:112,ProductName:Geitost,UnitPrice:2.5,Category:Dairy Products,ProductId:33}]} +{category:Confections,cheapest-products:[{UnitsInStock:25,ProductName:Teatime Chocolate Biscuits,UnitPrice:9.2,Category:Confections,ProductId:19}]} +{category:Grains/Cereals,cheapest-products:[{UnitsInStock:38,ProductName:Filo Mix,UnitPrice:7,Category:Grains/Cereals,ProductId:52}]} +".NormalizeNewLines()).Or.StartsWith(@" +{category:Beverages,cheapest-products:[{Category:Beverages,UnitPrice:4.5,ProductId:24,ProductName:Guaraná Fantástica,UnitsInStock:20}]} +{category:Condiments,cheapest-products:[{Category:Condiments,UnitPrice:10,ProductId:3,ProductName:Aniseed Syrup,UnitsInStock:13}]} +{category:Produce,cheapest-products:[{Category:Produce,UnitPrice:10,ProductId:74,ProductName:Longlife Tofu,UnitsInStock:4}]} +{category:Meat/Poultry,cheapest-products:[{Category:Meat/Poultry,UnitPrice:7.45,ProductId:54,ProductName:Tourtière,UnitsInStock:21}]} +{category:Seafood,cheapest-products:[{Category:Seafood,UnitPrice:6,ProductId:13,ProductName:Konbu,UnitsInStock:24}]} +{category:Dairy Products,cheapest-products:[{Category:Dairy Products,UnitPrice:2.5,ProductId:33,ProductName:Geitost,UnitsInStock:112}]} +{category:Confections,cheapest-products:[{Category:Confections,UnitPrice:9.2,ProductId:19,ProductName:Teatime Chocolate Biscuits,UnitsInStock:25}]} +{category:Grains/Cereals,cheapest-products:[{Category:Grains/Cereals,UnitPrice:7,ProductId:52,ProductName:Filo Mix,UnitsInStock:38}]} +".NormalizeNewLines())); + } + + [Test] + public void linq85() + { + Assert.That(render(@" +(defn linq85 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (max-num) ) + (setq max-num (apply max numbers)) + (println ""The maximum number is "" max-num) + )) +(linq85)"), + + Does.StartWith(@" +The maximum number is 9 +".NormalizeNewLines())); + } + + [Test] + public void linq86() + { + Assert.That(render(@" +(defn linq82 [] + (let ( (words [""cherry"", ""apple"", ""blueberry""]) + (shortest-word) ) + (setq longest-word (apply max (map count words))) + (println ""The longest word is "" longest-word "" characters long."") + )) +(linq82)"), + + Does.StartWith(@" +The longest word is 9 characters long. +".NormalizeNewLines())); + } + + [Test] + public void linq87() + { + Assert.That(render(@" +(defn linq87 [] + (let ( (categories + (map #(it { + :category (.Key %) + :most-expensive-price (apply max (map .UnitPrice %)) + }) + (group-by .Category products-list))) ) + (doseq (x categories) (dump-inline x)) + )) +(linq87)"), + + Does.StartWith(@" +{category:Beverages,most-expensive-price:263.5} +{category:Condiments,most-expensive-price:43.9} +{category:Produce,most-expensive-price:53} +{category:Meat/Poultry,most-expensive-price:123.79} +{category:Seafood,most-expensive-price:62.5} +{category:Dairy Products,most-expensive-price:55} +{category:Confections,most-expensive-price:81} +{category:Grains/Cereals,most-expensive-price:38} +".NormalizeNewLines())); + } + + [Test] + public void linq88() + { + Assert.That(render(@" +(defn linq88 [] + (let ( (categories + (map (fn [g] ( + let ( (max-price (apply max (map .UnitPrice g))) ) + { + :category (.Key g) + :most-expensive-products (where #(= (.UnitPrice %) max-price) g) + })) + (group-by .Category products-list))) ) + (doseq (x categories) (dump-inline x)) + )) +(linq88)"), + + Does.StartWith(@" +{category:Beverages,most-expensive-products:[{Category:Beverages,UnitPrice:263.5,ProductId:38,ProductName:Côte de Blaye,UnitsInStock:17}]} +{category:Condiments,most-expensive-products:[{Category:Condiments,UnitPrice:43.9,ProductId:63,ProductName:Vegie-spread,UnitsInStock:24}]} +{category:Produce,most-expensive-products:[{Category:Produce,UnitPrice:53,ProductId:51,ProductName:Manjimup Dried Apples,UnitsInStock:20}]} +{category:Meat/Poultry,most-expensive-products:[{Category:Meat/Poultry,UnitPrice:123.79,ProductId:29,ProductName:Thüringer Rostbratwurst,UnitsInStock:0}]} +{category:Seafood,most-expensive-products:[{Category:Seafood,UnitPrice:62.5,ProductId:18,ProductName:Carnarvon Tigers,UnitsInStock:42}]} +{category:Dairy Products,most-expensive-products:[{Category:Dairy Products,UnitPrice:55,ProductId:59,ProductName:Raclette Courdavault,UnitsInStock:79}]} +{category:Confections,most-expensive-products:[{Category:Confections,UnitPrice:81,ProductId:20,ProductName:Sir Rodney's Marmalade,UnitsInStock:40}]} +{category:Grains/Cereals,most-expensive-products:[{Category:Grains/Cereals,UnitPrice:38,ProductId:56,ProductName:Gnocchi di nonna Alice,UnitsInStock:21}]} +".NormalizeNewLines()).Or.StartsWith(@" +{category:Beverages,most-expensive-products:[{UnitsInStock:17,ProductName:Côte de Blaye,UnitPrice:263.5,Category:Beverages,ProductId:38}]} +{category:Condiments,most-expensive-products:[{UnitsInStock:24,ProductName:Vegie-spread,UnitPrice:43.9,Category:Condiments,ProductId:63}]} +{category:Produce,most-expensive-products:[{UnitsInStock:20,ProductName:Manjimup Dried Apples,UnitPrice:53,Category:Produce,ProductId:51}]} +{category:Meat/Poultry,most-expensive-products:[{UnitsInStock:0,ProductName:Thüringer Rostbratwurst,UnitPrice:123.79,Category:Meat/Poultry,ProductId:29}]} +{category:Seafood,most-expensive-products:[{UnitsInStock:42,ProductName:Carnarvon Tigers,UnitPrice:62.5,Category:Seafood,ProductId:18}]} +{category:Dairy Products,most-expensive-products:[{UnitsInStock:79,ProductName:Raclette Courdavault,UnitPrice:55,Category:Dairy Products,ProductId:59}]} +{category:Confections,most-expensive-products:[{UnitsInStock:40,ProductName:Sir Rodney's Marmalade,UnitPrice:81,Category:Confections,ProductId:20}]} +{category:Grains/Cereals,most-expensive-products:[{UnitsInStock:21,ProductName:Gnocchi di nonna Alice,UnitPrice:38,Category:Grains/Cereals,ProductId:56}]} +".NormalizeNewLines()).Or.StartsWith(@" +{category:Beverages,most-expensive-products:[{ProductId:38,ProductName:Côte de Blaye,Category:Beverages,UnitPrice:263.5,UnitsInStock:17}]} +{category:Condiments,most-expensive-products:[{ProductId:63,ProductName:Vegie-spread,Category:Condiments,UnitPrice:43.9,UnitsInStock:24}]} +{category:Produce,most-expensive-products:[{ProductId:51,ProductName:Manjimup Dried Apples,Category:Produce,UnitPrice:53,UnitsInStock:20}]} +{category:Meat/Poultry,most-expensive-products:[{ProductId:29,ProductName:Thüringer Rostbratwurst,Category:Meat/Poultry,UnitPrice:123.79,UnitsInStock:0}]} +{category:Seafood,most-expensive-products:[{ProductId:18,ProductName:Carnarvon Tigers,Category:Seafood,UnitPrice:62.5,UnitsInStock:42}]} +{category:Dairy Products,most-expensive-products:[{ProductId:59,ProductName:Raclette Courdavault,Category:Dairy Products,UnitPrice:55,UnitsInStock:79}]} +{category:Confections,most-expensive-products:[{ProductId:20,ProductName:Sir Rodney's Marmalade,Category:Confections,UnitPrice:81,UnitsInStock:40}]} +{category:Grains/Cereals,most-expensive-products:[{ProductId:56,ProductName:Gnocchi di nonna Alice,Category:Grains/Cereals,UnitPrice:38,UnitsInStock:21}]} +".NormalizeNewLines())); + } + + [Test] + public void linq89() + { + Assert.That(render(@" +(defn linq89 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (avg) ) + (setq avg (average numbers)) + (println ""The average number is "" avg) + )) +(linq89)"), + + Does.StartWith(@" +The average number is 4.5 +".NormalizeNewLines())); + } + + [Test] + public void linq90() + { + Assert.That(render(@" +(defn linq90 [] + (let ( (words [""cherry"", ""apple"", ""blueberry""]) + (average-length) ) + (setq average-length (apply average (map count words))) + (println ""The average word length is "" average-length "" characters."") + )) +(linq90)"), + + Does.StartWith(@" +The average word length is 6.6666666666666 +".NormalizeNewLines())); + } + + [Test] + public void linq91() + { + Assert.That(render(@" +(defn linq91 [] + (let ( (categories + (map #(it { + :category (.Key %) + :average-price (apply average (map .UnitPrice %)) + }) + (group-by .Category products-list))) ) + (doseq (x categories) (dump-inline x)) + )) +(linq91)") + .Replace("37.979166666666664","37.9791666666667") //.NET Core 3.1 + .Replace("54.00666666666667","54.0066666666667"), + + Does.StartWith(@" +{category:Beverages,average-price:37.9791666666667} +{category:Condiments,average-price:23.0625} +{category:Produce,average-price:32.37} +{category:Meat/Poultry,average-price:54.0066666666667} +{category:Seafood,average-price:20.6825} +{category:Dairy Products,average-price:28.73} +{category:Confections,average-price:25.16} +{category:Grains/Cereals,average-price:20.25} +".NormalizeNewLines())); + } + + [Test] + public void linq92() + { + Assert.That(render(@" +(defn linq92 [] + (let ( (dbls [1.7 2.3 1.9 4.1 2.9]) + (product) ) + (setq product (reduce * dbls)) + (println ""Total product of all numbers: "" product) + )) +(linq92)"), + + Does.StartWith(@" +Total product of all numbers: 88.3308".NormalizeNewLines())); + } + + [Test] + public void linq93() + { + Assert.That(render(@" +(defn linq93 [] + (let ( (start-balance 100) + (attempted-withdrawls [20 10 40 50 10 70 30]) + (end-balance) ) + (setq end-balance (reduce (fn [balance withdrawl] (if (> balance withdrawl) (- balance withdrawl) balance)) + attempted-withdrawls start-balance)) + (println ""Ending balance: "" end-balance) + )) +(linq93)"), + + Does.StartWith(@" +Ending balance: 20 +".NormalizeNewLines())); + } + + [Test] + public void linq94() + { + Assert.That(render(@" +(defn linq94 [] + (let ( (numbers-a [0 2 4 5 6 8 9]) + (numbers-b [1 3 5 7 8]) ) + (setq all-numbers (flatten [numbers-a numbers-b])) + (println ""All numbers from both arrays:"") + (doseq (n all-numbers) (println n)) + )) +(linq94)"), + + Does.StartWith(@" +All numbers from both arrays: +0 +2 +4 +5 +6 +8 +9 +1 +3 +5 +7 +8 +".NormalizeNewLines())); + } + + [Test] + public void linq95() + { + Assert.That(render(@" +(defn linq95 [] + (let ( (customer-names (map .CompanyName customers-list)) + (product-names (map .ProductName products-list)) + (all-names) ) + (setq all-names (flatten [customer-names product-names])) + (println ""Customer and product names:"") + (doseq (x all-names) (println x)) + )) +(linq95)"), + + Does.StartWith(@" +Customer and product names: +Alfreds Futterkiste +Ana Trujillo Emparedados y helados +Antonio Moreno Taquería +Around the Horn +Berglunds snabbköp +Blauer See Delikatessen +".NormalizeNewLines())); + } + + [Test] + public void linq96() + { + Assert.That(render(@" +(defn linq96 [] + (let ( (words-a [""cherry"" ""apple"" ""blueberry""]) + (words-b [""cherry"" ""apple"" ""blueberry""]) ) + + (setq match (/sequenceEquals words-a words-b)) + (println ""The sequences match: "" match) + )) +(linq96)"), + + Does.StartWith(@" +The sequences match: True +".NormalizeNewLines())); + } + + [Test] + public void linq97() + { + Assert.That(render(@" +(defn linq97 [] + (let ( (words-a [""cherry"" ""apple"" ""blueberry""]) + (words-b [""apple"" ""blueberry"" ""cherry""]) ) + + (setq match (/sequenceEquals words-a words-b)) + (println ""The sequences match: "" match) + )) +(linq97)"), + + Does.StartWith(@" +The sequences match: nil +".NormalizeNewLines())); + } + + [Test] + public void linq99() + { + Assert.That(render(@" +(defn linq99 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (i 0) ) + (setq q (map #(it (fn [] (f++ i))) numbers)) + (doseq (v q) (println ""v = "" (v) "", i = "" i)) + )) +(linq99)"), + + Does.StartWith(@" +v = 0, i = 1 +v = 1, i = 2 +v = 2, i = 3 +v = 3, i = 4 +v = 4, i = 5 +v = 5, i = 6 +v = 6, i = 7 +v = 7, i = 8 +v = 8, i = 9 +v = 9, i = 10 +".NormalizeNewLines())); + } + + [Test] + public void linq100() + { + Assert.That(render(@" +(defn linq100 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) + (i 0) ) + (setq q (map #(it (f++ i)) numbers)) + (doseq (v q) (println ""v = "" v "", i = "" i)) + )) +(linq100)"), + + Does.StartWith(@" +v = 0, i = 10 +v = 1, i = 10 +v = 2, i = 10 +v = 3, i = 10 +v = 4, i = 10 +v = 5, i = 10 +v = 6, i = 10 +v = 7, i = 10 +v = 8, i = 10 +v = 9, i = 10 +".NormalizeNewLines())); + } + + [Test] + public void linq101() + { + Assert.That(render(@" +(defn linq101 [] + (let ( (numbers [5 4 1 3 9 8 6 7 2 0]) ) + + (defn low-numbers [] + (where #(<= % 3) numbers)) + + (println ""First run numbers <= 3:"") + (doseq (n (low-numbers)) (println n)) + + (setq numbers (map #(- %) numbers)) + + (println ""Second run numbers <= 3"") + (doseq (n (low-numbers)) (println n)) + )) +(linq101)"), + + Does.StartWith(@" +First run numbers <= 3: +1 +3 +2 +0 +Second run numbers <= 3 +-5 +-4 +-1 +-3 +-9 +-8 +-6 +-7 +-2 +0 +".NormalizeNewLines())); + } + + [Test] + public void test() + { + print("(where #(<= % 3) [-5 -4 1])"); + print(@"(setq numbers [5 4 1 3 9 8 6 7 2 0]) + (defn low-numbers [] + (where #(<= % 3) (map #(- %) numbers))) + (low-numbers)"); + +// print(@"(setq numbers '(5 4 1 3 9 8 6 7 2 0)) (take-while (fn (c) (>= (1st c) (2nd c))) (mapcar-index cons numbers))"); + +// print("(setq numbers-a '(1 2 3)) (setq numbers-b '(3 4 5)) (zip (fn (a b) { :a a :b b }) numbers-a numbers-b)"); +// print("(map #(* 2 %) (range 10))"); +// print("(fn (x) (.ProductName x))"); +// print(@"(fn (x) (new-map (list ""ProductName"" (.ProductName x)) ))"); + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispTests.cs new file mode 100644 index 00000000000..7c172b0d2bb --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptLispTests.cs @@ -0,0 +1,1024 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using NUnit.Framework; +using ServiceStack.Logging; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptLispTests + { + [Test] + public void Can_eval_fib_lisp() + { + var lisp = @" +(defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2)) ) + )) +"; + + try + { + var lispCtx = Lisp.CreateInterpreter(); + + var sExpressions = Lisp.Parse(lisp); + var x = lispCtx.Eval(sExpressions); + $"{x}".Print(); + + sExpressions = Lisp.Parse("(fib 15)"); + x = lispCtx.Eval(sExpressions); + + $"{x}".Print(); + Assert.That((int)x, Is.EqualTo(987)); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + [Test] + public void Can_eval_lisp_in_lisp() + { + var lisp = @" +;;; A circular Lisp interpreter in Common/Emacs/Nukata Lisp +;;; by SUZUKI Hisao on H28.8/10, H29.3/13 +;;; cf. Zick Standard Lisp (https://github.com/zick/ZickStandardLisp) + +(progn + ;; Expr: (EXPR environment (symbol...) expression...) + ;; Subr: (SUBR . function) + ;; Environment: ((symbol . value)...) + ;; N.B. Expr has its own environment since this Lisp is lexically scoped. + + ;; Language-specific Hacks + (setq funcall (lambda (f x) (f x))) ; for Nukata Lisp and this Lisp + (setq max-lisp-eval-depth 10000) ; for Emacs Lisp + (setq max-specpdl-size 7000) ; for Emacs Lisp + + ;; The global environment of this Lisp + (setq global-env + (list '(*version* . (1.2 ""Lisp"" ""circlisp"")) + (cons 'car + (cons 'SUBR (lambda (x) (car (car x))))) + (cons 'cdr + (cons 'SUBR (lambda (x) (cdr (car x))))) + (cons 'cons + (cons 'SUBR (lambda (x) (cons (car x) (cadr% x))))) + (cons 'eq + (cons 'SUBR (lambda (x) (eq (car x) (cadr% x))))) + (cons 'atom + (cons 'SUBR (lambda (x) (atom (car x))))) + (cons 'rplaca + (cons 'SUBR (lambda (x) (rplaca (car x) (cadr% x))))) + (cons 'rplacd + (cons 'SUBR (lambda (x) (rplacd (car x) (cadr% x))))) + (cons 'list + (cons 'SUBR (lambda (x) x))) + (cons '+ + (cons 'SUBR (lambda (x) (+ (car x) (cadr% x))))) + (cons '* + (cons 'SUBR (lambda (x) (* (car x) (cadr% x))))) + (cons '- + (cons 'SUBR (lambda (x) (- (car x) (cadr% x))))) + (cons 'truncate + (cons 'SUBR (lambda (x) (truncate (car x) (cadr% x))))) + (cons 'mod + (cons 'SUBR (lambda (x) (mod (car x) (cadr% x))))) + (cons '= + (cons 'SUBR (lambda (x) (= (car x) (cadr% x))))) + (cons '< + (cons 'SUBR (lambda (x) (< (car x) (cadr% x))))) + (cons 'print + (cons 'SUBR (lambda (x) (print (car x))))) + (cons 'apply + (cons 'SUBR (lambda (x) (apply% (car x) (cadr% x))))) + (cons 'eval + (cons 'SUBR (lambda (x) (eval% (car x) global-env)))))) + + (defun caar% (x) (car (car x))) + (defun cadr% (x) (car (cdr x))) + (defun cddr% (x) (cdr (cdr x))) + (defun caddr% (x) (car (cdr (cdr x)))) + (defun cdddr% (x) (cdr (cdr (cdr x)))) + (defun cadddr% (x) (car (cdr (cdr (cdr x))))) + + (defun assq% (key alist) ; cf. Emacs/Nukata Lisp + (if alist + (if (eq key (caar% alist)) + (car alist) + (assq% key (cdr alist))) + nil)) + + (defun pairlis% (keys data alist) ; cf. Common Lisp + (if keys + (cons (cons (car keys) (car data)) + (pairlis% (cdr keys) (cdr data) alist)) + alist)) + + ;; Define symbol as value in the global environment. + (defun global-def (sym val) + (rplacd global-env + (cons (car global-env) + (cdr global-env))) + (rplaca global-env + (cons sym val))) + + (defun eval% (e env) + (if (atom e) + ((lambda (var) + (if var + (cdr var) + e)) + (assq% e env)) + (if (eq (car e) 'quote) ; (quote e) + (cadr% e) + (if (eq (car e) 'if) ; (if e e e) + (if (eval% (cadr% e) env) + (eval% (caddr% e) env) + (eval% (cadddr% e) env)) + (if (eq (car e) 'progn) ; (progn e...) + (eval-progn (cdr e) env nil) + (if (eq (car e) 'lambda) ; (lambda (v...) e...) + (make-closure env (cdr e)) + (if (eq (car e) 'defun) ; (defun f (v...) e...) + (global-def (cadr% e) + (make-closure env (cddr% e))) + (if (eq (car e) 'setq) ; (setq v e) + ((lambda (var value) + (if var + (rplacd var value) + (global-def (cadr% e) value)) + value) + (assq% (cadr% e) env) + (eval% (caddr% e) env)) + (apply% (eval% (car e) env) ; (f e...) + (evlis (cdr e) env)))))))))) + + ;; (make-closure env '((v...) e...)) => (EXPR env (v...) e...) + (defun make-closure (env ve) + (cons 'EXPR + (cons env ve))) + + ;; (eval-progn '((+ 1 2) 3 (+ 4 5)) global-env nil) => 9 + (defun eval-progn (x env result) + (if x + (if (cdr x) + (eval-progn (cdr x) + env + (eval% (car x) env)) + (eval% (car x) env)) + result)) + + ;; (evlis '((+ 1 2) 3 (+ 4 5)) global-env) => (3 3 9) + (defun evlis (x env) + (if x + (cons (eval% (car x) env) + (evlis (cdr x) env)) + nil)) + + (defun apply% (fun arg) + (if (eq (car fun) 'EXPR) ; (EXPR env (v...) e...) + (eval-progn (cdddr% fun) + (pairlis% (caddr% fun) + arg + (cadr% fun)) + nil) + (if (eq (car fun) 'SUBR) ; (SUBR . f) + (funcall (cdr fun) arg) + fun))) + + (defun global-eval (e) + (eval% e global-env)) + + (global-eval (quote + +;; -- WRITE YOUR EXPRESSION HERE -- +(progn + (defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2))))) + (print (fib 10))) +;; -------------------------------- +))) +"; + + try + { + var lispCtx = Lisp.CreateInterpreter(); + + var sExpressions = Lisp.Parse(lisp); + var x = lispCtx.Eval(sExpressions); + Assert.That((int)x, Is.EqualTo(89)); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + [Test] + public void Can_min_max_int_long_double_values() + { + var lispCtx = Lisp.CreateInterpreter(); + + Assert.That((int)lispCtx.Eval(Lisp.Parse("(min 1 2)")), Is.EqualTo(1)); + Assert.That((int)lispCtx.Eval(Lisp.Parse("(max 1 2)")), Is.EqualTo(2)); + + Assert.That((double)lispCtx.Eval(Lisp.Parse("(min 1.0 2.0)")), Is.EqualTo(1.0)); + Assert.That((double)lispCtx.Eval(Lisp.Parse("(max 1.0 2.0)")), Is.EqualTo(2.0)); + + Assert.That((long)lispCtx.Eval(Lisp.Parse($"(min {int.MaxValue + 1L} {int.MaxValue + 2L})")), Is.EqualTo(int.MaxValue + 1L)); + Assert.That((long)lispCtx.Eval(Lisp.Parse($"(max {int.MaxValue + 1L} {int.MaxValue + 2L})")), Is.EqualTo(int.MaxValue + 2L)); + } + + private static ScriptContext LispScriptContext(Dictionary<string, object> args = null) + { + var context = new ScriptContext { + ScriptLanguages = {ScriptLisp.Language} + }.Init(); + args?.Each((k,v) => context.Args[k] = v); + return context; + } + + [Test] + public void Can_eval_lisp_in_ScriptPage() + { + var context = LispScriptContext(); + + var script = @" +BEGIN LISP + +```lisp +(defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2)) ) + )) + +(fib 15) +``` + +AFTER LISP +"; + + var output = context.EvaluateScript(script); + var expected = @" +BEGIN LISP + +987 + +AFTER LISP".NormalizeNewLines(); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(expected)); + + // Can run twice with identical results + output = context.EvaluateScript(script); + Assert.That(output.NormalizeNewLines(), Is.EqualTo(expected)); + } + + [Test] + public void Can_get_and_export_script_value() + { + var context = LispScriptContext(new ObjectDictionary { ["contextArg"] = 1 }); + + var output = context.EvaluateScript(@" +{{ 2 | assignToGlobal => pageResultArg }} +{{ 3 | to => scopeArg }} +```lisp +(+ contextArg pageResultArg scopeArg) +```"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("6")); + + output = context.EvaluateScript(@" +{{ 2 | assignToGlobal => pageResultArg }} +{{ 3 | to => scopeArg }} +```lisp +(export retVal (+ contextArg pageResultArg scopeArg) + newVal 2) +``` +Global: {{ retVal + newVal }} +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("Global: 8")); + } + + [Test] + public void Can_call_exported_delegate() + { + var context = LispScriptContext(); + + string output; + output = context.EvaluateScript(@" +{{ 1 | to => scopeArg }} +```lisp|q +(setq lispArg 2) +(setq localArg 3) +(defn lispAdd [a b] (+ a b localArg)) +(export exportedArg lispArg + lispAdd (to-delegate lispAdd)) +``` +Global: {{ lispAdd(scopeArg, exportedArg) }} +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("Global: 6")); + + // def returns null output + output = context.EvaluateScript(@" +{{ 1 | to => scopeArg }} +```lisp +(def lispArg 2) +(def localArg 3) +(def lispAdd #(+ %1 %2 localArg)) +(export exportedArg lispArg + lispAdd (to-delegate lispAdd)) +``` +Global: {{ lispAdd(scopeArg, exportedArg) }} +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("Global: 6")); + + } + + + [Test] + public void Does_support_quiet_blocks() + { + var context = LispScriptContext(new ObjectDictionary { ["contextArg"] = 1 }); + + var output = context.EvaluateScript(@" +{{ 2 | assignToGlobal => pageResultArg }} +{{ 3 | to => scopeArg }} +```lisp +(setq retVal (+ contextArg pageResultArg scopeArg)) +(setq newVal 2) +(export retVal retVal + newVal newVal) +``` +Global: {{ retVal + newVal }} +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("6\n2\nGlobal: 8")); + + output = context.EvaluateScript(@" +{{ 2 | assignToGlobal => pageResultArg }} +{{ 3 | to => scopeArg }} +```lisp|quiet +(setq retVal (+ contextArg pageResultArg scopeArg)) +(setq newVal 2) +(export retVal retVal + newVal newVal) +``` +Global: {{ retVal + newVal }} +"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("Global: 8")); + } + + [Test] + public void Can_convert_IEnumerable_to_and_from_cons() + { + var context = LispScriptContext(new ObjectDictionary { + ["numArray"] = new[] { 1, 2, 3 }, + ["numList"] = new[] { 1, 2, 3 }.ToList(), + ["numSet"] = new[] { 1, 2, 3 }.ToSet(), + }); + + string render(string lisp) => context.EvaluateScript(lisp).NormalizeNewLines(); + + Assert.That(render(@" +```lisp +(export array1 (map 1+ '(1 2 3)) ) +``` +SUM: {{ array1.sum() }} +"), Is.EqualTo("SUM: 9")); + + Assert.That(render(@" +```lisp +(export array1 (map 1+ '(1 2 3)) ) +``` +SUM: {{ array1.toList().sum() }} +"), Is.EqualTo("SUM: 9")); + + Assert.That(render(@" +```lisp +(export + sum (reduce + (mapcar 1+ (to-cons numArray))) +) +``` +SUM: {{ sum }} +"), Is.EqualTo("SUM: 9")); + + } + + private static ScriptContext LispNetContext(Dictionary<string, object> args = null) + { + var context = new ScriptContext { + ScriptLanguages = { + ScriptLisp.Language + }, + ScriptMethods = { + new ProtectedScripts(), + }, + AllowScriptingOfAllTypes = true, + ScriptNamespaces = { + "System", + "System.Collections.Generic", + "ServiceStack", + typeof(StaticLog).Namespace, + }, + ScriptTypes = { + typeof(DynamicInt), + } + }; + args?.Each((k,v) => context.Args[k] = v); + return context.Init(); + } + + [Test] + public void Can_call_delegates_LISP() + { + var context = LispNetContext(new ObjectDictionary { + ["stringNums"] = "1 2 3", + ["strings"] = new List<string> { " A ", " B ", " C " }, + ["argIncr"] = (Func<int,int>)(x => x + 1), + }); + + string render(string lisp) => context.RenderLisp(lisp).NormalizeNewLines(); + + Assert.That(render(@"(/join (map 1+ '(1 2 3)))"), Is.EqualTo("2,3,4")); + Assert.That(render(@"(/join (map 1+ '(1 2 3)) "", "")"), Is.EqualTo("2, 3, 4")); + Assert.That(render(@"(String/Join "","" (to-array (map 1+ '(1 2 3))))"), Is.EqualTo("2,3,4")); + Assert.That(render(@"((/F ""String.Join(string,object[])"") "","" (to-array (map 1+ '(1 2 3))))"), Is.EqualTo("2,3,4")); + Assert.That(render(@"(F ""String.Join(string,object[])"" "","" (map 1+ '(1 2 3)))"), Is.EqualTo("2,3,4")); + Assert.That(render(@"(F ""String.Join"" "","" (to-array (map 1+ '(1 2 3))))"), Is.EqualTo("2,3,4")); + + Assert.That(render(@"(/sum (map 1+ '(1 2 3)))"), Is.EqualTo("9")); + Assert.That(render(@"(/sum (map argIncr '(1 2 3)))"), Is.EqualTo("9")); + Assert.That(render(@"(/sum (map /incr '(1 2 3)))"), Is.EqualTo("9")); + + Assert.That(render(@"(/sum (map Math/Sqrt '(1 4 9)))"), Is.EqualTo("6")); + Assert.That(render(@"(/sum (map (/F ""Math.Sqrt"") '(1 4 9)))"), Is.EqualTo("6")); + + Assert.That(render(@"(/concat (map .Trim strings))"), Is.EqualTo("ABC")); + Assert.That(render(@"(/join (map .Trim strings))"), Is.EqualTo("A,B,C")); + Assert.That(render(@"(.Replace stringNums "" "" "", "")"), Is.EqualTo("1, 2, 3")); + Assert.That(render(@"(.Name (/typeof ""int""))"), Is.EqualTo("Int32")); + + Assert.That(context.RenderScript(@" +{{#function templateIncr(i) }} + i | incr | return +{{/function}} + +```lisp +(/sum (map templateIncr '(1 2 3))) +``` +").NormalizeNewLines(), Is.EqualTo("9")); + + Assert.That(context.RenderScript(@" +```code +#function codeIncr(i) + return (i.incr()) +/function +``` + +```lisp +(/sum (map codeIncr '(1 2 3))) +``` +").NormalizeNewLines(), Is.EqualTo("9")); + + Assert.That(context.RenderScript(@" +A + +```code +#function codeIncr(i) + return (i.incr()) +/function +``` + +B + +```lisp +(/sum (map codeIncr '(1 2 3))) +``` + +C +").NormalizeNewLines(), Is.EqualTo("A\n\n\nB\n\n9\nC")); + } + + [Test] + public void Can_create_Function_for_static_Methods_LISP() + { + var context = LispNetContext(new ObjectDictionary { + ["msg"] = "msg string" + }); + + string eval(string lisp) => context.EvaluateLisp<string>(lisp); + + context.RenderLisp(@"(setq writeln (/F ""Console.WriteLine(string)"")) (writeln msg)"); + + Assert.That(eval(@"(StaticLog/Clear) (StaticLog/Log msg) (return (StaticLog/AllLogs))"), + Is.EqualTo("msg string")); + Assert.That(eval(@"(StaticLog/Clear) (StaticLog/Log<int> msg) (return (StaticLog/AllLogs))"), + Is.EqualTo("Int32 msg string")); + Assert.That(eval(@"(StaticLog/Clear) ((/F ""StaticLog.Log"") msg) (return (StaticLog/AllLogs))"), + Is.EqualTo("msg string")); + } + + [Test] + public void Can_create_Function_for_generic_type_static_Methods_LISP() + { + var context = LispNetContext(new ObjectDictionary { + ["msg"] = "msg string" + }); + + string eval(string lisp) => context.EvaluateLisp<string>(lisp); + + Assert.That(eval(@"(GenericStaticLog<string>/Clear) (setq log (/F ""GenericStaticLog<string>.Log(string)"")) (log msg) (return (GenericStaticLog<string>/AllLogs))"), + Is.EqualTo("String msg string")); + Assert.That(eval(@"(GenericStaticLog<string>/Clear) (setq log (/F ""GenericStaticLog<string>.Log<int>(string)"")) (log msg) (return (GenericStaticLog<string>/AllLogs))"), + Is.EqualTo("String Int32 msg string")); + } + + + [Test] + public void Can_create_Function_for_instance_methods_LISP() + { + var context = LispNetContext(new ObjectDictionary { + ["msg"] = "msg string" + }); + + string eval(string lisp) => context.EvaluateLisp<string>(lisp); + + Assert.That(eval(@"(setq o (InstanceLog. ""instance"")) (.Log o msg) (return (.AllLogs o))"), + Is.EqualTo("instance msg string")); + } + + [Test] + public void Can_create_Type_from_registered_Script_Assembly_LISP() + { + var context = LispNetContext(); + + string render(string lisp) => context.RenderLisp(lisp).NormalizeNewLines(); + string eval(string lisp) => context.EvaluateLisp<string>(lisp); + + Assert.That(render("(.add (DynamicInt.) 1 2)"), Is.EqualTo("3")); + Assert.That(render(@"(.add (new ""DynamicInt"") 1 2)"), Is.EqualTo("3")); + Assert.That(render(@"(.add (new (/typeof ""DynamicInt"")) 1 2)"), Is.EqualTo("3")); + Assert.That(render(@"(.add (C ""DynamicInt()"") 1 2)"), Is.EqualTo("3")); + Assert.That(render(@"(.add ((/C ""DynamicInt()"")) 1 2)"), Is.EqualTo("3")); + + Assert.That(render("(.GetTotal (Ints. 1 2))"), Is.EqualTo("3")); + + Assert.That(render(@"(.ToString (new ""Adder"" ""A""))"), Is.EqualTo($"string: A")); + Assert.That(render(@"(.ToString (C ""Adder(string)"" ""A""))"), Is.EqualTo($"string: A")); + Assert.That(render(@"(.ToString ((/C ""Adder(string)"") ""A""))"), Is.EqualTo($"string: A")); + + Assert.That(eval("(setq ints (Ints. 1 2)) (.AddA ints 3) (.AddA ints 4) (return (.GetTotal ints))"), Is.EqualTo("10")); + + //Assert.That(render("(.GetTotal (doto (Ints. 1 2) (.C 3) (.D 4)) )"), Is.EqualTo("10")); + } + + [Test] + public void Can_create_generic_types_LISP() + { + var context = LispNetContext(); + + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + Assert.That(eval(@"((/C ""Tuple<String,int>(String,int)"") ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + Assert.That(eval(@"(C ""Tuple<String,int>(String,int)"" ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + + Assert.That(eval(@"((/C ""Tuple< String, int >( String, int )"") ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + Assert.That(eval(@"(C ""Tuple< String, int >( String, int )"" ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + } + + [Test] + public void Can_call_generic_methods_LISP() + { + + var context = LispNetContext(); + + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + Assert.That(eval(@"((/F ""Tuple.Create<String,int>(String,int)"") ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + Assert.That(eval(@"(F ""Tuple.Create<String,int>(String,int)"" ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + + Assert.That(eval(@"((/F ""Tuple.Create< String , int >( String , int )"") ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + Assert.That(eval(@"(F ""Tuple.Create< String , int >( String , int )"" ""A"" 1)"), + Is.EqualTo(new Tuple<string, int>("A", 1))); + } + + [Test] + public void Can_create_type_with_constructor_arguments_LISP() + { + var context = LispNetContext(); + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + Assert.That(eval("(.GetTotal (Ints. 1 2))"), Is.EqualTo(3)); + Assert.That(eval("(.GetTotal (/set (Ints. 1 2) { :C 3 :D 4 }))"), Is.EqualTo(10)); + Assert.That(eval("(.GetTotal (set (Ints. 1 2) { :C 3 :D 4 }))"), Is.EqualTo(10)); + } + + [Test] + public void Can_call_inner_class_properties_LISP() + { + var context = LispNetContext(new ObjectDictionary { + ["o"] = new StaticLog(), + ["o1"] = new StaticLog.Inner1(), + }); + + string result = null; + + Assert.That(context.EvaluateLisp<string>("(return (StaticLog/Prop))"), Is.EqualTo("StaticLog.Prop")); + Assert.That(context.EvaluateLisp<string>("(return (StaticLog/Field))"), Is.EqualTo("StaticLog.Field")); + Assert.That(context.EvaluateLisp<string>("(return (StaticLog/Const))"), Is.EqualTo("StaticLog.Const")); + + Assert.That(context.EvaluateLisp<string>("(return (StaticLog.Inner1/Prop1))"), Is.EqualTo("StaticLog.Inner1.Prop1")); + Assert.That(context.EvaluateLisp<string>("(return (StaticLog.Inner1/Field1))"), Is.EqualTo("StaticLog.Inner1.Field1")); + Assert.That(context.EvaluateLisp<string>("(return (StaticLog.Inner1/Const1))"), Is.EqualTo("StaticLog.Inner1.Const1")); + + Assert.That(context.EvaluateLisp<string>("(return (StaticLog.Inner1.Inner2/Prop2))"), Is.EqualTo("StaticLog.Inner1.Inner2.Prop2")); + Assert.That(context.EvaluateLisp<string>("(return (StaticLog.Inner1.Inner2/Field2))"), Is.EqualTo("StaticLog.Inner1.Inner2.Field2")); + Assert.That(context.EvaluateLisp<string>("(return (StaticLog.Inner1.Inner2/Const2))"), Is.EqualTo("StaticLog.Inner1.Inner2.Const2")); + + Assert.That(context.EvaluateLisp<string>("(return (.InstanceProp o))"), Is.EqualTo("StaticLog.InstanceProp")); + Assert.That(context.EvaluateLisp<string>("(return (.InstanceField o))"), Is.EqualTo("StaticLog.InstanceField")); + + Assert.That(context.EvaluateLisp<string>("(return (.InstanceProp1 o1))"), Is.EqualTo("StaticLog.Inner1.InstanceProp1")); + Assert.That(context.EvaluateLisp<string>("(return (.InstanceField1 o1))"), Is.EqualTo("StaticLog.Inner1.InstanceField1")); + } + + [Test] + public void Can_Call_registered_IOC_Dependency_LISP() + { + var context = LispNetContext(); + context.ScriptTypes.Add(typeof(InstanceLog)); + context.Container.AddTransient(() => new InstanceLog("ioc")); + context.Init(); + + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + var result = eval(@" + (def o (/resolve ""InstanceLog"")) + (.Log o ""arg"") + (.AllLogs o)".NormalizeNewLines()); + + Assert.That(result, Is.EqualTo("ioc arg")); + } + + [Test] + public void Can_map_on_IEnumerables() + { + var context = LispScriptContext(new ObjectDictionary { + ["numArray"] = new[] { 1, 2, 3 }, + ["numList"] = new[] { 1, 2, 3 }.ToList(), + ["numSet"] = new[] { 1, 2, 3 }.ToSet(), + }); + + string render(string lisp) => context.RenderLisp(lisp).NormalizeNewLines(); + + Assert.That(render(@"(reduce + (mapcar 1+ '(1 2 3)))"), Is.EqualTo("9")); + + // sum can do mapcar + all num's + Assert.That(render(@"(sum (mapcar 1+ '(1 2 3)))"), Is.EqualTo("9")); + Assert.That(render(@"(sum (mapcar 1+ '(1.1 2 3)))"), Is.EqualTo("9.1")); + Assert.That(render(@"(sum (mapcar 1+ '(1 2 3.1)))"), Is.EqualTo("9.1")); + + Assert.That(render(@"(sum (map 1+ '(1 2 3)))"), Is.EqualTo("9")); + Assert.That(render(@"(sum (map 1+ numArray))"), Is.EqualTo("9")); + Assert.That(render(@"(sum (map 1+ numList))"), Is.EqualTo("9")); + Assert.That(render(@"(sum (map 1+ numSet))"), Is.EqualTo("9")); + + Assert.That(render(@"(defmacro 2+ (n) `(+ ,n 2)) (sum (map 2+ '(1 2 3)))"), Is.EqualTo("12")); + } + + [Test] + public void Does_print_to_Output_Stream() + { + var context = LispScriptContext(); + + Assert.That(context.RenderLisp(@"10 (let () (println ""A"")(print '(1 2 3)) (terpri) nil) 20").NormalizeNewLines(), + Is.EqualTo("10\nA\n(1 2 3)\n20")); + + Assert.That(context.RenderLisp(@"10 (/write ""A"") 20").Replace("\r",""), + Is.EqualTo("10\nA20\n")); + } + + [Test] + public void Does_limit_max_iterations() + { + var context = LispScriptContext(); + + // Context.MaxIterations = 1000000 but LISP Eval can be called 10x+ for evaluating 1 op + context.RenderLisp(@"(dotimes (i 90000) (print i))"); + + // Count resets per LISP Statement Block + context.EvaluateScript(@" +```lisp +(dotimes (i 90000) (print i)) +``` + +```lisp +(dotimes (i 90000) (print i)) +``` +"); + + try + { + context.RenderLisp("(dotimes (i 100001) (print i))"); + Assert.Fail("Should Throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException is NotSupportedException); + } + + try + { + context.EvaluateScript(@" + ```lisp + (dotimes (i 100001) (print i)) + ``` + "); + Assert.Fail("Should Throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException is NotSupportedException); + } + + try + { + context.RenderLisp(@" + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 10000) (print i)) + (dotimes (i 1) (print i)) + "); + Assert.Fail("Should Throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException is NotSupportedException); + } + + // 23 Max =~ 92735 iterations + context.RenderLisp(@" + (defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2)) ) + )) + (fib 23) + "); + + try + { + // 24 Max =~ 150049 iterations + context.RenderLisp(@" + (defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2)) ) + )) + (fib 24) + "); + Assert.Fail("Should Throw"); + } + catch (Exception e) + { + Console.WriteLine(e); + Assert.That(e.InnerException is NotSupportedException); + } + } + + [Test] + public void Can_embed_lisp_expressions_in_Script() + { + var context = LispScriptContext(); + + Assert.That(context.RenderScript(@"1 + 1 = {|lisp (+ 1 1) |}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = 2.")); + Assert.That(context.RenderScript(@"1 + 1 = {|lisp (+ 1 1) |}, 3 + 4 = {|lisp (+ 3 4) |}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = 2, 3 + 4 = 7.")); + Assert.That(context.RenderScript(@"1 + 1 = {|lisp (+ 1 1) |}, 3 + 4 = {{ 3 + 4 }}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = 2, 3 + 4 = 7.")); + + Assert.That(context.RenderScript(@"1 + 1 = {|code 1 + 1 |}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = 2\n.")); //every code expression statement is printed with a new line + Assert.That(context.RenderScript(@"1 + 1 = {{ 1 + 1 }}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = 2.")); // but not for template expressions + + Assert.That(context.RenderScript(@"fib(10) = +{|lisp + +(defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2)) ) + )) + +(fib 10) + +|}.").NormalizeNewLines(), + Is.EqualTo("fib(10) = \n89\n.")); + + // no LISP configured + context = new ScriptContext().Init(); + + Assert.That(context.RenderScript(@"1 + 1 = {|lisp (+ 1 1) |}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = {|lisp (+ 1 1) |}.")); + Assert.That(context.RenderScript(@"1 + 1 = {|lisp (+ 1 1) |}, 3 + 4 = {|lisp (+ 3 4) |}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = {|lisp (+ 1 1) |}, 3 + 4 = {|lisp (+ 3 4) |}.")); + Assert.That(context.RenderScript(@"1 + 1 = {|lisp (+ 1 1) |}, 3 + 4 = {{ 3 + 4 }}.").NormalizeNewLines(), + Is.EqualTo("1 + 1 = {|lisp (+ 1 1) |}, 3 + 4 = 7.")); + } + + [Test] + public void Can_import_into_global_symbols() + { + var SExprs = Lisp.Parse("(fib 10)"); + + var lispCtx = Lisp.CreateInterpreter(); + + try + { + lispCtx.Eval(SExprs); + Assert.Fail("should throw"); + } + catch (LispEvalException e) {} + + Lisp.Import(@" +(defun fib (n) + (if (< n 2) + 1 + (+ (fib (- n 1)) + (fib (- n 2)) ) + )) +"); + lispCtx = Lisp.CreateInterpreter(); + + Assert.That(lispCtx.Eval(SExprs), Is.EqualTo(89)); + + Lisp.Reset(); + + lispCtx = Lisp.CreateInterpreter(); + try + { + lispCtx.Eval(SExprs); + Assert.Fail("should throw"); + } + catch (LispEvalException e) {} + } + + // https://news.ycombinator.com/rss + private const string rss = @"<rss version=""2.0""> + <channel> + <title>Hacker News</title> + <link>https://news.ycombinator.com/</link> + <description>Links for the intellectually curious, ranked by readers.</description> + <item> + <title>Breaking Pills</title> + <link>https://blog.plover.com/math/breaking-pills.html</link> + <pubDate>Fri, 20 Sep 2019 07:57:54 +0000</pubDate> + <comments>https://news.ycombinator.com/item?id=21024224</comments> + </item> + <item> + <title>A Gentle introduction to Kubernetes with more than just the basics</title> + <link>https://github.com/eon01/kubernetes-workshop</link> + <pubDate>Thu, 19 Sep 2019 22:04:14 +0000</pubDate> + <comments>https://news.ycombinator.com/item?id=21021184</comments> + </item> + <item> + <title>EasyOS: An experimental Linux distribution designed from scratch for containers</title> + <link>https://easyos.org</link> + <pubDate>Fri, 20 Sep 2019 07:17:07 +0000</pubDate> + <comments>https://news.ycombinator.com/item?id=21023989</comments> + </item> + </channel> +</rss>"; + + private ObjectDictionary expected = new ObjectDictionary { + ["title"] = "Hacker News", + ["link"] = "https://news.ycombinator.com/", + ["description"] = "Links for the intellectually curious, ranked by readers.", + ["items"] = new List<ObjectDictionary> { + new ObjectDictionary { + ["title"] = "Breaking Pills", + ["link"] = "https://blog.plover.com/math/breaking-pills.html", + ["pubDate"] = "Fri, 20 Sep 2019 07:57:54 +0000", + ["comments"] = "https://news.ycombinator.com/item?id=21024224", + }, + new ObjectDictionary { + ["title"] = "A Gentle introduction to Kubernetes with more than just the basics", + ["link"] = "https://github.com/eon01/kubernetes-workshop", + ["pubDate"] = "Thu, 19 Sep 2019 22:04:14 +0000", + ["comments"] = "https://news.ycombinator.com/item?id=21021184", + }, + new ObjectDictionary { + ["title"] = "EasyOS: An experimental Linux distribution designed from scratch for containers", + ["link"] = "https://easyos.org", + ["pubDate"] = "Fri, 20 Sep 2019 07:17:07 +0000", + ["comments"] = "https://news.ycombinator.com/item?id=21023989", + }, + }, + }; + + [Test] + public void Can_parse_rss_LISP() + { + ConsoleLogFactory.Configure(); + var context = LispNetContext(new Dictionary<string, object> { + ["rss"] = rss + }).Init(); + + object eval(string lisp) => context.EvaluateLisp($"(return (let () {lisp}))"); + + var result = eval(@" +(defn parse-rss [xml] + (let ( (to) (doc) (channel) (items) (el) ) + (def doc (System.Xml.Linq.XDocument/Parse xml)) + (def to (ObjectDictionary.)) + (def items (List<ObjectDictionary>.)) + (def channel (first (.Descendants doc ""channel""))) + (def el (XLinqExtensions/FirstElement channel)) + + (while (not= (.LocalName (.Name el)) ""item"") + (.Add to (.LocalName (.Name el)) (.Value el)) + (def el (XLinqExtensions/NextElement el))) + + (doseq (elItem (.Descendants channel ""item"")) + (def item (ObjectDictionary.)) + (def el (XLinqExtensions/FirstElement elItem)) + + (while el + (.Add item (.LocalName (.Name el)) (.Value el)) + (def el (XLinqExtensions/NextElement el))) + + (.Add items item)) + + (.Add to ""items"" (to-list items)) + to + ) +) +(parse-rss rss) +"); + Assert.That(result, Is.EqualTo(expected)); + + var to = new ObjectDictionary(); + var items = new List<ObjectDictionary>(); + + var doc = XDocument.Parse(rss); + var channel = doc.Descendants("channel").First(); + var el = channel.FirstElement(); + while (el.Name != "item") + { + to[el.Name.LocalName] = el.Value; + el = el.NextElement(); + } + + var elItems = channel.Descendants("item"); + foreach (var elItem in elItems) + { + var item = new ObjectDictionary(); + el = elItem.FirstElement(); + while (el != null) + { + item[el.Name.LocalName] = el.Value; + el = el.NextElement(); + } + items.Add(item); + } + + to["items"] = items; + Assert.That(to, Is.EqualTo(expected)); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptMethodsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptMethodsTests.cs new file mode 100644 index 00000000000..cfff0399c40 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptMethodsTests.cs @@ -0,0 +1,309 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.IO; +using ServiceStack.OrmLite; +using ServiceStack.OrmLite.Sqlite; +using ServiceStack.Script; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public interface IDep + { + string Greeting { get; set; } + + string SayHi(string name); + } + + public class Dep : IDep + { + public string Greeting { get; set; } = "Hello "; + + public string SayHi(string name) => Greeting + name; + } + + public class FilterExamples : ScriptMethods + { + public IDep Dep { get; set; } + + public IAppSettings AppSettings { get; set; } + + public string greet(string name) => Dep.SayHi(name); + + public int addInt(int target, int value) => + target + value; + } + + public class ScriptMethodsTests + { + [Test] + public void Can_Scan_FilterExamples_TemplateFilter() + { + var contexts = new[] + { + new ScriptContext + { + ScanTypes = {typeof(FilterExamples)} + }, + new ScriptContext + { + ScanAssemblies = {typeof(FilterExamples).Assembly} + }, + new ScriptContext + { + ScriptMethods = {new FilterExamples { Dep = new Dep()} } + }, + }; + + foreach (var context in contexts) + { + context.Container.AddSingleton<IDep>(() => new Dep()); + + context.Init(); + Assert.That(context.ScriptMethods.Count, Is.GreaterThanOrEqualTo(2)); + var filter = (FilterExamples)context.ScriptMethods.First(x => x is FilterExamples); + Assert.That(filter.Pages, Is.EqualTo(context.Pages)); + Assert.That(filter.Dep, Is.Not.Null); + } + } + + class AppHost : BasicAppHost + { + public AppHost() : base(typeof(AppHost).Assembly) {} + } + + [Test] + public void Does_scan_AppHost_Service_Assemblies_in_SharpPagesFeature() + { + using (new AppHost().Init()) + { + var context = new SharpPagesFeature().Init(); + + Assert.That(context.ScriptMethods.Count, Is.GreaterThanOrEqualTo(2)); + var filter = (FilterExamples)context.ScriptMethods.First(x => x is FilterExamples); + Assert.That(filter.Pages, Is.EqualTo(context.Pages)); + Assert.That(filter.AppSettings, Is.Not.Null); + } + } + + public ScriptContext CreateContext() + { + var context = new ScriptContext + { + ScanAssemblies = {typeof(FilterExamples).Assembly} + }; + + context.Container.AddSingleton<IDep>(() => new Dep { Greeting = "hi " }); + + return context; + } + + [Test] + public async Task Does_call_simple_filter() + { + var context = CreateContext().Init(); + + context.VirtualFiles.WriteFile("page.html", "<h1>{{ 'foo' |> greet }}, {{ \"bar\" |> greet }}</h1>"); + + var result = new PageResult(context.GetPage("page")); + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo("<h1>hi foo, hi bar</h1>")); + } + + [Test] + public async Task Does_call_addInt_filter_with_args() + { + var context = CreateContext().Init(); + + context.VirtualFiles.WriteFile("page.html", "<h1>{{ 1 |> addInt(2) }}</h1>"); + + var result = new PageResult(context.GetPage("page")); + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo("<h1>3</h1>")); + } + + [Test] + public async Task Does_call_multiple_addInt_filters_with_args() + { + var context = CreateContext().Init(); + + context.VirtualFiles.WriteFile("page.html", "<h1>{{ 1 |> addInt(2) |> addInt(3) }}</h1>"); + + var result = new PageResult(context.GetPage("page")); + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo("<h1>6</h1>")); + } + + [Test] + public async Task Can_use_addInt_filter_with_page_and_result_args() + { + var context = CreateContext().Init(); + + context.VirtualFiles.WriteFile("page.html", @" +<!-- +pageArg: 2 +--> + +<h1>{{ 1 |> addInt(pageArg) |> addInt(resultArg) }}</h1>"); + + var result = new PageResult(context.GetPage("page")) + { + Args = + { + { "resultArg", "3" }, + } + }; + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo("<h1>6</h1>")); + } + + [Test] + public async Task Does_call_recursive_addInt_filter_with_args() + { + var context = CreateContext().Init(); + + context.VirtualFiles.WriteFile("page.html", "<h1>{{ 1 |> addInt(addInt(2,3)) }}</h1>"); + + var result = new PageResult(context.GetPage("page")); + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo("<h1>6</h1>")); + } + + [Test] + public async Task Can_use_nested_addInt_filter_with_page_and_result_args() + { + var context = CreateContext().Init(); + + context.Args["contextArg"] = 10; + + context.VirtualFiles.WriteFile("page.html", @" +<!-- +pageArg: 2 +--> + +<h1>{{ 1 |> addInt(pageArg) |> addInt( addInt(addInt(2,resultArg),contextArg) ) }}</h1>"); + + var result = new PageResult(context.GetPage("page")) + { + Args = + { + { "resultArg", "3" }, + } + }; + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo("<h1>18</h1>")); + } + + [Test] + public void Can_disable_disable_filters() + { + var context = new ScriptContext + { + ExcludeFiltersNamed = { "repeat" } + }.Init(); + + var page = context.OneTimePage("{{ '.' |> repeat(3) }}{{ 3 |> repeating('-') }}"); + + Assert.That(new PageResult(page).Result, Is.EqualTo("---")); + + Assert.That(new PageResult(page){ ExcludeFiltersNamed = {"repeating"} }.Result, + Is.EqualTo("")); + } + + [Test] + public void Caches_are_kept_isolated_in_each_Context_Filter_instance() + { + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() } + }.Init(); + context.VirtualFiles.WriteFile("file.txt", "foo"); + context.VirtualFiles.WriteFile("page.html", "{{ 'file.txt' |> includeFileWithCache |> assignTo: contents }}" + + "{{ contents |> append('bar') |> upper |> repeat(2) }}"); + + Assert.That(new PageResult(context.GetPage("page")).Result, Is.EqualTo("FOOBARFOOBAR")); + Assert.That(context.ExpiringCache.Count, Is.EqualTo(1)); + Assert.That(context.ScriptMethods.First(x => x is DefaultScripts).InvokerCache.Count, Is.EqualTo(4)); + + /* TEMP START */ + var tempContext = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() } + }.Init(); + tempContext.VirtualFiles.WriteFile("file.txt", "..."); + + var tmpPage = tempContext.OneTimePage("{{ 'file.txt' |> includeFileWithCache |> assignTo: contents }}" + + "{{ contents |> append('bar') |> repeat(3) }}"); + Assert.That(new PageResult(tmpPage).Result, Is.EqualTo("...bar...bar...bar")); + Assert.That(new PageResult(tmpPage).Result, Is.EqualTo("...bar...bar...bar")); + + Assert.That(tempContext.ExpiringCache.Count, Is.EqualTo(1)); + Assert.That(tempContext.ScriptMethods.First(x => x is DefaultScripts).InvokerCache.Count, Is.EqualTo(3)); + /* TEMP END */ + + Assert.That(new PageResult(context.GetPage("page")).Result, Is.EqualTo("FOOBARFOOBAR")); + Assert.That(context.ExpiringCache.Count, Is.EqualTo(1)); + Assert.That(context.ScriptMethods.First(x => x is DefaultScripts).InvokerCache.Count, Is.EqualTo(4)); + } + + class Post + { + [AutoIncrement] + public int Id { get; set; } + public string Title { get; set; } + public string Content { get; set; } + public DateTime Created { get; set; } + public string CreatedBy { get; set; } + public DateTime Modified { get; set; } + public string ModifiedBy { get; set; } + } + + [Test] + public void Filters_evaluates_async_results() + { + OrmLiteConfig.BeforeExecFilter = cmd => cmd.GetDebugString().Print(); + + var context = new ScriptContext + { + ScriptMethods = { new DbScriptsAsync() }, + Args = { + ["objectCount"] = Task.FromResult((object)1) + } + }; + context.Container.AddSingleton<IDbConnectionFactory>(() => new OrmLiteConnectionFactory(":memory:", SqliteOrmLiteDialectProvider.Instance)); + context.Init(); + + using (var db = context.Container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<Post>(); + db.Insert(new Post { Title = "The Title", Content = "The Content", Created = DateTime.Now, Modified = DateTime.Now }); + } + + context.VirtualFiles.WriteFile("objectCount.html", "{{ objectCount |> assignTo: count }}{{ count }}"); + context.VirtualFiles.WriteFile("dbCount.html", "{{ dbScalar(`SELECT COUNT(*) FROM Post`) |> assignTo: count }}{{ count }}"); + + Assert.That(new PageResult(context.GetPage("objectCount")).Result, Is.EqualTo("1")); + Assert.That(new PageResult(context.GetPage("dbCount")).Result, Is.EqualTo("1")); + + OrmLiteConfig.BeforeExecFilter = null; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptPreprocessorTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptPreprocessorTests.cs new file mode 100644 index 00000000000..acf061ef723 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptPreprocessorTests.cs @@ -0,0 +1,113 @@ +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptPreprocessorTests + { + private const string CodeBlock = @" +<!-- +title: The title +--> + +# {{title}} + +{{ 1 + 1 }} + +```code +* Odd numbers < 5 * +#each i in range(1,5) + + #if i.isOdd() + `${i} is odd` + else + `${i} is even` + /if + +/each +``` + +```code +1 + 2 * 3 +``` + +```code + {{ 1 + 1 }} + + {{#if debug}} + {{ range(1,5) + |> where => it.isOdd() + |> map => it * it + |> join(',') + }} + {{/if}} +``` +"; + + [Test] + public void Does_process_code_block() + { + var processed = ScriptPreprocessors.TransformCodeBlocks(CodeBlock); + processed.Print(); + Assert.That(processed.NormalizeNewLines(), Is.EqualTo(@" +<!-- +title: The title +--> + +# {{title}} + +{{ 1 + 1 }} + +{{* Odd numbers < 5 *}} +{{#each i in range(1,5)}} +{{#if i.isOdd()}} +{{`${i} is odd`}} +{{else}} +{{`${i} is even`}} +{{/if}} +{{/each}} + +{{1 + 2 * 3}} + +{{ 1 + 1 }} +{{#if debug}} +{{ range(1,5) +|> where => it.isOdd() +|> map => it * it +|> join(',') +}} +{{/if}} +".NormalizeNewLines())); + } + + [Test] + public void Does_preprocess_code_blocks_by_default() + { + var context = new ScriptContext { + Preprocessors = { ScriptPreprocessors.TransformCodeBlocks } + }.Init(); + + var script = context.OneTimePage(CodeBlock); + + var output = new PageResult(script).Result; + output.Print(); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +# The title + +2 + +1 is odd +2 is even +3 is odd +4 is even +5 is odd + +7 + +2 +1,9,25".NormalizeNewLines())); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptSandboxTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptSandboxTests.cs new file mode 100644 index 00000000000..8e985bb544f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptSandboxTests.cs @@ -0,0 +1,51 @@ +using System; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptSandboxIssues + { + [Test] + public void Does_not_allow_multiple_page_arguments() + { + var context = new ScriptContext(); + context.VirtualFiles.WriteFile("_layout.html", "The {{page}} layout"); + context.VirtualFiles.WriteFile("page.html", "A {{page}} variable"); + context.Init(); + + var page = context.GetPage("page"); + + try + { + new PageResult(page).RenderScript(); + Assert.Fail("should throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException is NotSupportedException); + } + } + + [Test] + public void Does_not_allow_recursive_partials() + { + var context = new ScriptContext(); + context.VirtualFiles.WriteFile("partial.html", "A recursive {{'partial' |> partial}}"); + context.Init(); + + var page = context.GetPage("partial"); + + try + { + new PageResult(page).RenderScript(); + Assert.Fail("should throw"); + } + catch (ScriptException e) + { + Assert.That(e.InnerException is NotSupportedException); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptSyntaxErrorTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptSyntaxErrorTests.cs new file mode 100644 index 00000000000..301d69826a5 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptSyntaxErrorTests.cs @@ -0,0 +1,26 @@ +using System; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptSyntaxErrorTests + { + [Test] + public void Does_handle_unterminated_expression() + { + var context = new ScriptContext().Init(); + + try + { + context.Evaluate("{{"); + Assert.Fail("Should throw"); + } + catch (SyntaxErrorException e) + { + e.Message.Print(); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptTestUtils.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptTestUtils.cs new file mode 100644 index 00000000000..4851db839c5 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptTestUtils.cs @@ -0,0 +1,33 @@ +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + + public Person() { } + public Person(string name, int age) + { + Name = name; + Age = age; + } + + protected bool Equals(Person other) => string.Equals(Name, other.Name) && Age == other.Age; + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == this.GetType() && Equals((Person) obj); + } + + public override int GetHashCode() + { + unchecked + { + return ((Name != null ? Name.GetHashCode() : 0) * 397) ^ Age; + } + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptUseCaseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptUseCaseTests.cs new file mode 100644 index 00000000000..7a48adeeb53 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptUseCaseTests.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.IO; +using ServiceStack.OrmLite; +using ServiceStack.OrmLite.Sqlite; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ScriptUseCaseTests + { + [Test] + public void Does_execute_live_document() + { + var context = new ScriptContext().Init(); + + var template = @"{{ 11200 |> assignTo: balance }} +{{ 3 |> assignTo: projectedMonths }} +{{' +Salary: 4000 +App Royalties: 200 +'|> trim |> parseKeyValueText(':') |> assignTo: monthlyRevenues }} +{{' +Rent 1000 +Internet 50 +Mobile 50 +Food 400 +Misc 200 +'|> trim |> parseKeyValueText |> assignTo: monthlyExpenses }} +{{ monthlyRevenues |> values |> sum |> assignTo: totalRevenues }} +{{ monthlyExpenses |> values |> sum |> assignTo: totalExpenses }} +{{ subtract(totalRevenues, totalExpenses) |> assignTo: totalSavings }} + +Current Balance: <b>{{ balance |> currency }}</b> + +Monthly Revenues: +{{ monthlyRevenues |> toList |> select: { it.Key |> padRight(17) }{ it.Value |> currency }\n }} +Total <b>{{ totalRevenues |> currency }}</b> + +Monthly Expenses: +{{ monthlyExpenses |> toList |> select: { it.Key |> padRight(17) }{ it.Value |> currency }\n }} +Total <b>{{ totalExpenses |> currency }}</b> + +Monthly Savings: <b>{{ totalSavings |> currency }}</b> +{{ htmlErrorDebug }}"; + + var output = context.EvaluateScript(template); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +Current Balance: <b>$11,200.00</b> + +Monthly Revenues: +Salary $4,000.00 +App Royalties $200.00 + +Total <b>$4,200.00</b> + +Monthly Expenses: +Rent $1,000.00 +Internet $50.00 +Mobile $50.00 +Food $400.00 +Misc $200.00 + +Total <b>$1,700.00</b> + +Monthly Savings: <b>$2,500.00</b>".NormalizeNewLines())); + } + + class FilterInfoFilters : ScriptMethods + { + Type GetFilterType(string name) + { + switch(name) + { + case nameof(DefaultScripts): + return typeof(DefaultScripts); + case nameof(HtmlScripts): + return typeof(HtmlScripts); + case nameof(ProtectedScripts): + return typeof(ProtectedScripts); + case nameof(InfoScripts): + return typeof(InfoScripts); + case nameof(ServiceStackScripts): + return typeof(ServiceStackScripts); + case nameof(AutoQueryScripts): + return typeof(AutoQueryScripts); + } + + throw new NotSupportedException("Unknown Filter: " + name); + } + + public FilterInfo[] filtersAvailable(string name) + { + var filterType = GetFilterType(name); + var filters = filterType.GetMethods(BindingFlags.Instance | BindingFlags.Public); + var to = filters + .OrderBy(x => x.Name) + .ThenBy(x => x.GetParameters().Count()) + .Where(x => x.DeclaringType != typeof(ScriptMethods) && x.DeclaringType != typeof(object)) + .Where(m => !m.IsSpecialName) + .Select(x => FilterInfo.Create(x)); + + return to.ToArray(); + } + } + + public class FilterInfo + { + public string Name { get; set; } + public string FirstParam { get; set; } + public string ReturnType { get; set; } + public int ParamCount { get; set; } + public string[] RemainingParams { get; set; } + + public static FilterInfo Create(MethodInfo mi) + { + var paramNames = mi.GetParameters() + .Where(x => x.ParameterType != typeof(ScriptScopeContext)) + .Select(x => x.Name) + .ToArray(); + + var to = new FilterInfo { + Name = mi.Name, + FirstParam = paramNames.FirstOrDefault(), + ParamCount = paramNames.Length, + RemainingParams = paramNames.Length > 1 ? paramNames.Skip(1).ToArray() : new string[]{}, + ReturnType = mi.ReturnType?.Name, + }; + + return to; + } + + public string Return => ReturnType != null && ReturnType != nameof(StopExecution) ? " -> " + ReturnType : ""; + + public string Body => ParamCount == 0 + ? $"{Name}" + : ParamCount == 1 + ? $"|> {Name}" + : $"|> {Name}(" + string.Join(", ", RemainingParams) + $")"; + + public string Display => ParamCount == 0 + ? $"{Name}{Return}" + : ParamCount == 1 + ? $"{FirstParam} |> {Name}{Return}" + : $"{FirstParam} |> {Name}(" + string.Join(", ", RemainingParams) + $"){Return}"; + } + + [Test] + public void Can_query_filters() + { + var context = new ScriptContext + { + ScriptMethods = { new FilterInfoFilters() } + }.Init(); + + var results = context.EvaluateScript(@"{{ 'DefaultScripts' |> assignTo: filter }} +{{ filter |> filtersAvailable |> where => contains(lower(it.Name), lower(nameContains ?? '')) + |> assignTo: filters }} +{{#each filters}} +{{Body |> raw}} +{{/each}}", new Dictionary<string, object> { ["nameContains"] = "atan" }); + + Assert.That(results.NormalizeNewLines(), Is.EqualTo(@" +|> atan +|> atan2(x)".NormalizeNewLines())); + } + + + [Test] + public void Can_convert_dbScript_Results_to_Customer_Poco() + { + void AssertProduct(Product actual, Product expected) + { + Assert.That(actual.ProductId, Is.EqualTo(expected.ProductId)); + Assert.That(actual.ProductName, Is.EqualTo(expected.ProductName)); + Assert.That(actual.Category, Is.EqualTo(expected.Category)); + Assert.That(actual.UnitPrice, Is.EqualTo(expected.UnitPrice)); + Assert.That(actual.UnitsInStock, Is.EqualTo(expected.UnitsInStock)); + } + + var product1 = QueryData.Products[0]; + var product2 = QueryData.Products[1]; + var context = new ScriptContext + { + ScriptMethods = { new DbScriptsAsync() }, + Args = { + ["id"] = product1.ProductId, + } + }; + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteOrmLiteDialectProvider.Instance); + context.Container.AddSingleton<IDbConnectionFactory>(() => dbFactory); + context.Init(); + + using (var db = context.Container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<Product>(); + db.Insert(product1); + db.Insert(product2); + } + + + var result = context.Evaluate<Product>("{{ `select * from product where productId=@id` |> dbSingle({ id }) |> return }}"); + + result.TextDump().Print(); + + AssertProduct(result, product1); + + var results = context.Evaluate<Product[]>("{{ `select * from product where productId IN (@ids) order by productId` |> dbSelect({ ids }) |> return }}", + new ObjectDictionary { + ["ids"] = new[]{ product1.ProductId, product2.ProductId }, + }); + + results.TextDump().Print(); + + Assert.That(results.Length, Is.EqualTo(2)); + + AssertProduct(results[0], product1); + AssertProduct(results[1], product2); + } + + private static ScriptContext CreateDbContext() + { + var context = new ScriptContext { + ScriptMethods = {new DbScriptsAsync()}, + }; + + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteOrmLiteDialectProvider.Instance); + context.Container.AddSingleton<IDbConnectionFactory>(() => dbFactory); + context.Init(); + return context; + } + + [Test] + public void Can_use_GetTableNames_with_textDump() + { + var context = CreateDbContext(); + + using (var db = context.Container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<Customer>(); + db.DropAndCreateTable<Product>(); + + QueryData.Customers.Take(1).Each(x => db.Insert(x)); + QueryData.Products.Take(3).Each(x => db.Insert(x)); + } + + var output = context.EvaluateScript("{{ dbTableNames |> textDump({ caption:'Tables' }) }}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("| Tables |\n|----------|\n| Customer |\n| Product |")); + + output = context.EvaluateScript("{{ dbTableNamesWithRowCounts |> textDump({ caption:'Tables' }) }}"); + Assert.That(output.NormalizeNewLines(), Is.EqualTo("| Tables ||\n|----------|---|\n| Product | 3 |\n| Customer | 1 |")); + } + + [Test] + public void Can_catch_dbSelect_exceptions() + { + var context = CreateDbContext(); + + var output = context.EvaluateScript("{{ `SELECT * FROM Unknown` |> dbSelect(null, { ifErrorReturn: 'No Table' }) }}"); + Assert.That(output, Is.EqualTo("No Table")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptValidationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptValidationTests.cs new file mode 100644 index 00000000000..319e3e2e4fc --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ScriptValidationTests.cs @@ -0,0 +1,111 @@ +using System; +using System.IO; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + /* + public class DynamicValidationServices : Service + { + public override void OnBeforeExecute(object requestDto) + { + try + { + // check if there's a script for this service + var script = TryResolve<IAppSettings>().GetString($"script.{requestDto.GetType().Name}.validation"); + if (script == null) + return; + + var context = HostContext.GetPlugin<SharpPagesFeature>(); + + var pageResult = new PageResult(context.OneTimePage(script)) { + Model = requestDto + }; + pageResult.WriteToAsync(Stream.Null); + } + catch (ScriptException e) + { + throw e.InnerException ?? e; + } + } + } + * + */ + + public class ScriptValidationTests + { + public class Person + { + public string Name { get; set; } + public int? Age { get; set; } + } + + [Test] + public void Can_validate_person_in_code() + { + var context = new ScriptContext().Init(); + + var code = @" +['Name','Age'] |> to => requiredProps +#each requiredProps + #if !model[it] + it.throwArgumentNullException() + /if +/each + +(Age < 13) |> ifThrowArgumentException('Must be 13 or over', 'Age') +"; + + try + { + var pageResult = new PageResult(context.CodeBlock(code)) { + Model = new Person() + }; + pageResult.RenderToStream(Stream.Null); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + if (!(e.InnerException is ArgumentNullException ne)) + throw; + + Assert.That(ne.ParamName, Is.EqualTo(nameof(Person.Name))); + } + + try + { + var pageResult = new PageResult(context.CodeBlock(code)) { + Model = new Person { Name = "A" } + }; + pageResult.RenderToStream(Stream.Null); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + if (!(e.InnerException is ArgumentNullException ne)) + throw; + + Assert.That(ne.ParamName, Is.EqualTo(nameof(Person.Age))); + } + + try + { + var pageResult = new PageResult(context.CodeBlock(code)) { + Model = new Person { Name = "A", Age = 1 } + }; + pageResult.RenderToStream(Stream.Null); + Assert.Fail("Should throw"); + } + catch (ScriptException e) + { + if (!(e.InnerException is ArgumentException ae)) + throw; + + Assert.That(ae.Message.Replace("\r",""), + Does.StartWith("Must be 13 or over")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ServiceStackScriptTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ServiceStackScriptTests.cs new file mode 100644 index 00000000000..6f505763a41 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/ServiceStackScriptTests.cs @@ -0,0 +1,436 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.OrmLite; +using ServiceStack.Script; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class QueryProducts : QueryData<Product> {} + + public class GetAllProducts : IReturn<GetAllProductsResponse> {} + + public class GetAllProductsResponse + { + public Product[] Results { get; set; } + } + + public class TemplateServiceStackFiltersService : Service + { + public object Any(GetAllProducts request) => new GetAllProductsResponse + { + Results = QueryData.Products + }; + } + + public class QueryTemplateRockstars : QueryDb<Rockstar> {} + + public class QueryCustomers : QueryDb<Customer> + { + public string CustomerId { get; set; } + public string CompanyNameContains { get; set; } + public string[] CountryIn { get; set; } + } + + public class ServiceStackScriptTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(SharpPagesIntegrationTests), typeof(MyTemplateServices).Assembly) {} + + public readonly List<IVirtualPathProvider> TemplateFiles = new() { + new MemoryVirtualFiles(), + new ResourceVirtualFiles(typeof(HtmlFormat).Assembly), + }; + public override List<IVirtualPathProvider> GetVirtualFileSources() => TemplateFiles; + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DebugMode = true + }); + + container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(":memory:", + SqliteDialect.Provider)); + + using (var db = container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<Rockstar>(); + db.InsertAll(UnitTestExample.SeedData); + + db.DropAndCreateTable<Customer>(); + db.InsertAll(QueryData.Customers); + } + + Plugins.Add(new SharpPagesFeature + { + ApiPath = "/sharpapi", + Args = + { + ["products"] = QueryData.Products, + }, + ScriptMethods = + { + new DbScriptsAsync(), + new AutoQueryScripts(), + }, + }); + + Plugins.Add(new AutoQueryDataFeature { MaxLimit = 100 } + .AddDataSource(ctx => ctx.ServiceSource<Product>(ctx.ConvertTo<GetAllProducts>())) + ); + + Plugins.Add(new AutoQueryFeature { MaxLimit = 100 }); + + var files = TemplateFiles[0]; + + files.WriteFile("_layout.html", @" +<html> +<body id=root> +{{ page }} +{{ htmlErrorDebug }} +</body> +</html> +"); + files.WriteFile("autoquery-data-products.html", @" +{{ 'category,orderBy,take' |> importRequestParams }}{{ { category, orderBy, take } |> withoutNullValues |> sendToAutoQuery('QueryProducts') + |> toResults |> select: { it.ProductName }\n }}"); + + files.WriteFile("autoquery-rockstars.html", @" +{{ { qs.age, qs.orderBy, qs.take } |> withoutNullValues |> sendToAutoQuery('QueryTemplateRockstars') + |> toResults |> select: { it.FirstName } { it.LastName }\n }}"); + + files.WriteFile("autoquery-customer.html", @" +{{ { qs.customerId } |> sendToAutoQuery('QueryCustomers') + |> toResults |> select: { it.CustomerId }: { it.CompanyName }, { it.City }\n }}"); + + files.WriteFile("autoquery-customers.html", @" +{{ { qs.countryIn, qs.orderBy } |> sendToAutoQuery('QueryCustomers') + |> toResults |> select: { it.CustomerId }: { it.CompanyName }, { it.Country }\n }}"); + + files.WriteFile("autoquery-top5-de-uk.html", @" +{{ { countryIn:['UK','Germany'], orderBy:'customerId', take:5 } |> sendToAutoQuery('QueryCustomers') + |> toResults |> select: { it.CustomerId }: { it.CompanyName }, { it.Country }\n }}"); + + files.WriteFile("sharpapi/customers.html", @" +{{ 'id,city,country' |> importRequestParams }} +{{ qs.limit ?? 100 |> assignTo: limit }} + +{{ 'select CustomerId, CompanyName, City, Country from Customer' |> assignTo: sql }} + +{{ PathArgs |> endIfEmpty |> useFmt('{0} where CustomerId = @id', sql) |> dbSingle({ id: PathArgs[0] }) + |> return }} + +{{ id |> endIfEmpty |> use('CustomerId = @id') |> addTo: filters }} +{{ city |> endIfEmpty |> use('City = @city') |> addTo: filters }} +{{ country |> endIfEmpty |> use('Country = @country') |> addTo: filters }} +{{ filters |> endIfEmpty |> useFmt('{0} where {1}', sql, join(filters, ' and ')) |> assignTo: sql }} + +{{ sql |> appendFmt(' ORDER BY CompanyName {0}', sqlLimit(limit)) + |> dbSelect({ country, city, id }) + |> return }} +"); + } + } + + public static string BaseUrl = Config.ListeningOn; + + private readonly ServiceStackHost appHost; + public ServiceStackScriptTests() + { + appHost = new AppHost() + .Init() + .Start(BaseUrl); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_call_AutoQuery_Data_services() + { + var html = BaseUrl.CombineWith("autoquery-data-products").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html.NormalizeNewLines(), Does.StartWith(@" +<html> +<body id=root> + +Chai +Chang +Aniseed Syrup".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_Data_services_with_limit() + { + var html = BaseUrl.CombineWith("autoquery-data-products?orderBy=ProductName&take=3").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html.NormalizeNewLines(), Does.StartWith(@" +<html> +<body id=root> + +Alice Mutton +Aniseed Syrup +Boston Crab Meat + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_Data_services_with_category() + { + var html = BaseUrl.CombineWith("autoquery-data-products?category=Beverages").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +Chai +Chang +Guaran&#225; Fant&#225;stica +Sasquatch Ale +Steeleye Stout +C&#244;te de Blaye +Chartreuse verte +Ipoh Coffee +Laughing Lumberjack Lager +Outback Lager +Rh&#246;nbr&#228;u Klosterbier +Lakkalik&#246;&#246;ri + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_Db_services() + { + var html = BaseUrl.CombineWith("autoquery-rockstars").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html.NormalizeNewLines(), Does.StartWith(@" +<html> +<body id=root> + +Jimi Hendrix +Jim Morrison +Kurt Cobain +Elvis Presley +David Grohl +Eddie Vedder +Michael Jackson + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_Db_services_with_limit() + { + var html = BaseUrl.CombineWith("autoquery-rockstars?orderBy=FirstName&take=3").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html.NormalizeNewLines(), Does.StartWith(@" +<html> +<body id=root> + +David Grohl +Eddie Vedder +Elvis Presley + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_Db_services_by_age() + { + var html = BaseUrl.CombineWith("autoquery-rockstars?age=27&orderBy=LastName").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +Kurt Cobain +Jimi Hendrix +Jim Morrison + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_QueryCustomer_service_by_CityIn() + { + var html = BaseUrl.CombineWith("autoquery-customers") + .AddQueryParam("countryIn","UK,Germany") + .AddQueryParam("orderBy","customerId") + .GetStringFromUrl(responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + html.Print(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<html> +<body id=root> + +ALFKI: Alfreds Futterkiste, Germany +AROUT: Around the Horn, UK +BLAUS: Blauer See Delikatessen, Germany +BSBEV: B&#39;s Beverages, UK +CONSH: Consolidated Holdings, UK +DRACD: Drachenblut Delikatessen, Germany +EASTC: Eastern Connection, UK +FRANK: Frankenversand, Germany +ISLAT: Island Trading, UK +KOENE: K&#246;niglich Essen, Germany +LEHMS: Lehmanns Marktstand, Germany +MORGK: Morgenstern Gesundkost, Germany +NORTS: North/South, UK +OTTIK: Ottilies K&#228;seladen, Germany +QUICK: QUICK-Stop, Germany +SEVES: Seven Seas Imports, UK +TOMSP: Toms Spezialit&#228;ten, Germany +WANDK: Die Wandernde Kuh, Germany + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_AutoQuery_QueryCustomer_top5_UK_Germany() + { + var html = BaseUrl.CombineWith("autoquery-top5-de-uk").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + html.Print(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<html> +<body id=root> + +ALFKI: Alfreds Futterkiste, Germany +AROUT: Around the Horn, UK +BLAUS: Blauer See Delikatessen, Germany +BSBEV: B&#39;s Beverages, UK +CONSH: Consolidated Holdings, UK + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_customers_sharpapi_page_without_arguments() + { + var url = BaseUrl.CombineWith("sharpapi", "customers"); + + var json = url.GetJsonFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Json)); + var customers = json.FromJson<List<Customer>>(); + Assert.That(customers.Count, Is.EqualTo(QueryData.Customers.Count)); + } + + [Test] + public void Can_call_customers_sharpapi_page_with_all_arguments() + { + var url = BaseUrl.CombineWith("sharpapi", "customers") + .AddQueryParam("country", "UK") + .AddQueryParam("city", "London") + .AddQueryParam("limit", 10); + + var json = url.GetJsonFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Json)); + var customers = json.FromJson<List<Customer>>(); + + Assert.That(customers.Map(x => x.CustomerId), Is.EquivalentTo("AROUT,BSBEV,CONSH,EASTC,NORTS,SEVES".Split(','))); + Assert.That(customers.All(x => x.Country == "UK")); + Assert.That(customers.All(x => x.City == "London")); + } + + [Test] + public void Can_call_single_customer_with_path_args() + { + var json = BaseUrl.CombineWith("sharpapi", "customers", "ALFKI").GetJsonFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Json)); + var customer = json.FromJson<Customer>(); + Assert.That(customer.CustomerId, Is.EqualTo("ALFKI")); + Assert.That(customer.CompanyName, Is.EqualTo("Alfreds Futterkiste")); + Assert.That(customer.City, Is.EqualTo("Berlin")); + Assert.That(customer.Country, Is.EqualTo("Germany")); + } + + [Test] + public void Can_call_customer_with_csv_extension_to_force_ContentType() + { + var json = BaseUrl.CombineWith("sharpapi", "customers").AddQueryParam("limit", 1).GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Json)); + Assert.That(json, Does.StartWith("[")); + + var html = BaseUrl.CombineWith("sharpapi", "customers.html").AddQueryParam("limit", 1).GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Html)); + Assert.That(html, Does.StartWith("<")); + + var csv = BaseUrl.CombineWith("sharpapi", "customers.csv").AddQueryParam("limit", 1).GetStringFromUrl(); + Assert.That(csv, Does.StartWith("CustomerId,")); + } + + [Test] + public void Can_call_single_customer_with_json_extension_to_force_ContentType() + { + var json = BaseUrl.CombineWith("sharpapi", "customers", "ALFKI.json").GetStringFromUrl( + responseFilter:res => res.MatchesContentType(MimeTypes.Json)); + var customer = json.FromJson<Customer>(); + Assert.That(customer.CustomerId, Is.EqualTo("ALFKI")); + Assert.That(customer.CompanyName, Is.EqualTo("Alfreds Futterkiste")); + Assert.That(customer.City, Is.EqualTo("Berlin")); + Assert.That(customer.Country, Is.EqualTo("Germany")); + } + + [Test] + public void Can_use_ifAuthenticated_filters_when_authenticated() + { + var context = new ScriptContext + { + ScriptMethods = { new ServiceStackScripts() }, + Args = + { + [ScriptConstants.Request] = new MockHttpRequest + { + Items = + { + [Keywords.Session] = new AuthUserSession { DisplayName = "Auth User", IsAuthenticated = true } + } + } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ isAuthenticated }}"), Is.EqualTo("True")); + Assert.That(context.EvaluateScript("{{ ifAuthenticated |> show: Y }}"), Is.EqualTo("Y")); + Assert.That(context.EvaluateScript("{{ ifNotAuthenticated |> show: N }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> onlyIfAuthenticated }}"), Is.EqualTo("1")); + Assert.That(context.EvaluateScript("{{ 1 |> endIfAuthenticated }}"), Is.EqualTo("")); + } + + [Test] + public void Can_use_ifAuthenticated_filters_when_not_authenticated() + { + var context = new ScriptContext + { + ScriptMethods = { new ServiceStackScripts() }, + }.Init(); + + Assert.That(context.EvaluateScript("{{ isAuthenticated }}"), Is.EqualTo("False")); + Assert.That(context.EvaluateScript("{{ ifAuthenticated |> show: Y }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ ifNotAuthenticated |> show: N }}"), Is.EqualTo("N")); + Assert.That(context.EvaluateScript("{{ 1 |> onlyIfAuthenticated }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ 1 |> endIfAuthenticated }}"), Is.EqualTo("1")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpApiTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpApiTests.cs new file mode 100644 index 00000000000..722be9d1a52 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpApiTests.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class SharpApiTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(SharpPageTests), typeof(SharpPagesService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new SharpPagesFeature()); + + AfterInitCallbacks.Add(host => { + var memFs = VirtualFileSources.GetMemoryVirtualFiles(); + foreach (var entry in HtmlFiles) + { + memFs.AppendFile(entry.Key, entry.Value); + } + }); + } + + private static readonly Dictionary<string, string> HtmlFiles = new Dictionary<string, string> { + { + "_layout.html", + "<html><head><title>{{ title }}</title></head><body id='layout'>{{ page }}</body></html>" + }, { + "preview.html", + @"API /preview +* content : string - #Script to evaluate + +{{ qs.content |> evalTemplate({use:{plugins:'MarkdownScriptPlugin'}}) |> assignTo:response }} +{{ response |> return({ contentType:'text/plain' }) }}" + }, + }; + } + + private readonly ServiceStackHost appHost; + public SharpApiTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_evaluate_SharpAPi() + { + var output = Config.ListeningOn.CombineWith("preview.html") + .AddQueryParam("content", "{{10|times|select:{pow(index,2)},}}") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo("0,1,4,9,16,25,36,49,64,81,")); + } + + [Test] + public void Does_evaluateTemplate_with_no_content_returns_empty() + { + var output = Config.ListeningOn.CombineWith("preview.html") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(output.NormalizeNewLines(), Is.Empty); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageContextScriptMethodsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageContextScriptMethodsTests.cs new file mode 100644 index 00000000000..4f92e5bcdbd --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageContextScriptMethodsTests.cs @@ -0,0 +1,364 @@ +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; +using ServiceStack.Testing; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class SharpPageContextScriptMethodsTests + { + [Test] + public void Can_pass_variables_into_partials() + { + var context = new ScriptContext + { + Args = { ["defaultMessage"] = "this is the default message" } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> + <title>{{ title }}</title> +</head> +<body> +{{ 'header' |> partial({ id: 'the-page', message: 'in your header' }) }} +{{ page }} +</body>"); + + context.VirtualFiles.WriteFile("header.html", @" +<header id='{{ id |> otherwise('header') }}'> + {{ message |> otherwise(defaultMessage) }} +</header>"); + + context.VirtualFiles.WriteFile("page.html", @"<h1>{{ title }}</h1>"); + + var result = new PageResult(context.GetPage("page")) + { + Args = { ["title"] = "The title" } + }.Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<html> + <title>The title</title> +</head> +<body> + +<header id='the-page'> + in your header +</header> +<h1>The title</h1> +</body> +".NormalizeNewLines())); + } + + [Test] + public void Can_load_page_with_partial_and_scoped_variables() + { + var context = new ScriptContext + { + Args = + { + ["myPartial"] = "my-partial" + } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> + <title>{{ title }}</title> +</head> +<body> +{{ 'my-partial' |> partial({ title: 'with-partial', tag: 'h2' }) }} +{{ myPartial |> partial({ title: 'with-partial-binding', tag: 'h2' }) }} +<footer>{{ title }}</footer> +</body>"); + + context.VirtualFiles.WriteFile("my-partial.html", "<{{ tag }}>{{ title }}</{{ tag }}>"); + + var result = new PageResult(context.GetPage("my-partial")) + { + Args = { ["title"] = "The title" } + }.Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<html> + <title>The title</title> +</head> +<body> +<h2>with-partial</h2> +<h2>with-partial-binding</h2> +<footer>The title</footer> +</body> +".NormalizeNewLines())); + } + + [Test] + public void Can_load_page_with_page_or_partial_with_scoped_variables_containing_bindings() + { + var context = new ScriptContext + { + Args = + { + ["myPartial"] = "my-partial", + ["headingTag"] = "h2", + } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> + <title>{{ title }}</title> +</head> +<body> +{{ 'my-partial' |> partial({ title: title, tag: headingTag }) }} +{{ myPartial |> partial({ title: partialTitle, tag: headingTag }) }} +</body>"); + + context.VirtualFiles.WriteFile("my-partial.html", "<{{ tag }}>{{ title }}</{{ tag }}>"); + + var result = new PageResult(context.GetPage("my-partial")) + { + Args = + { + ["title"] = "The title", + ["partialTitle"] = "Partial Title", + } + }.Result; + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<html> + <title>The title</title> +</head> +<body> +<h2>The title</h2> +<h2>Partial Title</h2> +</body> +".NormalizeNewLines())); + } + + [Test] + public void Does_replace_bindings() + { + var context = new ScriptContext + { + Args = + { + ["contextTitle"] = "The title", + ["contextPartial"] = "bind-partial", + ["contextTag"] = "h2", + ["a"] = "foo", + ["b"] = "bar", + } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> + <title>{{ title }}</title> +</head> +<body> +{{ contextPartial |> partial({ title: contextTitle, tag: contextTag, items: [a,b] }) }} +{{ page }} +</body>"); + + context.VirtualFiles.WriteFile("bind-partial.html", @" +<{{ tag }}>{{ title |> upper }}</{{ tag }}> +<p>{{ items |> join(', ') }}</p>"); + + context.VirtualFiles.WriteFile("bind-page.html", @" +<section> +{{ pagePartial |> partial({ tag: pageTag, items: items }) }} +</section> +"); + + var result = new PageResult(context.GetPage("bind-page")) + { + Args = + { + ["title"] = "Page title", + ["pagePartial"] = "bind-partial", + ["pageTag"] = "h3", + ["items"] = new[] { 1, 2, 3 }, + } + }.Result; + + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<html> + <title>Page title</title> +</head> +<body> + +<h2>THE TITLE</h2> +<p>foo, bar</p> + +<section> + +<h3>PAGE TITLE</h3> +<p>1, 2, 3</p> +</section> + +</body> +".NormalizeNewLines())); + + } + + [Test] + public void Can_repeat_templates_using_selectEach() + { + var context = new ScriptContext + { + Args = + { + ["letters"] = new[]{ "A", "B", "C" }, + ["numbers"] = new[]{ 1, 2, 3 }, + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("<ul> {{ '<li> {{it}} </li>' |> selectEach(letters) }} </ul>")).Result, + Is.EqualTo("<ul> <li> A </li><li> B </li><li> C </li> </ul>")); + + Assert.That(new PageResult(context.OneTimePage("<ul> {{ '<li> {{it}} </li>' |> selectEach(numbers) }} </ul>")).Result, + Is.EqualTo("<ul> <li> 1 </li><li> 2 </li><li> 3 </li> </ul>")); + } + + [Test] + public void Can_use_escaped_chars_in_selectEach() + { + var context = new ScriptContext + { + Args = + { + ["letters"] = new[]{ "A", "B", "C" }, + } + }.Init(); + + var result = context.EvaluateScript("<ul>\n{{ '<li> {{it}} </li>\n' |> selectEach(letters) }}</ul>"); + Assert.That(result.NormalizeNewLines(), + Is.EqualTo(@"<ul> +<li> A </li> +<li> B </li> +<li> C </li> +</ul>".NormalizeNewLines())); + } + + [Test] + public void Can_repeat_templates_using_forEach_in_page_and_layouts() + { + var context = new ScriptContext + { + Args = + { + ["numbers"] = new[]{ 1, 2, 3 }, + } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body> +<header> +<ul> {{ '<li> {{it}} </li>' |> selectEach(numbers) }} </ul> +</header> +<section> +{{ page }} +</section> +</body> +</html> +"); + context.VirtualFiles.WriteFile("page.html", "<ul> {{ '<li> {{it}} </li>' |> selectEach(letters) }} </ul>"); + + var result = new PageResult(context.GetPage("page")) + { + Args = + { + ["letters"] = new[]{ "A", "B", "C" }, + } + }.Result; + + Assert.That(result.NormalizeNewLines(), + Is.EqualTo(@" +<html> +<body> +<header> +<ul> <li> 1 </li><li> 2 </li><li> 3 </li> </ul> +</header> +<section> +<ul> <li> A </li><li> B </li><li> C </li> </ul> +</section> +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_repeat_templates_with_bindings_using_selectEach() + { + var context = new ScriptContext + { + Args = + { + ["items"] = new[] + { + new ModelBinding { Object = new NestedModelBinding { Prop = "A" }}, + new ModelBinding { Object = new NestedModelBinding { Prop = "B" }}, + new ModelBinding { Object = new NestedModelBinding { Prop = "C" }}, + }, + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("<ul> {{ '<li> {{ it.Object.Prop }} </li>' |> selectEach(items) }} </ul>")).Result, + Is.EqualTo("<ul> <li> A </li><li> B </li><li> C </li> </ul>")); + } + + [Test] + public void Can_repeat_templates_with_bindings_and_custom_scope_using_selectEach() + { + var context = new ScriptContext + { + Args = + { + ["items"] = new[] + { + new ModelBinding { Object = new NestedModelBinding { Prop = "A" }}, + new ModelBinding { Object = new NestedModelBinding { Prop = "B" }}, + new ModelBinding { Object = new NestedModelBinding { Prop = "C" }}, + }, + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("<ul> {{ '<li> {{ item.Object.Prop }} </li>' |> selectEach(items, { it: 'item' } ) }} </ul>")).Result, + Is.EqualTo("<ul> <li> A </li><li> B </li><li> C </li> </ul>")); + + // Equivalent with select: + Assert.That(new PageResult(context.OneTimePage("<ul> {{ items |> select: <li> { it.Object.Prop } </li> }} </ul>")).Result, + Is.EqualTo("<ul> <li> A </li><li> B </li><li> C </li> </ul>")); + } + + [Test] + public void Can_use_forEach_with_markdown() + { + using (new BasicAppHost().Init()) + { + var context = new SharpPagesFeature + { + Args = + { + ["items"] = new[]{ "foo", "bar", "qux" } + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ ' - {{it}}\n' |> selectEach(items) |> markdown }}")).Result.RemoveAllWhitespace(), + Is.EqualTo("<ul><li>foo</li><li>bar</li><li>qux</li></ul>".RemoveAllWhitespace())); + } + } + + [Test] + public void Can_access_partial_arguments() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("component.html", @"{{ files |> toList |> select: { it.Key }: { it.Value }\n }}"); + + context.VirtualFiles.WriteFile("page.html", "{{ 'component' |> partial({ files: { 'a': 'foo', 'b': 'bar' } }) }}"); + + var output = new PageResult(context.GetPage("page")).Result; + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +a: foo +b: bar +".NormalizeNewLines())); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageRawTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageRawTests.cs new file mode 100644 index 00000000000..4384db119b0 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageRawTests.cs @@ -0,0 +1,953 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.IO; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class ModelBinding + { + public int Int { get; set; } + + public string Prop { get; set; } + + public NestedModelBinding Object { get; set; } + + public Dictionary<string, ModelBinding> Dictionary { get; set; } + + public List<ModelBinding> List { get; set; } + + public ModelBinding this[int i] + { + get => List[i]; + set => List[i] = value; + } + } + + public class NestedModelBinding + { + public int Int { get; set; } + + public string Prop { get; set; } + + public ModelBinding Object { get; set; } + + public AltNested AltNested { get; set; } + + public Dictionary<string, ModelBinding> Dictionary { get; set; } + + public List<ModelBinding> List { get; set; } + } + + public class AltNested + { + public string Field { get; set; } + } + + + public class SharpPageRawTests + { + [Test] + public async Task Can_generate_html_template_with_layout_in_memory() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> + <title>{{ title }}</title> +</head> +<body> + {{ page }} +</body>"); + + context.VirtualFiles.WriteFile("page.html", @"<h1>{{ title }}</h1>"); + + var page = context.GetPage("page"); + var result = new PageResult(page) + { + Args = + { + {"title", "The Title"}, + } + }; + + var html = await result.RenderToStringAsync(); + + Assert.That(html, Is.EqualTo(@" +<html> + <title>The Title</title> +</head> +<body> + <h1>The Title</h1> +</body>")); + } + + [Test] + public async Task Can_generate_markdown_template_with_layout_in_memory() + { + var context = new ScriptContext + { + PageFormats = + { + new MarkdownPageFormat() + } + }.Init();; + + context.VirtualFiles.WriteFile("_layout.md", @" +# {{ title }} + +Brackets in Layout < & > + +{{ page }}"); + + context.VirtualFiles.WriteFile("page.md", @"## {{ title }}"); + + var page = context.GetPage("page"); + var result = new PageResult(page) + { + Args = + { + {"title", "The Title"}, + }, + ContentType = MimeTypes.Html, + OutputTransformers = { MarkdownPageFormat.TransformToHtml }, + }; + + var html = await result.RenderToStringAsync(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<h1>The Title</h1> +<p>Brackets in Layout &lt; &amp; &gt; </p> +<h2>The Title</h2>".NormalizeNewLines())); + + } + + [Test] + public async Task Can_generate_markdown_template_with_html_layout_in_memory() + { + var context = new ScriptContext + { + PageFormats = + { + new MarkdownPageFormat() + } + }.Init();; + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> + <title>{{ title }}</title> +</head> +<body> + {{ page }} +</body>"); + + context.VirtualFiles.WriteFile("page.md", @"### {{ title }}"); + + var page = context.GetPage("page"); + var result = new PageResult(page) + { + Args = + { + {"title", "The Title"}, + }, + ContentType = MimeTypes.Html, + PageTransformers = { MarkdownPageFormat.TransformToHtml }, + }; + + var html = await result.RenderToStringAsync(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<html> + <title>The Title</title> +</head> +<body> + <h3>The Title</h3> + +</body>".NormalizeNewLines())); + } + + [Test] + public async Task Does_explode_Model_properties_into_scope() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("page.html", @"Id: {{ Id }}, Name: {{ Name }}"); + + var result = await new PageResult(context.GetPage("page")) + { + Model = new Model { Id = 1, Name = "<foo>" } + }.RenderToStringAsync(); + + Assert.That(result, Is.EqualTo("Id: 1, Name: &lt;foo&gt;")); + } + + [Test] + public async Task Does_explode_Model_properties_of_anon_object_into_scope() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("page.html", @"Id: {{ Id }}, Name: {{ Name }}"); + + var result = await new PageResult(context.GetPage("page")) + { + Model = new { Id = 1, Name = "<foo>" } + }.RenderToStringAsync(); + + Assert.That(result, Is.EqualTo("Id: 1, Name: &lt;foo&gt;")); + } + + [Test] + public async Task Does_reload_modified_page_contents_in_DebugMode() + { + var context = new ScriptContext + { + DebugMode = true, //default + }.Init(); + + context.VirtualFiles.WriteFile("page.html", "<h1>Original</h1>"); + Assert.That(await new PageResult(context.GetPage("page")).RenderToStringAsync(), Is.EqualTo("<h1>Original</h1>")); + + await Task.Delay(1); //Memory VFS is too fast! + + context.VirtualFiles.WriteFile("page.html", "<h1>Updated</h1>"); + Assert.That(await new PageResult(context.GetPage("page")).RenderToStringAsync(), Is.EqualTo("<h1>Updated</h1>")); + } + + [Test] + public void Context_Throws_FileNotFoundException_when_page_does_not_exist() + { + var context = new ScriptContext(); + + Assert.That(context.Pages.GetPage("not-exists.html"), Is.Null); + + try + { + var page = context.GetPage("not-exists.html"); + Assert.Fail("Should throw"); + } + catch (FileNotFoundException e) + { + e.ToString().Print(); + } + } + + class MyFilter : ScriptMethods + { + public string echo(string text) => $"{text} {text}"; + public double squared(double value) => value * value; + public string greetArg(string key) => $"Hello {Context.Args[key]}"; + + public ICacheClient Cache { get; set; } + public string fromCache(string key) => Cache.Get<string>(key); + } + + [Test] + public void Does_use_custom_filter() + { + var context = new ScriptContext + { + Args = + { + ["contextArg"] = "foo" + }, + ScriptMethods = { new MyFilter() } + }.Init(); + + var output = context.EvaluateScript("<p>{{ 'contextArg' |> greetArg }}</p>"); + Assert.That(output, Is.EqualTo("<p>Hello foo</p>")); + + output = context.EvaluateScript("<p>{{ 10 |> squared }}</p>"); + Assert.That(output, Is.EqualTo("<p>100</p>")); + + output = new PageResult(context.OneTimePage("<p>{{ 'hello' |> echo }}</p>")) + { + ScriptMethods = { new MyFilter() } + }.Result; + Assert.That(output, Is.EqualTo("<p>hello hello</p>")); + + context = new ScriptContext + { + ScanTypes = { typeof(MyFilter) }, + }; + context.Container.AddSingleton<ICacheClient>(() => new MemoryCacheClient()); + context.Container.Resolve<ICacheClient>().Set("key", "foo"); + context.Init(); + + output = context.EvaluateScript("<p>{{ 'key' |> fromCache }}</p>"); + Assert.That(output, Is.EqualTo("<p>foo</p>")); + } + + [Test] + public async Task Does_embed_partials() + { + var context = new ScriptContext + { + Args = + { + ["copyright"] = "Copyright &copy; ServiceStack 2008-2017", + ["footer"] = "global-footer" + } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<head><title>{{ title }}</title></head> +<body> +{{ 'header' |> partial }} +<div id='content'>{{ page }}</div> +{{ footer |> partial }} +</body> +</html> +"); + context.VirtualFiles.WriteFile("header.html", "<header>{{ pageTitle |> titleCase }}</header>"); + context.VirtualFiles.WriteFile("page.html", "<h2>{{ contentTitle }}</h2><section>{{ 'page-content' |> partial }}</section>"); + context.VirtualFiles.WriteFile("page-content.html", "<p>{{ contentBody |> padRight(20,'.') }}</p>"); + context.VirtualFiles.WriteFile("global-footer.html", "<footer>{{ copyright |> raw }}</footer>"); + + var result = await new PageResult(context.GetPage("page")) + { + Args = + { + ["pageTitle"] = "I'm in your header", + ["contentTitle"] = "Content is King!", + ["contentBody"] = "About this page", + } + }.RenderToStringAsync(); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +<html> +<head><title></title></head> +<body> +<header>I&#39;m In Your Header</header> +<div id='content'><h2>Content is King!</h2><section><p>About this page.....</p></section></div> +<footer>Copyright &copy; ServiceStack 2008-2017</footer> +</body> +</html> +".NormalizeNewLines())); + } + + private static ModelBinding CreateModelBinding() + { + var model = new ModelBinding + { + Int = 1, + Prop = "The Prop", + Object = new NestedModelBinding + { + Int = 2, + Prop = "Nested Prop", + Object = new ModelBinding + { + Int = 21, + Prop = "Nested Nested Prop", + }, + AltNested = new AltNested + { + Field = "Object AltNested Field" + } + }, + Dictionary = new Dictionary<string, ModelBinding> + { + { + "map-key", + new ModelBinding + { + Int = 3, + Prop = "Dictionary Prop", + Object = new NestedModelBinding + { + Int = 5, + Prop = "Nested Dictionary Prop", + AltNested = new AltNested + { + Field = "Dictionary AltNested Field" + } + } + } + }, + }, + List = new List<ModelBinding> + { + new ModelBinding + { + Int = 4, + Prop = "List Prop", + Object = new NestedModelBinding {Int = 5, Prop = "Nested List Prop"} + } + } + }; + return model; + } + + [Test] + public async Task Does_evaluate_variable_binding_expressions() + { + var context = new ScriptContext + { + Args = + { + ["key"] = "the-key", + } + }.Init(); + + context.VirtualFiles.WriteFile("page.html", @"Prop = {{ Prop }}"); + + var model = CreateModelBinding(); + + var pageResultArg = new NestedModelBinding + { + Int = 2, + Prop = "Nested Prop", + Object = new ModelBinding + { + Int = 21, + Prop = "Nested Nested Prop", + }, + AltNested = new AltNested + { + Field = "Object AltNested Field" + } + }; + + var result = await new PageResult(context.GetPage("page")) + { + Model = model, + Args = { ["pageResultArg"] = pageResultArg } + }.Init(); + + var scope = result.CreateScope(); + + object value; + + value = scope.EvaluateExpression("key"); + Assert.That(value, Is.EqualTo("the-key")); + value = scope.EvaluateExpression("Prop"); + Assert.That(value, Is.EqualTo(model.Prop)); + + value = scope.EvaluateExpression("model.Prop"); + Assert.That(value, Is.EqualTo(model.Prop)); + value = scope.EvaluateExpression("model.Object.Prop"); + Assert.That(value, Is.EqualTo(model.Object.Prop)); + value = scope.EvaluateExpression("model.Object.Object.Prop"); + Assert.That(value, Is.EqualTo(model.Object.Object.Prop)); + value = scope.EvaluateExpression("model.Object.AltNested.Field"); + Assert.That(value, Is.EqualTo(model.Object.AltNested.Field)); + value = scope.EvaluateExpression("model[0].Prop"); + Assert.That(value, Is.EqualTo(model[0].Prop)); + value = scope.EvaluateExpression("model[0].Object.Prop"); + Assert.That(value, Is.EqualTo(model[0].Object.Prop)); + value = scope.EvaluateExpression("model.List[0]"); + Assert.That(value, Is.EqualTo(model.List[0])); + value = scope.EvaluateExpression("model.List[0].Prop"); + Assert.That(value, Is.EqualTo(model.List[0].Prop)); + value = scope.EvaluateExpression("model.List[0].Object.Prop"); + Assert.That(value, Is.EqualTo(model.List[0].Object.Prop)); + value = scope.EvaluateExpression("model.Dictionary[\"map-key\"].Prop"); + Assert.That(value, Is.EqualTo(model.Dictionary["map-key"].Prop)); + value = scope.EvaluateExpression("model.Dictionary['map-key'].Object.Prop"); + Assert.That(value, Is.EqualTo(model.Dictionary["map-key"].Object.Prop)); + value = scope.EvaluateExpression("model.Dictionary['map-key'].Object.AltNested.Field"); + Assert.That(value, Is.EqualTo(model.Dictionary["map-key"].Object.AltNested.Field)); + value = scope.EvaluateExpression("Object.AltNested.Field"); + Assert.That(value, Is.EqualTo(model.Object.AltNested.Field)); + + value = scope.EvaluateExpression("pageResultArg.Object.Prop"); + Assert.That(value, Is.EqualTo(pageResultArg.Object.Prop)); + value = scope.EvaluateExpression("pageResultArg.AltNested.Field"); + Assert.That(value, Is.EqualTo(pageResultArg.AltNested.Field)); + } + + [Test] + public async Task Does_evaluate_variable_binding_expressions_in_template() + { + var context = new ScriptContext + { + Args = + { + ["key"] = "the-key", + } + }.Init(); + + context.VirtualFiles.WriteFile("page.html", @" +Object.Object.Prop = '{{ Object.Object.Prop }}' +model.Object.Object.Prop = '{{ model.Object.Object.Prop }}' +model.Dictionary['map-key'].Object.AltNested.Field = '{{ model.Dictionary['map-key'].Object.AltNested.Field }}' +model.Dictionary['map-key'].Object.AltNested.Field |> lower = '{{ model.Dictionary['map-key'].Object.AltNested.Field |> lower }}' +"); + + var model = CreateModelBinding(); + + var result = await new PageResult(context.GetPage("page")) { Model = model }.RenderToStringAsync(); + + Assert.That(result.NormalizeNewLines(), Is.EqualTo(@" +Object.Object.Prop = 'Nested Nested Prop' +model.Object.Object.Prop = 'Nested Nested Prop' +model.Dictionary['map-key'].Object.AltNested.Field = 'Dictionary AltNested Field' +model.Dictionary['map-key'].Object.AltNested.Field |> lower = 'dictionary altnested field' +".NormalizeNewLines())); + } + + [Test] + public void Can_render_onetime_page_and_layout() + { + var context = new ScriptContext + { + Args = { ["key"] = "the-key" } + }.Init(); + + var adhocPage = context.OneTimePage("<h1>{{ key }}</h1>", "html"); + var result = new PageResult(adhocPage) { Model = CreateModelBinding() }.Result; + Assert.That(result, Is.EqualTo("<h1>the-key</h1>")); + + adhocPage = context.OneTimePage("<h1>{{ model.Dictionary['map-key'].Object.AltNested.Field |> lower }}</h1>", "html"); + result = new PageResult(adhocPage) { Model = CreateModelBinding() }.Result; + Assert.That(result, Is.EqualTo("<h1>dictionary altnested field</h1>")); + + adhocPage = context.OneTimePage("<h1>{{ key }}</h1>", "html"); + result = new PageResult(adhocPage) + { + LayoutPage = context.OneTimePage("<html><title>{{ model.List[0].Object.Prop |> lower }}</title><body>{{ page }}</body></html>", "html"), + Model = CreateModelBinding() + }.Result; + Assert.That(result, Is.EqualTo("<html><title>nested list prop</title><body><h1>the-key</h1></body></html>")); + } + + [Test] + public async Task Can_render_onetime_page_with_real_layout() + { + var context = new ScriptContext + { + Args = { ["key"] = "the-key" } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", "<html><title>{{ model.List[0].Object.Prop |> lower }}</title><body>{{ page }}</body></html>"); + + var adhocPage = context.OneTimePage(@"<h1>{{ key }}</h1>", "html"); + var result = await new PageResult(adhocPage) + { + LayoutPage = context.GetPage("_layout"), + Model = CreateModelBinding() + }.RenderToStringAsync(); + Assert.That(result, Is.EqualTo("<html><title>nested list prop</title><body><h1>the-key</h1></body></html>")); + } + + public class ModelWithMethods + { + public string Name { get; set; } + + public string GetName() => Name; + + public ModelWithMethods Nested { get; set; } + } + + [Test] + public void Does_parse_MemberExpression_methods() + { + JsToken token; + + "model.GetName()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression(new JsIdentifier("model"), new JsIdentifier("GetName")) + ))); + + "model.Nested.GetName()".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsCallExpression( + new JsMemberExpression( + new JsMemberExpression( + new JsIdentifier("model"), + new JsIdentifier("Nested") + ), + new JsIdentifier("GetName") + ) + ))); + } + + [Test] + public void Does_not_allow_invoking_method_on_MemberExpression() + { + var context = new ScriptContext().Init(); + + var model = new ModelWithMethods { Nested = new ModelWithMethods { Name = "Nested" } }; + + try + { + var r = new PageResult(context.OneTimePage("{{ model.GetName() }}")){ Model = model }.Result; + Assert.Fail("Should throw"); + } + catch (BindingExpressionException e) + { + e.Message.Print(); + } + + try + { + var r = new PageResult(context.OneTimePage("{{ model.Nested.GetName() }}")){ Model = model }.Result; + Assert.Fail("Should throw"); + } + catch (BindingExpressionException e) + { + e.Message.Print(); + } + } + + [Test] + public void Binding_expressions_with_null_references_evaluate_to_null() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ model.Object.Prop }}")) { Model = new ModelBinding() }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ Object.Prop }}")) { Model = new ModelBinding() }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ model.Object.Object.Prop }}")) { Model = new ModelBinding() }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ model[0].Prop }}")) { Model = new ModelBinding() }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ model.List[0].Prop }}")) { Model = new ModelBinding() }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ model.Dictionary['key'].Prop }}")) { Model = new ModelBinding() }.Result, Is.Empty); + } + + [Test] + public void when_only_shows_code_when_true() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> when(auth) }}")) + { + Args = {["auth"] = true } + }.Result, Is.EqualTo("Is Authenticated")); + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> when(auth) }}")) + { + Args = {["auth"] = (bool?)true } + }.Result, Is.EqualTo("Is Authenticated")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> when(auth) }}")) + { + Args = {["auth"] = null} + }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> when(auth) }}")) + { + Args = {["auth"] = false} + }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> when(auth) }}")) + { + Args = {["auth"] = new AuthUserSession().IsAuthenticated} + }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> when(auth) }}")).Result, Is.Empty); + } + + [Test] + public void unless_shows_code_when_not_true() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unless(auth) }}")) + { + Args = {["auth"] = true } + }.Result, Is.Empty); + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unless(auth) }}")) + { + Args = {["auth"] = (bool?)true } + }.Result, Is.Empty); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unless(auth) }}")) + { + Args = {["auth"] = null} + }.Result, Is.EqualTo("Not Authenticated")); + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unless(auth) }}")) + { + Args = {["auth"] = false} + }.Result, Is.EqualTo("Not Authenticated")); + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unless(auth) }}")) + { + Args = {["auth"] = new AuthUserSession().IsAuthenticated} + }.Result, Is.EqualTo("Not Authenticated")); + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unless(auth) }}")) { + }.Result, Is.EqualTo("Not Authenticated")); + } + + [Test] + public void can_use_if_and_ifNot_as_alias_to_when_and_unless() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> if(auth) }}")) + { + Args = {["auth"] = true } + }.Result, Is.EqualTo("Is Authenticated")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> ifNot(auth) }}")) + { + Args = {["auth"] = true } + }.Result, Is.Empty); + } + + [Test] + public void Can_use_else_and_otherwise_filter_to_show_alternative_content() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unlessElse(auth, 'Is Authenticated') }}")) + { + Args = {["auth"] = false } + }.Result, Is.EqualTo("Not Authenticated")); + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> unlessElse(auth, 'Is Authenticated') }}")) + { + Args = {["auth"] = true } + }.Result, Is.EqualTo("Is Authenticated")); + + + Assert.That(new PageResult(context.OneTimePage("{{ 'Is Authenticated' |> ifElse(auth, 'Not Authenticated') }}")) + { + Args = {["auth"] = false } + }.Result, Is.EqualTo("Not Authenticated")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'Not Authenticated' |> ifNotElse(auth, 'Is Authenticated') }}")) + { + Args = {["auth"] = true } + }.Result, Is.EqualTo("Is Authenticated")); + } + + [Test] + public void Returns_original_string_with_unknown_variable() + { + var context = new ScriptContext + { + Args = + { + ["serverArg"] = "defined" + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ undefined }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ serverArg }}")).Result, Is.EqualTo("defined")); + Assert.That(new PageResult(context.OneTimePage("{{ serverArg |> unknownFilter }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ undefined |> titleCase }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ '' }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ null }}")).Result, Is.EqualTo("")); + } + + [Test] + public void Filters_with_HandleUnknownValueAttribute_handles_unkownn_values() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ undefined |> otherwise('undefined serverArg') }}")).Result, Is.EqualTo("undefined serverArg")); + } + + [Test] + public void Handles_truthy_and_falsy_conditions() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ undefined |> falsy('undefined value') }}")).Result, Is.EqualTo("undefined value")); + Assert.That(new PageResult(context.OneTimePage("{{ null |> falsy('null value') }}")).Result, Is.EqualTo("null value")); + Assert.That(new PageResult(context.OneTimePage("{{ '' |> falsy('empty string') }}")).Result, Is.EqualTo("empty string")); + Assert.That(new PageResult(context.OneTimePage("{{ false |> falsy('false value') }}")).Result, Is.EqualTo("false value")); + Assert.That(new PageResult(context.OneTimePage("{{ 0 |> falsy('0') }}")).Result, Is.EqualTo("0")); + + Assert.That(new PageResult(context.OneTimePage("{{ true |> falsy('true value') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ ' ' |> falsy('0') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> falsy('one value') }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ undefined |> truthy('undefined value') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ true |> truthy('true value') }}")).Result, Is.EqualTo("true value")); + Assert.That(new PageResult(context.OneTimePage("{{ ' ' |> truthy('whitespace') }}")).Result, Is.EqualTo("whitespace")); + Assert.That(new PageResult(context.OneTimePage("{{ 1 |> truthy('one value') }}")).Result, Is.EqualTo("one value")); + + Assert.That(new PageResult(context.OneTimePage("{{ null |> truthy('null value') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ '' |> truthy('empty string') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ false |> truthy('false value') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 0 |> truthy('0') }}")).Result, Is.EqualTo("")); + } + + [Test] + public void Handles_ifTruthy_and_ifFalsy_conditions() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'undefined value' |> ifFalsy(undefined) }}")).Result, Is.EqualTo("undefined value")); + Assert.That(new PageResult(context.OneTimePage("{{ 'null value' |> ifFalsy(null) }}")).Result, Is.EqualTo("null value")); + Assert.That(new PageResult(context.OneTimePage("{{ 'empty string' |> ifFalsy('') }}")).Result, Is.EqualTo("empty string")); + Assert.That(new PageResult(context.OneTimePage("{{ 'false value' |> ifFalsy(false) }}")).Result, Is.EqualTo("false value")); + Assert.That(new PageResult(context.OneTimePage("{{ 0 |> ifFalsy(0) }}")).Result, Is.EqualTo("0")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'true value' |> ifFalsy(true) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'whitespace' |> ifFalsy(' ') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'one value' |> ifFalsy(1) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'undefined value' |> ifTruthy(undefined) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'null value' |> ifTruthy(null) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'empty string' |> ifTruthy('') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'false value' |> ifTruthy(false) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 0 |> ifTruthy(0) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'true value' |> ifTruthy(true) }}")).Result, Is.EqualTo("true value")); + Assert.That(new PageResult(context.OneTimePage("{{ 'whitespace' |> ifTruthy(' ') }}")).Result, Is.EqualTo("whitespace")); + Assert.That(new PageResult(context.OneTimePage("{{ 'one value' |> ifTruthy(1) }}")).Result, Is.EqualTo("one value")); + } + + [Test] + public void Handles_strict_if_and_else_conditions() + { + var context = new ScriptContext().Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ 'undefined value' |> ifNot(undefined) }}")).Result, Is.EqualTo("undefined value")); + Assert.That(new PageResult(context.OneTimePage("{{ 'null value' |> ifNot(null) }}")).Result, Is.EqualTo("null value")); + Assert.That(new PageResult(context.OneTimePage("{{ 'empty string' |> ifNot('') }}")).Result, Is.EqualTo("empty string")); + Assert.That(new PageResult(context.OneTimePage("{{ 'false value' |> ifNot(false) }}")).Result, Is.EqualTo("false value")); + Assert.That(new PageResult(context.OneTimePage("{{ 0 |> ifNot(0) }}")).Result, Is.EqualTo("0")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'true value' |> ifNot(true) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'whitespace' |> ifNot(' ') }}")).Result, Is.EqualTo("whitespace")); + Assert.That(new PageResult(context.OneTimePage("{{ 'one value' |> ifNot(1) }}")).Result, Is.EqualTo("one value")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'undefined value' |> if(undefined) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'null value' |> if(null) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'empty string' |> if('') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'false value' |> if(false) }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 0 |> if(0) }}")).Result, Is.EqualTo("")); + + Assert.That(new PageResult(context.OneTimePage("{{ 'true value' |> if(true) }}")).Result, Is.EqualTo("true value")); + Assert.That(new PageResult(context.OneTimePage("{{ 'whitespace' |> if(' ') }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ 'one value' |> if(1) }}")).Result, Is.EqualTo("")); + } + + [Test] + public void Null_exceptions_render_empty_string() + { + var context = new ScriptContext + { +// RenderExpressionExceptions = true, + Args = + { + ["contextModel"] = new ModelBinding() + } + }.Init(); + + Assert.That(new PageResult(context.OneTimePage("{{ contextModel.Object.Prop }}")).Result, Is.EqualTo("")); + Assert.That(new PageResult(context.OneTimePage("{{ contextModel.Object.Prop |> otherwise('there is nothing') }}")).Result, Is.EqualTo("there is nothing")); + } + + [Test] + public void Can_use_whitespace_for_last_string_arg() + { + var context = new ScriptContext + { + Args = + { + ["ten"] = 10 + } + }.Init(); + + Assert.That(context.EvaluateScript(@"{{ ten |> multiply(ten) |> assignTo: result }} + 10 x 10 = {{ result }}").Trim(), Is.EqualTo("10 x 10 = 100")); + } + + [Test] + public void Can_emit_var_fragment_example() + { + var context = new ScriptContext().Init(); + + var output = context.EvaluateScript("The time is now:{{ pass: now |> dateFormat('HH:mm:ss') }}"); + Assert.That(output, Is.EqualTo("The time is now:{{ now |> dateFormat('HH:mm:ss') }}")); + } + + [Test] + public void Does_escape_quotes_in_strings() + { + var context = new ScriptContext().Init(); + + Assert.That(context.EvaluateScript("{{ \"string \\\"in\\\" quotes\" |> raw }}"), Is.EqualTo("string \"in\" quotes")); + Assert.That(context.EvaluateScript("{{ 'string \\'in\\' quotes' |> raw }}"), Is.EqualTo("string 'in' quotes")); + Assert.That(context.EvaluateScript("{{ `string \\`in\\` quotes` |> raw }}"), Is.EqualTo("string `in` quotes")); + } + + [Test] + public void Does_not_exceed_MaxQuota() + { + //times / range / itemsOf / repeat / repeating / padLeft / padRight + + var context = new ScriptContext().Init(); + + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 10001 |> times }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ range(10001) }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ range(1,10001) }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 10001 |> itemsOf(1) }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 'text' |> repeat(10001) }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 10001 |> repeating('text') }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 'text' |> padLeft(10001) }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 'text' |> padLeft(10001,'.') }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 'text' |> padRight(10001) }}")); + Assert.Throws<ScriptException>(() => context.EvaluateScript("{{ 'text' |> padRight(10001,'.') }}")); + } + + [Test] + public void Can_execute_filters_in_let_binding() + { + var context = new ScriptContext().Init(); + + var output = context.EvaluateScript( + @"{{ [{name:'Alice',score:50},{name:'Bob',score:40}] |> assignTo:scoreRecords }} +{{ scoreRecords + |> let({ name: `it['name']`, score: `it['score']`, i:`incr(index)` }) + |> select: {i}) {name} = {score}\n }}"); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +1) Alice = 50 +2) Bob = 40 +".NormalizeNewLines())); + } + + [Test] + public void Can_use_map_to_transform_lists_into_dictionaries() + { + var context = new ScriptContext().Init(); + + var output = context.EvaluateScript(@"{{ [[1,-1],[2,-2],[3,-3]] |> assignTo:coords }} +{{ coords + |> map('{ x: it[0], y: it[1] }') + |> scopeVars + |> select: {index |> incr}. ({x}, {y})\n +}}"); + + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +1. (1, -1) +2. (2, -2) +3. (3, -3) +".NormalizeNewLines())); + } + + [Test] + public void Can_control_whats_emitted_on_Unhandled_expression() + { + var context = new ScriptContext + { + OnUnhandledExpression = var => var.OriginalTextUtf8 + }.Init(); + + Assert.That(context.EvaluateScript("{{ unknownArg |> lower }}"), Is.EqualTo("{{ unknownArg |> lower }}")); + + context.OnUnhandledExpression = var => null; + Assert.That(context.EvaluateScript("{{ unknownArg |> lower }}"), Is.EqualTo("")); + } + + [Test] + public void null_binding_on_existing_object_renders_empty_string() + { + var c = new Dictionary<string, object> { {"name", "the name"} }; + var context = new ScriptContext + { + Args = + { + ["c"] = c, + ["it"] = new Dictionary<string, object> { {"customer", c} } + } + }.Init(); + + Assert.That(context.EvaluateScript("{{ c.name }}"), Is.EqualTo("the name")); + Assert.That(context.EvaluateScript("{{ c.missing }}"), Is.EqualTo("")); + Assert.That(context.EvaluateScript("{{ it.customer |> assignTo: c }}{{ c.missing }}"), Is.EqualTo("")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageTests.cs new file mode 100644 index 00000000000..c9db653fe34 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageTests.cs @@ -0,0 +1,527 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [Route("/products/{Id}")] + public class GetProduct + { + public int Id { get; set; } + } + + [Route("/existing-page")] + public class OverrideExistingPage + { + public string RequestVar { get; set; } + } + + public class SharpPagesService : Service + { + public ISharpPages Pages { get; set; } + + public object AnyHtml(GetProduct request) + { + return new PageResult(Pages.GetPage("product-view")) + { + Model = request, + LayoutPage = Pages.GetPage("product-layout"), + }; + } + + public object Any(OverrideExistingPage request) + { + return new PageResult(Pages.GetPage("override-page")) + { + Model = request, + Args = + { + { "title", "Service Title" } + }, + LayoutPage = Pages.GetPage("override-layout"), + }; + } + } + + class Model + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class SharpPageTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(SharpPageTests), typeof(SharpPagesService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new SharpPagesFeature()); + + AfterInitCallbacks.Add(host => { + var memFs = VirtualFileSources.GetMemoryVirtualFiles(); + foreach (var entry in HtmlFiles) + { + memFs.AppendFile(entry.Key, entry.Value); + } + }); + } + + static readonly Dictionary<string,string> HtmlFiles = new Dictionary<string, string> + { + { "_layout.html", "<html><head><title>{{ title }}</title></head><body id='layout'>{{ page }}</body></html>" }, + { "alt-layout.html", "<html><head><title>{{ title }}</title></head><body id='alt-layout'>{{ page }}</body></html>" }, + { "override-layout.html", "<html><head><title>{{ title }}</title></head><body id='override-layout'>{{ page }}</body></html>" }, + { "root-static-page.html", "<h1>/root-static page!</h1>" }, + { "full-static-page.html", "<html><head><title>Full Page</title></head><body><h1>Full Page</h1></body></html>" }, + { "existing-page.html", "<h1>Existing Page</h1>" }, + { "override-page.html", @" +<!-- +layout: alt-layout +title: Override Title +--> +<h1>Override Page</h1>" }, + { "noprefix-page.html", @" +<!-- +layout: alt-layout +--> +<h1>/noprefix page!</h1>" }, + { "dir/alt-layout.html", "<html><head><title>{{ title }}</title></head><body id='dir-alt-layout'>{{ page }}</body></html>" }, + { "dir/index.html", @" +<!-- +layout: alt-layout +title: no prefix @ /dir +--> +<h1>/dir/noprefix page!</h1>" }, + { "variable-layout-page.html", @" +<!-- +layout: alt-layout.html +title: Variable Layout +--> + +<h1>Variable Page</h1>" }, + { "variable-layout-page-space-delim.html", @" +<!-- +layout alt-layout.html +title Variable Layout +files.config {AccessKey:$AWS_S3_ACCESS_KEY} +--> + +<h1>Variable Page</h1>" }, + { "htmlencode-layout.html", @" +<!-- +layoutvar: layoutvar(< & > "" ') +--> +<html><head><title>{{ title }}</title></head><body id='htmlencode-layout'>{{ page }}<p>{{ layoutvar }}</p></body></html>" }, + { "htmlencode-page.html", @" +<!-- +layout: htmlencode-layout.html +title: We encode < & > +--> +<h1>/htmlencode-page!</h1>" }, + }; + } + + private readonly ServiceStackHost appHost; + public SharpPageTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + SharpPage CreatePage(IVirtualFile file) => + new SharpPage(appHost.GetPlugin<SharpPagesFeature>(), file); + + [Test] + public void Request_for_partial_page_returns_complete_page_with_default_layout() + { + var html = Config.ListeningOn.CombineWith("root-static-page.html") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(html, Does.StartWith("<html><head><title>")); + Assert.That(html, Does.Contain("id='layout'")); + Assert.That(html, Does.Contain("<h1>/root-static page!</h1>")); + } + + [Test] + public void Request_for_noprefix_page_returns_alt_layout() + { + var html = Config.ListeningOn.CombineWith("noprefix-page") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(html, Does.StartWith("<html><head><title>")); + Assert.That(html, Does.Contain("id='alt-layout'")); + Assert.That(html, Does.Contain("<h1>/noprefix page!</h1>")); + } + + [Test] + public void Request_for_variable_page_returns_complete_page_with_alt_layout() + { + var html = Config.ListeningOn.CombineWith("variable-layout-page.html") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(html, Does.StartWith("<html><head><title>Variable Layout</title>")); + Assert.That(html, Does.Contain("id='alt-layout'")); + Assert.That(html, Does.Contain("<h1>Variable Page</h1>")); + } + + [Test] + public void Request_for_htmlencode_pages_returns_htmlencoded_variables() + { + var html = Config.ListeningOn.CombineWith("htmlencode-page.html") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(html, Does.StartWith("<html><head><title>We encode &lt; &amp; &gt;</title>")); + Assert.That(html, Does.Contain("id='htmlencode-layout'")); + Assert.That(html, Does.Contain("<h1>/htmlencode-page!</h1>")); + Assert.That(html, Does.Contain("<p>layoutvar(&lt; &amp; &gt; &quot; &#39;)</p>")); + } + + [Test] + public void Request_for_dir_index_page_using_supported_conventions() + { + var htmlOrig = Config.ListeningOn.CombineWith("dir/index.html") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(htmlOrig, Does.StartWith("<html><head><title>no prefix @ /dir</title>")); + Assert.That(htmlOrig, Does.Contain("id='dir-alt-layout'")); + Assert.That(htmlOrig, Does.Contain("<h1>/dir/noprefix page!</h1>")); + + var html = Config.ListeningOn.CombineWith("dir/index") + .GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html, Is.EqualTo(htmlOrig)); + + html = Config.ListeningOn.CombineWith("dir/") + .GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html, Is.EqualTo(htmlOrig)); + + html = Config.ListeningOn.CombineWith("dir") + .GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html, Is.EqualTo(htmlOrig)); + } + +#if NETFX + [Test] + public void Request_for_dir_index_page_without_trailing_slash_auto_redirects() + { + Config.ListeningOn.CombineWith("dir") + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], Is.EqualTo(Config.ListeningOn.CombineWith("dir/"))); + }); + } +#endif + + [Test] + public void Request_for_page_with_underscore_prefix_is_forbidden() + { + try + { + Config.ListeningOn.CombineWith("_layout.html") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.Forbidden)); + } + + try + { + Config.ListeningOn.CombineWith("_layout") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.Forbidden)); + } + } + + [Test] + public void Request_for_existing_page_can_be_overridden_by_Service() + { + var html = Config.ListeningOn.CombineWith("existing-page") + .GetStringFromUrl(accept: MimeTypes.Html); + + Assert.That(html, Does.StartWith("<html><head><title>Service Title</title>")); + Assert.That(html, Does.Contain("id='override-layout'")); + Assert.That(html, Does.Contain("<h1>Override Page</h1>")); + } + + [Test] + public async Task Can_parse_page_with_page_variables() + { + var file = HostContext.AppHost.VirtualFileSources.GetFile("variable-layout-page.html"); + + var page = await CreatePage(file).Init(); + + Assert.That(page.Args["layout"], Is.EqualTo("alt-layout.html")); + Assert.That(page.Args["title"], Is.EqualTo("Variable Layout")); + Assert.That(((PageStringFragment)page.PageFragments[0]).Value.ToString(), Is.EqualTo("<h1>Variable Page</h1>")); + } + + [Test] + public async Task Can_parse_page_with_page_variables_without_colon_separators() + { + var file = HostContext.AppHost.VirtualFileSources.GetFile("variable-layout-page-space-delim.html"); + + var page = await CreatePage(file).Init(); + + Assert.That(page.Args["layout"], Is.EqualTo("alt-layout.html")); + Assert.That(page.Args["title"], Is.EqualTo("Variable Layout")); + Assert.That(page.Args["files.config"], Is.EqualTo("{AccessKey:$AWS_S3_ACCESS_KEY}")); + Assert.That(((PageStringFragment)page.PageFragments[0]).Value.ToString(), Is.EqualTo("<h1>Variable Page</h1>")); + } + + [Test] + public async Task Can_parse_template_with_body_variable() + { + var file = HostContext.AppHost.VirtualFileSources.GetFile("_layout.html"); + + var page = await CreatePage(file).Init(); + + Assert.That(page.PageFragments.Length, Is.EqualTo(5)); + var strFragment1 = (PageStringFragment)page.PageFragments[0]; + var varFragment2 = (PageVariableFragment)page.PageFragments[1]; + var strFragment3 = (PageStringFragment)page.PageFragments[2]; + var varFragment4 = (PageVariableFragment)page.PageFragments[3]; + var strFragment5 = (PageStringFragment)page.PageFragments[4]; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<html><head><title>")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</title></head><body id='layout'>")); + Assert.That(varFragment4.Binding, Is.EqualTo("page")); + Assert.That(strFragment5.Value.ToString(), Is.EqualTo("</body></html>")); + } + + [NUnit.Framework.Ignore("Flaky when run in suite on .NET Framework only, passes when run on its own or on .NET Core")] + [Test] + public void Does_limit_file_changes_checks_to_specified_time() + { + var context = new ScriptContext + { + DebugMode = false, + CheckForModifiedPagesAfter = TimeSpan.FromMilliseconds(100) + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body id=original> +{{ page }} +</body> +</html> +"); + context.VirtualFiles.WriteFile("page.html", "<h1>Original Contents</h1>"); + + var pageResult = new PageResult(context.GetPage("page")); + Assert.That(pageResult.ResultOutput, Is.Null); + + var output = pageResult.Result; + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=original> +<h1>Original Contents</h1> +</body> +</html> +".NormalizeNewLines())); + + context.VirtualFiles.WriteFile("_layout.html", + context.VirtualFiles.GetFile("_layout.html").ReadAllText().Replace("original", "updated")); + context.VirtualFiles.WriteFile("page.html", + context.VirtualFiles.GetFile("page.html").ReadAllText().Replace("Original", "Updated")); + + //Should return same contents when within CheckForModifiedPagesAfter + output = new PageResult(context.GetPage("page")).Result; + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=original> +<h1>Original Contents</h1> +</body> +</html> +".NormalizeNewLines())); + + Thread.Sleep(300); + + //Should render updated content + output = new PageResult(context.GetPage("page")).Result; + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=updated> +<h1>Updated Contents</h1> +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Never_checks_for_changes_if_CheckForModifiedPagesAfter_is_null() + { + var context = new ScriptContext + { + DebugMode = false, + CheckForModifiedPagesAfter = null + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", @" +<html> +<body id=original> +{{ page }} +</body> +</html> +"); + context.VirtualFiles.WriteFile("page.html", "<h1>Original Contents</h1>"); + + var output = new PageResult(context.GetPage("page")).Result; + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=original> +<h1>Original Contents</h1> +</body> +</html> +".NormalizeNewLines())); + + context.VirtualFiles.WriteFile("_layout.html", + context.VirtualFiles.GetFile("_layout.html").ReadAllText().Replace("original", "updated")); + context.VirtualFiles.WriteFile("page.html", + context.VirtualFiles.GetFile("page.html").ReadAllText().Replace("Original", "Updated")); + + Thread.Sleep(150); + + output = new PageResult(context.GetPage("page")).Result; + Assert.That(output.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=original> +<h1>Original Contents</h1> +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_find_last_modified_file_in_page() + { + var context = new ScriptContext + { + ScriptMethods = { new ProtectedScripts() } + }.Init(); + + context.VirtualFiles.WriteFile("_layout.html", "layout {{ page }} {{ 'layout-partial' |> partial }} {{ 'layout-file.txt' |> includeFile }} "); + context.VirtualFiles.WriteFile("page.html", "page: partial {{ 'root-partial' |> partial }}, file {{ 'file.txt' |> includeFile }}, selectParital: {{ true |> selectPartial: select-partial }}"); + context.VirtualFiles.WriteFile("root-partial.html", "root-partial: partial {{ 'inner-partial' |> partial }}, partial-file {{ 'partial-file.txt' |> includeFile }}"); + context.VirtualFiles.WriteFile("file.txt", "file.txt"); + context.VirtualFiles.WriteFile("inner-partial.html", "inner-partial.html"); + context.VirtualFiles.WriteFile("partial-file.txt", "partial-file.txt"); + context.VirtualFiles.WriteFile("select-partial.html", "select-partial.html"); + context.VirtualFiles.WriteFile("layout-partial.html", "layout-partial.html"); + context.VirtualFiles.WriteFile("layout-file.txt", "layout-file.txt"); + + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("page.html")).FileLastModified = new DateTime(2001, 01, 01); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("_layout.html")).FileLastModified = new DateTime(2001, 01, 02); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("root-partial.html")).FileLastModified = new DateTime(2001, 01, 03); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("file.txt")).FileLastModified = new DateTime(2001, 01, 04); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("inner-partial.html")).FileLastModified = new DateTime(2001, 01, 05); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("partial-file.txt")).FileLastModified = new DateTime(2001, 01, 06); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("select-partial.html")).FileLastModified = new DateTime(2001, 01, 07); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("layout-partial.html")).FileLastModified = new DateTime(2001, 01, 08); + ((InMemoryVirtualFile)context.VirtualFiles.GetFile("layout-file.txt")).FileLastModified = new DateTime(2001, 01, 09); + + var page = context.Pages.GetPage("page").Init().Result; + context.Pages.GetPage("root-partial").Init().Wait(); + + var lastModified = context.Pages.GetLastModified(page); + Assert.That(lastModified, Is.EqualTo(new DateTime(2001, 01, 09))); + } + + public class AsyncFilters : ScriptMethods + { + public async Task<object> reverseString(string text) + { + await Task.Yield(); + var chars = text.ToCharArray(); + Array.Reverse(chars); + return new string(chars); + } + } + + [Test] + public void Can_call_async_filters() + { + var context = new ScriptContext + { + ScriptMethods = { new AsyncFilters() } + }.Init(); + + var output = context.EvaluateScript("{{ 'foo' |> reverseString }}"); + Assert.That(output, Is.EqualTo("oof")); + } + + [Test] + public void Can_ignore_page_template_and_layout_with_Page_args() + { + var context = new ScriptContext().Init(); + + context.VirtualFiles.WriteFile("_layout.html", "<html><body>{{ page }}</body></html>"); + context.VirtualFiles.WriteFile("page.html", "<pre>{{ 12.34 |> currency }}</pre>"); + context.VirtualFiles.WriteFile("page-nolayout.html", "<!--\nlayout: none\n-->\n<pre>{{ 12.34 |> currency }}</pre>"); + context.VirtualFiles.WriteFile("ignore-page.html", "<!--\nignore: page\n-->\n<pre>{{ 12.34 |> currency }}</pre>"); + context.VirtualFiles.WriteFile("ignore-template.html", "<!--\nignore: template\n-->\n<pre>{{ 12.34 |> currency }}</pre>"); + + Assert.That(new PageResult(context.GetPage("page")).Result, Is.EqualTo("<html><body><pre>$12.34</pre></body></html>")); + Assert.That(new PageResult(context.GetPage("page-nolayout")).Result, Is.EqualTo("<pre>$12.34</pre>")); + Assert.That(new PageResult(context.GetPage("ignore-page")).Result, Is.EqualTo("<html><body><pre>{{ 12.34 |> currency }}</pre></body></html>")); + Assert.That(new PageResult(context.GetPage("ignore-template")).Result, Is.EqualTo("<pre>{{ 12.34 |> currency }}</pre>")); + } + + [Test] + public void Can_comment_out_filters() + { + var context = new ScriptContext().Init(); + context.VirtualFiles.WriteFile("page.html", "<pre>currency: {{* 12.34 |> currency *}}, date: {{* now *}}</pre>"); + + Assert.That(new PageResult(context.GetPage("page")).Result, Is.EqualTo("<pre>currency: , date: </pre>")); + } + + [Test] + public void Does_preverve_content_after_html_comments() + { + var context = new ScriptContext().Init(); + context.VirtualFiles.WriteFile("_layout.html", "<html><body><h1>{{title}}</h1>{{ page }}</body></html>"); + context.VirtualFiles.WriteFile("page.html", "<!--\ntitle:The Title\n--><p>para</p>"); + + var html = new PageResult(context.GetPage("page")).Result; + Assert.That(html, Is.EqualTo("<html><body><h1>The Title</h1><p>para</p></body></html>")); + } + + [Test] + public void Can_resolve_hidden_partials_without_prefix() + { + var context = new ScriptContext().Init(); + context.VirtualFiles.WriteFile("page.html", "Page {{ 'menu' |> partial }} {{ '_test-partial' |> partial }}"); + context.VirtualFiles.WriteFile("_menu-partial.html", "MENU"); + context.VirtualFiles.WriteFile("_test-partial.html", "TEST"); + + var result = new PageResult(context.GetPage("page")).Result; + result.Print(); + + Assert.That(result, Is.EqualTo("Page MENU TEST")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageUtilsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageUtilsTests.cs new file mode 100644 index 00000000000..8a8157f3a28 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPageUtilsTests.cs @@ -0,0 +1,797 @@ +using System; +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class SharpPageUtilsTests + { + [Test] + public void Can_parse_template_with_no_vars() + { + Assert.That(ScriptTemplateUtils.ParseTemplate("").Count, Is.EqualTo(0)); + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>title</h1>"); + Assert.That(fragments.Count, Is.EqualTo(1)); + + var strFragment = fragments[0] as PageStringFragment; + Assert.That(strFragment.Value.ToString(), Is.EqualTo("<h1>title</h1>")); + } + + [Test] + public void Can_parse_template_with_variable() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title }}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(0)); + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>")); + } + + [Test] + public void Can_parse_template_with_filter() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title |> filter }}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title |> filter }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(0)); + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>")); + + fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title |> filter() }}</h1>"); + + varFragment2 = fragments[1] as PageVariableFragment; + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title |> filter() }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(0)); + } + + [Test] + public void Can_parse_template_with_filter_without_whitespace() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{title}}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(0)); + + fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{title|filter}}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + strFragment1 = fragments[0] as PageStringFragment; + varFragment2 = fragments[1] as PageVariableFragment; + strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{title|filter}}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(0)); + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>")); + } + + [Test] + public void Can_parse_template_with_filter_with_arg() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title |> filter(1) }}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title |> filter(1) }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Arguments[0], Is.EqualTo(new JsLiteral(1))); + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>")); + } + + [Test] + public void Can_parse_template_with_filter_with_multiple_args() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title |> filter(1,2.2,'a',\"b\",true) }}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title |> filter(1,2.2,'a',\"b\",true) }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(5)); + Assert.That(varFragment2.FilterExpressions[0].Arguments[0], Is.EqualTo(new JsLiteral(1))); + Assert.That(varFragment2.FilterExpressions[0].Arguments[1], Is.EqualTo(new JsLiteral(2.2))); + Assert.That(varFragment2.FilterExpressions[0].Arguments[2], Is.EqualTo(new JsLiteral("a"))); + Assert.That(varFragment2.FilterExpressions[0].Arguments[3], Is.EqualTo(new JsLiteral("b"))); + Assert.That(varFragment2.FilterExpressions[0].Arguments[4], Is.EqualTo(JsLiteral.True)); + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>")); + } + + [Test] + public void Can_parse_template_with_multiple_filters_and_multiple_args() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title |> filter1 |> filter2(1) |> filter3(1,2.2,'a',\"b\",true) }}</h1>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title |> filter1 |> filter2(1) |> filter3(1,2.2,'a',\"b\",true) }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(3)); + + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter1")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(0)); + + Assert.That(varFragment2.FilterExpressions[1].Name, Is.EqualTo("filter2")); + Assert.That(varFragment2.FilterExpressions[1].Arguments.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[1].Arguments[0], Is.EqualTo(new JsLiteral(1))); + + Assert.That(varFragment2.FilterExpressions[2].Name, Is.EqualTo("filter3")); + Assert.That(varFragment2.FilterExpressions[2].Arguments.Length, Is.EqualTo(5)); + Assert.That(varFragment2.FilterExpressions[2].Arguments[0], Is.EqualTo(new JsLiteral(1))); + Assert.That(varFragment2.FilterExpressions[2].Arguments[1], Is.EqualTo(new JsLiteral(2.2))); + Assert.That(varFragment2.FilterExpressions[2].Arguments[2], Is.EqualTo(new JsLiteral("a"))); + Assert.That(varFragment2.FilterExpressions[2].Arguments[3], Is.EqualTo(new JsLiteral("b"))); + Assert.That(varFragment2.FilterExpressions[2].Arguments[4], Is.EqualTo(JsLiteral.True)); + + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>")); + } + + [Test] + public void Can_parse_template_with_multiple_variables_and_filters() + { + var fragments = ScriptTemplateUtils.ParseTemplate("<h1>{{ title |> filter1 }}</h1>\n<p>{{ content |> filter2(a) }}</p>"); + Assert.That(fragments.Count, Is.EqualTo(5)); + + var strFragment1 = fragments[0] as PageStringFragment; + var varFragment2 = fragments[1] as PageVariableFragment; + var strFragment3 = fragments[2] as PageStringFragment; + var varFragment4 = fragments[3] as PageVariableFragment; + var strFragment5 = fragments[4] as PageStringFragment; + + Assert.That(strFragment1.Value.ToString(), Is.EqualTo("<h1>")); + + Assert.That(varFragment2.OriginalText.ToString(), Is.EqualTo("{{ title |> filter1 }}")); + Assert.That(varFragment2.Binding, Is.EqualTo("title")); + Assert.That(varFragment2.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment2.FilterExpressions[0].Name, Is.EqualTo("filter1")); + Assert.That(varFragment2.FilterExpressions[0].Arguments.Length, Is.EqualTo(0)); + + Assert.That(strFragment3.Value.ToString(), Is.EqualTo("</h1>\n<p>")); + + Assert.That(varFragment4.OriginalText.ToString(), Is.EqualTo("{{ content |> filter2(a) }}")); + Assert.That(varFragment4.Binding, Is.EqualTo("content")); + Assert.That(varFragment4.FilterExpressions.Length, Is.EqualTo(1)); + Assert.That(varFragment4.FilterExpressions[0].Name, Is.EqualTo("filter2")); + Assert.That(varFragment4.FilterExpressions[0].Arguments.Length, Is.EqualTo(1)); + Assert.That(varFragment4.FilterExpressions[0].Arguments[0], Is.EqualTo(new JsIdentifier("a"))); + + Assert.That(strFragment5.Value.ToString(), Is.EqualTo("</p>")); + } + + [Test] + public void Can_parse_template_with_only_variable() + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ filter }}"); + Assert.That(fragments.Count, Is.EqualTo(1)); + Assert.That(((PageVariableFragment)fragments[0]).Binding, Is.EqualTo("filter")); + } + + [Test] + public void Can_parse_template_with_arg_and_multiple_filters() + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ ' - {{it}}' |> forEach(items) |> markdown }}"); + var varFragment = fragments[0] as PageVariableFragment; + + Assert.That(varFragment.OriginalText.ToString(), Is.EqualTo("{{ ' - {{it}}' |> forEach(items) |> markdown }}")); + Assert.That(varFragment.FilterExpressions.Length, Is.EqualTo(2)); + Assert.That(varFragment.FilterExpressions[0].Name, Is.EqualTo("forEach")); + Assert.That(varFragment.FilterExpressions[0].Arguments.Length, Is.EqualTo(1)); + Assert.That(varFragment.FilterExpressions[0].Arguments[0], Is.EqualTo(new JsIdentifier("items"))); + Assert.That(varFragment.FilterExpressions[1].Name, Is.EqualTo("markdown")); + } + + [Test] + public void Can_parse_filter_with_different_arg_types() + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ array(['a',1,'c']) }}"); + var varFragment = (PageVariableFragment)fragments[0]; + + Assert.That(varFragment.OriginalText.ToString(), Is.EqualTo("{{ array(['a',1,'c']) }}")); + Assert.That(varFragment.InitialExpression.Name, Is.EqualTo("array")); + Assert.That(varFragment.InitialExpression.Arguments.Length, Is.EqualTo(1)); + } + + [Test] + public void Can_parse_next_token() + { + JsToken token; + + "a".ParseJsExpression(out token); + Assert.That(((JsIdentifier)token).Name, Is.EqualTo("a")); + "a2".ParseJsExpression(out token); + Assert.That(((JsIdentifier)token).Name, Is.EqualTo("a2")); + " a2 ".ParseJsExpression(out token); + Assert.That(((JsIdentifier)token).Name, Is.EqualTo("a2")); + "'a'".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral("a"))); + "\"a\"".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral("a"))); + "`a`".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsTemplateLiteral("a"))); + "1".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(1))); + "100".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(100))); + "100.0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(100d))); + "1.0E+2".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(100d))); + "1e+2".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral(100d))); + "true".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(JsLiteral.True)); + "false".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(JsLiteral.False)); + "null".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(JsNull.Value)); + "{foo:1}".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression(new JsProperty(new JsIdentifier("foo"), new JsLiteral(1))) + )); + "{ foo : 1 , bar: 'qux', d: 1.1, b:false, n:null }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsIdentifier("foo"), new JsLiteral(1)), + new JsProperty(new JsIdentifier("bar"), new JsLiteral("qux")), + new JsProperty(new JsIdentifier("d"), new JsLiteral(1.1)), + new JsProperty(new JsIdentifier("b"), new JsLiteral(false)), + new JsProperty(new JsIdentifier("n"), JsNull.Value) + ) + )); + "{ map : { bar: 'qux', b: true } }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty( + new JsIdentifier("map"), + new JsObjectExpression( + new JsProperty(new JsIdentifier("bar"), new JsLiteral("qux")), + new JsProperty(new JsIdentifier("b"), new JsLiteral(true)) + ) + ) + ) + )); + "{varRef:foo}".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression(new JsProperty(new JsIdentifier("varRef"), new JsIdentifier("foo"))) + )); + "{ \"foo\" : 1 , \"bar\": 'qux', \"d\": 1.1, \"b\":false, \"n\":null }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsLiteral("foo"), new JsLiteral(1)), + new JsProperty(new JsLiteral("bar"), new JsLiteral("qux")), + new JsProperty(new JsLiteral("d"), new JsLiteral(1.1)), + new JsProperty(new JsLiteral("b"), new JsLiteral(false)), + new JsProperty(new JsLiteral("n"), JsNull.Value) + ) + )); + "{ `foo` : 1 , `bar`: 'qux', `d`: 1.1, `b`:false, `n`:null }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsTemplateLiteral("foo"), new JsLiteral(1)), + new JsProperty(new JsTemplateLiteral("bar"), new JsLiteral("qux")), + new JsProperty(new JsTemplateLiteral("d"), new JsLiteral(1.1)), + new JsProperty(new JsTemplateLiteral("b"), new JsLiteral(false)), + new JsProperty(new JsTemplateLiteral("n"), JsNull.Value) + ) + )); + + "[1,2,3]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression(new JsLiteral(1),new JsLiteral(2),new JsLiteral(3)))); + "[a,b,c]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression(new JsIdentifier("a"),new JsIdentifier("b"),new JsIdentifier("c")))); + "[a.Id,b.Name]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression( + new JsMemberExpression(new JsIdentifier("a"), new JsIdentifier("Id")), + new JsMemberExpression(new JsIdentifier("b"), new JsIdentifier("Name")) + ))); + "{ x: a.Id, y: b.Name }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsIdentifier("x"), new JsMemberExpression(new JsIdentifier("a"), new JsIdentifier("Id"))), + new JsProperty(new JsIdentifier("y"), new JsMemberExpression(new JsIdentifier("b"), new JsIdentifier("Name"))) + ) + )); + "['a',\"b\",`c`]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression(new JsLiteral("a"),new JsLiteral("b"),new JsTemplateLiteral("c")))); + " [ 'a' , \"b\" , 'c' ] ".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsArrayExpression(new JsLiteral("a"),new JsLiteral("b"),new JsLiteral("c")))); + "[ {a: 1}, {b: 2} ]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsArrayExpression( + new JsObjectExpression( + new JsProperty(new JsIdentifier("a"), new JsLiteral(1)) + ), + new JsObjectExpression( + new JsProperty(new JsIdentifier("b"), new JsLiteral(2)) + ) + ) + )); + "[ {a: { 'aa': [1,2,3] } }, { b: [a,b,c] }, 3, true, null ]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsArrayExpression( + new JsObjectExpression( + new JsProperty( + new JsIdentifier("a"), + new JsObjectExpression( + new JsProperty( + new JsLiteral("aa"), + new JsArrayExpression(new JsLiteral(1),new JsLiteral(2),new JsLiteral(3)) + ) + ) + ) + ), + new JsObjectExpression( + new JsProperty( + new JsIdentifier("b"), + new JsArrayExpression(new JsIdentifier("a"),new JsIdentifier("b"),new JsIdentifier("c")) + ) + ), + new JsLiteral(3), + new JsLiteral(true), + JsNull.Value + ) + )); + "{ k:'v', data: { id: 1, name: 'foo' }, k2: 'v2', k3: 'v3' }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsIdentifier("k"), new JsLiteral("v")), + new JsProperty( + new JsIdentifier("data"), + new JsObjectExpression( + new JsProperty(new JsIdentifier("id"), new JsLiteral(1)), + new JsProperty(new JsIdentifier("name"), new JsLiteral("foo")) + ) + ), + new JsProperty(new JsIdentifier("k2"), new JsLiteral("v2")), + new JsProperty(new JsIdentifier("k3"), new JsLiteral("v3")) + ) + )); + "[{name:'Alice', score:50}, {name: 'Bob', score:40}, {name:'Cathy', score:45}]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsArrayExpression( + new JsObjectExpression( + new JsProperty(new JsIdentifier("name"), new JsLiteral("Alice")), + new JsProperty(new JsIdentifier("score"), new JsLiteral(50)) + ), + new JsObjectExpression( + new JsProperty(new JsIdentifier("name"), new JsLiteral("Bob")), + new JsProperty(new JsIdentifier("score"), new JsLiteral(40)) + ), + new JsObjectExpression( + new JsProperty(new JsIdentifier("name"), new JsLiteral("Cathy")), + new JsProperty(new JsIdentifier("score"), new JsLiteral(45)) + ) + ) + )); + } + + [Test] + public void Can_parse_templates_within_literals() + { + JsToken token; + + "'<li>{{it}}</li>'".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral("<li>{{it}}</li>"))); + + var fragments = ScriptTemplateUtils.ParseTemplate("<ul>{{ '<li>{{it}}</li>' }}</ul>"); + Assert.That(fragments.Count, Is.EqualTo(3)); + } + + [Test] + public void Can_parse_method_binding_expressions() + { + JsToken token; + + "if(OR(gt(1,2),lt(3,4)))".ParseJsExpression(out token); + + Assert.That(token, Is.EqualTo( + new JsCallExpression( + new JsIdentifier("if"), + new JsCallExpression( + new JsIdentifier("OR"), + new JsCallExpression( + new JsIdentifier("gt"), + new JsLiteral(1), + new JsLiteral(2) + ), + new JsCallExpression( + new JsIdentifier("lt"), + new JsLiteral(3), + new JsLiteral(4) + ) + ) + ) + )); + + + @" + if ( + OR ( + gt ( 1 , 2 ) , + lt ( 3 , 4 ) + ) + )".ParseJsExpression(out token); + + Assert.That(token, Is.EqualTo( + new JsCallExpression( + new JsIdentifier("if"), + new JsCallExpression( + new JsIdentifier("OR"), + new JsCallExpression( + new JsIdentifier("gt"), + new JsLiteral(1), + new JsLiteral(2) + ), + new JsCallExpression( + new JsIdentifier("lt"), + new JsLiteral(3), + new JsLiteral(4) + ) + ) + ) + )); + } + + [Test] + public void Does_support_shorthand_object_initializers() + { + "{key}".ParseJsExpression(out var token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsIdentifier("key"), new JsIdentifier("key"), shorthand:true) + ) + )); + "{ key }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty(new JsIdentifier("key"), new JsIdentifier("key"), shorthand:true) + ) + )); + "{ map : { key , foo: 'bar' , qux } }".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsObjectExpression( + new JsProperty( + new JsIdentifier("map"), + new JsObjectExpression( + new JsProperty(new JsIdentifier("key"), new JsIdentifier("key"), shorthand:true), + new JsProperty(new JsIdentifier("foo"), new JsLiteral("bar")), + new JsProperty(new JsIdentifier("qux"), new JsIdentifier("qux"), shorthand:true) + ) + ) + ) + )); + } + + [Test] + public void Does_preserve_new_lines() + { + JsToken token; + + "'a\n'".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo(new JsLiteral("a\n"))); + } + + [Test] + public void Can_parse_boolean_logic_expressions() + { + JsToken token; + + "it.Id == 0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsBinaryExpression( + new JsMemberExpression(new JsIdentifier("it"), new JsIdentifier("Id")), + JsEquals.Operator, + new JsLiteral(0) + ) + )); + + var hold = ScriptConfig.AllowAssignmentExpressions; + ScriptConfig.AllowAssignmentExpressions = false; + + "it.Id = 0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsBinaryExpression( + new JsMemberExpression(new JsIdentifier("it"), new JsIdentifier("Id")), + JsEquals.Operator, + new JsLiteral(0) + ) + )); + + ScriptConfig.AllowAssignmentExpressions = hold; + } + + [Test] + public void Can_parse_assignment_expression() + { + JsToken token; + + "id = 0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsAssignmentExpression( + new JsIdentifier("id"), + JsAssignment.Operator, + new JsLiteral(0) + ) + )); + + "global.id = 0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsAssignmentExpression( + new JsMemberExpression(new JsIdentifier("global"), new JsIdentifier("id")), + JsAssignment.Operator, + new JsLiteral(0) + ) + )); + } + + [Test] + public void Can_parse_variable_declarations() + { + JsToken token; + + "var id = 0".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsVariableDeclaration( + JsVariableDeclarationKind.Var, + new JsDeclaration(new JsIdentifier("id"), new JsLiteral(0)) + ) + )); + + "var id = 0;".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsVariableDeclaration( + JsVariableDeclarationKind.Var, + new JsDeclaration(new JsIdentifier("id"), new JsLiteral(0)) + ) + )); + + "let a = 1 + 2, b = 3 * 4, c, d = 'D'".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsVariableDeclaration( + JsVariableDeclarationKind.Let, + new JsDeclaration(new JsIdentifier("a"), + new JsBinaryExpression(new JsLiteral(1), JsAddition.Operator, new JsLiteral(2) )) + ,new JsDeclaration(new JsIdentifier("b"), + new JsBinaryExpression(new JsLiteral(3), JsMultiplication.Operator, new JsLiteral(4) )) + ,new JsDeclaration(new JsIdentifier("c"), null) + ,new JsDeclaration(new JsIdentifier("d"), new JsLiteral("D") )) + ) + ); + + "const c = [1]".ParseJsExpression(out token); + Assert.That(token, Is.EqualTo( + new JsVariableDeclaration( + JsVariableDeclarationKind.Const, + new JsDeclaration(new JsIdentifier("c"), + new JsArrayExpression(new JsLiteral(1))) + ) + )); + } + + [Test] + public void Can_execute_variable_declarations() + { + var context = new ScriptContext().Init(); + Assert.That(context.RenderScript("{{var a = 1}}{{a}}"), Is.EqualTo("1")); + Assert.That(context.RenderScript("{{let a = 1, b = 1 + 2}}{{b}}"), Is.EqualTo("3")); + Assert.That(context.RenderScript("{{const a = 1, b = 1 + 2, c}}{{b}}"), Is.EqualTo("3")); + Assert.That(context.RenderScript("{{var a = 1, b = 1 + 2, c}}{{c}}"), Is.EqualTo("")); + Assert.That(context.RenderScript("{{let a = 1, b = 1 + 2,c,d='A'}}{{d}}"), Is.EqualTo("A")); + Assert.That(context.RenderScript("{{var a=1, b=1+2, c, d='A'}}{{d}}"), Is.EqualTo("A")); + + var expr = JS.expression("var a=1, b = 1 + 2, c, d='A'"); + var str = expr.ToJsAstString(); + } + + [Test] + public void Can_use_cleaner_whitespace_sensitive_syntax_for_string_arguments() + { + var fragments1 = ScriptTemplateUtils.ParseTemplate( + @"{{ +products + |> where: it.UnitsInStock = 0 + |> select: { it.productName |> raw } is sold out!\n +}}"); + + var fragments2 = ScriptTemplateUtils.ParseTemplate( + @"{{ products + |> where: it.UnitsInStock = 0 + |> select: { it.productName |> raw } is sold out!\n }}"); + + // i.e. is rewritten and is equivalent to: + var fragments3 = ScriptTemplateUtils.ParseTemplate( + @"{{ products |> where(′it.UnitsInStock = 0′) |> select(′{{ it.productName |> raw }} is sold out!\n′)}}"); + Assert.That(fragments3.Count, Is.EqualTo(1)); + + Assert.That(fragments1.Count, Is.EqualTo(1)); + var varFragment1 = fragments1[0] as PageVariableFragment; + Assert.That(varFragment1.FilterExpressions[0].Name, Is.EqualTo("where")); + Assert.That(varFragment1.FilterExpressions[0].Arguments.Length, Is.EqualTo(1)); + Assert.That(varFragment1.FilterExpressions[0].Arguments[0], Is.EqualTo( + new JsLiteral("it.UnitsInStock = 0") + )); + Assert.That(varFragment1.FilterExpressions[1].Name, Is.EqualTo("select")); + Assert.That(varFragment1.FilterExpressions[1].Arguments.Length, Is.EqualTo(1)); + Assert.That(varFragment1.FilterExpressions[1].Arguments[0], Is.EqualTo( + new JsLiteral("{{ it.productName |> raw }} is sold out!\\n") + )); + + foreach (var fragments in new[]{ fragments2, fragments3 }) + { + var varFragment = fragments[0] as PageVariableFragment; + Assert.That(varFragment.FilterExpressions[0].Name, Is.EqualTo(varFragment1.FilterExpressions[0].Name)); + Assert.That(varFragment.FilterExpressions[0].Arguments.Length, Is.EqualTo(varFragment1.FilterExpressions[0].Arguments.Length)); + Assert.That(varFragment.FilterExpressions[0].Arguments[0], Is.EqualTo(varFragment1.FilterExpressions[0].Arguments[0])); + Assert.That(varFragment.FilterExpressions[1].Name, Is.EqualTo(varFragment1.FilterExpressions[1].Name)); + Assert.That(varFragment.FilterExpressions[1].Arguments.Length, Is.EqualTo(varFragment1.FilterExpressions[1].Arguments.Length)); + Assert.That(varFragment.FilterExpressions[1].Arguments[0], Is.EqualTo(varFragment1.FilterExpressions[1].Arguments[0])); + } + } + + [Test] + public void Can_parse_pages_starting_with_values() + { + var fragments = ScriptTemplateUtils.ParseTemplate( + @"{{ [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }}\n"); + + var varFragment = (PageVariableFragment) fragments[0]; + Assert.That(varFragment.Expression, Is.EqualTo(new JsArrayExpression( + new JsMemberExpression(new JsIdentifier("c"), new JsIdentifier("CustomerId")), + new JsMemberExpression(new JsIdentifier("o"), new JsIdentifier("OrderId")), + new JsMemberExpression(new JsIdentifier("o"), new JsIdentifier("OrderDate")) + ))); + + Assert.That(varFragment.OriginalText.ToString(), Is.EqualTo("{{ [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }}")); + + var newLine = (PageStringFragment) fragments[1]; + Assert.That(newLine.Value.ToString(), Is.EqualTo("\\n")); + } + + [Test] + public void Can_parse_pages_starting_with_values_newLine() + { + var context = new ScriptContext().Init(); + var page = context.OneTimePage("{{ [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }}\n"); + var fragments = page.PageFragments; + +// var fragments = TemplatePageUtils.ParseTemplatePage( +// "{{ [c.CustomerId, o.OrderId, o.OrderDate] |> jsv }}\n"); + + var varFragment = (PageVariableFragment) fragments[0]; + Assert.That(varFragment.Expression, Is.EqualTo(new JsArrayExpression( + new JsMemberExpression(new JsIdentifier("c"), new JsIdentifier("CustomerId")), + new JsMemberExpression(new JsIdentifier("o"), new JsIdentifier("OrderId")), + new JsMemberExpression(new JsIdentifier("o"), new JsIdentifier("OrderDate")) + ))); + + var newLine = (PageStringFragment) fragments[1]; + Assert.That(newLine.Value.ToString(), Is.EqualTo("\n")); + } + + [Test] + public void Can_detect_invalid_syntax() + { + try + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ arg |> filter(' 1) }}"); + Assert.Fail("should throw"); + } + catch (ArgumentException e) + { + e.Message.Print(); + } + + try + { + var fragments = ScriptTemplateUtils.ParseTemplate("square = {{ 'square-partial |> partial({ ten }) }}"); + Assert.Fail("should throw"); + } + catch (ArgumentException e) + { + e.Message.Print(); + } + + try + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ arg |> filter({ unterminated:1) }}"); + Assert.Fail("should throw"); + } + catch (ArgumentException e) + { + e.Message.Print(); + } + + try + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ arg |> filter([ 1) }}"); + Assert.Fail("should throw"); + } + catch (ArgumentException e) + { + e.Message.Print(); + } + + } + + [Test] + public void Does_remove_new_line_between_var_literals() + { + var fragments = ScriptTemplateUtils.ParseTemplate("{{ 'foo' |> assignTo: bar }}\n{{ bar }}"); + Assert.That(fragments.Count, Is.EqualTo(2)); + fragments = ScriptTemplateUtils.ParseTemplate("{{ 'foo' |> assignTo: bar }}\r\n{{ bar }}"); + Assert.That(fragments.Count, Is.EqualTo(2)); + + fragments = ScriptTemplateUtils.ParseTemplate("{{ ['foo'] |> do: assign('bar', it) }}\n{{ bar }}"); + Assert.That(fragments.Count, Is.EqualTo(2)); + fragments = ScriptTemplateUtils.ParseTemplate("{{ do: assign('bar', 'foo') }}\n{{ bar }}"); + Assert.That(fragments.Count, Is.EqualTo(2)); + fragments = ScriptTemplateUtils.ParseTemplate("{{ 10 |> times |> do: assign('bar', 'foo') }}\n{{ bar }}"); + Assert.That(fragments.Count, Is.EqualTo(2)); + fragments = ScriptTemplateUtils.ParseTemplate("{{ 10 |> times |> do: assign('bar', 'foo') }}\nbar"); + Assert.That(fragments.Count, Is.EqualTo(2)); + var stringFragment = (PageStringFragment) fragments[1]; + Assert.That(stringFragment.Value.ToString(), Is.EqualTo("bar")); + } + + [Test] + public void Can_parse_empty_arguments() + { + JsToken token; + + "fn()".ParseJsExpression(out token); + Assert.That(((JsCallExpression)token).Name, Is.EqualTo("fn")); + "fn({})".ParseJsExpression(out token); + Assert.That(((JsCallExpression)token).Arguments.Length, Is.EqualTo(1)); + "fn({ })".ParseJsExpression(out token); + Assert.That(((JsCallExpression)token).Arguments.Length, Is.EqualTo(1)); + "fn({ })".ParseJsExpression(out token); + Assert.That(((JsCallExpression)token).Arguments.Length, Is.EqualTo(1)); + } + + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPagesIntegrationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPagesIntegrationTests.cs new file mode 100644 index 00000000000..24861cdf5da --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpPagesIntegrationTests.cs @@ -0,0 +1,713 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.Data; +using ServiceStack.IO; +using ServiceStack.OrmLite; +using ServiceStack.Script; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [Route("/rockstar-pages/{Id}")] + public class RockstarsPage + { + public int Id { get; set; } + public string Layout { get; set; } + } + + public class GetRockstarTemplate : IReturn<Rockstar> + { + public int Id { get; set; } + public string FirstName { get; set; } + } + + public class AddRockstarTemplate : IReturnVoid + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int Age { get; set; } + } + + public class MyTemplateServices : Service + { + public object Any(RockstarsPage request) => + new PageResult(Request.GetCodePage("rockstar-view")) + { + Layout = request.Layout, + Args = + { + ["rockstar"] = Db.SingleById<Rockstar>(request.Id) + } + }; + + public object Any(GetRockstarTemplate request) => !string.IsNullOrEmpty(request.FirstName) + ? Db.Single<Rockstar>(x => x.FirstName == request.FirstName) + : Db.SingleById<Rockstar>(request.Id); + + public void Any(AddRockstarTemplate request) => + Db.Save(request.ConvertTo<Rockstar>()); + } + + [Page("shadowed-page")] + public class ShadowedPage : SharpCodePage + { + string render() => @"<h1>Shadowed Template Code Page</h1>"; + } + + [Page("shadowed/index")] + public class ShadowedIndexPage : SharpCodePage + { + string render() => @"<h1>Shadowed Index Code Page</h1>"; + } + + [Page("rockstar")] + public class RockstarPage : ServiceStackCodePage + { + string render(int id) => renderRockstar(Db.SingleById<Rockstar>(id)); + + string renderRockstar(Rockstar rockstar) => $@" +<h1>{Request.RawUrl}</h1> +<h2>{rockstar.FirstName} {rockstar.LastName}</h2> +<b>{rockstar.Age}</b> +"; + } + + [Page("rockstar-view")] + public class RockstarPageView : ServiceStackCodePage + { + string render(Rockstar rockstar) => $@" +<h1>{Request.RawUrl}</h1> +<h2>{rockstar.FirstName} {rockstar.LastName}</h2> +<b>{rockstar.Age}</b> +"; + } + + [Page("products")] + [PageArg("title", "Products")] + public class ProductsPage : SharpCodePage + { + string render(Product[] products) => $@" + <table class='table'> + <thead> + <tr> + <th>Category</th> + <td>Name</td> + <td>Price</td> + </tr> + </thead> + {products.OrderBy(x => x.Category).Map(x => + $"<tr><th>{x.Category}</th><td>{x.ProductName}</td><td>{x.UnitPrice:C}</td></tr>\n").Join("")} + </table>"; + } + + [Page("products-sidebar", "layout-with-sidebar")] + [PageArg("title", "Products with Sidebar")] + public class ProductsSidebarPage : SharpCodePage + { + string render(Product[] products) => $@" + <table class='table'> + <thead> + <tr> + <th>Category</th> + <td>Name</td> + <td>Price</td> + </tr> + </thead> + {products.OrderBy(x => x.Category).Map(x => + $"<tr><th>{x.Category}</th><td>{x.ProductName}</td><td>{x.UnitPrice:C}</td></tr>\n").Join("")} + </table>"; + } + + [Page("sidebar")] + public class SidebarPage : SharpCodePage + { + string render(Dictionary<string, object> links) => $@"<ul> + {links.Map(entry => $"<li><a href='{entry.Key}'>{entry.Value}</a></li>\n").Join("")} +</ul>"; + } + + [Page("requestInfo")] + public class RequestInfoPartial : ServiceStackCodePage + { + string render() => $@"PathInfo: {Request.PathInfo}"; + } + + public class SharpPagesIntegrationTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(SharpPagesIntegrationTests), typeof(MyTemplateServices).Assembly) {} + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + DebugMode = true, + ForbiddenPaths = { "/plugins" } + }); + + container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + using (var db = container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<Rockstar>(); + db.InsertAll(UnitTestExample.SeedData); + } + + Plugins.Add(new SharpPagesFeature + { + Args = + { + ["products"] = QueryData.Products, + } + }); + + var files = TemplateFiles[0]; + + files.WriteFile("_layout.html", @" +<html> +<body id=root> +{{ page }} +</body> +</html> +"); + files.WriteFile("custom_layout.html", @" +<html> +<body id=custom> +{{ page }} +</body> +</html> +"); + files.WriteFile("layout-with-sidebar.html", @" +<html> +<body id=sidebar> +{{ 'sidebar' |> partial({ links: { 'a.html': 'A Page', 'b.html': 'B Page' } }) }} +{{ page }} +</body> +</html> +"); + files.WriteFile("dir/_layout.html", @" +<html> +<body id=dir> +{{ page }} +</body> +</html> +"); + files.WriteFile("alt-layout.html", @" +<html> +<body id=alt-layout> +{{ page }} +</body> +</html> +"); + files.WriteFile("dir/alt-layout.html", @" +<html> +<body id=dir-alt-layout> +{{ page }} +</body> +</html> +"); + files.WriteFile("alt/alt-layout.html", @" +<html> +<body id=alt-alt-layout> +{{ page }} +</body> +</html> +"); + files.WriteFile("dir/dir-page.html", @" +<h1>Dir Page</h1> +"); + + files.WriteFile("dir/alt-dir-page.html", @"<!-- +layout: alt-layout +--> + +<h1>Alt Dir Page</h1> +"); + + files.WriteFile("dir/alt-layout-alt-dir-page.html", @"<!-- +layout: alt/alt-layout +--> + +<h1>Alt Layout Alt Dir Page</h1> +"); + + files.WriteFile("index.html", @" +<h1>The Home Page</h1> +"); + + files.WriteFile("direct-page.html", @" +<h1>Direct Page</h1> +"); + files.WriteFile("shadowed-page.html", @" +<h1>Shadowed Template Page</h1> +"); + + files.WriteFile("shadowed/index.html", @" +<h1>Shadowed Index Page</h1> +"); + files.WriteFile("requestinfo-page.html", @" +<h1>The Request Info Page</h1> +<p>{{ 'requestInfo' |> partial }}</p> +"); + + files.WriteFile("dir/dir-partial.html", @" +<h2>Dir Partial</h2> +"); + files.WriteFile("dir/dir-page-partial.html", @" +<h1>Dir Page Partial</h1> +{{ 'dir-partial' |> partial }} +"); + + files.WriteFile("dir/dir-file.txt", @" +<h2>Dir File</h2> +"); + files.WriteFile("dir/dir-page-file.html", @" +<h1>Dir Page File</h1> +{{ 'dir-file.txt' |> includeFile }} +"); + files.WriteFile("dir/dir-page-file-cache.html", @" +<h1>Dir Page File Cache</h1> +{{ 'dir-file.txt' |> includeFileWithCache }} +"); + + files.WriteFile("rockstar-details.html", @"{{ it.FirstName }} {{ it.LastName }} ({{ it.Age }})"); + + files.WriteFile("rockstar-gateway.html", @" +{{ { qs.id, qs.firstName } |> ensureAnyArgsNotNull |> sendToGateway('GetRockstarTemplate') |> assignTo: rockstar }} +{{ rockstar |> ifExists |> selectPartial: rockstar-details }} +{{ rockstar |> endIfExists |> select: No rockstar with id: { qs.id } }} +{{ htmlError }} +"); + + files.WriteFile("rockstar-gateway-publish.html", @" +{{ 'id,firstName,lastName,age' |> importRequestParams }}{{ { id, firstName, lastName, age } |> ensureAllArgsNotNull |> publishToGateway('AddRockstarTemplate') }} +{{ 'rockstar-gateway' |> partial({ firstName }) }} +{{ htmlError }}"); + + files.WriteFile("plugins/dll.txt", "Forbidden File"); + } + + public readonly List<IVirtualPathProvider> TemplateFiles = new List<IVirtualPathProvider> { new MemoryVirtualFiles() }; + public override List<IVirtualPathProvider> GetVirtualFileSources() => TemplateFiles; + } + + public static string BaseUrl = Config.ListeningOn; + + private readonly ServiceStackHost appHost; + public SharpPagesIntegrationTests() + { + appHost = new AppHost() + .Init() + .Start(BaseUrl); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Can_process_home_page() + { + var html = BaseUrl.GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +<h1>The Home Page</h1> + +</body> +</html> +".NormalizeNewLines())); + } + + void Assert404(string url) + { + try + { + var response = url.GetStreamFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception e) + { + Assert.That(e.GetStatus(), Is.EqualTo(HttpStatusCode.NotFound)); + } + } + + [Test] + public void Unknown_paths_throw_404() + { + Assert404(BaseUrl.CombineWith(".unknown")); + Assert404(BaseUrl.CombineWith(".unknown/path")); + } + + [Test] + public void Does_direct_page_with_layout() + { + var html = BaseUrl.AppendPath("direct-page").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +<h1>Direct Page</h1> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_return_dir_page_with_dir_layout_by_default() + { + var html = BaseUrl.AppendPath("dir", "dir-page").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=dir> + +<h1>Dir Page</h1> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_return_alt_dir_page_with_closest_alt_layout() + { + var html = BaseUrl.AppendPath("dir", "alt-dir-page").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=dir-alt-layout> +<h1>Alt Dir Page</h1> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Can_request_alt_layout_within_alt_subdir() + { + var html = BaseUrl.AppendPath("dir", "alt-layout-alt-dir-page").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=alt-alt-layout> +<h1>Alt Layout Alt Dir Page</h1> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_return_shadowed_code_page_with_layout() + { + var html = BaseUrl.AppendPath("shadowed-page").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> +<h1>Shadowed Template Code Page</h1> +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_return_shadowed_index_code_page_with_layout() + { + var html = BaseUrl.AppendPath("shadowed").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> +<h1>Shadowed Index Code Page</h1> +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_execute_ServiceStackCodePage_with_Db_and_Request() + { + var html = BaseUrl.AppendPath("rockstar").AddQueryParam("id", "1").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +<h1>/rockstar?id=1</h1> +<h2>Jimi Hendrix</h2> +<b>27</b> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_execute_RockstarPageView() + { + var html = BaseUrl.AppendPath("rockstar-pages", "1").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=root> + +<h1>/rockstar-pages/1</h1> +<h2>Jimi Hendrix</h2> +<b>27</b> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_execute_RockstarPageView_with_custom_layout() + { + var html = BaseUrl.AppendPath("rockstar-pages", "1").AddQueryParam("layout", "custom_layout").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=custom> + +<h1>/rockstar-pages/1?layout=custom_layout</h1> +<h2>Jimi Hendrix</h2> +<b>27</b> + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_execute_ProductsPage_with_default_layout() + { + var html = BaseUrl.AppendPath("products").GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Does.StartWith(@"<html> +<body id=root> + + <table class='table'> + <thead> + <tr> + <th>Category</th> + <td>Name</td> + <td>Price</td> + </tr> + </thead> + <tr><th>Beverages</th><td>Chai</td><td>$18.00</td></tr> +<tr><th>Beverages</th><td>Chang</td><td>$19.00</td></tr>".NormalizeNewLines())); + } + + [Test] + public void Does_execute_ProductsPage_with_Sidebar_CodePage_layout() + { + var html = BaseUrl.AppendPath("products-sidebar").GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Does.StartWith(@"<html> +<body id=sidebar> +<ul> + <li><a href='a.html'>A Page</a></li> +<li><a href='b.html'>B Page</a></li> + +</ul> + + <table class='table'> + <thead> + <tr> + <th>Category</th> + <td>Name</td> + <td>Price</td> + </tr> + </thead> + <tr><th>Beverages</th><td>Chai</td><td>$18.00</td></tr> +<tr><th>Beverages</th><td>Chang</td><td>$19.00</td></tr>".NormalizeNewLines())); + } + + [Test] + public void CodePage_partials_are_injected_with_current_Request() + { + var html = BaseUrl.AppendPath("requestinfo-page").GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Does.StartWith(@" +<html> +<body id=root> + +<h1>The Request Info Page</h1> +<p>PathInfo: /requestinfo-page</p> + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_resolve_closest_partial_starting_from_page_directory() + { + var html = BaseUrl.AppendPath("dir","dir-page-partial").GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=dir> + +<h1>Dir Page Partial</h1> + +<h2>Dir Partial</h2> + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_resolve_closest_file_starting_from_page_directory() + { + var html = BaseUrl.AppendPath("dir", "dir-page-file").GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=dir> + +<h1>Dir Page File</h1> + +<h2>Dir File</h2> + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_resolve_closest_file_with_cache_starting_from_page_directory() + { + var html = BaseUrl.AppendPath("dir", "dir-page-file-cache").GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=dir> + +<h1>Dir Page File Cache</h1> + +<h2>Dir File</h2> + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Can_call_sendToGateway() + { + var html = BaseUrl.AppendPath("rockstar-gateway").AddQueryParam("id","1").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<html> +<body id=root> + +Jimi Hendrix (27) + + + +</body> +</html>".NormalizeNewLines())); + + html = BaseUrl.AppendPath("rockstar-gateway").AddQueryParam("firstName","Kurt").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<html> +<body id=root> + +Kurt Cobain (27) + + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Does_handle_error_calling_sendToGateway() + { + var html = BaseUrl.AppendPath("rockstar-gateway").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines() + .Replace("\nParameter name: firstName","") + .Replace(" (Parameter 'firstName')",""), + Does.StartWith(@"<html> +<body id=root> + + + +<pre class=""alert alert-danger"">ArgumentNullException: Value cannot be null. + +StackTrace: + at JsObjectExpression: {:qs.:id,:qs.:firstName}".NormalizeNewLines())); + + html = BaseUrl.AppendPath("rockstar-gateway").AddQueryParam("id","Kurt").GetStringFromUrl(); + Assert.That(html.NormalizeNewLines(), Does.StartWith(@"<html> +<body id=root> + + + +<pre class=""alert alert-danger"">FormatException: Input string was not in a correct format. + +StackTrace: + at JsObjectExpression: {:qs.:id,:qs.:firstName}".NormalizeNewLines())); + } + + [Test] + public void Can_call_publishToGateway() + { + var html = BaseUrl.AppendPath("rockstar-gateway-publish") + .AddQueryParam("id","8") + .AddQueryParam("firstName","Amy") + .AddQueryParam("lastName","Winehouse") + .AddQueryParam("age","27") + .GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@"<html> +<body id=root> + + +Amy Winehouse (27) + + + + +</body> +</html>".NormalizeNewLines())); + } + + [Test] + public void Does_handle_error_calling_publishToGateway() + { + var html = BaseUrl.AppendPath("rockstar-gateway-publish") + .AddQueryParam("id","8") + .AddQueryParam("firstName","Amy") + .AddQueryParam("age","27") + .GetStringFromUrl(); + + Assert.That(html.NormalizeNewLines() + .Replace("\nParameter name: lastName","") + .Replace(" (Parameter 'lastName')",""), + Does.StartWith(@"<html> +<body id=root> + + +<pre class=""alert alert-danger"">ArgumentNullException: Value cannot be null. + +StackTrace: + at JsObjectExpression: {:id,".NormalizeNewLines())); + } + + [Test] + public void Should_not_be_allowed_to_access_plugins_folder() + { + + try + { + var contents = BaseUrl.AppendPath("plugins", "dll.txt").GetStringFromUrl(); + Assert.Fail("Should throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.Forbidden)); + } + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpViewsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpViewsTests.cs new file mode 100644 index 00000000000..9b36f6484d6 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/SharpViewsTests.cs @@ -0,0 +1,305 @@ +using System.Collections.Generic; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Formats; +using ServiceStack.IO; +using ServiceStack.Script; +using ServiceStack.Testing; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + [Route("/view-pages/{Name}")] + public class TemplateViewPage : IReturn<TemplateViewPageResponse> + { + public string Name { get; set; } + } + public class TemplateViewPageResponse + { + public string Name { get; set; } + } + + [Route("/view-pages-request/{Name}")] + public class TemplateViewPageRequest : IReturn<TemplateViewPageRequest> + { + public string Name { get; set; } + } + + [Route("/view-pages-nested/{Name}")] + public class TemplateViewPageNested : IReturn<TemplateViewPageNested> + { + public string Name { get; set; } + } + + [Route("/view-pages-nested-sub/{Name}")] + public class TemplateViewPageNestedSub : IReturn<TemplateViewPageNested> + { + public string Name { get; set; } + } + + [Route("/view-pages-custom/{Name}")] + public class TemplateViewPageCustom : IReturn<TemplateViewPageCustom> + { + public string Name { get; set; } + public string View { get; set; } + public string Layout { get; set; } + } + + public class TemplateViewPagesServices : Service + { + public object Any(TemplateViewPage request) => new TemplateViewPageResponse { Name = request.Name }; + public object Any(TemplateViewPageRequest request) => request; + public object Any(TemplateViewPageNested request) => request; + public object Any(TemplateViewPageNestedSub request) => request; + public object Any(TemplateViewPageCustom request) => new HttpResult(request) + { + View = request.View, + Template = request.Layout, + }; + } + + public class SharpViewsTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(SharpViewsTests), typeof(TemplateViewPagesServices).Assembly) {} + + public readonly List<IVirtualPathProvider> TemplateFiles = new List<IVirtualPathProvider> + { + new MemoryVirtualFiles(), + new ResourceVirtualFiles(typeof(HtmlFormat).Assembly), + }; + + public override List<IVirtualPathProvider> GetVirtualFileSources() => TemplateFiles; + + public override void Configure(Container container) + { + Plugins.Add(new SharpPagesFeature()); + + var files = TemplateFiles[0]; + + files.WriteFile("_layout.html", @" +<html> +<body id=root> +{{ page }} +{{ htmlErrorDebug }} +</body> +</html> +"); + + files.WriteFile("alt-layout.html", @" +<html> +<body id=alt-root> +{{ page }} +{{ htmlErrorDebug }} +</body> +</html> +"); + + files.WriteFile("Views/_layout.html", @" +<html> +<body id=views> +{{ page }} +{{ htmlErrorDebug }} +</body> +</html> +"); + + files.WriteFile("Views/TemplateViewPageRequest.html", @" +<h1>TemplateViewPageRequest</h1> +<p>Name: {{ Name }}</p> +"); + + files.WriteFile("Views/TemplateViewPageRequest.html", @" +<h1>TemplateViewPageRequest</h1> +<p>Name: {{ Name }}</p> +"); + + files.WriteFile("Views/TemplateViewPageResponse.html", @" +<h1>TemplateViewPageResponse</h1> +<p>Name: {{ Name }}</p> +"); + + files.WriteFile("Views/nested/TemplateViewPageNested.html", @" +<h1>TemplateViewPageNested</h1> +<p>Name: {{ Name }}</p> +"); + + files.WriteFile("Views/nested/sub/TemplateViewPageNestedSub.html", @" +<h1>TemplateViewPageNestedSub</h1> +<p>Name: {{ Name }}</p> +"); + files.WriteFile("Views/nested/sub/_layout.html", @" +<html> +<body id=views-nested-sub> +{{ page }} +{{ htmlErrorDebug }} +</body> +</html> +"); + + } + } + public static string BaseUrl = Config.ListeningOn; + + private readonly ServiceStackHost appHost; + public SharpViewsTests() + { + appHost = new AppHost() + .Init() + .Start(BaseUrl); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_render_TemplateViewPageResponse_on_HTML_requests() + { + var html = BaseUrl.CombineWith("view-pages", "test") + .GetStringFromUrl(accept:MimeTypes.Html, + responseFilter:res => Assert.That(res.MatchesContentType(MimeTypes.Html))); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=views> + +<h1>TemplateViewPageResponse</h1> +<p>Name: test</p> + + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_render_TemplateViewPageRequest_on_HTML_requests() + { + var html = BaseUrl.CombineWith("view-pages-request", "test") + .GetStringFromUrl(accept: MimeTypes.Html, + responseFilter:res => Assert.That(res.MatchesContentType(MimeTypes.Html))); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=views> + +<h1>TemplateViewPageRequest</h1> +<p>Name: test</p> + + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_render_TemplateViewPageNested_on_HTML_requests() + { + var html = BaseUrl.CombineWith("view-pages-nested", "test") + .GetStringFromUrl(accept: MimeTypes.Html, + responseFilter:res => Assert.That(res.MatchesContentType(MimeTypes.Html))); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=views> + +<h1>TemplateViewPageNested</h1> +<p>Name: test</p> + + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_render_TemplateViewPageNestedSub_on_HTML_requests() + { + var html = BaseUrl.CombineWith("view-pages-nested-sub", "test") + .GetStringFromUrl(accept: MimeTypes.Html, + responseFilter:res => Assert.That(res.MatchesContentType(MimeTypes.Html))); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=views-nested-sub> + +<h1>TemplateViewPageNestedSub</h1> +<p>Name: test</p> + + +</body> +</html> +".NormalizeNewLines())); + } + + [Test] + public void Does_render_TemplateViewPageCustom_with_custom_view() + { + var html = BaseUrl.CombineWith("view-pages-custom", "test") + .AddQueryParam("view", "TemplateViewPageRequest") + .GetStringFromUrl(accept: MimeTypes.Html, + responseFilter:res => Assert.That(res.MatchesContentType(MimeTypes.Html))); + + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=views> + +<h1>TemplateViewPageRequest</h1> +<p>Name: test</p> + + +</body> +</html> +".NormalizeNewLines())); + + html = BaseUrl.CombineWith("view-pages-custom", "test") + .AddQueryParam("view", "TemplateViewPageResponse") + .AddQueryParam("layout", "alt-layout") + .GetStringFromUrl(accept: MimeTypes.Html); + Assert.That(html.NormalizeNewLines(), Is.EqualTo(@" +<html> +<body id=alt-root> + +<h1>TemplateViewPageResponse</h1> +<p>Name: test</p> + + +</body> +</html> +".NormalizeNewLines())); + + } + } + + public class TemplatePageFeatureTests + { + class InitFilter : ScriptMethods + { + public static bool HasInit = false; + + public bool initFilter() => HasInit = true; + } + + [Test] + public void Does_evaluate_init_page() + { + using (new BasicAppHost + { + ConfigureAppHost = host => { + var templateFiles = new MemoryVirtualFiles(); + templateFiles.WriteFile("_init.html", "{{ initFilter }}"); + host.AddVirtualFileSources.Add(templateFiles); + host.Plugins.Add(new SharpPagesFeature { + ScriptMethods = { new InitFilter() } + }); + } + }.Init()) + { + Assert.That(InitFilter.HasInit); + } + } + } + +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/TemplatedLiteralsTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/TemplatedLiteralsTests.cs new file mode 100644 index 00000000000..2bb2d623a71 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/TemplatedLiteralsTests.cs @@ -0,0 +1,47 @@ +using NUnit.Framework; +using ServiceStack.Script; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public class TemplateLiteralsTests + { + [Test] + public void Can_embed_escaped_strings_in_template_literals() + { + const string text = @"C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\favicon.ico +C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\app.exe +C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\app.deps.json +C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\app.runtimeconfig.json +C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\app.runtimeconfig.dev.json +C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\app.dll +C:\src\dotnet-app\src\WebApp\bin\Release\net6.0\app.pdb"; + + var context = new ScriptContext { + Args = { + ["file"] = text + } + }.Init(); + + var output = context.RenderCode(@" +#each line in file.readLines() where line.contains('\\bin\\') + line.substring(line.indexOf('\\bin\\') + 1) |> to => src + line.lastRightPart('\\') |> to => target + `<file src=""${src}"" target=""tools\\net6.0\\any\\${target}"" />`.raw() +/each +"); + // output.Print(); + Assert.That(output.NormalizeNewLines(), + Does.StartWith("<file src=\"bin\\Release\\net6.0\\favicon.ico\" target=\"tools\\net6.0\\any\\favicon.ico\" />")); + } + + [Test] + public void Does_UnRaw_RawStrings_in_Template_Literals() + { + var context = new ScriptContext().Init(); + var output = context.RenderCode("`type: ${1.typeName()}`"); + Assert.That(output.Trim(), Is.EqualTo("type: Int32")); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/TestUtils.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/TestUtils.cs new file mode 100644 index 00000000000..6aa9060cf9f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ScriptTests/TestUtils.cs @@ -0,0 +1,13 @@ +using System.Text.RegularExpressions; + +namespace ServiceStack.WebHost.Endpoints.Tests.ScriptTests +{ + public static class TestUtils + { + public static string NormalizeNewLines(this string text) => text.Trim().Replace("\r", ""); + public static string RemoveNewLines(this string text) => text.Trim().Replace("\r", "").Replace("\n", ""); + + static readonly Regex whitespace = new Regex(@"\s+", RegexOptions.Compiled); + public static string RemoveAllWhitespace(this string text) => whitespace.Replace(text, ""); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SendOneWayTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SendOneWayTests.cs index 83cfe9d0595..68115b07668 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/SendOneWayTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SendOneWayTests.cs @@ -1,21 +1,9 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Net; using System.Runtime.Serialization; using System.Text; -using System.Threading; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceHost; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Utils; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -37,17 +25,17 @@ public class PostOneWayRequest : IReturnVoid public string Title { get; set; } } - public class OneWayService : ServiceInterface.Service + public class OneWayService : Service { public static string LastResult { get; set; } public void Delete(DeleteOneWayRequest oneWayRequest) { - LastResult = oneWayRequest.Prefix + " " + Request.HttpMethod; + LastResult = oneWayRequest.Prefix + " " + Request.Verb; } public void Post(PostOneWayRequest oneWayRequest) { - LastResult = oneWayRequest.Prefix + " " + Request.HttpMethod + oneWayRequest.Title; + LastResult = oneWayRequest.Prefix + " " + Request.Verb + oneWayRequest.Title; } public void Put(PostOneWayRequest oneWayRequest) @@ -77,7 +65,7 @@ public override void Configure(Funq.Container container) OneWayServiceAppHostHttpListener appHost; private IRestClient client; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { appHost = new OneWayServiceAppHostHttpListener(); @@ -88,7 +76,7 @@ public void OnTestFixtureSetUp() OneWayService.LastResult = null; } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); @@ -119,15 +107,14 @@ public void Should_Respect_DataMember_Name() public static string GetResponse(String url, string json) { - var webRequest = (HttpWebRequest)WebRequest.Create(url); + var webRequest = WebRequest.CreateHttp(url); webRequest.Method = "PUT"; var formDataBytes = Encoding.UTF8.GetBytes(json); - webRequest.ContentLength = formDataBytes.Length; + webRequest.SetContentLength(formDataBytes.Length); webRequest.ContentType = "application/json"; - webRequest.GetRequestStream().Write(formDataBytes, 0, formDataBytes.Length); + PclExport.Instance.GetRequestStream(webRequest).Write(formDataBytes, 0, formDataBytes.Length); var webResponse = webRequest.GetResponse(); - return new StreamReader(webResponse.GetResponseStream()).ReadToEnd(); + return webResponse.GetResponseStream().ReadToEnd(); } - } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventIntegrationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventIntegrationTests.cs new file mode 100644 index 00000000000..50738a53b43 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventIntegrationTests.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Ignore("Requires SSE AppHost on"), TestFixture] //requires SSE AppHost on + public class ServerEventIntegrationTests + { + [Test] + public async Task Does_reconnect_when_remote_AppServer_restarts() + { + var client = new ServerEventsClient("http://localhost:11001", "home") + { + OnConnect = ctx => "OnConnect: {0}".Print(ctx.Channel), + OnCommand = msg => "OnCommand: {0}".Print(msg.Data), + OnException = ex => "OnException: {0}".Print(ex.Message), + OnMessage = msg => "OnMessage: {0}".Print(msg.Data), + OnHeartbeat = () => "OnHeartbeat".Print() + }; + + client.Handlers["chat"] = (source, msg) => + { + "Received Chat: {0}".Print(msg.Data); + }; + + await client.Connect(); + + await Task.Delay(TimeSpan.FromMinutes(10)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventTests.cs new file mode 100644 index 00000000000..9015f87db2a --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventTests.cs @@ -0,0 +1,1794 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Configuration; +using ServiceStack.Logging; +using ServiceStack.Redis; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/channels/{Channel}/chat")] + public class PostChatToChannel : IReturn<ChatMessage> + { + public string From { get; set; } + public string ToUserId { get; set; } + public string Channel { get; set; } + public string Message { get; set; } + public string Selector { get; set; } + } + + public class ChatMessage + { + public long Id { get; set; } + public string FromUserId { get; set; } + public string FromName { get; set; } + public string DisplayName { get; set; } + public string Message { get; set; } + public string UserAuthId { get; set; } + public bool Private { get; set; } + } + + [Route("/channels/{Channel}/raw")] + public class PostRawToChannel : IReturnVoid + { + public string From { get; set; } + public string ToUserId { get; set; } + public string Channel { get; set; } + public string Message { get; set; } + public string Selector { get; set; } + } + + [Route("/channels/{Channel}/object")] + public class PostObjectToChannel : IReturnVoid + { + public string ToUserId { get; set; } + public string Channel { get; set; } + public string Selector { get; set; } + + public CustomType CustomType { get; set; } + public SetterType SetterType { get; set; } + } + + public class CustomType + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class SetterType + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class ServerEventsService : Service + { + private static long msgId; + + public IServerEvents ServerEvents { get; set; } + + public async Task<object> Any(PostChatToChannel request) + { + var sub = ServerEvents.GetSubscriptionInfo(request.From); + if (sub == null) + throw HttpError.NotFound("Subscription {0} does not exist".Fmt(request.From)); + + var msg = new ChatMessage + { + Id = Interlocked.Increment(ref msgId), + FromUserId = sub.UserId, + FromName = sub.DisplayName, + Message = request.Message, + }; + + if (request.ToUserId != null) + { + msg.Private = true; + ServerEvents.NotifyUserId(request.ToUserId, request.Selector, msg); + var toSubs = ServerEvents.GetSubscriptionInfosByUserId(request.ToUserId); + foreach (var toSub in toSubs) + { + msg.Message = "@{0}: {1}".Fmt(toSub.DisplayName, msg.Message); + if (UseAsync) + await ServerEvents.NotifySubscriptionAsync(request.From, request.Selector, msg); + else + ServerEvents.NotifySubscription(request.From, request.Selector, msg); + } + } + else + { + if (UseAsync) + await ServerEvents.NotifyChannelAsync(request.Channel, request.Selector, msg); + else + ServerEvents.NotifyChannel(request.Channel, request.Selector, msg); + } + + return msg; + } + + public async Task Any(PostRawToChannel request) + { + var sub = ServerEvents.GetSubscriptionInfo(request.From); + if (sub == null) + throw HttpError.NotFound("Subscription {0} does not exist".Fmt(request.From)); + + if (request.ToUserId != null) + { + if (UseAsync) + await ServerEvents.NotifyUserIdAsync(request.ToUserId, request.Selector, request.Message); + else + ServerEvents.NotifyUserId(request.ToUserId, request.Selector, request.Message); + } + else + { + if (UseAsync) + await ServerEvents.NotifyChannelAsync(request.Channel, request.Selector, request.Message); + else + ServerEvents.NotifyChannel(request.Channel, request.Selector, request.Message); + } + } + + public bool UseAsync => ((ServerEventsAppHost) HostContext.AppHost).UseAsync; + + public async Task Any(PostObjectToChannel request) + { + if (request.ToUserId != null) + { + if (request.CustomType != null) + if (UseAsync) + await ServerEvents.NotifyUserIdAsync(request.ToUserId, request.Selector ?? Selector.Id<CustomType>(), request.CustomType); + else + ServerEvents.NotifyUserId(request.ToUserId, request.Selector ?? Selector.Id<CustomType>(), request.CustomType); + if (request.SetterType != null) + if (UseAsync) + await ServerEvents.NotifyUserIdAsync(request.ToUserId, request.Selector ?? Selector.Id<SetterType>(), request.SetterType); + else + ServerEvents.NotifyUserId(request.ToUserId, request.Selector ?? Selector.Id<SetterType>(), request.SetterType); + } + else + { + if (request.CustomType != null) + if (UseAsync) + await ServerEvents.NotifyChannelAsync(request.Channel, request.Selector ?? Selector.Id<CustomType>(), request.CustomType); + else + ServerEvents.NotifyChannel(request.Channel, request.Selector ?? Selector.Id<CustomType>(), request.CustomType); + if (request.SetterType != null) + if (UseAsync) + await ServerEvents.NotifyChannelAsync(request.Channel, request.Selector ?? Selector.Id<SetterType>(), request.SetterType); + else + ServerEvents.NotifyChannel(request.Channel, request.Selector ?? Selector.Id<SetterType>(), request.SetterType); + } + } + } + + public class ServerEventsAppHost : AppSelfHostBase + { + public ServerEventsAppHost() + : base(typeof(ServerEventsAppHost).Name, typeof(ServerEventsAppHost).Assembly) + { + NotifyChannelOfSubscriptions = true; + } + + public bool UseAsync { get; set; } + public bool UseRedisServerEvents { get; set; } + public bool LimitToAuthenticatedUsers { get; set; } + + public bool NotifyChannelOfSubscriptions { get; set; } + + public int IdleTimeoutMs { get; set; } + + public Action<IEventSubscription, Web.IResponse, string> OnPublish { get; set; } + + public override void Configure(Container container) + { + var ssePlugin = new ServerEventsFeature + { + HeartbeatInterval = TimeSpan.FromMilliseconds(200), + LimitToAuthenticatedUsers = LimitToAuthenticatedUsers, + OnPublish = OnPublish, + NotifyChannelOfSubscriptions = NotifyChannelOfSubscriptions + }; + if(IdleTimeoutMs > 0) + ssePlugin.IdleTimeout = TimeSpan.FromMilliseconds(IdleTimeoutMs); + Plugins.Add(ssePlugin); + + if (UseRedisServerEvents) + { + container.Register<IRedisClientsManager>(new PooledRedisClientManager()); + + container.Register<IServerEvents>(c => + new RedisServerEvents(c.Resolve<IRedisClientsManager>())); + + container.Resolve<IServerEvents>().Start(); + } + + if (LimitToAuthenticatedUsers) + { + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CustomCredentialsAuthProvider(), + })); + } + } + } + + public class CustomCredentialsAuthProvider : CredentialsAuthProvider + { + public override async Task<bool> TryAuthenticateAsync(IServiceBase authService, string userName, string password, CancellationToken token=default) + { + return userName == "user" && password == "pass"; + } + } + +#if DEBUG + +// [Ignore("Can hang builds")] + [TestFixture] + public class MemoryServerEventsTests : ServerEventsTests + { + protected override ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + } + + [Ignore("Can hang builds")] + [TestFixture] + public class MemoryServerEventsTestsAsync : ServerEventsTests + { + protected override ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost { UseAsync = true } + .Init() + .Start(Config.AbsoluteBaseUri); + } + } + + [Ignore("Hangs in new build server")] + [TestFixture] + public class RedisServerEventsTests : ServerEventsTests + { + protected override ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost { UseRedisServerEvents = true } + .Init() + .Start(Config.AbsoluteBaseUri); + } + } + + [TestFixture] + public class RedisServerEventsStatefulTests + { + public ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost + { + UseRedisServerEvents = true, + NotifyChannelOfSubscriptions = false, + IdleTimeoutMs = 400 + } + .Init() + .Start(Config.AbsoluteBaseUri); + } + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetup() + { + appHost = CreateAppHost(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + if (appHost.Resolve<IServerEvents>() is RedisServerEvents redisEvents) + redisEvents.Dispose(); + + appHost.Dispose(); + } + + [SetUp] + public void SetUp() + { + var serverEvents = appHost.TryResolve<IServerEvents>(); + serverEvents.Reset(); + } + + protected static ServerEventsClient CreateServerEventsClient(params string[] channels) + { + var client = new ServerEventsClient(Config.AbsoluteBaseUri, channels); + return client; + } + + [Test] + public async Task Does_clean_up_sse_id_subscriptions_regardless_of_config() + { + var manyClients = new List<ServerEventsClient>(); + for (var i = 0; i < 10; i++) + { + var client = CreateServerEventsClient(); + var task = client.Start(); + manyClients.Add(client); + } + + var mainClient = CreateServerEventsClient(); + mainClient.Start(); + + var redisPool = HostContext.Container.Resolve<IRedisClientsManager>(); + using var redisClient = redisPool.GetClient(); + + var initialResult = redisClient.ScanAllKeys("sse:id:*"); + var initialCount = initialResult.Count(); + + Assert.That(initialCount, Is.EqualTo(11)); + + foreach (var client in manyClients) + { + await client.Stop(); + client.Dispose(); + } + + // Message to process so that cleanup processes can start + mainClient.PostChat("hello from client1"); + + // Small wait for Redis async cleanup to happen + Thread.Sleep(200); + + var result = redisClient.ScanAllKeys("sse:id:*"); + var count = result.Count(); + + Assert.That(count, Is.EqualTo(1)); + } + } + + [Ignore("Hangs in new build server")] + [TestFixture] + public class RedisServerEventsTestsAsync : ServerEventsTests + { + protected override ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost { UseRedisServerEvents = true, UseAsync = true } + .Init() + .Start(Config.AbsoluteBaseUri); + } + } + + public abstract class ServerEventsTests + { + private ServiceStackHost appHost; + + public ServerEventsTests() + { + //LogManager.LogFactory = new ConsoleLogFactory(debugEnabled: true); + appHost = CreateAppHost(); + } + + protected abstract ServiceStackHost CreateAppHost(); + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + if (appHost.Resolve<IServerEvents>() is RedisServerEvents redisEvents) + redisEvents.Dispose(); + + appHost.Dispose(); + } + + [SetUp] + public void SetUp() + { + var serverEvents = appHost.TryResolve<IServerEvents>(); + serverEvents.Reset(); + } + + private static ServerEventsClient CreateServerEventsClient(params string[] channels) + { + var client = new ServerEventsClient(Config.AbsoluteBaseUri, channels); + return client; + } + + [Test] + public async Task Can_connect_to_ServerEventsStream() + { + using (var client = CreateServerEventsClient()) + { + var task = client.Connect(); + var connectMsg = await task.WaitAsync(); + + Assert.That(connectMsg.HeartbeatUrl, Does.StartWith(Config.AbsoluteBaseUri)); + Assert.That(connectMsg.UnRegisterUrl, Does.StartWith(Config.AbsoluteBaseUri)); + Assert.That(connectMsg.HeartbeatIntervalMs, Is.GreaterThan(0)); + Assert.That(connectMsg.IdleTimeoutMs, Is.EqualTo(TimeSpan.FromSeconds(30).TotalMilliseconds)); + } + } + + [Test] + public async Task Does_fire_onJoin_events() + { + using (var client = CreateServerEventsClient()) + { + var taskConnect = client.Connect(); + var taskMsg = client.WaitForNextCommand(); + + var connectMsg = await taskConnect.WaitAsync(); + Assert.That(connectMsg.HeartbeatUrl, Does.StartWith(Config.AbsoluteBaseUri)); + + var joinMsg = (ServerEventJoin)await taskMsg.WaitAsync(); + Assert.That(joinMsg.DisplayName, Is.EqualTo(client.ConnectionInfo.DisplayName)); + } + } + + [Test] + public async Task Does_fire_onJoin_events_for_multiple_Channels() + { + var channels = new[] { "A", "B", "C" }; + using (var client = CreateServerEventsClient(channels)) + { + var joinMsgs = new List<ServerEventJoin>(); + var allJoinsReceived = new TaskCompletionSource<bool>(); + + client.OnJoin = msg => + { + joinMsgs.Add(msg); + if (joinMsgs.Count == channels.Length) + allJoinsReceived.SetResult(true); + }; + + var connectMsg = await client.Connect().WaitAsync(2000); + Assert.That(connectMsg.HeartbeatUrl, Does.StartWith(Config.AbsoluteBaseUri)); + + await allJoinsReceived.Task.WaitAsync(3000); + + Assert.That(joinMsgs.Count, Is.EqualTo(channels.Length)); + for (int i = 0; i < channels.Length; i++) + { + var joinMsg = joinMsgs[i]; + Assert.That(joinMsg.Channel, Is.EqualTo(channels[i])); + Assert.That(joinMsg.DisplayName, Is.EqualTo(client.ConnectionInfo.DisplayName)); + } + } + } + + [Test] + public async Task Does_not_fire_UnobservedTaskException() + { + var unobservedTaskException = false; + TaskScheduler.UnobservedTaskException += (s, e) => + { + unobservedTaskException = true; + }; + using (var client1 = CreateServerEventsClient()) + { + using (var connectedEvent = new ManualResetEvent(false)) + { + client1.OnConnect += e => { connectedEvent.Set(); }; + client1.Start(); + Assert.True(connectedEvent.WaitOne(TimeSpan.FromSeconds(10))); + } + + // Ensure that "stream.ReadAsync" is called + await Task.Delay(200); + } + + GC.Collect(); + GC.WaitForPendingFinalizers(); + + // collect finalized objects + GC.Collect(); + GC.WaitForPendingFinalizers(); + + Assert.IsFalse(unobservedTaskException); + } + + [Test] + public async Task Does_fire_all_callbacks() + { + using (var client1 = CreateServerEventsClient()) + { + ServerEventConnect connectMsg = null; + var msgs = new List<ServerEventMessage>(); + var commands = new List<ServerEventMessage>(); + var errors = new List<Exception>(); + + client1.OnConnect = e => connectMsg = e; + client1.OnCommand = e => commands.Add(e); + client1.OnMessage = msgs.Add; + client1.OnException = errors.Add; + + //Pop Connect + onJoin messages off + var taskConnect = client1.Connect(); + var taskCmd = client1.WaitForNextCommand(); + + await taskConnect.WaitAsync(); + await taskCmd.WaitAsync(); + + var joinMsg = commands.OfType<ServerEventJoin>().FirstOrDefault(); + + Assert.That(connectMsg, Is.Not.Null, "connectMsg == null"); + Assert.That(joinMsg, Is.Not.Null, "joinMsg == null"); + + Assert.That(msgs.Count, Is.EqualTo(0)); + Assert.That(errors.Count, Is.EqualTo(0)); + Assert.That(commands.Count, Is.EqualTo(1)); //join + + commands.Clear(); + + "New Client....".Print(); + taskCmd = client1.WaitForNextCommand(); + + using (var client2 = CreateServerEventsClient()) + { + var connectMsg2 = await client2.Connect(); + + if (taskCmd != await Task.WhenAny(taskCmd, Task.Delay(2000))) + throw new TimeoutException(); + + joinMsg = commands.OfType<ServerEventJoin>().FirstOrDefault(); + + taskCmd = client1.WaitForNextCommand(); + + connectMsg2.UnRegisterUrl.GetStringFromUrl(); //unsubscribe 2nd client + } + + await taskCmd.WaitAsync(); + + var leaveMsg = commands.OfType<ServerEventLeave>().FirstOrDefault(); + + Assert.That(joinMsg, Is.Not.Null, "joinMsg == null"); //2nd connection + Assert.That(leaveMsg, Is.Not.Null, "leaveMsg == null"); + Assert.That(commands.Count, Is.GreaterThanOrEqualTo(2)); //join + leave + Assert.That(errors.Count, Is.EqualTo(0)); + } + } + + [Test] + public async Task Does_receive_messages() + { + using (var client1 = CreateServerEventsClient()) + using (var client2 = CreateServerEventsClient()) + { + var msgs1 = new List<ServerEventMessage>(); + var msgs2 = new List<ServerEventMessage>(); + + client1.OnMessage = msgs1.Add; + client2.OnMessage = msgs2.Add; + + await Task.WhenAll(client1.Connect(), client1.WaitForNextCommand()); //connect1 + join1 + + "client2.Connect()...".Print(); + var join1 = client1.WaitForNextCommand(); + await Task.WhenAll(client2.Connect(), client2.WaitForNextCommand(), join1); //connect2 + join2 + join1 + + "Waiting for Msg1...".Print(); + var taskMsg1 = client1.WaitForNextMessage(); + var taskMsg2 = client2.WaitForNextMessage(); + + var info1 = client1.ConnectionInfo; + client1.PostChat("hello from client1"); + + var msg1 = await taskMsg1.WaitAsync(); + var msg2 = await taskMsg2.WaitAsync(); + + Assert.That(msg1.EventId, Is.GreaterThan(0)); + Assert.That(msg2.EventId, Is.GreaterThan(0)); + Assert.That(msg1.Selector, Is.EqualTo("cmd.chat")); + Assert.That(msg2.Selector, Is.EqualTo("cmd.chat")); + + var chatMsg1 = msg1.Json.FromJson<ChatMessage>(); + Assert.That(chatMsg1.Id, Is.GreaterThan(0)); + Assert.That(chatMsg1.FromUserId, Is.EqualTo(info1.UserId)); //-1 / anon user + Assert.That(chatMsg1.FromName, Is.EqualTo(info1.DisplayName)); //user1 / anon user + Assert.That(chatMsg1.Message, Is.EqualTo("hello from client1")); + + var chatMsg2 = msg2.Json.FromJson<ChatMessage>(); + Assert.That(chatMsg2.Id, Is.GreaterThan(0)); + Assert.That(chatMsg2.FromUserId, Is.EqualTo(info1.UserId)); + Assert.That(chatMsg2.FromName, Is.EqualTo(info1.DisplayName)); + Assert.That(chatMsg2.Message, Is.EqualTo("hello from client1")); + + Assert.That(msgs1.Count, Is.EqualTo(1)); + Assert.That(msgs2.Count, Is.EqualTo(1)); + + "Waiting for Msg2...".Print(); + taskMsg1 = client1.WaitForNextMessage(); + taskMsg2 = client2.WaitForNextMessage(); + + var info2 = client2.ConnectionInfo; + client2.PostChat("hello from client2"); + + msg1 = await taskMsg1.WaitAsync(); + msg2 = await taskMsg2.WaitAsync(); + + chatMsg1 = msg1.Json.FromJson<ChatMessage>(); + Assert.That(chatMsg1.FromUserId, Is.EqualTo(info2.UserId)); + Assert.That(chatMsg1.FromName, Is.EqualTo(info2.DisplayName)); + Assert.That(chatMsg1.Message, Is.EqualTo("hello from client2")); + + chatMsg2 = msg2.Json.FromJson<ChatMessage>(); + Assert.That(chatMsg2.FromUserId, Is.EqualTo(info2.UserId)); + Assert.That(chatMsg2.FromName, Is.EqualTo(info2.DisplayName)); + Assert.That(chatMsg2.Message, Is.EqualTo("hello from client2")); + + Assert.That(msgs1.Count, Is.EqualTo(2)); + Assert.That(msgs2.Count, Is.EqualTo(2)); + } + } + + [Test] + public async Task Does_send_multiple_heartbeats() + { + using (var client1 = CreateServerEventsClient()) + { + var heartbeats = 0; + var tcs = new TaskCompletionSource<object>(); + client1.OnHeartbeat = () => + { + //configured to 1s interval in AppHost + if (heartbeats++ == 2) + tcs.SetResult(null); + }; + client1.Start(); + + await tcs.Task.WaitAsync(); + + Assert.That(heartbeats, Is.GreaterThanOrEqualTo(2)); + } + } + + private static void EnsureSynchronizationContext() + { + if (SynchronizationContext.Current != null) return; + + SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); + } + + [Test] + public async Task GetStringFromUrlAsync_does_throw_error() + { + EnsureSynchronizationContext(); + + var heartbeatUrl = Config.AbsoluteBaseUri.CombineWith("event-heartbeat") + .AddQueryParam("id", "unknown"); + + var task = heartbeatUrl.GetStringFromUrlAsync() + .Success(t => + { + "Was success".Print(); + Assert.Fail("Should Error"); + }) + .Error(ex => + { + "Was error".Print(); + }) + .ContinueWith(t => + { + "was cancelled".Print(); + Assert.Fail("Should Error"); + }, TaskContinuationOptions.OnlyOnCanceled) + ; + + if (task != await Task.WhenAny(task, Task.Delay(2000))) + throw new TimeoutException(); + } + + [Test] + public async Task Does_reconnect_on_lost_connection() + { + try + { + using (var client1 = CreateServerEventsClient()) + { + var serverEvents = appHost.TryResolve<IServerEvents>(); + var msgs = new List<ServerEventMessage>(); + + client1.OnMessage = msgs.Add; + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + + client1.PostChat("msg1 from client1"); + + var msg1 = await msgTask.WaitAsync(); + + serverEvents.Reset(); //Dispose all existing subscriptions + + using (var client2 = CreateServerEventsClient()) + { + await client2.Connect(); + + await Task.WhenAny(client1.Connect(), Task.Delay(2000)); + + msgTask = client1.WaitForNextMessage(); + client2.PostChat("msg2 from client2"); + } + + "Waiting for max 5s...".Print(); + var msg2 = await msgTask.WaitAsync(5000); + + var chatMsg2 = msg2.Json.FromJson<ChatMessage>(); + + Assert.That(chatMsg2.Message, Is.EqualTo("msg2 from client2")); + } + } + catch (Exception ex) + { + ex.Message.Print(); + throw; + } + } + + [Test] + public async Task Does_send_message_to_Handler() + { + using (var client1 = CreateServerEventsClient()) + { + await client1.Connect(); + + ChatMessage chatMsg = null; + client1.Handlers["chat"] = (client, msg) => + { + chatMsg = msg.Json.FromJson<ChatMessage>(); + }; + + var msgTask = client1.WaitForNextMessage(); + client1.PostChat("msg1"); + await msgTask.WaitAsync(); + + Assert.That(chatMsg, Is.Not.Null); + Assert.That(chatMsg.Message, Is.EqualTo("msg1")); + + msgTask = client1.WaitForNextMessage(); + client1.PostChat("msg2"); + await msgTask.WaitAsync(); + + Assert.That(chatMsg, Is.Not.Null); + Assert.That(chatMsg.Message, Is.EqualTo("msg2")); + } + } + + [Test] + public async Task Does_send_message_to_named_receiver() + { + using (var client1 = CreateServerEventsClient()) + { + client1.RegisterNamedReceiver<TestNamedReceiver>("test"); + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + client1.Post(new CustomType { Id = 1, Name = "Foo" }, "test.FooMethod"); + await msgTask.WaitAsync(); + + var foo = TestNamedReceiver.FooMethodReceived; + Assert.That(foo, Is.Not.Null); + Assert.That(foo.Id, Is.EqualTo(1)); + Assert.That(foo.Name, Is.EqualTo("Foo")); + + msgTask = client1.WaitForNextMessage(); + client1.Post(new CustomType { Id = 2, Name = "Bar" }, "test.BarMethod"); + await msgTask.WaitAsync(); + + var bar = TestNamedReceiver.BarMethodReceived; + Assert.That(bar, Is.Not.Null); + Assert.That(bar.Id, Is.EqualTo(2)); + Assert.That(bar.Name, Is.EqualTo("Bar")); + + msgTask = client1.WaitForNextMessage(); + client1.Post(new CustomType { Id = 3, Name = "Baz" }, "test.BazMethod"); + await msgTask.WaitAsync(); + + var baz = TestNamedReceiver.NoSuchMethodReceived; + Assert.That(baz, Is.Not.Null); + Assert.That(baz.Id, Is.EqualTo(3)); + Assert.That(baz.Name, Is.EqualTo("Baz")); + Assert.That(TestNamedReceiver.NoSuchMethodSelector, Is.EqualTo("BazMethod")); + + msgTask = client1.WaitForNextMessage(); + client1.Post(new CustomType { Id = 4, Name = "Qux" }, "test.QuxSetter"); + await msgTask.WaitAsync(); + var qux = TestNamedReceiver.QuxSetterReceived; + Assert.That(qux, Is.Not.Null); + Assert.That(qux.Id, Is.EqualTo(4)); + Assert.That(qux.Name, Is.EqualTo("Qux")); + } + } + + [Test] + public async Task Does_send_message_to_global_receiver() + { + using (var client1 = CreateServerEventsClient()) + { + client1.RegisterReceiver<TestGlobalReceiver>(); + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + client1.Post(new CustomType { Id = 1, Name = "Foo" }); + await msgTask.WaitAsync(); + + var foo = TestGlobalReceiver.CustomTypeReceived; + Assert.That(foo, Is.Not.Null); + Assert.That(foo.Id, Is.EqualTo(1)); + Assert.That(foo.Name, Is.EqualTo("Foo")); + } + } + + [Test] + public async Task Does_set_properties_on_global_receiver() + { + using (var client1 = CreateServerEventsClient()) + { + client1.RegisterReceiver<TestGlobalReceiver>(); + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + client1.Post(new SetterType { Id = 1, Name = "Foo" }); + await msgTask.WaitAsync(); + + var foo = TestGlobalReceiver.SetterTypeReceived; + Assert.That(foo, Is.Not.Null); + Assert.That(foo.Id, Is.EqualTo(1)); + Assert.That(foo.Name, Is.EqualTo("Foo")); + } + } + + [Test] + public async Task Does_send_raw_string_messages() + { + using (var client1 = CreateServerEventsClient()) + { + client1.RegisterReceiver<TestJavaScriptReceiver>(); + client1.RegisterNamedReceiver<TestJavaScriptReceiver>("css"); + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + client1.PostChat("chat msg"); + await msgTask.WaitAsync(); + + var chatMsg = TestJavaScriptReceiver.ChatReceived; + Assert.That(chatMsg, Is.Not.Null); + Assert.That(chatMsg.Message, Is.EqualTo("chat msg")); + + msgTask = client1.WaitForNextMessage(); + client1.PostRaw("cmd.announce", "This is your captain speaking..."); + await msgTask.WaitAsync(); + + var announce = TestJavaScriptReceiver.AnnounceReceived; + Assert.That(announce, Is.EqualTo("This is your captain speaking...")); + + msgTask = client1.WaitForNextMessage(); + client1.PostRaw("cmd.toggle$#channels", null); + await msgTask.WaitAsync(); + + var toggle = TestJavaScriptReceiver.ToggleReceived; + Assert.That(toggle, Is.EqualTo("")); + var toggleRequest = TestJavaScriptReceiver.ToggleRequestReceived; + Assert.That(toggleRequest.Selector, Is.EqualTo("cmd.toggle$#channels")); + Assert.That(toggleRequest.Op, Is.EqualTo("cmd")); + Assert.That(toggleRequest.Target, Is.EqualTo("toggle")); + Assert.That(toggleRequest.CssSelector, Is.EqualTo("#channels")); + + msgTask = client1.WaitForNextMessage(); + client1.PostRaw("css.background-image$#top", "url(http://bit.ly/1yIJOBH)"); + await msgTask.WaitAsync(); + + var bgImage = TestJavaScriptReceiver.BackgroundImageReceived; + Assert.That(bgImage, Is.EqualTo("url(http://bit.ly/1yIJOBH)")); + var bgImageRequest = TestJavaScriptReceiver.BackgroundImageRequestReceived; + Assert.That(bgImageRequest.Selector, Is.EqualTo("css.background-image$#top")); + Assert.That(bgImageRequest.Op, Is.EqualTo("css")); + Assert.That(bgImageRequest.Target, Is.EqualTo("background-image")); + Assert.That(bgImageRequest.CssSelector, Is.EqualTo("#top")); + } + } + + [Test] + public async Task Can_reuse_same_instance() + { + using (var client1 = CreateServerEventsClient()) + { + client1.RegisterReceiver<TestJavaScriptReceiver>(); + client1.RegisterNamedReceiver<TestJavaScriptReceiver>("css"); + client1.Resolver = new SingletonInstanceResolver(); + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + client1.PostRaw("cmd.announce", "This is your captain speaking..."); + await msgTask.WaitAsync(); + + var instance = client1.Resolver.TryResolve<TestJavaScriptReceiver>(); + Assert.That(instance.AnnounceInstance, Is.EqualTo("This is your captain speaking...")); + + msgTask = client1.WaitForNextMessage(); + client1.PostRaw("cmd.announce", "2nd Announcement"); + await msgTask.WaitAsync(); + + Assert.That(instance.AnnounceInstance, Is.EqualTo("2nd Announcement")); + } + } + + [Test] + public async Task Can_use_IOC_to_autowire_Receivers() + { + using (var client1 = CreateServerEventsClient()) + { + client1.RegisterReceiver<TestContainerReceiver>(); + + var container = new Container(); + container.RegisterAs<Dependency, IDependency>(); + container.RegisterAutoWiredTypes(client1.ReceiverTypes); + + client1.Resolver = container; + + await client1.Connect(); + + var msgTask = client1.WaitForNextMessage(); + client1.Post(new CustomType { Id = 1, Name = "Foo" }, "cmd.Custom"); + await msgTask.WaitAsync(); + + var instance = (Dependency)container.Resolve<IDependency>(); + var customType = instance.CustomTypeReceived; + Assert.That(customType, Is.Not.Null); + Assert.That(customType.Id, Is.EqualTo(1)); + Assert.That(customType.Name, Is.EqualTo("Foo")); + + msgTask = client1.WaitForNextMessage(); + client1.Post(new SetterType { Id = 2, Name = "Bar" }, "cmd.Setter"); + await msgTask.WaitAsync(); + + var setterType = instance.SetterTypeReceived; + Assert.That(setterType, Is.Not.Null); + Assert.That(setterType.Id, Is.EqualTo(2)); + Assert.That(setterType.Name, Is.EqualTo("Bar")); + } + } + + [Test] + public async Task Does_receive_messages_on_to_clients_subscribed_on_multiple_channels() + { + using (var clientA = CreateServerEventsClient("A")) + using (var clientAB = CreateServerEventsClient("A", "B")) + using (var clientABC = CreateServerEventsClient("A", "B", "C")) + using (var clientABCD = CreateServerEventsClient("A", "B", "C", "D")) + { + var msgsA = new List<ServerEventMessage>(); + var msgsAB = new List<ServerEventMessage>(); + var msgsABC = new List<ServerEventMessage>(); + var msgsABCD = new List<ServerEventMessage>(); + + clientA.OnMessage = msgsA.Add; + clientAB.OnMessage = msgsAB.Add; + clientABC.OnMessage = msgsABC.Add; + clientABCD.OnMessage = msgsABCD.Add; + + await Task.WhenAll( + clientA.Connect(), + clientAB.Connect(), + clientABC.Connect(), + clientABCD.Connect() + ); + + var channelAsubscribers = clientA.GetChannelSubscribers(); + Assert.That(channelAsubscribers.Count, Is.EqualTo(4)); + + var channelABsubscribers = clientA.GetChannelSubscribers(); + Assert.That(channelABsubscribers.Count, Is.EqualTo(4)); + + "Publishing Msg Batch #1 ...".Print(); + clientA.PostChat("#1 hello to A", channel: "A"); + clientA.PostChat("#2 hello to B", channel: "B"); + clientA.PostChat("#3 hello to C", channel: "C"); + clientA.PostChat("#4 hello to D", channel: "D"); + + await Task.Delay(1000); + + "msgsA: {0}".Print(msgsA.Count); + "msgsAB: {0}".Print(msgsAB.Count); + "msgsABC: {0}".Print(msgsABC.Count); + "msgsABCD: {0}".Print(msgsABCD.Count); + + Assert.That(msgsA.Count, Is.EqualTo(1)); + Assert.That(msgsAB.Count, Is.EqualTo(2)); + Assert.That(msgsABC.Count, Is.EqualTo(3)); + Assert.That(msgsABCD.Count, Is.EqualTo(4)); + + await Task.Delay(1000); + + "Publishing Msg Batch #2 ...".Print(); + clientA.PostChat("#5 hello to A", channel: "A"); + clientA.PostChat("#6 hello to B", channel: "B"); + clientA.PostChat("#7 hello to C", channel: "C"); + clientA.PostChat("#8 hello to D", channel: "D"); + + await Task.Delay(1000); + + Assert.That(msgsA.Count, Is.EqualTo(2)); + Assert.That(msgsAB.Count, Is.EqualTo(4)); + Assert.That(msgsABC.Count, Is.EqualTo(6)); + Assert.That(msgsABCD.Count, Is.EqualTo(8)); + } + } + + [Test] + public async Task Does_receive_all_join_and_leave_messages() + { + var joinA = new List<ServerEventJoin>(); + var joinB = new List<ServerEventJoin>(); + var joinAB = new List<ServerEventJoin>(); + + var leaveA = new List<ServerEventLeave>(); + var leaveB = new List<ServerEventLeave>(); + var leaveAB = new List<ServerEventLeave>(); + + using (var clientA = CreateServerEventsClient("A")) + using (var clientB = CreateServerEventsClient("B")) + using (var clientAB = CreateServerEventsClient("A", "B")) + { + var joinAReceived = new TaskCompletionSource<bool>(); + var joinBReceived = new TaskCompletionSource<bool>(); + var joinABReceived = new TaskCompletionSource<bool>(); + + clientA.OnCommand = e => + { + if (e is ServerEventJoin) + { + joinA.Add((ServerEventJoin)e); + if (joinA.Count == 2) + joinAReceived.SetResult(true); + } + else if (e is ServerEventLeave) + leaveA.Add((ServerEventLeave)e); + }; + + clientB.OnCommand = e => + { + if (e is ServerEventJoin) + { + joinB.Add((ServerEventJoin)e); + if (joinB.Count == 2) + joinBReceived.SetResult(true); + } + else if (e is ServerEventLeave) + leaveB.Add((ServerEventLeave)e); + }; + + clientAB.OnCommand = e => + { + if (e is ServerEventJoin) + { + joinAB.Add((ServerEventJoin)e); + if (joinAB.Count == 2) + joinABReceived.SetResult(true); + } + else if (e is ServerEventLeave) + leaveAB.Add((ServerEventLeave)e); + }; + + await clientA.Connect(); + await clientB.Connect(); + await clientAB.Connect(); + + await Task.WhenAll(joinAReceived.Task, joinBReceived.Task, joinABReceived.Task); + + Assert.That(joinA.Count, Is.EqualTo(2)); //A + [(A) B] + Assert.That(joinB.Count, Is.EqualTo(2)); //B + [A (B)] + Assert.That(joinAB.Count, Is.EqualTo(2)); //[(A) B] + [A (B)] + + var channelAsubscribers = clientA.GetChannelSubscribers(); + Assert.That(channelAsubscribers.Count, Is.EqualTo(2)); + + var channelBsubscribers = clientB.GetChannelSubscribers(); + Assert.That(channelBsubscribers.Count, Is.EqualTo(2)); + + var channelABsubscribers = clientAB.GetChannelSubscribers(); + Assert.That(channelABsubscribers.Count, Is.EqualTo(3)); + + + var usersA = clientA.ServiceClient.Get(new GetEventSubscribers { Channels = new[] { "A" } }); + var usersB = clientA.ServiceClient.Get(new GetEventSubscribers { Channels = new[] { "B" } }); + var usersAB = clientA.ServiceClient.Get(new GetEventSubscribers { Channels = new[] { "A", "B" } }); + + Assert.That(usersA.Count, Is.EqualTo(2)); + Assert.That(usersB.Count, Is.EqualTo(2)); + Assert.That(usersAB.Count, Is.EqualTo(3)); + + await clientAB.Stop(); + await Task.Delay(100); + + await clientB.Stop(); + await clientA.Stop(); + + await Task.Delay(100); + + Assert.That(leaveA.Count, Is.EqualTo(1)); + Assert.That(leaveB.Count, Is.EqualTo(1)); + Assert.That(leaveAB.Count, Is.EqualTo(0)); + } + } + + [Test] + public async Task MultiChannel_Does_receive_all_join_and_leave_messages() + { + var joinA = new List<ServerEventJoin>(); + var joinB = new List<ServerEventJoin>(); + var joinAB = new List<ServerEventJoin>(); + + var leaveA = new List<ServerEventLeave>(); + var leaveB = new List<ServerEventLeave>(); + var leaveAB = new List<ServerEventLeave>(); + + using (var clientAB = CreateServerEventsClient("A", "B")) + using (var clientA = CreateServerEventsClient("A")) + using (var clientB = CreateServerEventsClient("B")) + { + var joinAReceived = new TaskCompletionSource<bool>(); + var joinBReceived = new TaskCompletionSource<bool>(); + var joinABReceived = new TaskCompletionSource<bool>(); + + clientA.OnCommand = e => + { + if (e is ServerEventJoin) + { + joinA.Add((ServerEventJoin)e); + if (joinA.Count == 1) + joinAReceived.SetResult(true); + } + else if (e is ServerEventLeave) + leaveA.Add((ServerEventLeave)e); + }; + + clientB.OnCommand = e => + { + if (e is ServerEventJoin) + { + joinB.Add((ServerEventJoin)e); + if (joinB.Count == 1) + joinBReceived.SetResult(true); + } + else if (e is ServerEventLeave) + leaveB.Add((ServerEventLeave)e); + }; + + clientAB.OnCommand = e => + { + if (e is ServerEventJoin) + { + joinAB.Add((ServerEventJoin)e); + if (joinAB.Count == 4) + joinABReceived.SetResult(true); + } + else if (e is ServerEventLeave) + leaveAB.Add((ServerEventLeave)e); + }; + + await clientAB.Connect(); + await clientA.Connect(); + await clientB.Connect(); + + await Task.WhenAll(joinAReceived.Task, joinBReceived.Task, joinABReceived.Task); + + Assert.That(joinAB.Count, Is.EqualTo(4)); //[(A) B] + [A (B)] + A + B + Assert.That(joinA.Count, Is.EqualTo(1)); //A + Assert.That(joinB.Count, Is.EqualTo(1)); //B + + await clientA.Stop(); + await clientB.Stop(); + + await Task.Delay(100); + await clientAB.Stop(); + + Assert.That(leaveAB.Count, Is.EqualTo(2)); + Assert.That(leaveA.Count, Is.EqualTo(0)); + Assert.That(leaveB.Count, Is.EqualTo(0)); + } + } + + [Test] + public async Task Can_subscribe_to_channels_whilst_connected() + { + var msgs1 = new List<ServerEventMessage>(); + var msgs2 = new List<ServerEventMessage>(); + + using (var client1 = CreateServerEventsClient("A")) + using (var client2 = CreateServerEventsClient("B")) + { + client1.OnMessage = msgs1.Add; + client2.OnMessage = msgs2.Add; + + await Task.WhenAll( + client1.Connect(), + client2.Connect() + ); + + Assert.That(client1.Channels, Is.EquivalentTo(new[] {"A" })); + + client2.PostChat("#1 hello to B", channel: "B"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(0)); + Assert.That(msgs2.Count, Is.EqualTo(1)); + + await client1.SubscribeToChannelsAsync("B"); + await Task.Delay(500); + + client2.PostChat("#2 hello to B", channel: "B"); + client2.PostChat("#3 hello to C", channel: "C"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(1)); + Assert.That(msgs2.Count, Is.EqualTo(2)); + + Assert.That(client1.Channels, Is.EquivalentTo(new[] { "A", "B" })); + Assert.That(client2.Channels, Is.EquivalentTo(new[] { "B" })); + + Assert.That(client1.EventStreamUri, Does.EndWith("?channels=A,B")); + Assert.That(client2.EventStreamUri, Does.EndWith("?channels=B")); + + await client1.SubscribeToChannelsAsync("C"); + await client2.SubscribeToChannelsAsync("C"); + await Task.Delay(500); + + client2.PostChat("#4 hello to C", channel: "C"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(2)); + Assert.That(msgs2.Count, Is.EqualTo(3)); + + Assert.That(client1.Channels, Is.EquivalentTo(new[] { "A", "B", "C" })); + Assert.That(client2.Channels, Is.EquivalentTo(new[] { "B", "C" })); + + Assert.That(client1.EventStreamUri, Does.EndWith("?channels=A,B,C")); + Assert.That(client2.EventStreamUri, Does.EndWith("?channels=B,C")); + } + } + + [Test] + public async Task Can_unsubscribe_from_channels_whilst_connected() + { + var msgs1 = new List<ServerEventMessage>(); + var msgs2 = new List<ServerEventMessage>(); + + using (var client1 = CreateServerEventsClient("A","B","C")) + using (var client2 = CreateServerEventsClient("B","C")) + { + client1.OnMessage = msgs1.Add; + client2.OnMessage = msgs2.Add; + + await Task.WhenAll( + client1.Connect(), + client2.Connect() + ); + + Assert.That(client1.Channels, Is.EquivalentTo(new[] { "A","B","C" })); + + client2.PostChat("#1 hello to B", channel: "B"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(1)); + Assert.That(msgs2.Count, Is.EqualTo(1)); + + await client1.UnsubscribeFromChannelsAsync("B"); + await Task.Delay(500); + + client2.PostChat("#2 hello to B", channel: "B"); + client2.PostChat("#3 hello to C", channel: "C"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(2)); + Assert.That(msgs2.Count, Is.EqualTo(3)); + + Assert.That(client1.Channels, Is.EquivalentTo(new[] { "A", "C" })); + Assert.That(client2.Channels, Is.EquivalentTo(new[] { "B", "C" })); + + Assert.That(client1.EventStreamUri, Does.EndWith("?channels=A,C")); + Assert.That(client2.EventStreamUri, Does.EndWith("?channels=B,C")); + + await client1.UnsubscribeFromChannelsAsync("C"); + await client2.UnsubscribeFromChannelsAsync("C"); + await Task.Delay(500); + + client2.PostChat("#4 hello to C", channel: "C"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(2)); + Assert.That(msgs2.Count, Is.EqualTo(3)); + + Assert.That(client1.Channels, Is.EquivalentTo(new[] { "A" })); + Assert.That(client2.Channels, Is.EquivalentTo(new[] { "B" })); + + Assert.That(client1.EventStreamUri, Does.EndWith("?channels=A")); + Assert.That(client2.EventStreamUri, Does.EndWith("?channels=B")); + } + } + + [Test] + public async Task Does_fire_multiple_listeners_for_custom_trigger() + { + var msgs1 = new List<ServerEventMessage>(); + var msgs2 = new List<ServerEventMessage>(); + + using (var client1 = CreateServerEventsClient()) + using (var client2 = CreateServerEventsClient()) + { + Action<ServerEventMessage> handler = msg => { + msgs1.Add(msg); + }; + + client1.AddListener("customEvent", handler); + client1.AddListener("customEvent", msg => { + msgs2.Add(msg); + }); + + await client1.Connect(); + await client2.Connect(); + + client2.PostRaw("trigger.customEvent", "arg"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(1)); + Assert.That(msgs2.Count, Is.EqualTo(1)); + + client1.RemoveListener("customEvent", handler); + + client2.PostRaw("trigger.customEvent", "arg"); + await Task.Delay(500); + + Assert.That(msgs1.Count, Is.EqualTo(1)); + Assert.That(msgs2.Count, Is.EqualTo(2)); + + Assert.That(msgs1.All(x => x.Json.FromJson<string>() == "arg")); + Assert.That(msgs2.All(x => x.Json.FromJson<string>() == "arg")); + } + } + + [Test] + public async Task Can_consume_messages_in_async_handler_with_BlockingCollection() + { + using var bc = new BlockingCollection<ServerEventMessage>(); + var callbacks = 0; + + using var client = new ServerEventsClient(Config.AbsoluteBaseUri, "A") { + OnMessage = m => { + bc.Add(m); + callbacks++; + } + }; + + await client.Connect(); + + 10.Times(i => client.PostChat($"msg{i+1}", channel:"A")); + + var handled = 0; + var consumerTask = Task.Run(async () => { + foreach (var msg in bc.GetConsumingEnumerable()) + { + handled++; + await Task.Delay(1); + } + }); + + var producerTask = ExecUtils.RetryUntilTrueAsync(async () => { + if (callbacks == 10) + { + bc.CompleteAdding(); + return true; + } + await Task.Delay(100); + return false; + }, TimeSpan.FromSeconds(5)); + + await Task.WhenAll(consumerTask, producerTask); + + Assert.That(handled, Is.EqualTo(10)); + } + } + + class Conf + { + public const string AbsoluteBaseUri = "http://127.0.0.1:10000/"; + } + + [TestFixture] + public class ServerEventConnectionTests + { + protected virtual ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost() + .Init() + .Start(Conf.AbsoluteBaseUri); + } + + private static ServerEventsClient CreateServerEventsClient() + { + var client = new ServerEventsClient(Conf.AbsoluteBaseUri); + return client; + } + + private readonly ServiceStackHost appHost; + public ServerEventConnectionTests() + { + appHost = CreateAppHost(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost.Dispose(); + + [Test] + public void Only_allows_one_Thread_through_at_a_time() + { + using (var client = CreateServerEventsClient()) + { + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => client.Start()); + }); + + Thread.Sleep(100); + Assert.That(client.TimesStarted, Is.EqualTo(1)); + + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => client.Restart()); + }); + Thread.Sleep(100); + Assert.That(client.TimesStarted, Is.EqualTo(2)); + + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => client.Stop()); + }); + Thread.Sleep(100); + Assert.That(client.TimesStarted, Is.EqualTo(2)); + + // A stopped client doesn't get restarted + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => client.Restart()); + }); + Thread.Sleep(100); + Assert.That(client.TimesStarted, Is.EqualTo(2)); + + // Can restart a stopped client + 10.Times(i => + { + ThreadPool.QueueUserWorkItem(_ => client.Start()); + }); + + //.NET Core can have long delay + var wait = 10; + while (wait++ < 50) + { + if (client.TimesStarted == 3) + break; + Thread.Sleep(100); + } + + Assert.That(client.TimesStarted, Is.EqualTo(3)); + } + } + } + + [TestFixture] + public class AuthMemoryServerEventsTests + { + protected virtual ServiceStackHost CreateAppHost() + { + return new ServerEventsAppHost { LimitToAuthenticatedUsers = true } + .Init() + .Start(Conf.AbsoluteBaseUri); + } + + private static ServerEventsClient CreateServerEventsClient() + { + var client = new ServerEventsClient(Conf.AbsoluteBaseUri); + return client; + } + + private readonly ServiceStackHost appHost; + public AuthMemoryServerEventsTests() + { + appHost = CreateAppHost(); + + var serverEvents = appHost.TryResolve<IServerEvents>(); + serverEvents.Reset(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost.Dispose(); + + [Test] + public void UnAuthenticated_User_throws_UnAuthorized() + { + using var client = CreateServerEventsClient(); + try + { + client.Start(); + Assert.Fail("Should Throw"); + } + catch (Exception ex) + { + Assert.That(ex.GetStatus(), Is.EqualTo(HttpStatusCode.Unauthorized)); + } + } + + [Test] + public async Task Can_send_and_receive_messages_with_Authenticated_user() + { + using var client = CreateServerEventsClient(); + await client.AuthenticateAsync(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "user", + Password = "pass", + }); + + await client.Connect(); + + ChatMessage chatMsg = null; + client.Handlers["chat"] = (c, msg) => + { + chatMsg = msg.Json.FromJson<ChatMessage>(); + }; + + var msgTask = client.WaitForNextMessage(); + client.PostChat("msg1"); + await msgTask.WaitAsync(); + + Assert.That(chatMsg, Is.Not.Null); + Assert.That(chatMsg.Message, Is.EqualTo("msg1")); + + msgTask = client.WaitForNextMessage(); + client.PostChat("msg2"); + await msgTask.WaitAsync(); + + Assert.That(chatMsg, Is.Not.Null); + Assert.That(chatMsg.Message, Is.EqualTo("msg2")); + } + + [Test] + public async Task Channels_updated_after_Restart() + { + using var client = new ServerEventsClient(Conf.AbsoluteBaseUri, "home"); + Assert.That(client.EventStreamUri.EndsWith("home")); + + await client.AuthenticateAsync(new Authenticate + { + provider = CustomCredentialsAuthProvider.Name, + UserName = "user", + Password = "pass", + }); + + client.Start(); + client.Channels = new[] {"Foo", "Bar"}; + client.Restart(); + + Thread.Sleep(10); // Wait for SleepBackOffMultiplier to continue + + Assert.That(client.EventStreamUri.EndsWith("Foo,Bar")); + } + } + + + public class TestNamedReceiver : ServerEventReceiver + { + public static CustomType FooMethodReceived; + public static CustomType BarMethodReceived; + public static CustomType NoSuchMethodReceived; + public static string NoSuchMethodSelector; + + internal static CustomType QuxSetterReceived; + public CustomType QuxSetter + { + set => QuxSetterReceived = value; + } + + public void FooMethod(CustomType request) + { + FooMethodReceived = request; + } + + public CustomType BarMethod(CustomType request) + { + BarMethodReceived = request; + return request; + } + + public override void NoSuchMethod(string selector, object message) + { + var msg = (ServerEventMessage)message; + NoSuchMethodReceived = msg.Json.FromJson<CustomType>(); + NoSuchMethodSelector = selector; + } + } + + public class TestGlobalReceiver : ServerEventReceiver + { + public static CustomType CustomTypeReceived; + public static CustomType NoSuchMethodReceived; + public static string NoSuchMethodSelector; + + internal static SetterType SetterTypeReceived; + + public SetterType SetterType + { + set => SetterTypeReceived = value; + } + + public void CustomType(CustomType request) + { + CustomTypeReceived = request; + } + + public override void NoSuchMethod(string selector, object message) + { + var msg = (ServerEventMessage)message; + NoSuchMethodReceived = msg.Json.FromJson<CustomType>(); + NoSuchMethodSelector = selector; + } + } + + public class TestJavaScriptReceiver : ServerEventReceiver + { + public static ChatMessage ChatReceived; + public static string AnnounceReceived; + public string AnnounceInstance; + public static string ToggleReceived; + public static ServerEventMessage ToggleRequestReceived; + public static string BackgroundImageReceived; + public static ServerEventMessage BackgroundImageRequestReceived; + + public void Chat(ChatMessage message) + { + ChatReceived = message; + } + + public void Announce(string message) + { + AnnounceReceived = message; + AnnounceInstance = message; + } + + public void Toggle() + { + ToggleReceived = ""; + ToggleRequestReceived = Request; + } + + public void BackgroundImage(string cssRule) + { + BackgroundImageReceived = cssRule; + BackgroundImageRequestReceived = Request; + } + } + + public class ContainerResolver : IResolver + { + private readonly Container container; + + public ContainerResolver(Container container) + { + this.container = container; + } + + public T TryResolve<T>() + { + return container.TryResolve<T>(); + } + } + + public interface IDependency + { + void Record(CustomType msg); + void Record(SetterType msg); + } + + class Dependency : IDependency + { + public CustomType CustomTypeReceived; + public SetterType SetterTypeReceived; + + public void Record(CustomType msg) + { + CustomTypeReceived = msg; + } + + public void Record(SetterType msg) + { + SetterTypeReceived = msg; + } + } + + public class TestContainerReceiver : ServerEventReceiver + { + public IDependency Dependency { get; set; } + + public void Custom(CustomType request) + { + Dependency.Record(request); + } + + public void Setter(SetterType request) + { + Dependency.Record(request); + } + } + + public static class ServerClientExtensions + { + public static void PostChat(this ServerEventsClient client, + string message, string channel = null) + { + client.ServiceClient.PostChat(client.SubscriptionId, message, channel); + } + + public static void PostChat(this IServiceClient client, string subscriptionId, + string message, string channel = null) + { + client.Post(new PostChatToChannel + { + From = subscriptionId, + Message = message, + Channel = channel ?? EventSubscription.UnknownChannel[0], + Selector = "cmd.chat", + }); + } + + public static void PostRaw(this ServerEventsClient client, string selector, string message, string channel = null) + { + client.ServiceClient.Post(new PostRawToChannel + { + From = client.SubscriptionId, + Message = message, + Channel = channel ?? EventSubscription.UnknownChannel[0], + Selector = selector, + }); + } + + public static void Post(this ServerEventsClient client, + CustomType message, string selector = null, string channel = null) + { + client.ServiceClient.Post(new PostObjectToChannel + { + CustomType = message, + Channel = channel ?? EventSubscription.UnknownChannel[0], + Selector = selector, + }); + } + + public static void Post(this ServerEventsClient client, + SetterType message, string selector = null, string channel = null) + { + client.ServiceClient.Post(new PostObjectToChannel + { + SetterType = message, + Channel = channel ?? EventSubscription.UnknownChannel[0], + Selector = selector, + }); + } + + public static async Task<T> WaitAsync<T>(this Task<T> task, int timeMs = 1000) + { + if (task != await Task.WhenAny(task, Task.Delay(timeMs))) + throw new TimeoutException(); + + return await task; + } + } +#endif + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventsErrorHandlingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventsErrorHandlingTests.cs new file mode 100644 index 00000000000..481c1596305 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServerEventsErrorHandlingTests.cs @@ -0,0 +1,48 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ServerEventsErrorHandlingTests + { + private readonly ServiceStackHost appHost; + + public ServerEventsErrorHandlingTests() + { + appHost = new ServerEventsAppHost() + .Init() + .Start(Config.AbsoluteBaseUri);; + + appHost.GetPlugin<ServerEventsFeature>().OnInit = req => + throw new Exception("Always throws"); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Ignore("Hangs"), Test] + public async Task Does_dispose_SSE_Connection_when_Exception_in_OnInit_handler() + { + ServerEventsClient client = null; + using (client = new ServerEventsClient(Config.AbsoluteBaseUri) { + // OnException = e => client.Dispose() + }) + { + try + { + await client.Connect(); + } + catch (WebException e) + { + Assert.That(e.GetStatus(), Is.EqualTo(HttpStatusCode.InternalServerError)); + } + catch (Exception e) + { + Assert.Fail($"Unexpected Exception: {e.GetType().Name}: {e.Message}"); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientResolverTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientResolverTests.cs new file mode 100644 index 00000000000..0c0e2ae4ef3 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientResolverTests.cs @@ -0,0 +1,128 @@ +using System.Threading.Tasks; +using NUnit.Framework; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/test")] + public class DummyRequest : IReturn<MockResponse> { } + + public class DummyFallback : IReturn<MockResponse> { } + + [Route("/testsend")] + public class DummySendGet : IReturn<MockResponse>, IGet { } + + public class MockResponse + { + public string Url { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class JsonServiceClientResolverTests : ServiceClientResolverTestsBase + { + protected override IServiceClient CreateClient(string baseUrl, UrlResolverDelegate urlResolver = null, + TypedUrlResolverDelegate typedUrlResolver = null) + { + return new JsonServiceClient(baseUrl) + { + UrlResolver = urlResolver, + TypedUrlResolver = typedUrlResolver, + ResultsFilter = (type, method, uri, request) => + new MockResponse { Url = uri } + }; + } + } + + public class JsonHttpClientResolverTests : ServiceClientResolverTestsBase + { + protected override IServiceClient CreateClient(string baseUrl, UrlResolverDelegate urlResolver = null, + TypedUrlResolverDelegate typedUrlResolver = null) + { + return new JsonHttpClient(baseUrl) + { + UrlResolver = urlResolver, + TypedUrlResolver = typedUrlResolver, + ResultsFilter = (type, method, uri, request) => + new MockResponse { Url = uri } + }; + } + } + + public abstract class ServiceClientResolverTestsBase + { + protected abstract IServiceClient CreateClient(string baseUrl, + UrlResolverDelegate urlResolver = null, TypedUrlResolverDelegate typedUrlResolver = null); + + [Test] + public void Can_Change_RawUrls_with_UrlResolver() + { + var client = CreateClient("http://example.org/api", urlResolver: + (meta, httpMethod, url) => meta.BaseUri.Replace("example.org", "111.111.111.111").CombineWith(url)); + + var response = client.Get<MockResponse>("/dummy"); + Assert.That(response.Url, Is.EqualTo("http://111.111.111.111/api/dummy")); + + response = client.Post<MockResponse>("/dummy", new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://111.111.111.111/api/dummy")); + + response = client.Send(new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://111.111.111.111/api/json/reply/DummyRequest")); + } + + [Test] + public async Task Can_Change_RawUrls_with_UrlResolver_Async() + { + var client = CreateClient("http://example.org/api", urlResolver: + (meta, httpMethod, url) => meta.BaseUri.Replace("example.org", "111.111.111.111").CombineWith(url)); + + var response = await client.DeleteAsync<MockResponse>("/dummy"); + Assert.That(response.Url, Is.EqualTo("http://111.111.111.111/api/dummy")); + + response = await client.PutAsync<MockResponse>("/dummy", new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://111.111.111.111/api/dummy")); + + response = await client.SendAsync(new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://111.111.111.111/api/json/reply/DummyRequest")); + } + + [Test] + public void Can_Change_Typed_Urls_with_TypedUrlResolver() + { + var client = CreateClient("http://example.org/api", typedUrlResolver: + (meta, httpMethod, dto) => meta.BaseUri.Replace("example.org", dto.GetType().Name.ToLower() + ".example.org") + .CombineWith(dto.ToUrl(httpMethod, meta.Format))); + + var response = client.Get(new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://dummyrequest.example.org/api/test")); + + response = client.Send(new DummySendGet()); + Assert.That(response.Url, Is.EqualTo("http://dummysendget.example.org/api/testsend")); + + response = client.Get(new DummyFallback()); + Assert.That(response.Url, Is.EqualTo("http://dummyfallback.example.org/api/json/reply/DummyFallback")); + + response = client.Post(new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://dummyrequest.example.org/api/test")); + } + + [Test] + public async Task Can_Change_Typed_Urls_with_TypedUrlResolver_Async() + { + var client = CreateClient("http://example.org/api", typedUrlResolver: + (meta, httpMethod, dto) => meta.BaseUri.Replace("example.org", dto.GetType().Name.ToLower() + ".example.org") + .CombineWith(dto.ToUrl(httpMethod, meta.Format))); + + var response = await client.DeleteAsync(new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://dummyrequest.example.org/api/test")); + + response = await client.SendAsync(new DummySendGet()); + Assert.That(response.Url, Is.EqualTo("http://dummysendget.example.org/api/testsend")); + + response = await client.DeleteAsync(new DummyFallback()); + Assert.That(response.Url, Is.EqualTo("http://dummyfallback.example.org/api/json/reply/DummyFallback")); + + response = await client.PutAsync(new DummyRequest()); + Assert.That(response.Url, Is.EqualTo("http://dummyrequest.example.org/api/test")); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientSendBodyTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientSendBodyTests.cs new file mode 100644 index 00000000000..6098e04bd43 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientSendBodyTests.cs @@ -0,0 +1,212 @@ +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/sendjson")] + public class SendJson : IRequiresRequestStream, IReturn<string> + { + public int Id { get; set; } + public string Name { get; set; } + + public Stream RequestStream { get; set; } + } + + [Route("/sendtext")] + public class SendText : IRequiresRequestStream, IReturn<string> + { + public int Id { get; set; } + + public string Name { get; set; } + + public string ContentType { get; set; } + + public Stream RequestStream { get; set; } + } + + [Route("/sendraw")] + public class SendRaw : IRequiresRequestStream, IReturn<byte[]> + { + public int Id { get; set; } + + public string Name { get; set; } + + public string ContentType { get; set; } + + public Stream RequestStream { get; set; } + } + + public class SendRawService : Service + { + [JsonOnly] + public async Task<object> Any(SendJson request) + { + base.Response.AddHeader("X-Args", $"{request.Id},{request.Name}"); + + return await request.RequestStream.ReadToEndAsync(); + } + + public async Task<object> Any(SendText request) + { + base.Response.AddHeader("X-Args", $"{request.Id},{request.Name}"); + + base.Request.ResponseContentType = request.ContentType ?? base.Request.AcceptTypes[0]; + return await request.RequestStream.ReadToEndAsync(); + } + + public async Task<object> Any(SendRaw request) + { + base.Response.AddHeader("X-Args", $"{request.Id},{request.Name}"); + + base.Request.ResponseContentType = request.ContentType ?? base.Request.AcceptTypes[0]; + return await request.RequestStream.ReadToEndAsync(); + } + } + + public class TestBody + { + public string Foo { get; set; } + } + + public class JsonServiceClientSendBodyTests : ServiceClientSendBodyTests + { + public override IServiceClient CreateClient() + { + return new JsonServiceClient(Config.ListeningOn); + } + } + + public class JsonHttpClientSendBodyTests : ServiceClientSendBodyTests + { + public override IServiceClient CreateClient() + { + return new JsonHttpClient(Config.ListeningOn); + } + } + + public abstract class ServiceClientSendBodyTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ServiceClientSendBodyTests), typeof(SendRawService).Assembly) {} + + public override void Configure(Container container) + { + } + } + + private readonly ServiceStackHost appHost; + + protected ServiceClientSendBodyTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + + public abstract IServiceClient CreateClient(); + + public SendJson CreateSendJson(IServiceClient client) + { + if (client is ServiceClientBase scb) + { + scb.ResponseFilter = res => Assert.That(res.Headers["X-Args"], Is.EqualTo("1,name")); + } + else if (client is JsonHttpClient jhc) + { + jhc.ResponseFilter = res => Assert.That(res.Headers.GetValues("X-Args").FirstOrDefault(), Is.EqualTo("1,name")); + } + + return new SendJson + { + Id = 1, + Name = "name", + }; + } + + public SendText CreateSendText(IServiceClient client) + { + if (client is ServiceClientBase scb) + { + scb.ResponseFilter = res => Assert.That(res.Headers["X-Args"], Is.EqualTo("1,name")); + } + else if (client is JsonHttpClient jhc) + { + jhc.ResponseFilter = res => Assert.That(res.Headers.GetValues("X-Args").FirstOrDefault(), Is.EqualTo("1,name")); + } + + return new SendText + { + Id = 1, + Name = "name", + ContentType = "text/plain" + }; + } + + [Test] + public void Can_SendBody() + { + var client = CreateClient(); + var toRequest = CreateSendJson(client); + + var body = new TestBody { Foo = "Bar" }; + + var json = client.PostBody(toRequest, body); + Assert.That(json.FromJson<TestBody>().Foo, Is.EqualTo("Bar")); + + json = client.PutBody(toRequest, body.ToJson()); + Assert.That(json.FromJson<TestBody>().Foo, Is.EqualTo("Bar")); + + json = client.PatchBody(toRequest, MemoryStreamFactory.GetStream(body.ToJson().ToUtf8Bytes())); + Assert.That(json.FromJson<TestBody>().Foo, Is.EqualTo("Bar")); + } + + [Test] + public async Task Can_SendBody_Async() + { + var client = CreateClient(); + var toRequest = CreateSendJson(client); + + var body = new TestBody { Foo = "Bar" }; + + var json = await client.PostBodyAsync(toRequest, body); + Assert.That(json.FromJson<TestBody>().Foo, Is.EqualTo("Bar")); + + json = await client.PutBodyAsync(toRequest, body.ToJson()); + Assert.That(json.FromJson<TestBody>().Foo, Is.EqualTo("Bar")); + + json = await client.PatchBodyAsync(toRequest, MemoryStreamFactory.GetStream(body.ToJson().ToUtf8Bytes())); + Assert.That(json.FromJson<TestBody>().Foo, Is.EqualTo("Bar")); + } + + [Test] + public void Can_SendBody_Raw_String() + { + var client = CreateClient(); + var toRequest = CreateSendText(client); + + var str = client.PutBody(toRequest, "foo"); + Assert.That(str, Is.EqualTo("foo")); + } + + [Test] + public async Task Can_SendBody_Raw_String_Async() + { + var client = CreateClient(); + var toRequest = CreateSendText(client); + + var str = await client.PutBodyAsync(toRequest, "foo"); + Assert.That(str, Is.EqualTo("foo")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientTests.cs index d6916dc275e..efe37525d92 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientTests.cs @@ -1,31 +1,450 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; +using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; +using ServiceStack.WebHost.Endpoints.Tests.Support.Types; namespace ServiceStack.WebHost.Endpoints.Tests { - [TestFixture] - public class ServiceClientTests - : ServiceClientTestBase - { - /// <summary> - /// These tests require admin privillages - /// </summary> - /// <returns></returns> - public override AppHostHttpListenerBase CreateListener() - { - return new TestAppHostHttpListener(); - } - - [Test] - public void Can_GetCustomers() - { - var request = new GetCustomer { CustomerId = 5 }; - - Send<GetCustomerResponse>(request, - response => Assert.That(response.Customer.Id, Is.EqualTo(request.CustomerId))); - } - } + [TestFixture] + public class JsonServiceClientTests : ServiceClientTests + { + public override IServiceClient GetClient() + { + var client = new JsonServiceClient(BaseUrl); + // client.CaptureHttp(print:true); + return client; + } + + [Test] + public void Does_allow_sending_Cached_Response() + { + var cache = new Dictionary<string, object>(); + var client = (JsonServiceClient)GetClient(); + + client.ResultsFilter = (type, method, uri, request) => + { + var cacheKey = "{0} {1}".Fmt(method, uri); + Assert.That(cacheKey, Is.EqualTo("GET {0}json/reply/GetCustomer?customerId=5".Fmt(client.BaseUri))); + cache.TryGetValue(cacheKey, out var entry); + return entry; + }; + client.ResultsFilterResponse = (webRes, res, method, uri, request) => + { + Assert.That(webRes, Is.Not.Null); + var cacheKey = "{0} {1}".Fmt(method, uri); + cache[cacheKey] = res; + }; + + var response1 = client.Get(new GetCustomer { CustomerId = 5 }); + var response2 = client.Get(new GetCustomer { CustomerId = 5 }); + Assert.That(response1.Created, Is.EqualTo(response2.Created)); + } + + [Test] + public async Task Does_allow_sending_Cached_Response_Async() + { + var cache = new Dictionary<string, object>(); + var client = (JsonServiceClient)GetClient(); + + client.ResultsFilter = (type, method, uri, request) => + { + var cacheKey = "{0} {1}".Fmt(method, uri); + Assert.That(cacheKey, Is.EqualTo("GET {0}json/reply/GetCustomer?customerId=5".Fmt(client.BaseUri))); + cache.TryGetValue(cacheKey, out var entry); + return entry; + }; + client.ResultsFilterResponse = (webRes, res, method, uri, request) => + { + Assert.That(webRes, Is.Not.Null); + var cacheKey = "{0} {1}".Fmt(method, uri); + cache[cacheKey] = res; + }; + + var response1 = await client.GetAsync(new GetCustomer { CustomerId = 5 }); + var response2 = await client.GetAsync(new GetCustomer { CustomerId = 5 }); + Assert.That(response1.Created, Is.EqualTo(response2.Created)); + } + + [Test] + public async Task Does_add_HttpHeaders_in_RequestFilter_for_Get_Async() + { + var client = (JsonServiceClient)GetClient(); + client.RequestFilter = req => req.Headers["Foo"] = "Bar"; + + var response = await client.GetAsync(new EchoRequestInfo()); + + Assert.That(response.Headers["Foo"], Is.EqualTo("Bar")); + } + } + + [TestFixture] + public class JsonHttpClientTests : ServiceClientTests + { + public override IServiceClient GetClient() + { + return new JsonHttpClient(BaseUrl); + } + + [Test] + public void Does_allow_sending_Cached_Response() + { + var cache = new Dictionary<string, object>(); + var client = (JsonHttpClient)GetClient(); + + client.ResultsFilter = (type, method, uri, request) => + { + var cacheKey = "{0} {1}".Fmt(method, uri); + Assert.That(cacheKey, Is.EqualTo("GET {0}json/reply/GetCustomer?customerId=5".Fmt(client.BaseUri))); + cache.TryGetValue(cacheKey, out var entry); + return entry; + }; + client.ResultsFilterResponse = (webRes, res, method, uri, request) => + { + Assert.That(webRes, Is.Not.Null); + var cacheKey = "{0} {1}".Fmt(method, uri); + cache[cacheKey] = res; + }; + + var response1 = client.Get(new GetCustomer { CustomerId = 5 }); + var response2 = client.Get(new GetCustomer { CustomerId = 5 }); + Assert.That(response1.Created, Is.EqualTo(response2.Created)); + } + + [Test] + public async Task Does_allow_sending_Cached_Response_Async() + { + var cache = new Dictionary<string, object>(); + var client = (JsonHttpClient)GetClient(); + + client.ResultsFilter = (type, method, uri, request) => + { + var cacheKey = "{0} {1}".Fmt(method, uri); + Assert.That(cacheKey, Is.EqualTo("GET {0}json/reply/GetCustomer?customerId=5".Fmt(client.BaseUri))); + object entry; + cache.TryGetValue(cacheKey, out entry); + return entry; + }; + client.ResultsFilterResponse = (webRes, res, method, uri, request) => + { + Assert.That(webRes, Is.Not.Null); + var cacheKey = "{0} {1}".Fmt(method, uri); + cache[cacheKey] = res; + }; + + var response1 = await client.GetAsync(new GetCustomer { CustomerId = 5 }); + var response2 = await client.GetAsync(new GetCustomer { CustomerId = 5 }); + Assert.That(response1.Created, Is.EqualTo(response2.Created)); + } + + [Test] + public async Task Does_add_HttpHeaders_in_RequestFilter_for_Get_Async() + { + var client = (JsonHttpClient)GetClient(); + client.RequestFilter = req => req.Headers.Add("Foo", "Bar"); + + var response = await client.GetAsync(new EchoRequestInfo()); + + Assert.That(response.Headers["Foo"], Is.EqualTo("Bar")); + } + + [Test] + public async Task Doesnt_dispose_injected_handler() + { + var handler = new HttpClientHandler(); + + var client1 = (JsonHttpClient)GetClient(); + client1.HttpMessageHandler = handler; + await client1.GetAsync(new GetCustomer { CustomerId = 5 }); + client1.Dispose(); + + var client2 = (JsonHttpClient)GetClient(); + client2.HttpMessageHandler = handler; + var response = await client2.GetAsync(new GetCustomer { CustomerId = 5 }); + + Assert.That(response, Is.Not.Null); + } + } + + public abstract class ServiceClientTests + : ServiceClientTestBase + { + /// <summary> + /// These tests require admin privileges + /// </summary> + /// <returns></returns> + public override AppHostHttpListenerBase CreateListener() + { + return new TestAppHostHttpListener(); + } + + private IServiceClient client; + + public abstract IServiceClient GetClient(); + [SetUp] + public void SetUp() + { + client = GetClient(); + } + + [Test] + public void Can_GetCustomers() + { + var request = new GetCustomer { CustomerId = 5 }; + + Send<GetCustomerResponse>(request, + response => Assert.That(response.Customer.Id, Is.EqualTo(request.CustomerId))); + } + + [Test] + public void Does_add_HttpHeaders_for_Get_Sync() + { + client.AddHeader("Foo", "Bar"); + + var response = client.Get(new EchoRequestInfo()); + + Assert.That(response.Headers["Foo"], Is.EqualTo("Bar")); + } + + [Test] + public async Task Does_add_HttpHeaders_for_Get_Async() + { + client.AddHeader("Foo", "Bar"); + + var response = await client.GetAsync(new EchoRequestInfo()); + + Assert.That(response.Headers["Foo"], Is.EqualTo("Bar")); + } + + [Test] + public void Does_add_HttpHeaders_for_Post() + { + client.AddHeader("Foo", "Bar"); + + var response = client.Post(new EchoRequestInfo()); + + Assert.That(response.Headers["Foo"], Is.EqualTo("Bar")); + } + + [Test] + public async Task Does_add_HttpHeaders_for_Post_Async() + { + client.AddHeader("Foo", "Bar"); + + var response = await client.PostAsync(new EchoRequestInfo()); + + Assert.That(response.Headers["Foo"], Is.EqualTo("Bar")); + } + + [Test] + public async Task Can_call_return_void() + { + client.Post(new ReturnsVoid { Message = "Foo" }); + Assert.That(TestAsyncService.ReturnVoidMessage, Is.EqualTo("Foo")); + + await client.PostAsync(new ReturnsVoid { Message = "Foo" }); + Assert.That(TestAsyncService.ReturnVoidMessage, Is.EqualTo("Foo")); + + using (client.Post<HttpWebResponse>(new ReturnsVoid { Message = "Bar" })) { } + Assert.That(TestAsyncService.ReturnVoidMessage, Is.EqualTo("Bar")); + } + + [Test] + public async Task Can_call_return_HttpWebResponse() + { + client.Post(new ReturnsWebResponse { Message = "Foo" }); + Assert.That(TestAsyncService.ReturnWebResponseMessage, Is.EqualTo("Foo")); + + await client.PostAsync(new ReturnsWebResponse { Message = "Foo" }); + Assert.That(TestAsyncService.ReturnWebResponseMessage, Is.EqualTo("Foo")); + + using (client.Post<HttpWebResponse>(new ReturnsWebResponse { Message = "Bar" })) { } + Assert.That(TestAsyncService.ReturnWebResponseMessage, Is.EqualTo("Bar")); + } + + [Test] + public void Can_post_raw_response_as_raw_JSON() + { + var request = new GetCustomer { CustomerId = 5 }; + var response = client.Post(request); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + var requestPath = request.ToPostUrl(); + + string json = request.ToJson(); + response = client.Post<GetCustomerResponse>(requestPath, json); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + byte[] bytes = json.ToUtf8Bytes(); + response = client.Put<GetCustomerResponse>(requestPath, bytes); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + Stream ms = bytes.InMemoryStream(); + response = client.Post<GetCustomerResponse>(requestPath, ms); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + } + + [Test] + public async Task Can_post_raw_response_as_raw_JSON_async() + { + var request = new GetCustomer { CustomerId = 5 }; + var response = client.Post(request); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + var requestPath = request.ToPostUrl(); + + string json = request.ToJson(); + response = await client.PostAsync<GetCustomerResponse>(requestPath, json); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + byte[] bytes = json.ToUtf8Bytes(); + response = await client.PutAsync<GetCustomerResponse>(requestPath, bytes); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + Stream ms = bytes.InMemoryStream(); + response = await client.PostAsync<GetCustomerResponse>(requestPath, ms); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + } + + [Test] + public async Task Can_post_raw_response_as_raw_JSON_HttpClient() + { + var httpClient = new JsonHttpClient(BaseUrl); + var request = new GetCustomer { CustomerId = 5 }; + var response = httpClient.Post(request); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + var requestPath = request.ToPostUrl(); + + string json = request.ToJson(); + response = await httpClient.PostAsync<GetCustomerResponse>(requestPath, json); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + byte[] bytes = json.ToUtf8Bytes(); + response = await httpClient.PutAsync<GetCustomerResponse>(requestPath, bytes); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + + Stream ms = bytes.InMemoryStream(); + response = await httpClient.PostAsync<GetCustomerResponse>(requestPath, ms); + Assert.That(response.Customer.Id, Is.EqualTo(5)); + } + + [Test] + public void Can_WaitAsync() + { + var called = 0; + + PclExportClient.Instance.WaitAsync(100) + .ContinueWith(_ => + { + called++; + }); + + Thread.Sleep(200); + Assert.That(called, Is.EqualTo(1)); + } + } + + public class JsonServiceClientSendInterfaceTests : SendInterfaceTests + { + protected override IServiceClient CreateClient() + { + return new JsonServiceClient(BaseUrl); + } + } + + public class JsonHttpClientSendInterfaceTests : SendInterfaceTests + { + protected override IServiceClient CreateClient() + { + return new JsonHttpClient(BaseUrl); + } + } + + public abstract class SendInterfaceTests + : ServiceClientTestBase + { + /// <summary> + /// These tests require admin privileges + /// </summary> + /// <returns></returns> + public override AppHostHttpListenerBase CreateListener() + { + return new TestAppHostHttpListener(); + } + + private IServiceClient client; + + protected abstract IServiceClient CreateClient(); + + [SetUp] + public void SetUp() + { + client = CreateClient(); + } + + [Test] + public void Does_SendDefault_as_POST() + { + var response = client.Send(new SendDefault { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.RequestMethod, Is.EqualTo(HttpMethods.Post)); + Assert.That(response.PathInfo, Is.EqualTo("/json/reply/SendDefault")); + } + + [Test] + public void Does_SendRestGet_as_GET() + { + var response = client.Send(new SendRestGet { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.RequestMethod, Is.EqualTo(HttpMethods.Get)); + Assert.That(response.PathInfo, Is.EqualTo("/sendrestget/1")); + } + + [Test] + public async Task Does_SendRestGet_as_GET_Async() + { + var response = await client.SendAsync(new SendRestGet { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.RequestMethod, Is.EqualTo(HttpMethods.Get)); + Assert.That(response.PathInfo, Is.EqualTo("/sendrestget/1")); + } + + [Test] + public void Does_SendGet_as_GET() + { + var response = client.Send(new SendGet { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.RequestMethod, Is.EqualTo(HttpMethods.Get)); + Assert.That(response.PathInfo, Is.EqualTo("/json/reply/SendGet")); + } + + [Test] + public void Does_SendPost_as_POST() + { + var response = client.Send(new SendPost { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.RequestMethod, Is.EqualTo(HttpMethods.Post)); + Assert.That(response.PathInfo, Is.EqualTo("/json/reply/SendPost")); + } + + [Test] + public void Does_SendPut_as_PUT() + { + var response = client.Send(new SendPut { Id = 1 }); + Assert.That(response.Id, Is.EqualTo(1)); + Assert.That(response.RequestMethod, Is.EqualTo(HttpMethods.Put)); + Assert.That(response.PathInfo, Is.EqualTo("/json/reply/SendPut")); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientsBuiltInResponseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientsBuiltInResponseTests.cs index 5ff882861ea..6c4fdb8dbfb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientsBuiltInResponseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceClientsBuiltInResponseTests.cs @@ -3,13 +3,11 @@ using System.Linq; using System.Net; using System.Threading; +using System.Threading.Tasks; using Funq; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -43,6 +41,12 @@ public class Bytes : IReturn<byte[]> public string Text { get; set; } } + [Route("/bytes-streams/{Text}")] + public class BytesAsStreams : IReturn<Stream> + { + public string Text { get; set; } + } + [Route("/streams/{Text}")] public class Streams : IReturn<Stream> { @@ -55,7 +59,7 @@ public class StreamWriters : IReturn<Stream> public string Text { get; set; } } - public class BuiltInTypesService : ServiceInterface.Service + public class BuiltInTypesService : Service { public PocoResponse Any(Poco request) { @@ -77,18 +81,26 @@ public byte[] Any(Bytes request) return new Guid(request.Text).ToByteArray(); } - public byte[] Any(Streams request) + public byte[] Any(BytesAsStreams request) { return new Guid(request.Text).ToByteArray(); } - public IStreamWriter Any(StreamWriters request) + public Stream Any(Streams request) + { + var bytes = new Guid(request.Text).ToByteArray(); + var ms = new MemoryStream(); + ms.Write(bytes, 0, bytes.Length); + return ms; + } + + public IStreamWriterAsync Any(StreamWriters request) { return new StreamWriterResult(new Guid(request.Text).ToByteArray()); } } - public class StreamWriterResult : IStreamWriter + public class StreamWriterResult : IStreamWriterAsync { private byte[] result; @@ -97,18 +109,19 @@ public StreamWriterResult(byte[] result) this.result = result; } - public void WriteTo(Stream responseStream) + public async Task WriteToAsync(Stream responseStream, CancellationToken token = new CancellationToken()) { - responseStream.Write(result, 0, result.Length); + await responseStream.WriteAsync(result, token); } } + public class BuiltInTypesAppHost : AppHostHttpListenerBase { - public BuiltInTypesAppHost() : base(typeof(BuiltInTypesAppHost).Name, typeof(BuiltInTypesService).Assembly) { } + public BuiltInTypesAppHost() : base(nameof(BuiltInTypesAppHost), typeof(BuiltInTypesService).Assembly) { } public string LastRequestBody { get; set; } - public bool UseBufferredStream { get; set; } + public bool UseBufferedStream { get; set; } public bool EnableRequestBodyTracking { get; set; } public override void Configure(Container container) {} @@ -119,7 +132,7 @@ public class ServiceClientsBuiltInResponseTests { private BufferedRequestAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new BufferedRequestAppHost { EnableRequestBodyTracking = true }; @@ -127,16 +140,16 @@ public void TestFixtureSetUp() appHost.Start(Config.AbsoluteBaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } protected static IRestClient[] RestClients = { new JsonServiceClient(Config.AbsoluteBaseUri), + new JsonHttpClient(Config.AbsoluteBaseUri), new XmlServiceClient(Config.AbsoluteBaseUri), new JsvServiceClient(Config.AbsoluteBaseUri), }; @@ -157,7 +170,7 @@ public void Can_download_Poco_response_as_string(IRestClient client) { string response = client.Get<string>("/poco/Test"); - Assert.That(response, Is.StringContaining("Hello, Test")); + Assert.That(response, Does.Contain("Hello, Test")); } [Test, TestCaseSource("RestClients")] @@ -165,7 +178,7 @@ public void Can_download_Poco_response_as_bytes(IRestClient client) { byte[] response = client.Get<byte[]>("/poco/Test"); - Assert.That(response.FromUtf8Bytes(), Is.StringContaining("Hello, Test")); + Assert.That(response.FromUtf8Bytes(), Does.Contain("Hello, Test")); } [Test, TestCaseSource("RestClients")] @@ -174,42 +187,43 @@ public void Can_download_Poco_response_as_Stream(IRestClient client) Stream response = client.Get<Stream>("/poco/Test"); using (response) { - var bytes = response.ReadFully(); - Assert.That(bytes.FromUtf8Bytes(), Is.StringContaining("Hello, Test")); + Assert.That(response.ReadToEnd(), Does.Contain("Hello, Test")); } } [Test, TestCaseSource("RestClients")] public void Can_download_Poco_response_as_PocoResponse(IRestClient client) { + if (client is JsonHttpClient) return; + HttpWebResponse response = client.Get<HttpWebResponse>("/poco/Test"); using (var stream = response.GetResponseStream()) - using (var sr = new StreamReader(stream)) { - Assert.That(sr.ReadToEnd(), Is.StringContaining("Hello, Test")); + Assert.That(stream.ReadToEnd(), Does.Contain("Hello, Test")); } } [Test, TestCaseSource("RestClients")] public void Can_download_Headers_response(IRestClient client) { + if (client is JsonHttpClient) return; + HttpWebResponse response = client.Get(new Headers { Text = "Test" }); Assert.That(response.Headers["X-Response"], Is.EqualTo("Test")); } [Test, TestCaseSource("RestClients")] - public void Can_download_Headers_response_Async(IServiceClient client) + public async Task Can_download_Headers_response_Async(IServiceClient client) { - //Note: HttpWebResponse is returned before any response is read, so it's ideal point for streaming in app code + if (client is JsonHttpClient) return; - HttpWebResponse response = null; - client.GetAsync(new Headers { Text = "Test" }, r => response = r, - (r, ex) => Assert.Fail(ex.Message)); - - Thread.Sleep(2000); + //Note: HttpWebResponse is returned before any response is read, so it's ideal point for streaming in app code - Assert.That(response.Headers["X-Response"], Is.EqualTo("Test")); + using (var response = await client.GetAsync(new Headers { Text = "Test" })) + { + Assert.That(response.Headers["X-Response"], Is.EqualTo("Test")); + } } [Test, TestCaseSource("RestClients")] @@ -220,13 +234,9 @@ public void Can_download_Strings_response(IRestClient client) } [Test, TestCaseSource("RestClients")] - public void Can_download_Strings_response_Async(IServiceClient client) + public async Task Can_download_Strings_response_Async(IServiceClient client) { - string response = null; - client.GetAsync(new Strings { Text = "Test" }, r => response = r, - (r, ex) => Assert.Fail(ex.Message)); - - Thread.Sleep(2000); + var response = await client.GetAsync(new Strings { Text = "Test" }); Assert.That(response, Is.EqualTo("Hello, Test")); } @@ -240,18 +250,27 @@ public void Can_download_Bytes_response(IRestClient client) } [Test, TestCaseSource("RestClients")] - public void Can_download_Bytes_response_Async(IServiceClient client) + public async Task Can_download_Bytes_response_Async(IServiceClient client) { - byte[] bytes = null; var guid = Guid.NewGuid(); - client.GetAsync(new Bytes { Text = guid.ToString() }, r => bytes = r, - (r, ex) => Assert.Fail(ex.Message)); - Thread.Sleep(2000); + byte[] bytes = await client.GetAsync(new Bytes { Text = guid.ToString() }); Assert.That(new Guid(bytes), Is.EqualTo(guid)); } + [Test, TestCaseSource("RestClients")] + public void Can_download_BytesAsStreams_response(IRestClient client) + { + var guid = Guid.NewGuid(); + Stream response = client.Get(new BytesAsStreams { Text = guid.ToString() }); + using (response) + { + var bytes = response.ReadFully(); + Assert.That(new Guid(bytes), Is.EqualTo(guid)); + } + } + [Test, TestCaseSource("RestClients")] public void Can_download_Streams_response(IRestClient client) { @@ -265,20 +284,16 @@ public void Can_download_Streams_response(IRestClient client) } [Test, TestCaseSource("RestClients")] - public void Can_download_Streams_response_Async(IServiceClient client) + public async Task Can_download_Streams_response_Async(IServiceClient client) { //Note: The populated MemoryStream which bufferred the response is returned (i.e. after the response is read async-ly) byte[] bytes = null; var guid = Guid.NewGuid(); - client.GetAsync(new Streams { Text = guid.ToString() }, stream => { - using (stream) - { - bytes = stream.ReadFully(); - } - }, (stream, ex) => Assert.Fail(ex.Message)); - - Thread.Sleep(2000); + + var stream = await client.GetAsync(new BytesAsStreams { Text = guid.ToString() }); + + bytes = stream.ReadFully(); Assert.That(new Guid(bytes), Is.EqualTo(guid)); } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceFilterTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceFilterTests.cs new file mode 100644 index 00000000000..dd7fa81b75b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceFilterTests.cs @@ -0,0 +1,120 @@ +using System; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + class HelloFilter : IReturn<HelloFilterResponse> + { + public string Name { get; set; } + public bool Throw { get; set; } + } + + class HelloFilterResponse + { + public string Result { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + class FiltersService : Service + { + public override void OnBeforeExecute(object requestDto) + { + Assert.That(Request, Is.Not.Null); + if (requestDto is HelloFilter dto) + dto.Name += $" OnBeforeExecute"; + } + + public object Any(HelloFilter request) => !request.Throw + ? new HelloFilterResponse { Result = $"Hi {request.Name}!" } + : throw new ArgumentException(request.Name); + + public override object OnAfterExecute(object response) + { + Assert.That(Request, Is.Not.Null); + if (response is HelloFilterResponse dto) + dto.Result += $" OnAfterExecute"; + + return new HttpResult(response) { + Headers = { + ["X-Filter"] = nameof(OnAfterExecute) + } + }; + } + + public override Task<object> OnExceptionAsync(object requestDto, Exception ex) + { + Assert.That(Request, Is.Not.Null); + var error = DtoUtils.CreateErrorResponse(requestDto, ex); + if (error is IHttpError httpError) + { + var errorStatus = httpError.Response.GetResponseStatus(); + errorStatus.Message += " OnExceptionAsync"; + } + return Task.FromResult(error); + } + } + + public class ServiceFilterTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ServiceFilterTests), typeof(FiltersService).Assembly) { } + public override void Configure(Container container) + { + } + } + + private ServiceStackHost appHost; + + [OneTimeSetUp] public void OneTimeSetUp() => appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + + [OneTimeTearDown] public void TestFixtureTearDown() => appHost.Dispose(); + + [Test] + public void Does_call_OnBeforeExecute_and_OnAfterExecute() + { + var client = new JsonServiceClient(Config.ListeningOn) { + ResponseFilter = res => { + $"X-Filter: {res.Headers["X-Filter"]}".Print(); + Assert.That(res.Headers["X-Filter"], Is.EqualTo("OnAfterExecute")); + } + }; + + var request = new HelloFilter { Name = nameof(HelloFilter) }; + var response = client.Get(request); + + Assert.That(response.Result, Is.EqualTo($"Hi {request.Name} OnBeforeExecute! OnAfterExecute")); + } + + [Test] + public void Does_call_OnExceptionAsync_on_Error() + { + var client = new JsonServiceClient(Config.ListeningOn); + + var request = new HelloFilter { + Name = nameof(HelloFilter), + Throw = true, + }; + try + { + var response = client.Get(request); + + Assert.Fail("Should throw"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.Message, Is.EqualTo($"{request.Name} OnBeforeExecute OnExceptionAsync")); + } + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayTests.cs new file mode 100644 index 00000000000..8118793dd51 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayTests.cs @@ -0,0 +1,709 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Messaging; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class SGSendSyncGetInternal : IReturn<SGSendSyncGetInternal> + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGSendSyncGetExternal : IReturn<SGSendSyncGetExternal> + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGSendSyncPostInternal : IReturn<SGSendSyncPostInternal> + { + public string Value { get; set; } + } + + public class SGSendSyncPostExternal : IReturn<SGSendSyncPostExternal> + { + public string Value { get; set; } + } + + public class SGSendAllSyncGetAnyInternal : IReturn<List<SGSyncGetAnyInternal>> + { + public string Value { get; set; } + } + + public class SGSendAllSyncPostExternal : IReturn<List<SGSyncPostExternal>> + { + public string Value { get; set; } + } + + public class SGPublishPostInternalVoid : IReturnVoid, IGet + { + public string Value { get; set; } + } + + public class SGPublishPostExternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGPublishAllPostInternalVoid : IReturnVoid, IGet + { + public string Value { get; set; } + } + + public class SGPublishAllPostExternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGSendSyncGetSyncObjectInternal : IReturn<SGSendSyncGetSyncObjectInternal> + { + public string Value { get; set; } + } + + public class SGSendSyncGetAsyncObjectExternal : IReturn<SGSendSyncGetAsyncObjectExternal> + { + public string Value { get; set; } + } + + public class SGSyncPostValidationExternal : IReturn<SGSyncPostValidationExternal> + { + public string Value { get; set; } + public string Required { get; set; } + } + + public class SGSyncPostValidationAsyncExternal : IReturn<SGSyncPostValidationAsyncExternal> + { + public string Value { get; set; } + public string Required { get; set; } + } + + public class ServiceGatewayServices : Service + { + public object Any(SGSendSyncGetInternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSendSyncGetInternal); + return Gateway.Send(request.ConvertTo<SGSyncGetInternal>()); + } + + public object Any(SGSendSyncGetExternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSendSyncGetExternal); + return Gateway.Send(request.ConvertTo<SGSyncGetExternal>()); + } + + public object Any(SGSendSyncPostInternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSendSyncPostInternal); + return Gateway.Send(request.ConvertTo<SGSyncPostInternal>()); + } + + public object Any(SGSendSyncPostExternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSendSyncPostExternal); + return Gateway.Send(request.ConvertTo<SGSyncPostExternal>()); + } + + public object Any(SGSendAllSyncGetAnyInternal request) + { + var requests = 3.Times(i => new SGSyncGetAnyInternal + { + Value = request.Value + "> " + Request.Verb + " " + nameof(SGSendAllSyncGetAnyInternal) + i + }); + + return Gateway.SendAll(requests); + } + + public object Any(SGSendAllSyncPostExternal request) + { + var requests = 3.Times(i => new SGSyncPostExternal + { + Value = request.Value + "> " + Request.Verb + " " + nameof(SGSendAllSyncPostExternal) + i + }); + + return Gateway.SendAll(requests); + } + + public void Any(SGPublishPostInternalVoid request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGPublishPostInternalVoid); + Gateway.Publish(request.ConvertTo<SGSyncPostInternalVoid>()); + } + + public void Any(SGPublishPostExternalVoid request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGPublishPostExternalVoid); + Gateway.Publish(request.ConvertTo<SGSyncPostExternalVoid>()); + } + + public void Any(SGPublishAllPostInternalVoid request) + { + var requests = 3.Times(i => new SGSyncPostInternalVoid + { + Value = request.Value + "> " + Request.Verb + " " + nameof(SGPublishAllPostInternalVoid) + i + }); + + Gateway.PublishAll(requests); + } + + public void Any(SGPublishAllPostExternalVoid request) + { + var requests = 3.Times(i => new SGSyncPostExternalVoid + { + Value = request.Value + "> " + Request.Verb + " " + nameof(SGPublishAllPostExternalVoid) + i + }); + + Gateway.PublishAll(requests); + } + + public object Any(SGSendSyncGetSyncObjectInternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSendSyncGetSyncObjectInternal); + return Gateway.Send<object>(request.ConvertTo<SGSyncGetSyncObjectInternal>()); + } + + public object Any(SGSendSyncGetAsyncObjectExternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSendSyncGetAsyncObjectExternal); + return Gateway.SendAsync<object>(request.ConvertTo<SGSyncGetAsyncObjectExternal>()); + } + + public object Any(SGSyncPostValidationExternal request) + { + request.Value += "> " + Request.Verb + " " + nameof(SGSyncPostValidationExternal); + try + { + return Gateway.Send(request.ConvertTo<SGSyncPostValidationInternal>()); + } + catch (WebServiceException e) + { + throw; + } + catch (Exception e) + { + throw new NotImplementedException("Should throw WebServiceException", e); + } + } + + public async Task<object> Any(SGSyncPostValidationAsyncExternal request) + { + await Task.Yield(); + request.Value += "> " + Request.Verb + " " + nameof(SGSyncPostValidationAsyncExternal); + try + { + return await Gateway.SendAsync(request.ConvertTo<SGSyncPostValidationAsyncInternal>()); + } + catch (WebServiceException e) + { + throw; + } + catch (Exception e) + { + throw new NotImplementedException("Should throw WebServiceException", e); + } + } + + } + + public class SGSyncGetInternal : IReturn<SGSyncGetInternal>, IGet + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGSyncGetExternal : IReturn<SGSyncGetExternal>, IGet + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGSyncPostInternal : IReturn<SGSyncPostInternal>, IPost + { + public string Value { get; set; } + } + + public class SGSyncPostExternal : IReturn<SGSyncPostExternal>, IPost + { + public string Value { get; set; } + } + + public class SGSyncGetAnyInternal : IReturn<SGSyncGetAnyInternal>, IGet + { + public string Value { get; set; } + } + + public class SGSyncGetAnyExternal : IReturn<SGSyncGetAnyInternal>, IGet + { + public string Value { get; set; } + } + + public class SGSyncPostInternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGSyncPostExternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGSyncGetSyncObjectInternal : IReturn<SGSyncGetSyncObjectInternal>, IGet + { + public string Value { get; set; } + } + + public class SGSyncGetAsyncObjectExternal : IReturn<SGSyncGetAsyncObjectExternal>, IGet + { + public string Value { get; set; } + } + + public class SGSyncPostValidationInternal : IReturn<SGSyncPostValidationInternal> + { + public string Value { get; set; } + public string Required { get; set; } + } + + public class SGSyncPostValidationInternalValidator : AbstractValidator<SGSyncPostValidationInternal> + { + public SGSyncPostValidationInternalValidator() + { + RuleFor(x => x.Required).NotEmpty(); + } + } + + public class SGSyncPostValidationAsyncInternal : IReturn<SGSyncPostValidationAsyncInternal> + { + public string Value { get; set; } + public string Required { get; set; } + } + + public class SGSyncPostValidationAsyncInternalValidator : AbstractValidator<SGSyncPostValidationAsyncInternal> + { + public SGSyncPostValidationAsyncInternalValidator() + { + RuleFor(x => x.Required).NotEmpty(); + } + } + + public class ServiceGatewayInternalServices : Service + { + public object Get(SGSyncGetInternal request) + { + if (request.Throw) + throw new ArgumentException("ERROR " + nameof(SGSendSyncGetInternal)); + + request.Value += "> GET " + nameof(SGSyncGetInternal); + return request; + } + + public object Post(SGSyncPostInternal request) + { + request.Value += "> POST " + nameof(SGSyncPostInternal); + return request; + } + + public object Any(SGSyncGetAnyInternal request) + { + request.Value += "> ANY " + nameof(SGSyncGetAnyInternal); + return request; + } + + public void Post(SGSyncPostInternalVoid request) + { + request.Value += "> POST " + nameof(SGSyncPostInternalVoid); + } + + public object Any(SGSyncGetSyncObjectInternal request) + { + request.Value += "> GET " + nameof(SGSyncGetSyncObjectInternal); + return request; + } + + public object Any(SGSyncPostValidationInternal request) + { + request.Value += "> ANY " + nameof(SGSyncPostValidationInternal); + return request; + } + + public async Task<object> Any(SGSyncPostValidationAsyncInternal request) + { + await Task.Yield(); + request.Value += "> ANY " + nameof(SGSyncPostValidationAsyncInternal); + return request; + } + } + + public class ServiceGatewayExternalServices : Service + { + public object Get(SGSyncGetExternal request) + { + if (request.Throw) + throw new ArgumentException("ERROR " + nameof(SGSyncGetExternal)); + + request.Value += "> GET " + nameof(SGSyncGetExternal); + return request; + } + + public object Post(SGSyncPostExternal request) + { + request.Value += "> POST " + nameof(SGSyncPostExternal); + return request; + } + + public object Any(SGSyncGetAnyExternal request) + { + request.Value += "> ANY " + nameof(SGSyncGetAnyExternal); + return request; + } + + public void Post(SGSyncPostExternalVoid request) + { + request.Value += "> POST " + nameof(SGSyncPostExternalVoid); + } + + public async Task<object> Any(SGSyncGetAsyncObjectExternal request) + { + await Task.Yield(); + request.Value += "> GET " + nameof(SGSyncGetAsyncObjectExternal); + return request; + } + } + + //AppHosts + public class MixedServiceGatewayTests : ServiceGatewayTests + { + class MixedServiceGatewayFactory : IServiceGatewayFactory, IServiceGateway + { + private InProcessServiceGateway localGateway; + + public IServiceGateway GetServiceGateway(IRequest request) + { + localGateway = new InProcessServiceGateway(request); + return this; + } + + public IServiceGateway GetGateway(Type requestType) + { + var gateway = requestType.Name.Contains("External") + ? new JsonServiceClient(Config.ListeningOn) + : (IServiceGateway) localGateway; + return gateway; + } + + public TResponse Send<TResponse>(object requestDto) + { + return GetGateway(requestDto.GetType()).Send<TResponse>(requestDto); + } + + public List<TResponse> SendAll<TResponse>(IEnumerable<object> requestDtos) + { + return GetGateway(requestDtos.GetType().GetCollectionType()).SendAll<TResponse>(requestDtos); + } + + public void Publish(object requestDto) + { + GetGateway(requestDto.GetType()).Publish(requestDto); + } + + public void PublishAll(IEnumerable<object> requestDtos) + { + GetGateway(requestDtos.GetType().GetCollectionType()).PublishAll(requestDtos); + } + } + + class MixedAppHost : AppSelfHostBase + { + public MixedAppHost() : base(nameof(ServiceGatewayTests), typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + + container.Register<IServiceGatewayFactory>(x => new MixedServiceGatewayFactory()) + .ReusedWithin(ReuseScope.None); + + Plugins.Add(new ValidationFeature()); + container.RegisterValidator(typeof(SGSyncPostValidationInternalValidator)); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new MixedAppHost(); + } + } + + public class AllExternalServiceGatewayTests : ServiceGatewayTests + { + class AllExternalAppHost : AppSelfHostBase + { + public AllExternalAppHost() : base(nameof(ServiceGatewayTests), typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + var client = new JsonServiceClient(Tests.Config.ListeningOn); + // client.CaptureHttp(print:true); + container.Register<IServiceGateway>(c => client); + + Plugins.Add(new ValidationFeature()); + container.RegisterValidator(typeof(SGSyncPostValidationInternalValidator)); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new AllExternalAppHost(); + } + } + + //Tests + public class AllInternalServiceGatewayTests : ServiceGatewayTests + { + class AllInternalAppHost : AppSelfHostBase + { + public AllInternalAppHost() : base(nameof(ServiceGatewayTests), typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + + Plugins.Add(new ValidationFeature()); + container.RegisterValidator(typeof(SGSyncPostValidationInternalValidator)); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new AllInternalAppHost(); + } + } + + + public abstract class ServiceGatewayTests + { + public class MessageFactory : IMessageFactory + { + public IMessageProducer CreateMessageProducer() + { + return new MessageProducer(); + } + + public IMessageQueueClient CreateMessageQueueClient() { return null; } + public void Dispose() { } + } + + public class MessageProducer : IMessageProducer + { + public static List<object> Messages = new List<object>(); + + public void Publish<T>(T messageBody) + { + Messages.Add(messageBody); + } + + public void Publish<T>(IMessage<T> message) { } + public void Dispose() { } + } + + protected abstract ServiceStackHost CreateAppHost(); + + readonly IServiceClient client; + private readonly ServiceStackHost appHost; + public ServiceGatewayTests() + { + appHost = CreateAppHost() + .Init() + .Start(Config.ListeningOn); + + client = new JsonServiceClient(Config.ListeningOn); + // ((JsonServiceClient) client).CaptureHttp(print:true); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Does_SGSendSyncInternal() + { + var response = client.Get(new SGSendSyncGetInternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendSyncGetInternal> GET SGSyncGetInternal")); + } + + [Test] + public void Does_throw_original_Exception_in_SGSendSyncInternal() + { + try + { + var response = client.Get(new SGSendSyncGetInternal { Value = "GET CLIENT", Throw = true }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ERROR " + nameof(SGSendSyncGetInternal))); + } + } + + [Test] + public void Does_SGSendSyncGetExternal() + { + var response = client.Get(new SGSendSyncGetExternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendSyncGetExternal> GET SGSyncGetExternal")); + } + + [Test] + public void Does_throw_original_Exception_in_SGSendSyncGetExternal() + { + try + { + var response = client.Get(new SGSendSyncGetExternal { Value = "GET CLIENT", Throw = true }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ERROR " + nameof(SGSyncGetExternal))); + } + } + + [Test] + public void Does_throw_original_ValidationException_in_SGSyncPostValidationExternal() + { + try + { + var response = client.Get(new SGSyncPostValidationExternal { Value = "GET CLIENT" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo("NotEmpty")); + Assert.That(ex.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("'Required' must not be empty.")); + } + } + + [Test] + public void Does_throw_original_ValidationException_in_SGSyncPostValidationAsyncExternal() + { + try + { + var response = client.Get(new SGSyncPostValidationAsyncExternal { Value = "GET CLIENT" }); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo("NotEmpty")); + Assert.That(ex.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("'Required' must not be empty.")); + } + } + + [Test] + public void Does_SGSendSyncPostInternal() + { + var response = client.Get(new SGSendSyncPostInternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendSyncPostInternal> POST SGSyncPostInternal")); + } + + [Test] + public void Does_SGSendSyncPostExternal() + { + var response = client.Get(new SGSendSyncPostExternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendSyncPostExternal> POST SGSyncPostExternal")); + } + + [Test] + public void Does_SGSendAllSyncGetAnyInternal() + { + var response = client.Get(new SGSendAllSyncGetAnyInternal { Value = "GET CLIENT" }); + Assert.That(response.Map(x => x.Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> GET SGSendAllSyncGetAnyInternal{0}> ANY SGSyncGetAnyInternal".Fmt(i)))); + } + + [Test] + public void Does_SGSendAllSyncPostExternal() + { + var response = client.Get(new SGSendAllSyncPostExternal { Value = "GET CLIENT" }); + Assert.That(response.Map(x => x.Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> GET SGSendAllSyncPostExternal{0}> POST SGSyncPostExternal".Fmt(i)))); + } + + [Test] + public void Does_SGPublishPostInternalVoid() + { + MessageProducer.Messages.Clear(); + client.Send(new SGPublishPostInternalVoid { Value = "GET CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(1)); + var response = MessageProducer.Messages[0] as SGSyncPostInternalVoid; + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGPublishPostInternalVoid")); + } + + [Test] + public void Does_SGPublishPostExternalVoid() + { + MessageProducer.Messages.Clear(); + client.Send(new SGPublishPostExternalVoid { Value = "POST CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(1)); + var response = MessageProducer.Messages[0] as SGSyncPostExternalVoid; + Assert.That(response.Value, Is.EqualTo("POST CLIENT> POST SGPublishPostExternalVoid")); + } + + [Test] + public void Does_SGPublishAllPostInternalVoid() + { + MessageProducer.Messages.Clear(); + client.Send(new SGPublishAllPostInternalVoid { Value = "GET CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(3)); + Assert.That(MessageProducer.Messages.Map(x => ((SGSyncPostInternalVoid)x).Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> GET SGPublishAllPostInternalVoid{0}".Fmt(i)))); + } + + [Test] + public void Does_SGPublishAllPostExternalVoid() + { + MessageProducer.Messages.Clear(); + client.Send(new SGPublishAllPostExternalVoid { Value = "GET CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(3)); + Assert.That(MessageProducer.Messages.Map(x => ((SGSyncPostExternalVoid)x).Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> POST SGPublishAllPostExternalVoid{0}".Fmt(i)))); + } + + [Test] + public void Does_SGSendSyncGetSyncObjectInternal() + { + var response = client.Get(new SGSendSyncGetSyncObjectInternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendSyncGetSyncObjectInternal> GET SGSyncGetSyncObjectInternal")); + } + + [Test] + public void Does_SGSendSyncGetAsyncObjectExternal() + { + var response = client.Get(new SGSendSyncGetAsyncObjectExternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendSyncGetAsyncObjectExternal> GET SGSyncGetAsyncObjectExternal")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayTestsAsync.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayTestsAsync.cs new file mode 100644 index 00000000000..7d78f72d25a --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayTestsAsync.cs @@ -0,0 +1,596 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.Logging; +using ServiceStack.Messaging; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class SGSendAsyncGetInternal : IReturn<SGSendAsyncGetInternal> + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGSendAsyncGetExternal : IReturn<SGSendAsyncGetExternal> + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGSendAsyncPostInternal : IReturn<SGSendAsyncPostInternal> + { + public string Value { get; set; } + } + + public class SGSendAsyncPostExternal : IReturn<SGSendAsyncPostExternal> + { + public string Value { get; set; } + } + + public class SGSendAllAsyncGetAnyInternal : IReturn<List<SGAsyncGetAnyInternal>> + { + public string Value { get; set; } + } + + public class SGSendAllAsyncPostExternal : IReturn<List<SGAsyncPostExternal>> + { + public string Value { get; set; } + } + + public class SGPublishAsyncPostInternalVoid : IReturnVoid, IGet + { + public string Value { get; set; } + } + + public class SGPublishAsyncPostExternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGPublishAllAsyncPostInternalVoid : IReturnVoid, IGet + { + public string Value { get; set; } + } + + public class SGPublishAllAsyncPostExternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGMultiGatewayRequests : IReturn<SGMultiGatewayRequests>, IPost + { + public int Times { get; set; } + public int Delay { get; set; } + public string Value { get; set; } + } + + public class SGMInternalMultiGatewayRequests : IReturn<SGMInternalMultiGatewayRequests>, IPost + { + public int Delay { get; set; } + public string Value { get; set; } + } + + public class SGMInternalMultiGatewayRequestsValidator : AbstractValidator<SGMInternalMultiGatewayRequests> + { + public SGMInternalMultiGatewayRequestsValidator() + { + RuleFor(x => x.Value) + .CustomAsync((x,ctx,cancel) => Gateway.SendAsync(new SGAsyncPostInternal())); + } + } + + public class ServiceGatewayAsyncServices : Service + { + public object Any(SGSendAsyncGetInternal request) + { + request.Value += "> " + Request.Verb + " " + typeof(SGSendAsyncGetInternal).Name; + return Gateway.SendAsync(request.ConvertTo<SGAsyncGetInternal>()); + } + + public object Any(SGSendAsyncGetExternal request) + { + request.Value += "> " + Request.Verb + " " + typeof(SGSendAsyncGetExternal).Name; + return Gateway.SendAsync(request.ConvertTo<SGAsyncGetExternal>()); + } + + public object Any(SGSendAsyncPostInternal request) + { + request.Value += "> " + Request.Verb + " " + typeof(SGSendAsyncPostInternal).Name; + return Gateway.SendAsync(request.ConvertTo<SGAsyncPostInternal>()); + } + + public object Any(SGSendAsyncPostExternal request) + { + request.Value += "> " + Request.Verb + " " + typeof(SGSendAsyncPostExternal).Name; + return Gateway.SendAsync(request.ConvertTo<SGAsyncPostExternal>()); + } + + public object Any(SGSendAllAsyncGetAnyInternal request) + { + var requests = 3.Times(i => new SGAsyncGetAnyInternal + { + Value = request.Value + "> " + Request.Verb + " " + typeof(SGSendAllAsyncGetAnyInternal).Name + i + }); + + return Gateway.SendAllAsync(requests); + } + + public object Any(SGSendAllAsyncPostExternal request) + { + var requests = 3.Times(i => new SGAsyncPostExternal + { + Value = request.Value + "> " + Request.Verb + " " + typeof(SGSendAllAsyncPostExternal).Name + i + }); + + return Gateway.SendAllAsync(requests); + } + + public async Task Any(SGPublishAsyncPostInternalVoid request) + { + request.Value += "> " + Request.Verb + " " + typeof(SGPublishAsyncPostInternalVoid).Name; + await Gateway.PublishAsync(request.ConvertTo<SGAsyncPostInternalVoid>()); + } + + public async Task Any(SGPublishAsyncPostExternalVoid request) + { + request.Value += "> " + Request.Verb + " " + typeof(SGPublishAsyncPostExternalVoid).Name; + await Gateway.PublishAsync(request.ConvertTo<SGAsyncPostExternalVoid>()); + } + + public async Task Any(SGPublishAllAsyncPostInternalVoid request) + { + var requests = 3.Times(i => new SGAsyncPostInternalVoid + { + Value = request.Value + "> " + Request.Verb + " " + typeof(SGPublishAllAsyncPostInternalVoid).Name + i + }); + + await Gateway.PublishAllAsync(requests); + } + + public async Task Any(SGPublishAllAsyncPostExternalVoid request) + { + var requests = 3.Times(i => new SGAsyncPostExternalVoid + { + Value = request.Value + "> " + Request.Verb + " " + typeof(SGPublishAllAsyncPostExternalVoid).Name + i + }); + + await Gateway.PublishAllAsync(requests); + } + + public async Task<object> Any(SGMultiGatewayRequests request) + { + for (var i = 0; i < request.Times; i++) + { + await Gateway.SendAsync(new SGMInternalMultiGatewayRequests { + Delay = request.Delay + }); + } + return request; + } + + public async Task<object> Any(SGMInternalMultiGatewayRequests request) + { + if (!Request.IsInProcessRequest()) + throw new Exception("Gateway Request is not in process"); + + await Task.Delay(request.Delay); + return request; + } + } + + public class SGAsyncGetInternal : IReturn<SGAsyncGetInternal>, IGet + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGAsyncGetExternal : IReturn<SGAsyncGetExternal>, IGet + { + public bool Throw { get; set; } + public string Value { get; set; } + } + + public class SGAsyncPostInternal : IReturn<SGAsyncPostInternal>, IPost + { + public string Value { get; set; } + } + + public class SGAsyncPostExternal : IReturn<SGAsyncPostExternal>, IPost + { + public string Value { get; set; } + } + + public class SGAsyncGetAnyInternal : IReturn<SGAsyncGetAnyInternal>, IGet + { + public string Value { get; set; } + } + + public class SGAsyncGetAnyExternal : IReturn<SGAsyncGetAnyInternal>, IGet + { + public string Value { get; set; } + } + + public class SGAsyncPostInternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class SGAsyncPostExternalVoid : IReturnVoid, IPost + { + public string Value { get; set; } + } + + public class ServiceGatewayInternalAsyncServices : Service + { + public object Get(SGAsyncGetInternal request) + { + if (request.Throw) + throw new ArgumentException("ERROR " + typeof(SGSendAsyncGetInternal).Name); + + request.Value += "> GET " + typeof(SGAsyncGetInternal).Name; + return request; + } + + public object Post(SGAsyncPostInternal request) + { + request.Value += "> POST " + typeof(SGAsyncPostInternal).Name; + return Task.FromResult(request); + } + + public object Any(SGAsyncGetAnyInternal request) + { + request.Value += "> ANY " + typeof(SGAsyncGetAnyInternal).Name; + return request; + } + + public void Post(SGAsyncPostInternalVoid request) + { + request.Value += "> POST " + typeof(SGAsyncPostInternalVoid).Name; + } + } + + public class ServiceGatewayExternalAsyncServices : Service + { + public async Task<object> Get(SGAsyncGetExternal request) + { + await Task.Yield(); + + if (request.Throw) + throw new ArgumentException("ERROR " + typeof(SGAsyncGetExternal).Name); + + request.Value += "> GET " + typeof(SGAsyncGetExternal).Name; + return await Task.FromResult(request); + } + + public async Task<object> Post(SGAsyncPostExternal request) + { + request.Value += "> POST " + typeof(SGAsyncPostExternal).Name; + return await Task.FromResult(request); + } + + public Task Any(SGAsyncGetAnyExternal request) + { + request.Value += "> ANY " + typeof(SGAsyncGetAnyExternal).Name; + return Task.FromResult(request); + } + + public Task Post(SGAsyncPostExternalVoid request) + { + request.Value += "> POST " + typeof(SGAsyncPostExternalVoid).Name; + return Task.FromResult((object)null); + } + } + + //AppHosts + public class MixedServiceGatewayNativeAsyncTests : ServiceGatewayAsyncTests + { + class MixedServiceGatewayFactory : ServiceGatewayFactoryBase + { + public override IServiceGateway GetGateway(Type requestType) + { + var gateway = requestType.Name.Contains("External") + ? new JsonServiceClient(Config.ListeningOn) + : (IServiceGateway)localGateway; + return gateway; + } + } + + class MixedAppHost : AppSelfHostBase + { + public MixedAppHost() : base(typeof(ServiceGatewayTests).Name, typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + + container.Register<IServiceGatewayFactory>(x => new MixedServiceGatewayFactory()) + .ReusedWithin(ReuseScope.None); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new MixedAppHost(); + } + } + + public class MixedServiceGatewayAsyncTests : ServiceGatewayAsyncTests + { + class MixedServiceGatewayFactory : IServiceGatewayFactory, IServiceGateway + { + private InProcessServiceGateway localGateway; + + public IServiceGateway GetServiceGateway(IRequest request) + { + localGateway = new InProcessServiceGateway(request); + return this; + } + + public IServiceGateway GetGateway(Type requestType) + { + var gateway = requestType.Name.Contains("External") + ? new JsonServiceClient(Config.ListeningOn) + : (IServiceGateway) localGateway; + return gateway; + } + + public TResponse Send<TResponse>(object requestDto) + { + return GetGateway(requestDto.GetType()).Send<TResponse>(requestDto); + } + + public List<TResponse> SendAll<TResponse>(IEnumerable<object> requestDtos) + { + return GetGateway(requestDtos.GetType().GetCollectionType()).SendAll<TResponse>(requestDtos); + } + + public void Publish(object requestDto) + { + GetGateway(requestDto.GetType()).Publish(requestDto); + } + + public void PublishAll(IEnumerable<object> requestDtos) + { + GetGateway(requestDtos.GetType().GetCollectionType()).PublishAll(requestDtos); + } + } + + class MixedAppHost : AppSelfHostBase + { + public MixedAppHost() : base(typeof(ServiceGatewayTests).Name, typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + + container.Register<IServiceGatewayFactory>(x => new MixedServiceGatewayFactory()) + .ReusedWithin(ReuseScope.None); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new MixedAppHost(); + } + } + + public class AllExternalServiceGatewayAsyncTests : ServiceGatewayAsyncTests + { + class AllExternalAppHost : AppSelfHostBase + { + public AllExternalAppHost() : base(typeof(ServiceGatewayTests).Name, typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + container.Register<IServiceGateway>(c => new JsonServiceClient(Tests.Config.ListeningOn)); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new AllExternalAppHost(); + } + } + + //Tests + public class AllInternalServiceGatewayAsyncTests : ServiceGatewayAsyncTests + { + class AllInternalAppHost : AppSelfHostBase + { + public AllInternalAppHost() : base(typeof(ServiceGatewayTests).Name, typeof(ServiceGatewayServices).Assembly) { } + + public override void Configure(Container container) + { + container.Register<IMessageFactory>(c => new MessageFactory()); + + Plugins.Add(new ValidationFeature()); + } + } + + protected override ServiceStackHost CreateAppHost() + { + return new AllInternalAppHost(); + } + + [Test] + public async Task Verify_all_internal_gateway_requests_are_marked_as_in_process() + { + await client.GetAsync(new SGMultiGatewayRequests { Times = 3, Delay = 10 }); + } + } + + public abstract class ServiceGatewayAsyncTests + { + public class MessageFactory : IMessageFactory + { + public IMessageProducer CreateMessageProducer() + { + return new MessageProducer(); + } + + public IMessageQueueClient CreateMessageQueueClient() { return null; } + public void Dispose() { } + } + + public class MessageProducer : IMessageProducer + { + public static List<object> Messages = new List<object>(); + + public void Publish<T>(T messageBody) + { + Messages.Add(messageBody); + } + + public void Publish<T>(IMessage<T> message) { } + public void Dispose() { } + } + + protected abstract ServiceStackHost CreateAppHost(); + + protected readonly IServiceClient client; + private readonly ServiceStackHost appHost; + public ServiceGatewayAsyncTests() + { + appHost = CreateAppHost() + .Init() + .Start(Config.ListeningOn); + + client = new JsonServiceClient(Config.ListeningOn); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() => appHost.Dispose(); + + [Test] + public void Does_SGSendAsyncInternal() + { + var response = client.Get(new SGSendAsyncGetInternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendAsyncGetInternal> GET SGAsyncGetInternal")); + } + + [Test] + public void Does_throw_original_Exception_in_SGSendAsyncInternal() + { + try + { + var response = client.Get(new SGSendAsyncGetInternal { Value = "GET CLIENT", Throw = true }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(typeof(ArgumentException).Name)); + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(ArgumentException).Name)); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(typeof(ArgumentException).Name)); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ERROR " + typeof(SGSendAsyncGetInternal).Name)); + } + } + + [Test] + public async Task Does_SGSendAsyncGetExternal() + { + var response = await client.GetAsync(new SGSendAsyncGetExternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendAsyncGetExternal> GET SGAsyncGetExternal")); + } + + [Test] + public async Task Does_throw_original_Exception_in_SGSendAsyncGetExternal() + { + try + { + var response = await client.GetAsync(new SGSendAsyncGetExternal { Value = "GET CLIENT", Throw = true }); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.StatusDescription, Is.EqualTo(typeof(ArgumentException).Name)); + Assert.That(ex.ErrorCode, Is.EqualTo(typeof(ArgumentException).Name)); + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(typeof(ArgumentException).Name)); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo("ERROR " + typeof(SGAsyncGetExternal).Name)); + } + } + + [Test] + public void Does_SGSendAsyncPostInternal() + { + var response = client.Get(new SGSendAsyncPostInternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendAsyncPostInternal> POST SGAsyncPostInternal")); + } + + [Test] + public async Task Does_SGSendAsyncPostExternal() + { + var response = await client.GetAsync(new SGSendAsyncPostExternal { Value = "GET CLIENT" }); + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGSendAsyncPostExternal> POST SGAsyncPostExternal")); + } + + [Test] + public void Does_SGSendAllAsyncGetAnyInternal() + { + var response = client.Get(new SGSendAllAsyncGetAnyInternal { Value = "GET CLIENT" }); + Assert.That(response.Map(x => x.Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> GET SGSendAllAsyncGetAnyInternal{0}> ANY SGAsyncGetAnyInternal".Fmt(i)))); + } + + [Test] + public async Task Does_SGSendAllAsyncPostExternal() + { + var response = await client.GetAsync(new SGSendAllAsyncPostExternal { Value = "GET CLIENT" }); + Assert.That(response.Map(x => x.Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> GET SGSendAllAsyncPostExternal{0}> POST SGAsyncPostExternal".Fmt(i)))); + } + + [Test] + public void Does_SGPublishAsyncPostInternalVoid() + { + MessageProducer.Messages.Clear(); + client.Send(new SGPublishAsyncPostInternalVoid { Value = "GET CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(1)); + var response = MessageProducer.Messages[0] as SGAsyncPostInternalVoid; + Assert.That(response.Value, Is.EqualTo("GET CLIENT> GET SGPublishAsyncPostInternalVoid")); + } + + [Test] + public async Task Does_SGPublishAsyncPostExternalVoid() + { + MessageProducer.Messages.Clear(); + await client.SendAsync(new SGPublishAsyncPostExternalVoid { Value = "POST CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(1)); + var response = MessageProducer.Messages[0] as SGAsyncPostExternalVoid; + Assert.That(response.Value, Is.EqualTo("POST CLIENT> POST SGPublishAsyncPostExternalVoid")); + } + + [Test] + public void Does_SGPublishAllAsyncPostInternalVoid() + { + MessageProducer.Messages.Clear(); + client.Send(new SGPublishAllAsyncPostInternalVoid { Value = "GET CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(3)); + Assert.That(MessageProducer.Messages.Map(x => ((SGAsyncPostInternalVoid)x).Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> GET SGPublishAllAsyncPostInternalVoid{0}".Fmt(i)))); + } + + [Test] + public async Task Does_SGPublishAllAsyncPostExternalVoid() + { + MessageProducer.Messages.Clear(); + await client.SendAsync(new SGPublishAllAsyncPostExternalVoid { Value = "GET CLIENT" }); + + Assert.That(MessageProducer.Messages.Count, Is.EqualTo(3)); + Assert.That(MessageProducer.Messages.Map(x => ((SGAsyncPostExternalVoid)x).Value), Is.EquivalentTo( + 3.Times(i => "GET CLIENT> POST SGPublishAllAsyncPostExternalVoid{0}".Fmt(i)))); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayUsageTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayUsageTests.cs new file mode 100644 index 00000000000..02a0465424e --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceGatewayUsageTests.cs @@ -0,0 +1,154 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + class UsageNone { } + class UsageReturn : IReturn<UsageReturn> { } + class UsageVoid : IReturnVoid { } + + /// <summary> + /// Ensure no ambiguous compile errors with normal API Usage + /// </summary> + public class ServiceGatewayUsageTests + { + void ConcreteSyncApiUsage(JsonServiceClient client) + { + UsageNone none = client.Send<UsageNone>(new UsageNone()); + UsageReturn @return = client.Send(new UsageReturn()); + client.Send(new UsageVoid()); + List<UsageReturn> @returnAll = client.SendAll(new[] { new UsageReturn() }); + client.Publish(new UsageNone()); + client.Publish(new UsageReturn()); + client.Publish(new UsageVoid()); + client.PublishAll(new[] { new UsageNone() }); + client.PublishAll(new [] { new UsageReturn() }); + client.PublishAll(new [] { new UsageVoid() }); + } + + async Task ConcreteAsyncApiUsage(JsonServiceClient client) + { + UsageNone none = await client.SendAsync<UsageNone>(new UsageNone()); + UsageNone noneToken = await client.SendAsync<UsageNone>(new UsageNone(), CancellationToken.None); + UsageReturn @return = await client.SendAsync(new UsageReturn()); + UsageReturn returnToken = await client.SendAsync(new UsageReturn(), CancellationToken.None); + await client.SendAsync(new UsageVoid()); + await client.SendAsync(new UsageVoid(), CancellationToken.None); + List<UsageReturn> returnAll = await client.SendAllAsync(new[] { new UsageReturn() }); + List<UsageReturn> returnAllToken = await client.SendAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAsync(new UsageNone()); + await client.PublishAsync(new UsageNone(), CancellationToken.None); + await client.PublishAsync(new UsageReturn()); + await client.PublishAsync(new UsageReturn(), CancellationToken.None); + await client.PublishAsync(new UsageVoid()); + await client.PublishAsync(new UsageVoid(), CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageNone() }); + await client.PublishAllAsync(new[] { new UsageNone() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageReturn() }); + await client.PublishAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageVoid() }); + await client.PublishAllAsync(new[] { new UsageVoid() }, CancellationToken.None); + } + + void IServiceClientSyncApiUsage(IServiceClient client) + { + UsageNone none = client.Send<UsageNone>(new UsageNone()); + UsageReturn @return = client.Send(new UsageReturn()); + client.Send(new UsageVoid()); + List<UsageReturn> @returnAll = client.SendAll(new[] { new UsageReturn() }); + client.Publish(new UsageNone()); + client.Publish(new UsageReturn()); + client.Publish(new UsageVoid()); + client.PublishAll(new[] { new UsageNone() }); + client.PublishAll(new[] { new UsageReturn() }); + client.PublishAll(new[] { new UsageVoid() }); + } + + async Task IServiceClientAsyncApiUsage(IServiceClient client) + { + UsageNone none = await client.SendAsync<UsageNone>(new UsageNone()); + UsageNone noneToken = await client.SendAsync<UsageNone>(new UsageNone(), CancellationToken.None); + UsageReturn @return = await client.SendAsync(new UsageReturn()); + UsageReturn returnToken = await client.SendAsync(new UsageReturn(), CancellationToken.None); + await client.SendAsync(new UsageVoid()); + await client.SendAsync(new UsageVoid(), CancellationToken.None); + List<UsageReturn> returnAll = await client.SendAllAsync(new[] { new UsageReturn() }); + List<UsageReturn> returnAllToken = await client.SendAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAsync(new UsageNone()); + await client.PublishAsync(new UsageNone(), CancellationToken.None); + await client.PublishAsync(new UsageReturn()); + await client.PublishAsync(new UsageReturn(), CancellationToken.None); + await client.PublishAsync(new UsageVoid()); + await client.PublishAsync(new UsageVoid(), CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageNone() }); + await client.PublishAllAsync(new[] { new UsageNone() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageReturn() }); + await client.PublishAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageVoid() }); + await client.PublishAllAsync(new[] { new UsageVoid() }, CancellationToken.None); + } + + void IServiceGatewaySyncApiUsage(IServiceGateway client) + { + UsageNone none = client.Send<UsageNone>(new UsageNone()); + UsageReturn @return = client.Send(new UsageReturn()); + client.Send(new UsageVoid()); + List<UsageReturn> @returnAll = client.SendAll(new[] { new UsageReturn() }); + client.Publish(new UsageNone()); + client.Publish(new UsageReturn()); + client.Publish(new UsageVoid()); + client.PublishAll(new[] { new UsageNone() }); + client.PublishAll(new[] { new UsageReturn() }); + client.PublishAll(new[] { new UsageVoid() }); + } + + async Task IServiceGatewayAsyncApiUsage(IServiceGateway client) + { + UsageNone none = await client.SendAsync<UsageNone>(new UsageNone()); + UsageNone noneToken = await client.SendAsync<UsageNone>(new UsageNone(), CancellationToken.None); + UsageReturn @return = await client.SendAsync(new UsageReturn()); + UsageReturn returnToken = await client.SendAsync(new UsageReturn(), CancellationToken.None); + await client.SendAsync(new UsageVoid()); + await client.SendAsync(new UsageVoid(), CancellationToken.None); + List<UsageReturn> returnAll = await client.SendAllAsync(new[] { new UsageReturn() }); + List<UsageReturn> returnAllToken = await client.SendAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAsync(new UsageNone()); + await client.PublishAsync(new UsageNone(), CancellationToken.None); + await client.PublishAsync(new UsageReturn()); + await client.PublishAsync(new UsageReturn(), CancellationToken.None); + await client.PublishAsync(new UsageVoid()); + await client.PublishAsync(new UsageVoid(), CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageNone() }); + await client.PublishAllAsync(new[] { new UsageNone() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageReturn() }); + await client.PublishAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageVoid() }); + await client.PublishAllAsync(new[] { new UsageVoid() }, CancellationToken.None); + } + + async Task IServiceGatewayAsyncApiUsage(IServiceGatewayAsync client) + { + UsageNone none = await client.SendAsync<UsageNone>(new UsageNone()); + UsageNone noneToken = await client.SendAsync<UsageNone>(new UsageNone(), CancellationToken.None); + UsageReturn @return = await client.SendAsync<UsageReturn>(new UsageReturn()); + UsageReturn returnToken = await client.SendAsync<UsageReturn>(new UsageReturn(), CancellationToken.None); + await client.SendAsync<UsageReturn>(new UsageVoid()); + await client.SendAsync<UsageReturn>(new UsageVoid(), CancellationToken.None); + List<UsageReturn> returnAll = await client.SendAllAsync<UsageReturn>(new[] { new UsageReturn() }); + List<UsageReturn> returnAllToken = await client.SendAllAsync<UsageReturn>(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAsync(new UsageNone()); + await client.PublishAsync(new UsageNone(), CancellationToken.None); + await client.PublishAsync(new UsageReturn()); + await client.PublishAsync(new UsageReturn(), CancellationToken.None); + await client.PublishAsync(new UsageVoid()); + await client.PublishAsync(new UsageVoid(), CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageNone() }); + await client.PublishAllAsync(new[] { new UsageNone() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageReturn() }); + await client.PublishAllAsync(new[] { new UsageReturn() }, CancellationToken.None); + await client.PublishAllAsync(new[] { new UsageVoid() }); + await client.PublishAllAsync(new[] { new UsageVoid() }, CancellationToken.None); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceHostTestBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceHostTestBase.cs index 1c10362fb75..1ddcc7a812c 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceHostTestBase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceHostTestBase.cs @@ -1,19 +1,10 @@ using System; using NUnit.Framework; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests { public class ServiceHostTestBase { - public static TestAppHost CreateAppHost() - { - var appHost = new TestAppHost(); - appHost.Init(); - - return appHost; - } - public void ShouldThrow<T>(Action action) where T : Exception { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs index b5bd71610f3..fa3ba9f6d48 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceSetupTests.cs @@ -1,7 +1,5 @@ using Funq; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -10,7 +8,7 @@ public class ServiceSetup : IReturn<ServiceSetup> public int Id { get; set; } } - public class BaseService<T> : ServiceInterface.Service + public class BaseService<T> : Service { public virtual object Get(T dto) { @@ -36,11 +34,11 @@ public override void Configure(Container container) { } [TestFixture] public class ServiceSetupTests { - private const string BaseUri = "http://localhost:8000/"; + private const string BaseUri = "http://localhost:8001/"; JsonServiceClient client = new JsonServiceClient(BaseUri); private ServiceSetupAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new ServiceSetupAppHost(); @@ -48,11 +46,10 @@ public void TestFixtureSetUp() appHost.Start(BaseUri); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj index f61752e781a..f2ad186a472 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj @@ -1,328 +1,102 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> +<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.30729</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}</ProjectGuid> + <TargetFramework>net472</TargetFramework> +<!-- <TargetFramework>net6.0</TargetFramework>--> +<!-- <TargetFrameworks>net472;net6.0</TargetFrameworks>--> <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>ServiceStack.WebHost.Endpoints.Tests</RootNamespace> <AssemblyName>ServiceStack.WebHost.Endpoints.Tests</AssemblyName> - <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> - <FileAlignment>512</FileAlignment> - <FileUpgradeFlags> - </FileUpgradeFlags> - <OldToolsVersion>3.5</OldToolsVersion> - <UpgradeBackupLocation /> - <PublishUrl>publish\</PublishUrl> - <Install>true</Install> - <InstallFrom>Disk</InstallFrom> - <UpdateEnabled>false</UpdateEnabled> - <UpdateMode>Foreground</UpdateMode> - <UpdateInterval>7</UpdateInterval> - <UpdateIntervalUnits>Days</UpdateIntervalUnits> - <UpdatePeriodically>false</UpdatePeriodically> - <UpdateRequired>false</UpdateRequired> - <MapFileExtensions>true</MapFileExtensions> - <ApplicationRevision>0</ApplicationRevision> - <ApplicationVersion>1.0.0.%2a</ApplicationVersion> - <IsWebBootstrapper>false</IsWebBootstrapper> - <UseApplicationTrust>false</UseApplicationTrust> - <BootstrapperEnabled>true</BootstrapperEnabled> - <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\src\</SolutionDir> - <RestorePackages>true</RestorePackages> - <TargetFrameworkProfile /> + <PackageId>ServiceStack.WebHost.Endpoints.Tests</PackageId> + <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute> + <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute> + <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> + <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> + <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> + <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute> + <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute> + <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>True</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>False</Optimize> - <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - <PlatformTarget>x86</PlatformTarget> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> - <Optimize>True</Optimize> - <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <PlatformTarget>x86</PlatformTarget> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'STATIC_ONLY NO_EXPRESSIONS|AnyCPU' "> - <DebugSymbols>True</DebugSymbols> - <OutputPath>bin\STATIC_ONLY NO_EXPRESSIONS\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <DebugType>full</DebugType> - <PlatformTarget>AnyCPU</PlatformTarget> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <Optimize>False</Optimize> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MonoTouch|AnyCPU' "> - <DebugSymbols>True</DebugSymbols> - <OutputPath>bin\MonoTouch\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <DebugType>full</DebugType> - <PlatformTarget>AnyCPU</PlatformTarget> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <Optimize>False</Optimize> - <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - <ItemGroup> - <Reference Include="protobuf-net"> - <HintPath>..\..\src\packages\protobuf-net.2.0.0.640\lib\net40\protobuf-net.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite"> - <HintPath>..\..\lib\ServiceStack.OrmLite.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite.Sqlite"> - <HintPath>..\..\lib\ServiceStack.OrmLite.Sqlite.dll</HintPath> - </Reference> - <Reference Include="System" /> - <Reference Include="System.ComponentModel.DataAnnotations" /> - <Reference Include="System.Core"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Drawing" /> - <Reference Include="System.Runtime.Serialization"> - <RequiredTargetFramework>3.0</RequiredTargetFramework> - </Reference> - <Reference Include="System.ServiceModel"> - <RequiredTargetFramework>3.0</RequiredTargetFramework> - </Reference> - <Reference Include="System.Web" /> - <Reference Include="System.Windows.Forms" /> - <Reference Include="System.Xml.Linq"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Data.DataSetExtensions"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Data" /> + <PropertyGroup Condition=" '$(TargetFramework)' == 'net472' "> + <DefineConstants>$(DefineConstants);NETFX;NET472</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0' "> + <DefineConstants>$(DefineConstants);NETCORE;NET6_0;NET6_0_OR_GREATER</DefineConstants> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\..\src\ServiceStack.Api.OpenApi\ServiceStack.Api.OpenApi.csproj"> + <Project>{5E258282-86A6-4780-AB25-5E458F2E6F70}</Project> + <Name>ServiceStack.Api.OpenApi</Name> + </ProjectReference> + <ProjectReference Include="..\..\src\ServiceStack.Authentication.MongoDb\ServiceStack.Authentication.MongoDb.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.Authentication.RavenDb\ServiceStack.Authentication.RavenDb.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.Interfaces\ServiceStack.Interfaces.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.Client\ServiceStack.Client.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.Common\ServiceStack.Common.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.Server\ServiceStack.Server.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.HttpClient\ServiceStack.HttpClient.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.RabbitMq\ServiceStack.RabbitMq.csproj" /> + <ProjectReference Include="..\..\src\ServiceStack.ProtoBuf\ServiceStack.ProtoBuf.csproj" /> + <ProjectReference Include="..\ServiceStack.Common.Tests\ServiceStack.Common.Tests.csproj" /> + + <PackageReference Include="ServiceStack.Text" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Redis" Version="$(Version)" /> + <PackageReference Include="ServiceStack.OrmLite" Version="$(Version)" /> + <PackageReference Include="ServiceStack.OrmLite.Sqlite" Version="$(Version)" /> + <PackageReference Include="ServiceStack.OrmLite.SqlServer" Version="$(Version)" /> + <PackageReference Include="ServiceStack.OrmLite.MySql" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Aws" Version="$(Version)" /> + <PackageReference Include="NUnit3TestAdapter" Version="4.1.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> + <PackageReference Include="NUnit" Version="3.13.2" /> + <PackageReference Include="System.Data.SqlClient" Version="4.8.3" /> + <PackageReference Include="System.Data.SQLite.Core" Version="1.0.115.5" /> + <PackageReference Include="System.Memory" Version="4.5.4" /> + <PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" /> + <PackageReference Include="MongoDB.Bson" Version="2.13.1" /> + <PackageReference Include="MongoDB.Driver" Version="2.13.1" /> + <PackageReference Include="MongoDB.Driver.Core" Version="2.13.1" /> + <PackageReference Include="RavenDB.Client" Version="5.2.1" /> + </ItemGroup> + <ItemGroup Condition=" '$(TargetFramework)' == 'net472' "> + <ProjectReference Include="..\..\src\ServiceStack.NetFramework\ServiceStack.NetFramework.csproj" /> + <ProjectReference Include="..\ServiceStack.ServiceModel.Tests\ServiceStack.ServiceModel.Tests.csproj" /> + <PackageReference Include="Mysql.Data" Version="8.0.26" /> <Reference Include="System.Xml" /> - <Reference Include="Moq"> - <HintPath>..\..\lib\tests\Moq.dll</HintPath> - </Reference> - <Reference Include="Mono.Data.Sqlite"> - <HintPath>..\..\lib\tests\Mono.Data.Sqlite.dll</HintPath> - </Reference> - <Reference Include="nunit.framework"> - <HintPath>..\..\lib\tests\nunit.framework.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Text"> - <HintPath>..\..\lib\ServiceStack.Text.dll</HintPath> - </Reference> + <Reference Include="System.Data" /> <Reference Include="System.Configuration" /> + <Reference Include="System.Web" /> + <Reference Include="System.Net" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.ServiceModel" /> + <Reference Include="System.ComponentModel.DataAnnotations" /> </ItemGroup> - <ItemGroup> - <Compile Include="AppHostListenerEchoRequestTests.cs" /> - <Compile Include="AppHostHttpListenerLongRunningBaseTests.cs" /> - <Compile Include="AppHostListenerBaseTests.cs" /> - <Compile Include="AsyncRestClientTests.cs" /> - <Compile Include="AsyncServiceClientTests.cs" /> - <Compile Include="AttributeFiltersTest.cs" /> - <Compile Include="AuthTests.cs" /> - <Compile Include="BufferedRequestTests.cs" /> - <Compile Include="CachedServiceTests.cs" /> - <Compile Include="CompressionTests.cs" /> - <Compile Include="RouteTests.cs" /> - <Compile Include="CustomValidationErrorTests.cs" /> - <Compile Include="EncodingTests.cs" /> - <Compile Include="ExceptionHandling2Tests.cs" /> - <Compile Include="IntegrationTests\MovieSoap11Tests.cs" /> - <Compile Include="RestHandlerTests.cs" /> - <Compile Include="RouteInferenceTests.cs" /> - <Compile Include="ServiceClientsBuiltInResponseTests.cs" /> - <Compile Include="Support\Services\TestRestService.cs" /> - <Compile Include="Support\Types\KeyAttribute.cs" /> - <Compile Include="PartialContentResultTests.cs" /> - <Compile Include="ServiceSetupTests.cs" /> - <Compile Include="Support\Services\FailingService.cs" /> - <Compile Include="UniqueRequestTests.cs" /> - <Compile Include="SendOneWayTests.cs" /> - <Compile Include="Support\Services\EndpointAccessService.cs" /> - <Compile Include="SwaggerFeatureTests.cs" /> - <Compile Include="CorsFeatureTest.cs" /> - <Compile Include="IntegrationTests\CachedMoviesService.cs" /> - <Compile Include="IntegrationTests\ErrorRestTests.cs" /> - <Compile Include="NewApiTodos.cs" /> - <Compile Include="ProtoBufServiceTests.cs" /> - <Compile Include="SharedDtoTests.cs" /> - <Compile Include="Support\Operations\CustomRequestBinder.cs" /> - <Compile Include="TodoListTests.cs" /> - <Compile Include="CustomerServiceValidationTests.cs" /> - <Compile Include="ExceptionHandlingTests.cs" /> - <Compile Include="HttpResultContentTypeTests.cs" /> - <Compile Include="RemoteEndDropsConnectionTests.cs" /> - <Compile Include="IocServiceTests.cs" /> - <Compile Include="Support\EndpointHandlerBaseTests.cs" /> - <Compile Include="UserServiceValidationTests.cs" /> - <Compile Include="JsonpTests.cs" /> - <Compile Include="Support\Host\IocAppHost.cs" /> - <Compile Include="Support\Services\IocService.cs" /> - <Compile Include="CustomRequestDataTests.cs" /> - <Compile Include="HttpResultTests.cs" /> - <Compile Include="IntegrationTests\ResetMovies.cs" /> - <Compile Include="Support\Host\TestConfigAppHostHttpListener.cs" /> - <Compile Include="Support\Operations\CustomFormData.cs" /> - <Compile Include="Support\Services\CustomFormDataService.cs" /> - <Compile Include="AppHostConfigTests.cs" /> - <Compile Include="SyncRestClientTests.cs" /> - <Compile Include="CsvContentTypeFilterTests.cs" /> - <Compile Include="EndpointRestrictionTests.cs" /> - <Compile Include="FileUploadTests.cs" /> - <Compile Include="HttpErrorTests.cs" /> - <Compile Include="RequestContextTests.cs" /> - <Compile Include="RequestFiltersTests.cs" /> - <Compile Include="Support\DirectServiceClient.cs" /> - <Compile Include="Support\Host\ExampleAppHostHttpListener.cs" /> - <Compile Include="HtmlResultTests.cs" /> - <Compile Include="IntegrationTests\ConfigureDatabase.cs" /> - <Compile Include="IntegrationTests\ExampleConfig.cs" /> - <Compile Include="IntegrationTests\IntegrationTestBase.cs" /> - <Compile Include="IntegrationTests\RestMovie.cs" /> - <Compile Include="IntegrationTests\RestMovieService.cs" /> - <Compile Include="IntegrationTests\MovieRestTests.cs" /> - <Compile Include="IntegrationTests\ResetMovieDatabase.cs" /> - <Compile Include="IntegrationTests\ResetMovieDatabaseService.cs" /> - <Compile Include="KeyValueDataContractDeserializerTests.cs" /> - <Compile Include="MessageSerializationTests.cs" /> - <Compile Include="ServiceHostTestBase.cs" /> - <Compile Include="Support\ServiceClientTestBase.cs" /> - <Compile Include="ServiceClientTests.cs" /> - <Compile Include="ServiceStackHttpHandlerFactoryTests.cs" /> - <Compile Include="Support\Host\TestAppHostHttpListener.cs" /> - <Compile Include="Support\Operations\RequestOfAllTypes.cs" /> - <Compile Include="Support\Operations\RequestOfComplexTypes.cs" /> - <Compile Include="Support\Services\FileUploadService.cs" /> - <Compile Include="Support\Services\HttpErrorService.cs" /> - <Compile Include="Support\Services\RequestFilter.cs" /> - <Compile Include="Support\Services\HeadersService.cs" /> - <Compile Include="Support\Services\GetCustomerService.cs" /> - <Compile Include="Support\Services\HelloService.cs" /> - <Compile Include="Support\Services\TestAsyncService.cs" /> - <Compile Include="Support\Services\InSecureLiveEnvironmentRestriction.cs" /> - <Compile Include="Support\Services\SecureLiveEnvironmentRestriction.cs" /> - <Compile Include="Support\Services\SecureDevEnvironmentRestrictionService.cs" /> - <Compile Include="Support\Services\InsecureDevEnvironmentRestrictionService.cs" /> - <Compile Include="Support\Services\HttpPostXmlAndSecureLocalSubnetRestrictionService.cs" /> - <Compile Include="Support\Services\HttpPostXmlOrSecureLocalSubnetRestrictionService.cs" /> - <Compile Include="Support\Services\SecureLocalSubnetRestrictionService.cs" /> - <Compile Include="Support\Services\InternalRestrictionService.cs" /> - <Compile Include="Support\Services\LocalhostRestrictionService.cs" /> - <Compile Include="Support\Services\LocalSubnetRestrictionService.cs" /> - <Compile Include="Support\Services\NestedService.cs" /> - <Compile Include="ServiceStackHostTests.cs" /> - <Compile Include="Support\Operations\GetCustomers.cs" /> - <Compile Include="Support\Operations\StoreCustomer.cs" /> - <Compile Include="Support\Services\TestServiceBase.cs" /> - <Compile Include="Support\Host\TestAppHost.cs" /> - <Compile Include="Support\TestBase.cs" /> - <Compile Include="Support\Services\TestService.cs" /> - <Compile Include="WebServiceExceptionTests.cs" /> - <Compile Include="WsdlMetadataTests.cs" /> - <Compile Include="OperationTests.cs" /> - <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Support\Operations\GetCustomer.cs" /> - <Compile Include="Support\Types\Customer.cs" /> - <Compile Include="XmlMetaDataHandlerTests.cs" /> + <ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' "> + <ProjectReference Include="..\..\src\ServiceStack.Kestrel\ServiceStack.Kestrel.csproj" /> + <PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" /> + <PackageReference Include="System.Threading" Version="4.3.0" /> + <PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.0" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\..\src\ServiceStack.Api.Swagger\ServiceStack.Api.Swagger.csproj"> - <Project>{01D3F057-7984-498F-8B0A-EB375701E204}</Project> - <Name>ServiceStack.Api.Swagger</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Common\ServiceStack.Common.csproj"> - <Project>{982416DB-C143-4028-A0C3-CF41892D18D3}</Project> - <Name>ServiceStack.Common</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Interfaces\ServiceStack.Interfaces.csproj"> - <Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project> - <Name>ServiceStack.Interfaces</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Plugins.ProtoBuf\ServiceStack.Plugins.ProtoBuf.csproj"> - <Project>{EF36A253-C53F-4BF3-B0EC-4D29211FA67D}</Project> - <Name>ServiceStack.Plugins.ProtoBuf</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj"> - <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project> - <Name>ServiceStack.ServiceInterface</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj"> - <Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project> - <Name>ServiceStack</Name> - </ProjectReference> - <ProjectReference Include="..\ServiceStack.Common.Tests\ServiceStack.Common.Tests.csproj"> - <Project>{3FA9197A-462D-44CC-9AB3-61AF414D0B45}</Project> - <Name>ServiceStack.Common.Tests</Name> - </ProjectReference> - <ProjectReference Include="..\ServiceStack.ServiceModel.Tests\ServiceStack.ServiceModel.Tests.csproj"> - <Project>{A5646013-C243-453F-A2B6-3B6870A9637D}</Project> - <Name>ServiceStack.ServiceModel.Tests</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <Content Include="..\..\lib\sqlite3.dll"> - <Link>sqlite3.dll</Link> + <Content Update="App_Data\customers.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="TestExistingDir\textfile.txt"> + </ItemGroup> + <ItemGroup> + <None Update="TestExistingDir\default.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="webpage.forbidden"> + </None> + <None Update="TestExistingDir\textfile.txt"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="webpage.html"> + </None> + <None Update="TestExistingDir\upload.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="TestExistingDir\default.html"> + </None> + <None Update="webpage.forbidden"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - <Content Include="TestExistingDir\upload.html"> + </None> + <None Update="webpage.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> - </ItemGroup> - <ItemGroup> - <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> - <Visible>False</Visible> - <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName> - <Install>false</Install> - </BootstrapperPackage> - <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> - <Visible>False</Visible> - <ProductName>.NET Framework 3.5 SP1</ProductName> - <Install>true</Install> - </BootstrapperPackage> - <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1"> - <Visible>False</Visible> - <ProductName>Windows Installer 3.1</ProductName> - <Install>true</Install> - </BootstrapperPackage> - </ItemGroup> - <ItemGroup> - <Folder Include="ServiceModel\" /> - </ItemGroup> - <ItemGroup> - <None Include="packages.config" /> - <None Include="README.md" /> + </None> </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <Import Project="$(SolutionDir)\.nuget\NuGet.targets" /> - <!-- To modify your build process, add your task inside one of the targets below and uncomment it. - Other similar extension points exist, see Microsoft.Common.targets. - <Target Name="BeforeBuild"> - </Target> - <Target Name="AfterBuild"> - </Target> - --> -</Project> +</Project> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj.user b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj.user index 514f85af64e..aa9b7982706 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj.user +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStack.WebHost.Endpoints.Tests.csproj.user @@ -1,14 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> - <PublishUrlHistory /> - <InstallUrlHistory /> - <SupportUrlHistory /> - <UpdateUrlHistory /> - <BootstrapperUrlHistory /> - <ErrorReportUrlHistory /> - <FallbackCulture>en-US</FallbackCulture> - <VerifyUploadedFiles>false</VerifyUploadedFiles> - <ProjectView>ProjectFiles</ProjectView> + <ActiveDebugProfile>IIS Express</ActiveDebugProfile> + <ShowAllFiles>false</ShowAllFiles> </PropertyGroup> </Project> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHostTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHostTests.cs index 2d01cac3fa2..aa5635a1d8b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHostTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHostTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Reflection; -using System.Runtime.Serialization; using NUnit.Framework; -using ServiceStack.ServiceHost; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; @@ -11,14 +7,25 @@ namespace ServiceStack.WebHost.Endpoints.Tests [TestFixture] public class ServiceStackHostTests { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new TestAppHost().Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + [Test] public void Can_run_nested_service() { - var host = new TestAppHost(); - host.Init(); - var request = new Nested(); - var response = host.ExecuteService(request) as NestedResponse; + var response = appHost.ExecuteService(request) as NestedResponse; Assert.That(response, Is.Not.Null); } @@ -26,11 +33,8 @@ public void Can_run_nested_service() [Test] public void Can_run_test_service() { - var host = new TestAppHost(); - host.Init(); - var request = new Test(); - var response = host.ExecuteService(request) as TestResponse; + var response = appHost.ExecuteService(request) as TestResponse; Assert.That(response, Is.Not.Null); Assert.That(response.Foo, Is.Not.Null); @@ -39,33 +43,13 @@ public void Can_run_test_service() [Test] public void Call_AsyncOneWay_endpoint_on_TestService_calls_Execute() { - var host = new TestAppHost(); - host.Init(); - TestService.ResetStats(); var request = new Test(); - var response = host.ExecuteService(request, EndpointAttributes.OneWay) as TestResponse; + var response = appHost.ExecuteService(request, RequestAttributes.OneWay) as TestResponse; Assert.That(response, Is.Not.Null); Assert.That(response.ExecuteTimes, Is.EqualTo(1)); - Assert.That(response.ExecuteAsyncTimes, Is.EqualTo(0)); - } - - [Test] - public void Call_AsyncOneWay_endpoint_on_AsyncTestService_calls_ExecuteAsync() - { - var host = new TestAppHost(); - host.Init(); - - TestAsyncService.ResetStats(); - - var request = new TestAsync(); - var response = host.ExecuteService(request, EndpointAttributes.OneWay) as TestAsyncResponse; - - Assert.That(response, Is.Not.Null); - Assert.That(response.ExecuteTimes, Is.EqualTo(0)); - Assert.That(response.ExecuteAsyncTimes, Is.EqualTo(1)); } } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHttpHandlerFactoryTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHttpHandlerFactoryTests.cs index 59a71a6a891..125f5726fb5 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHttpHandlerFactoryTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ServiceStackHttpHandlerFactoryTests.cs @@ -1,89 +1,101 @@ using System; using System.Collections.Generic; -using System.Net; -using System.Web; using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints.Metadata; -using ServiceStack.WebHost.Endpoints.Support; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; +using ServiceStack.Metadata; +using ServiceStack.Testing; +using ServiceStack.Text; namespace ServiceStack.WebHost.Endpoints.Tests { [TestFixture] public class ServiceStackHttpHandlerFactoryTests { + ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost(GetType().Assembly) + { + ConfigureAppHost = host => + { + host.Plugins.Add(new PredefinedRoutesFeature()); +#if !NETCORE + host.Plugins.Add(new SoapFormat()); +#endif + host.CatchAllHandlers.Add(new PredefinedRoutesFeature().ProcessRequest); + host.CatchAllHandlers.Add(new MetadataFeature().ProcessRequest); + } + }.Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + readonly Dictionary<string, Type> pathInfoMap = new Dictionary<string, Type> { - {"Metadata", typeof(IndexMetadataHandler)}, - {"Soap11", typeof(Soap11MessageSyncReplyHttpHandler)}, - {"Soap12", typeof(Soap12MessageSyncReplyHttpHandler)}, + {"Metadata", typeof(IndexMetadataHandler)}, +#if !NETCORE + {"Soap11", typeof(Soap11MessageReplyHttpHandler)}, + {"Soap12", typeof(Soap12MessageReplyHttpHandler)}, +#endif - {"Json/SyncReply", typeof(JsonSyncReplyHandler)}, - {"Json/AsyncOneWay", typeof(JsonAsyncOneWayHandler)}, - {"Json/Metadata", typeof(JsonMetadataHandler)}, + {"Json/Reply", typeof(JsonReplyHandler)}, + {"Json/OneWay", typeof(JsonOneWayHandler)}, + {"Json/Metadata", typeof(JsonMetadataHandler)}, - {"Xml/SyncReply", typeof(XmlSyncReplyHandler)}, - {"Xml/AsyncOneWay", typeof(XmlAsyncOneWayHandler)}, - {"Xml/Metadata", typeof(XmlMetadataHandler)}, + {"Xml/Reply", typeof(XmlReplyHandler)}, + {"Xml/OneWay", typeof(XmlOneWayHandler)}, + {"Xml/Metadata", typeof(XmlMetadataHandler)}, - {"Jsv/SyncReply", typeof(JsvSyncReplyHandler)}, - {"Jsv/AsyncOneWay", typeof(JsvAsyncOneWayHandler)}, - {"Jsv/Metadata", typeof(JsvMetadataHandler)}, + {"Jsv/Reply", typeof(JsvReplyHandler)}, + {"Jsv/OneWay", typeof(JsvOneWayHandler)}, + {"Jsv/Metadata", typeof(JsvMetadataHandler)}, +#if !NETCORE {"Soap11/Wsdl", typeof(Soap11WsdlMetadataHandler)}, {"Soap11/Metadata", typeof(Soap11MetadataHandler)}, {"Soap12/Wsdl", typeof(Soap12WsdlMetadataHandler)}, {"Soap12/Metadata", typeof(Soap12MetadataHandler)}, +#endif }; - [TestFixtureSetUp] - public void Setup() - { - RegisterConfig(); - } - - [TestFixtureTearDown] - public void TearDown() - { - EndpointHost.CatchAllHandlers.Clear(); - } - [Test] public void Resolves_the_right_handler_for_expexted_paths() { foreach (var item in pathInfoMap) { var expectedType = item.Value; - var handler = ServiceStackHttpHandlerFactory.GetHandlerForPathInfo(null, item.Key, null, null); + var httpReq = new BasicHttpRequest + { + PathInfo = item.Key, + }; + var handler = HttpHandlerFactory.GetHandlerForPathInfo(httpReq, null); Assert.That(handler.GetType(), Is.EqualTo(expectedType)); } } - private void RegisterConfig() - { - EndpointHost.Config = new EndpointHostConfig("ServiceName", new ServiceManager(GetType().Assembly)) { - RawHttpHandlers = new List<Func<IHttpRequest,IHttpHandler>>(), - RouteNamingConventions = new List<RouteNamingConventionDelegate>(), - CustomHttpHandlers = new Dictionary<HttpStatusCode, IServiceStackHttpHandler>(), - WebHostPhysicalPath = "~/".MapServerPath() - }; - EndpointHost.CatchAllHandlers.Add(new PredefinedRoutesFeature().ProcessRequest); - EndpointHost.CatchAllHandlers.Add(new MetadataFeature().ProcessRequest); - } - [Test] - public void Resolves_the_right_handler_for_case_insensitive_expexted_paths() + public void Resolves_the_right_handler_for_case_insensitive_expected_paths() { foreach (var item in pathInfoMap) { var expectedType = item.Value; var lowerPathInfo = item.Key.ToLower(); - var handler = ServiceStackHttpHandlerFactory.GetHandlerForPathInfo(null, lowerPathInfo, null, null); - Assert.That(handler.GetType(), Is.EqualTo(expectedType)); + lowerPathInfo.Print(); + var httpReq = new BasicHttpRequest + { + PathInfo = lowerPathInfo, + }; + var handler = HttpHandlerFactory.GetHandlerForPathInfo(httpReq, null); + Assert.That(handler?.GetType(), Is.EqualTo(expectedType)); } } - - } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SessionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SessionTests.cs new file mode 100644 index 00000000000..4913d245cf3 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SessionTests.cs @@ -0,0 +1,272 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System; +using System.Net; +using System.Runtime.CompilerServices; +using Funq; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class SessionIncr : IReturn<SessionResponse> { } + + public class SessionResponse + { + public int Counter { get; set; } + } + + public class SessionCartIncr : IReturn<Cart> + { + public Guid CartId { get; set; } + } + + public class Cart + { + public int Qty { get; set; } + } + + public class SessionTypedIncr : IReturn<AuthUserSession> { } + + public class SessionService : Service + { + public SessionResponse Get(SessionIncr request) + { + var counter = base.SessionBag.Get<int>("counter"); + + base.SessionBag["counter"] = ++counter; + + return new SessionResponse + { + Counter = counter + }; + } + + public Cart Get(SessionCartIncr request) + { + var sessionKey = UrnId.Create<Cart>(request.CartId); + var cart = base.SessionBag.Get<Cart>(sessionKey) ?? new Cart(); + cart.Qty++; + + base.SessionBag[sessionKey] = cart; + + return cart; + } + + public AuthUserSession Get(SessionTypedIncr request) + { + var session = base.SessionAs<AuthUserSession>(); + session.Tag++; + + this.SaveSession(session); + + return session; + } + } + + [TestFixture] + public class SessionTests + { + private SessionAppHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new SessionAppHost(); + appHost.Init(); + appHost.Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + public class SessionAppHost : AppHostHttpListenerBase + { + public SessionAppHost() : base(typeof(SessionTests).Name, typeof(SessionTests).Assembly) { } + + static bool UseOrmLiteCache = false; + + public override void Configure(Container container) + { + Plugins.Add(new SessionFeature()); + + SetConfig(new HostConfig + { + AllowSessionIdsInHttpParams = true, + }); + + if (UseOrmLiteCache) + { + container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.RegisterAs<OrmLiteCacheClient, ICacheClient>(); + + container.Resolve<ICacheClient>().InitSchema(); + } + } + } + + [Test] + public void Can_increment_session_int_counter() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + Assert.That(client.Get(new SessionIncr()).Counter, Is.EqualTo(1)); + Assert.That(client.Get(new SessionIncr()).Counter, Is.EqualTo(2)); + } + + [Test] + public void Different_clients_have_different_session_int_counters() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var altClient = new JsonServiceClient(Config.AbsoluteBaseUri); + + Assert.That(client.Get(new SessionIncr()).Counter, Is.EqualTo(1)); + Assert.That(client.Get(new SessionIncr()).Counter, Is.EqualTo(2)); + Assert.That(altClient.Get(new SessionIncr()).Counter, Is.EqualTo(1)); + } + + [Test] + public void Can_increment_session_cart_qty() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var request = new SessionCartIncr { CartId = Guid.NewGuid() }; + + Assert.That(client.Get(request).Qty, Is.EqualTo(1)); + Assert.That(client.Get(request).Qty, Is.EqualTo(2)); + } + + [Test] + public void Different_clients_have_different_session_cart_qty() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var altClient = new JsonServiceClient(Config.AbsoluteBaseUri); + var request = new SessionCartIncr { CartId = Guid.NewGuid() }; + + Assert.That(client.Get(request).Qty, Is.EqualTo(1)); + Assert.That(client.Get(request).Qty, Is.EqualTo(2)); + Assert.That(altClient.Get(request).Qty, Is.EqualTo(1)); + } + + public static T Log<T>(T item, [CallerMemberName] string caller = null) + { + "{0}: {1}".Print(caller, item.Dump()); + return item; + } + + [Test] + public void Can_increment_typed_session_tag() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(1)); + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(2)); + } + + [Test] + public void Different_clients_have_different_typed_session_tag() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + var altClient = new JsonServiceClient(Config.AbsoluteBaseUri); + + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(1)); + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(2)); + Assert.That(Log(altClient.Get(new SessionTypedIncr())).Tag, Is.EqualTo(1)); + Assert.That(Log(altClient.Get(new SessionTypedIncr())).Tag, Is.EqualTo(2)); + + Assert.That(client.Get(new SessionTypedIncr()).Tag, Is.EqualTo(3)); + Assert.That(altClient.Get(new SessionTypedIncr()).Tag, Is.EqualTo(3)); + } + + [Test] + public void Can_access_session_with_HTTP_Headers() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(1)); + + var cookies = client.GetCookieValues(); + var sessionId = cookies["ss-id"]; + sessionId.Print(); + + var altClient = new JsonServiceClient(Config.AbsoluteBaseUri) + { + Headers = { + { "X-ss-id", sessionId } + } + }; + + Assert.That(Log(altClient.Get(new SessionTypedIncr())).Tag, Is.EqualTo(2)); + } + + [Test] + public void Can_access_session_with_QueryString() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(1)); + + var cookies = client.GetCookieValues(); + var sessionId = cookies["ss-id"]; + + var response = Config.AbsoluteBaseUri + .CombineWith(new SessionTypedIncr().ToGetUrl()) + .AddQueryParam("ss-id", sessionId) + .GetJsonFromUrl() + .FromJson<AuthUserSession>(); + + Assert.That(response.Tag, Is.EqualTo(2)); + } + +#if NETFX + [Test] + public void Can_override_existing_session_with_QueryString() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + Assert.That(Log(client.Get(new SessionTypedIncr())).Tag, Is.EqualTo(1)); + + var cookies = client.GetCookieValues(); + var sessionId = cookies["ss-id"]; + + var cookieContainer = new CookieContainer(); + cookieContainer.Add(new Uri(Config.AbsoluteBaseUri), + new Cookie + { + Name = "ss-id", + Value = "some-other-id", + Domain = new Uri(Config.AbsoluteBaseUri).Host, + }); + + var response = Config.AbsoluteBaseUri + .CombineWith(new SessionTypedIncr().ToGetUrl()) + .AddQueryParam("ss-id", sessionId) + .GetJsonFromUrl(req => req.CookieContainer = cookieContainer) + .FromJson<AuthUserSession>(); + + Assert.That(response.Tag, Is.EqualTo(2)); + } +#endif + + [Test] + public void Can_mock_IntegrationTest_Session_with_Request() + { + var mockRequest = new MockHttpRequest + { + Items = { [Keywords.Session] = new AuthUserSession { UserName = "Mocked" } } + }; + + using (var service = HostContext.ResolveService<SessionService>(mockRequest)) + { + Assert.That(service.GetSession().UserName, Is.EqualTo("Mocked")); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Shared/IocService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Shared/IocService.cs new file mode 100644 index 00000000000..2d5761bd35e --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Shared/IocService.cs @@ -0,0 +1,500 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Funq; +using ServiceStack.Configuration; +using ServiceStack.Web; + +namespace ServiceStack.Shared.Tests +{ + public static class IocShared + { + public static void Configure(ServiceStackHost appHost) + { + var container = appHost.Container; + + container.Adapter = new IocAdapter(); + container.Register(c => new FunqDepCtor()); + container.Register(c => new FunqDepProperty()); + container.Register(c => new FunqDepDisposableProperty()); + + container.Register(c => new FunqSingletonScope()).ReusedWithin(ReuseScope.Default); + container.Register(c => new FunqRequestScope()).ReusedWithin(ReuseScope.Request); + container.Register(c => new FunqNoneScope()).ReusedWithin(ReuseScope.None); + container.Register(c => new FunqInjectRequest()).ReusedWithin(ReuseScope.None); + container.Register(c => new FunqRequestScopeDepDisposableProperty()).ReusedWithin(ReuseScope.Request); + + container.Register(c => new FunqSingletonScopeDisposable()).ReusedWithin(ReuseScope.Default); + container.Register(c => new FunqRequestScopeDisposable()).ReusedWithin(ReuseScope.Request); + container.Register(c => new FunqNoneScopeDisposable()).ReusedWithin(ReuseScope.None); + } + } + + public class IocAdapter : IContainerAdapter, IRelease + { + public T TryResolve<T>() + { + if (typeof(T) == typeof(IRequest)) + throw new ArgumentException("should not ask for IRequestContext"); + + if (typeof(T) == typeof(AltDepProperty)) + return (T)(object)new AltDepProperty(); + if (typeof(T) == typeof(AltDepDisposableProperty)) + return (T)(object)new AltDepDisposableProperty(); + if (typeof(T) == typeof(AltRequestScopeDepDisposableProperty)) + return (T)(object)RequestContext.Instance.GetOrCreate(() => new AltRequestScopeDepDisposableProperty()); + + return default(T); + } + + public T Resolve<T>() + { + if (typeof(T) == typeof(AltDepCtor)) + return (T)(object)new AltDepCtor(); + + return default(T); + } + + public void Release(object instance) + { + var disposable = instance as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + } + + + public class FunqRequestScope + { + public static int Count = 0; + public FunqRequestScope() { Interlocked.Increment(ref Count); } + } + + public class FunqSingletonScope + { + public static int Count = 0; + public FunqSingletonScope() { Interlocked.Increment(ref Count); } + } + + public class FunqNoneScope + { + public static int Count = 0; + public FunqNoneScope() { Interlocked.Increment(ref Count); } + } + + public class FunqInjectRequest : IRequiresRequest + { + public FunqInjectRequest() + { + this.SecondLevel = new FunqInjectRequest2(); + } + + public IRequest Request { get; set; } + + public FunqInjectRequest2 SecondLevel { get; set; } + } + + public class FunqInjectRequest2 : IRequiresRequest + { + public IRequest Request { get; set; } + } + + public class FunqRequestScopeDisposable : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqRequestScopeDisposable() { Interlocked.Increment(ref Count); } + + public void Dispose() + { + Interlocked.Increment(ref DisposeCount); + } + } + + public class FunqSingletonScopeDisposable : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqSingletonScopeDisposable() { Interlocked.Increment(ref Count); } + + public void Dispose() + { + Interlocked.Increment(ref DisposeCount); + } + } + + public class FunqNoneScopeDisposable : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqNoneScopeDisposable() { Interlocked.Increment(ref Count); } + + public void Dispose() + { + Interlocked.Increment(ref DisposeCount); + } + } + + public class FunqRequestScopeDepDisposableProperty : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqRequestScopeDepDisposableProperty() { Interlocked.Increment(ref Count); } + public void Dispose() { Interlocked.Increment(ref DisposeCount); } + } + + public class AltRequestScopeDepDisposableProperty : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public AltRequestScopeDepDisposableProperty() { Interlocked.Increment(ref Count); } + public void Dispose() { Interlocked.Increment(ref DisposeCount); } + } + + public class FunqDepCtor { } + public class AltDepCtor { } + + public class FunqDepProperty { } + public class AltDepProperty { } + + public class FunqDepDisposableProperty : IDisposable + { + public static int DisposeCount = 0; + public void Dispose() { Interlocked.Increment(ref DisposeCount); } + } + public class AltDepDisposableProperty : IDisposable + { + public static int DisposeCount = 0; + public void Dispose() { Interlocked.Increment(ref DisposeCount); } + } + + [Route("/ioc")] + public class Ioc { } + [Route("/iocasync")] + public class IocAsync { } + + public class IocResponse : IHasResponseStatus + { + public IocResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new List<string>(); + } + + public List<string> Results { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + + [Route("/action-attr")] + public class ActionAttr : IReturn<IocResponse> { } + + [Route("/action-attr-async")] + public class ActionAttrAsync : IReturn<IocResponse> { } + + public class ActionLevelAttribute : RequestFilterAttribute + { + public IRequest RequestContext { get; set; } + public FunqDepProperty FunqDepProperty { get; set; } + public FunqDepDisposableProperty FunqDepDisposableProperty { get; set; } + public AltDepProperty AltDepProperty { get; set; } + public AltDepDisposableProperty AltDepDisposableProperty { get; set; } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var response = new IocResponse(); + + var deps = new object[] { + FunqDepProperty, FunqDepDisposableProperty, + AltDepProperty, AltDepDisposableProperty + }; + + foreach (var dep in deps) + { + if (dep != null) + response.Results.Add(dep.GetType().Name); + } + + req.Items["action-attr"] = response; + } + } + + public class ResetIoc + { + public bool ThrowErrors { get; set; } + } + + public class IocStats : IReturn<IocStatsResponse> { } + public class IocStatsResponse + { + public int FunqNoneScope_Count { get; set; } + public int FunqRequestScope_Count { get; set; } + public int IocService_DisposeCount { get; set; } + public int IocDisposableService_DisposeCount { get; set; } + public int FunqSingletonScopeDisposable_DisposeCount { get; set; } + public int FunqRequestScopeDisposable_DisposeCount { get; set; } + public int FunqNoneScopeDisposable_DisposeCount { get; set; } + public int FunqRequestScopeDepDisposableProperty_DisposeCount { get; set; } + public int AltRequestScopeDepDisposableProperty_DisposeCount { get; set; } + public int Container_disposablesCount { get; set; } + } + + + public class IocResetService : IService + { + public void Any(ResetIoc request) + { + FunqNoneScope.Count = + FunqRequestScope.Count = + IocService.DisposeCount = + IocDisposableService.DisposeCount = + FunqSingletonScopeDisposable.DisposeCount = + FunqRequestScopeDisposable.DisposeCount = + FunqNoneScopeDisposable.DisposeCount = + FunqRequestScopeDepDisposableProperty.DisposeCount = + AltRequestScopeDepDisposableProperty.DisposeCount = + 0; + + IocService.ThrowErrors = request.ThrowErrors; + } + + public object Any(IocStats request) + { + return new IocStatsResponse + { + FunqNoneScope_Count = FunqNoneScope.Count, + FunqRequestScope_Count = FunqRequestScope.Count, + IocService_DisposeCount = IocService.DisposeCount, + IocDisposableService_DisposeCount = IocDisposableService.DisposeCount, + FunqSingletonScopeDisposable_DisposeCount = FunqSingletonScopeDisposable.DisposeCount, + FunqRequestScopeDisposable_DisposeCount = FunqRequestScopeDisposable.DisposeCount, + FunqNoneScopeDisposable_DisposeCount = FunqNoneScopeDisposable.DisposeCount, + FunqRequestScopeDepDisposableProperty_DisposeCount = FunqRequestScopeDepDisposableProperty.DisposeCount, + AltRequestScopeDepDisposableProperty_DisposeCount = AltRequestScopeDepDisposableProperty.DisposeCount, + Container_disposablesCount = HostContext.Container.disposablesCount, + }; + } + } + + public class IocService : IService, IDisposable, IRequiresRequest + { + private readonly FunqDepCtor funqDepCtor; + private readonly AltDepCtor altDepCtor; + + public IocService(FunqDepCtor funqDepCtor, AltDepCtor altDepCtor) + { + this.funqDepCtor = funqDepCtor; + this.altDepCtor = altDepCtor; + } + + public IRequest Request { get; set; } + public FunqDepProperty FunqDepProperty { get; set; } + public FunqDepDisposableProperty FunqDepDisposableProperty { get; set; } + public AltDepProperty AltDepProperty { get; set; } + public AltDepDisposableProperty AltDepDisposableProperty { get; set; } + + public object Any(Ioc request) + { + var response = new IocResponse(); + + var deps = new object[] { + funqDepCtor, altDepCtor, + FunqDepProperty, FunqDepDisposableProperty, + AltDepProperty, AltDepDisposableProperty + }; + + foreach (var dep in deps) + { + if (dep != null) + response.Results.Add(dep.GetType().Name); + } + + if (ThrowErrors) throw new ArgumentException("This service has intentionally failed"); + + return response; + } + + public async Task<object> Any(IocAsync request) + { + await Task.Delay(10); + return Any(request.ConvertTo<Ioc>()); + } + + [ActionLevel] + public IocResponse Any(ActionAttr request) + { + return Request.Items["action-attr"] as IocResponse; + } + + [ActionLevel] + public async Task<IocResponse> Any(ActionAttrAsync request) + { + await Task.Delay(10); + return Request.Items["action-attr"] as IocResponse; + } + + public static int DisposeCount = 0; + public static bool ThrowErrors = false; + + public void Dispose() + { + Interlocked.Increment(ref DisposeCount); + } + } + + [Route("/iocscope")] + public class IocScope + { + public bool Throw { get; set; } + } + + [Route("/iocscopeasync")] + public class IocScopeAsync + { + public bool Throw { get; set; } + } + + public class IocScopeResponse : IHasResponseStatus + { + public IocScopeResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new Dictionary<string, int>(); + } + + public Dictionary<string, int> Results { get; set; } + + public int InjectsRequest { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class IocRequestFilterAttribute : AttributeBase, IHasRequestFilter + { + public FunqSingletonScope FunqSingletonScope { get; set; } + public FunqRequestScope FunqRequestScope { get; set; } + public FunqNoneScope FunqNoneScope { get; set; } + public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } + public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } + + public int Priority { get; set; } + + public void RequestFilter(IRequest req, IResponse res, object requestDto) + { + } + + public IRequestFilterBase Copy() => (IRequestFilterBase)this.MemberwiseClone(); + } + + [IocRequestFilter] + public class IocScopeService : IService, IDisposable + { + public FunqRequestScope FunqRequestScope { get; set; } + public FunqSingletonScope FunqSingletonScope { get; set; } + public FunqNoneScope FunqNoneScope { get; set; } + public FunqInjectRequest FunqInjectRequest { get; set; } + public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } + public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } + + public object Any(IocScope request) + { + if (request.Throw) + throw new Exception("Exception requested by user"); + + var response = new IocScopeResponse + { + Results = { + { typeof(FunqSingletonScope).Name, FunqSingletonScope.Count }, + { typeof(FunqRequestScope).Name, FunqRequestScope.Count }, + { typeof(FunqNoneScope).Name, FunqNoneScope.Count }, + }, + InjectsRequest = FunqInjectRequest.Request != null + ? 1 + (FunqInjectRequest.SecondLevel.Request != null ? 1 : 0) + : 0, + }; + + return response; + } + + public async Task<object> Any(IocScopeAsync request) + { + await Task.Delay(10); + return Any(request.ConvertTo<IocScope>()); + } + + public static int DisposedCount = 0; + public static bool ThrowErrors = false; + + public void Dispose() + { + Interlocked.Increment(ref DisposedCount); + } + } + + public class IocDispose : IReturn<IocDisposeResponse> + { + public bool Throw { get; set; } + } + + public class IocDisposeAsync : IReturn<IocDisposeResponse> + { + public bool Throw { get; set; } + } + + public class IocDisposeResponse : IHasResponseStatus + { + public IocDisposeResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new Dictionary<string, int>(); + } + + public Dictionary<string, int> Results { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class IocDisposableService : IService, IDisposable + { + public FunqRequestScopeDisposable FunqRequestScopeDisposable { get; set; } + public FunqSingletonScopeDisposable FunqSingletonScopeDisposable { get; set; } + public FunqNoneScopeDisposable FunqNoneScopeDisposable { get; set; } + public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } + public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } + + public object Any(IocDispose request) + { + if (request.Throw) + throw new Exception("Exception requested by user"); + + var response = new IocDisposeResponse + { + Results = { + { typeof(FunqSingletonScopeDisposable).Name, FunqSingletonScopeDisposable.DisposeCount }, + { typeof(FunqRequestScopeDisposable).Name, FunqRequestScopeDisposable.DisposeCount }, + { typeof(FunqNoneScopeDisposable).Name, FunqNoneScopeDisposable.DisposeCount }, + { typeof(FunqRequestScopeDepDisposableProperty).Name, FunqRequestScopeDepDisposableProperty.DisposeCount }, + { typeof(AltRequestScopeDepDisposableProperty).Name, AltRequestScopeDepDisposableProperty.DisposeCount }, + }, + }; + + return response; + } + + public async Task<object> Any(IocDisposeAsync request) + { + await Task.Delay(10); + return Any(request.ConvertTo<IocDispose>()); + } + + public static int DisposeCount = 0; + + public void Dispose() + { + Interlocked.Increment(ref DisposeCount); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SharedDtoTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SharedDtoTests.cs index a451b0690ed..ce0c488998c 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/SharedDtoTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SharedDtoTests.cs @@ -1,8 +1,5 @@ using Funq; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests { @@ -10,7 +7,7 @@ namespace ServiceStack.WebHost.Endpoints.Tests * Leave commented out - this pollutes and causes many failures in other tests */ - //[Explicit("This isn't supported at the moment.")] + //[Ignore("This isn't supported at the moment.")] //public class SharedDtoTests //{ // [Route("/shareddto")] @@ -52,7 +49,7 @@ namespace ServiceStack.WebHost.Endpoints.Tests // AppHost appHost; - // [TestFixtureSetUp] + // [OneTimeSetUp] // public void OnTestFixtureSetUp() // { // appHost = new AppHost(); @@ -60,7 +57,7 @@ namespace ServiceStack.WebHost.Endpoints.Tests // appHost.Start(ListeningOn); // } - // [TestFixtureTearDown] + // [OneTimeTearDown] // public void OnTestFixtureTearDown() // { // appHost.Dispose(); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SpanFormatTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SpanFormatTests.cs new file mode 100644 index 00000000000..1256c16a91b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SpanFormatTests.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Formats; +using ServiceStack.Text; +using ServiceStack.WebHost.Endpoints.Tests.Support.Host; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class CreateMovies : IReturn<CreateMovies> + { + public List<Tests.Support.Host.Movie> Movies { get; set; } + } + + public class CreateMoviesAsync : IReturn<CreateMoviesAsync> + { + public List<Tests.Support.Host.Movie> Movies { get; set; } + } + + public class CreateMoviesService : Service + { + public object Any(CreateMovies request) => request; + + public async Task<object> Any(CreateMoviesAsync request) + { + await Task.Yield(); + return request; + } + } + + public class SpanFormatTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(SpanFormatTests), typeof(SpanFormatTests).Assembly) {} + + public override void Configure(Container container) + { + } + } + + private readonly ServiceStackHost appHost; + + public SpanFormatTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + appHost.Dispose(); + DefaultMemory.Configure(); + } + + [Test] + public void Does_deserialize_json_RequestBody() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var response = client.Post(new CreateMovies { + Movies = ResetMoviesService.Top5Movies + }); + + Assert.That(response.Movies, Is.EquivalentTo(ResetMoviesService.Top5Movies)); + + var responseAsync = client.Post(new CreateMoviesAsync { + Movies = ResetMoviesService.Top5Movies + }); + + Assert.That(responseAsync.Movies, Is.EquivalentTo(ResetMoviesService.Top5Movies)); + } + + [Test] + public async Task Does_deserialize_json_RequestBody_Async() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var response = await client.PostAsync(new CreateMovies { + Movies = ResetMoviesService.Top5Movies + }); + + Assert.That(response.Movies, Is.EquivalentTo(ResetMoviesService.Top5Movies)); + + var responseAsync = await client.PostAsync(new CreateMoviesAsync { + Movies = ResetMoviesService.Top5Movies + }); + + Assert.That(responseAsync.Movies, Is.EquivalentTo(ResetMoviesService.Top5Movies)); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/StrictModeTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/StrictModeTests.cs new file mode 100644 index 00000000000..5c0a01357ca --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/StrictModeTests.cs @@ -0,0 +1,116 @@ +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ReturnsValueType : IReturn<string> { } + + public class BadService : Service + { + public object Any(ReturnsValueType request) => 1; + } + + [TestFixture] + public class StrictModeTests + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(StrictModeTests), typeof(BadService).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { StrictMode = true }); + } + } + + private readonly ServiceStackHost appHost; + + public StrictModeTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Returning_ValueTime_throws_StrictModeException() + { + var client = new JsonServiceClient(Config.ListeningOn); + + try + { + var response = client.Get(new ReturnsValueType()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(StrictModeException))); + } + } + } + + [TestFixture] + public class StrictModeAppHostTests + { + class BadUserSessionAppHost : AppSelfHostBase + { + public BadUserSessionAppHost() + : base(nameof(StrictModeTests), typeof(BadService).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig + { + StrictMode = true + }); + + Plugins.Add(new AuthFeature( + () => new BadUserSession(), new IAuthProvider[] { + new CredentialsAuthProvider(), + })); + } + } + + public class BadUserSession : AuthUserSession + { + public BadUserSession CyclicalDep { get; set; } + + public BadUserSession() + { + CyclicalDep = this; + } + } + + [Test] + public void Does_recognize_Cyclical_Deps() + { + Assert.That(TypeSerializer.HasCircularReferences(new BadUserSession())); + } + + [Test] + public void Using_UserSession_with_Cyclical_deps_throws_StrictModeException() + { + using (var appHost = new BadUserSessionAppHost()) + { + try + { + appHost + .Init() + .Start(Config.ListeningOn); //.NET Core has delayed initialization + Assert.Fail("Should throw"); + } + catch (StrictModeException ex) + { + Assert.That(ex.ParamName, Is.EqualTo("sessionFactory")); + Assert.That(ex.Code, Is.EqualTo(StrictModeCodes.CyclicalUserSession)); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/DirectServiceClient.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/DirectServiceClient.cs index c640c502a17..2f07106bc1d 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/DirectServiceClient.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/DirectServiceClient.cs @@ -1,338 +1,514 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support.Mocks; -using ServiceStack.WebHost.Endpoints.Tests.Mocks; +using System.Threading; +using System.Threading.Tasks; +using ServiceStack.Host; +using ServiceStack.Testing; namespace ServiceStack.WebHost.Endpoints.Tests.Support { - public class DirectServiceClient : IServiceClient, IRestClient - { - ServiceManager ServiceManager { get; set; } - - readonly HttpRequestMock httpReq = new HttpRequestMock(); - readonly HttpResponseMock httpRes = new HttpResponseMock(); - - public DirectServiceClient(ServiceManager serviceManager) - { - this.ServiceManager = serviceManager; - } - - public void SendOneWay(object request) - { - ServiceManager.Execute(request); - } - - public void SendOneWay(string relativeOrAbsoluteUrl, object request) - { - ServiceManager.Execute(request); - } - - private bool ApplyRequestFilters<TResponse>(object request) - { - if (EndpointHost.ApplyRequestFilters(httpReq, httpRes, request)) - { - ThrowIfError<TResponse>(httpRes); - return true; - } - return false; - } - - private void ThrowIfError<TResponse>(HttpResponseMock httpRes) - { - if (httpRes.StatusCode >= 400) - { - var webEx = new WebServiceException("WebServiceException, StatusCode: " + httpRes.StatusCode) { - StatusCode = httpRes.StatusCode, - StatusDescription = httpRes.StatusDescription, - }; - - try - { - var deserializer = EndpointHost.AppHost.ContentTypeFilters.GetStreamDeserializer(httpReq.ResponseContentType); - webEx.ResponseDto = deserializer(typeof(TResponse), httpRes.OutputStream); - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - - throw webEx; - } - } - - private bool ApplyResponseFilters<TResponse>(object response) - { - if (EndpointHost.ApplyResponseFilters(httpReq, httpRes, response)) - { - ThrowIfError<TResponse>(httpRes); - return true; - } - return false; - } - - public TResponse Send<TResponse>(object request) - { - httpReq.HttpMethod = HttpMethods.Post; - - if (ApplyRequestFilters<TResponse>(request)) return default(TResponse); - - var response = ServiceManager.ServiceController.Execute(request, - new HttpRequestContext(httpReq, httpRes, request, EndpointAttributes.HttpPost)); - - if (ApplyResponseFilters<TResponse>(response)) return (TResponse)response; - - return (TResponse)response; - } - - public TResponse Send<TResponse>(IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public void Send(IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse Get<TResponse>(IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public void Get(IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse Get<TResponse>(string relativeOrAbsoluteUrl) - { - httpReq.HttpMethod = HttpMethods.Get; - - var requestTypeName = typeof(TResponse).Namespace + "." + relativeOrAbsoluteUrl; - var requestType = typeof (TResponse).Assembly.GetType(requestTypeName); - if (requestType == null) - throw new ArgumentException("Type not found: " + requestTypeName); - - var request = requestType.CreateInstance(); - - if (ApplyRequestFilters<TResponse>(request)) return default(TResponse); - - var response = ServiceManager.ServiceController.Execute(request, - new HttpRequestContext(httpReq, httpRes, request, EndpointAttributes.HttpGet)); - - if (ApplyResponseFilters<TResponse>(response)) return (TResponse)response; - - return (TResponse)response; - } - - public TResponse Delete<TResponse>(IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public void Delete(IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse Delete<TResponse>(string relativeOrAbsoluteUrl) - { - throw new NotImplementedException(); - } - - public TResponse Post<TResponse>(IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public void Post(IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object request) - { - throw new NotImplementedException(); - } - - public TResponse Put<TResponse>(IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public void Put(IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse Put<TResponse>(string relativeOrAbsoluteUrl, object request) - { - throw new NotImplementedException(); - } - - public TResponse Patch<TResponse>(IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public void Patch(IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse Patch<TResponse>(string relativeOrAbsoluteUrl, object request) - { - throw new NotImplementedException(); - } - - public TResponse PostFile<TResponse>(string relativeOrAbsoluteUrl, FileInfo fileToUpload, string mimeType) - { - throw new NotImplementedException(); - } - - public void CustomMethod(string httpVerb, IReturnVoid request) - { - throw new NotImplementedException(); - } - - public TResponse CustomMethod<TResponse>(string httpVerb, IReturn<TResponse> request) - { - throw new NotImplementedException(); - } - - public HttpWebResponse Head(IReturn request) - { - throw new NotImplementedException(); - } - - public HttpWebResponse Head(string relativeOrAbsoluteUrl) - { - throw new NotImplementedException(); - } - - public TResponse PostFile<TResponse>(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileInfo, string mimeType) - { - throw new NotImplementedException(); - } - - public void SendAsync<TResponse>(object request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - var response = default(TResponse); - try - { - try - { - if (ApplyRequestFilters<TResponse>(request)) - { - onSuccess(default(TResponse)); - return; - } - } - catch (Exception ex) - { - onError(default(TResponse), ex); - return; - } - - response = this.Send<TResponse>(request); - - try - { - if (ApplyResponseFilters<TResponse>(request)) - { - onSuccess(response); - return; - } - } - catch (Exception ex) - { - onError(response, ex); - return; - } - - onSuccess(response); - } - catch (Exception ex) - { - if (onError != null) - { - onError(response, ex); - return; - } - Console.WriteLine("Error: " + ex.Message); - } - } - - public void SetCredentials(string userName, string password) - { - throw new NotImplementedException(); - } - - public void GetAsync<TResponse>(IReturn<TResponse> request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void GetAsync<TResponse>(string relativeOrAbsoluteUrl, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void DeleteAsync<TResponse>(string relativeOrAbsoluteUrl, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void DeleteAsync<TResponse>(IReturn<TResponse> request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void PostAsync<TResponse>(IReturn<TResponse> request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void PostAsync<TResponse>(string relativeOrAbsoluteUrl, object request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void PutAsync<TResponse>(IReturn<TResponse> request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void PutAsync<TResponse>(string relativeOrAbsoluteUrl, object request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void CustomMethodAsync<TResponse>(string httpVerb, IReturn<TResponse> request, Action<TResponse> onSuccess, Action<TResponse, Exception> onError) - { - throw new NotImplementedException(); - } - - public void CancelAsync() - { - throw new NotImplementedException(); - } - - public void Dispose() { } - public TResponse PostFileWithRequest<TResponse>(string relativeOrAbsoluteUrl, FileInfo fileToUpload, object request) - { - throw new NotImplementedException(); - } - - public TResponse PostFileWithRequest<TResponse>(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, object request) - { - throw new NotImplementedException(); - } - } + public class DirectServiceClient : IServiceClient, IRestClient + { + ServiceController ServiceController { get; set; } + + private readonly MockHttpRequest httpReq; + private readonly MockHttpResponse httpRes; + + public int Version { get; set; } + public string SessionId { get; set; } + public string BearerToken { get; set; } + + public DirectServiceClient(ServiceController serviceController) + { + this.ServiceController = serviceController; + httpReq = new MockHttpRequest(); + httpRes = new MockHttpResponse(httpReq); + } + + public void SendOneWay(object requestDto) + { + ServiceController.Execute(requestDto); + } + + public void SendOneWay(string relativeOrAbsoluteUri, object requestDto) + { + ServiceController.Execute(requestDto); + } + + public void SendAllOneWay(IEnumerable<object> requests) + { + throw new NotImplementedException(); + } + + private bool ApplyRequestFilters<TResponse>(object request) + { + HostContext.ApplyRequestFiltersAsync(httpReq, httpRes, request).Wait(); + if (httpRes.IsClosed) + { + ThrowIfError<TResponse>(httpRes); + return true; + } + return false; + } + + private void ThrowIfError<TResponse>(MockHttpResponse httpRes) + { + if (httpRes.StatusCode >= 400) + { + var webEx = new WebServiceException("WebServiceException, StatusCode: " + httpRes.StatusCode) + { + StatusCode = httpRes.StatusCode, + StatusDescription = httpRes.StatusDescription, + }; + + try + { + var deserializer = HostContext.ContentTypes.GetStreamDeserializer(httpReq.ResponseContentType); + webEx.ResponseDto = deserializer(typeof(TResponse), httpRes.ReadAsBytes().InMemoryStream()); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + + throw webEx; + } + } + + private bool ApplyResponseFilters<TResponse>(object response) + { + HostContext.ApplyResponseFiltersAsync(httpReq, httpRes, response).Wait(); + if (httpRes.IsClosed) + { + ThrowIfError<TResponse>(httpRes); + return true; + } + return false; + } + + public TResponse Patch<TResponse>(string relativeOrAbsoluteUrl, object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Send<TResponse>(string httpMethod, string relativeOrAbsoluteUrl, object request) + { + throw new NotImplementedException(); + } + + public void CustomMethod(string httpVerb, IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse CustomMethod<TResponse>(string httpVerb, IReturn<TResponse> requestDto) + { + throw new NotImplementedException(); + } + + public TResponse CustomMethod<TResponse>(string httpVerb, object requestDto) + { + throw new NotImplementedException(); + } + + TResponse PostFile<TResponse>(string relativeOrAbsoluteUrl, FileInfo fileToUpload, string mimeType) + { + throw new NotImplementedException(); + } + + public TResponse PostFile<TResponse>(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, string mimeType) + { + throw new NotImplementedException(); + } + + public TResponse PostFileWithRequest<TResponse>( + Stream fileToUpload, string fileName, object request, string fieldName = "upload") + { + throw new NotImplementedException(); + } + + public TResponse Get<TResponse>(IReturn<TResponse> requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Get<TResponse>(object requestDto) + { + throw new NotImplementedException(); + } + + public void AddHeader(string name, string value) + { + throw new NotImplementedException(); + } + + public void ClearCookies() + { + } + + public Dictionary<string, string> GetCookieValues() + { + return new Dictionary<string, string>(); + } + + public void SetCookie(string name, string value, TimeSpan? expiresIn = null) + { + throw new NotImplementedException(); + } + + public void Get(IReturnVoid request) + { + throw new NotImplementedException(); + } + + public TResponse Get<TResponse>(string relativeOrAbsoluteUrl) + { + httpReq.HttpMethod = HttpMethods.Get; + + var requestTypeName = typeof(TResponse).Namespace + "." + relativeOrAbsoluteUrl; + var requestType = typeof(TResponse).Assembly.GetType(requestTypeName); + if (requestType == null) + throw new ArgumentException("Type not found: " + requestTypeName); + + var request = requestType.CreateInstance(); + + if (ApplyRequestFilters<TResponse>(request)) return default(TResponse); + + httpReq.HttpMethod = HttpMethods.Get; + var response = ServiceController.Execute(request, httpReq); + + if (ApplyResponseFilters<TResponse>(response)) return (TResponse)response; + + return (TResponse)response; + } + + public IEnumerable<TResponse> GetLazy<TResponse>(IReturn<QueryResponse<TResponse>> queryDto) + { + throw new NotImplementedException(); + } + + public void Delete(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Delete<TResponse>(IReturn<TResponse> request) + { + throw new NotImplementedException(); + } + + public TResponse Delete<TResponse>(object request) + { + throw new NotImplementedException(); + } + + public TResponse Delete<TResponse>(string relativeOrAbsoluteUrl) + { + throw new NotImplementedException(); + } + + public void Post(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Post<TResponse>(IReturn<TResponse> requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Post<TResponse>(object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object request) + { + throw new NotImplementedException(); + } + + public void Put(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Put<TResponse>(IReturn<TResponse> requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Put<TResponse>(object requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Put<TResponse>(string relativeOrAbsoluteUrl, object requestDto) + { + throw new NotImplementedException(); + } + + public void Patch(IReturnVoid requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Patch<TResponse>(IReturn<TResponse> requestDto) + { + throw new NotImplementedException(); + } + + public TResponse Patch<TResponse>(object requestDto) + { + throw new NotImplementedException(); + } + + public void SetCredentials(string userName, string password) + { + throw new NotImplementedException(); + } + + public void CancelAsync() + { + throw new NotImplementedException(); + } + + public void Dispose() { } + public TResponse PostFileWithRequest<TResponse>(string relativeOrAbsoluteUrl, FileInfo fileToUpload, object request, string fieldName = "upload") + { + throw new NotImplementedException(); + } + + public TResponse PostFileWithRequest<TResponse>(string relativeOrAbsoluteUrl, Stream fileToUpload, string fileName, object request, string fieldName = "upload") + { + throw new NotImplementedException(); + } + + public TResponse PostFilesWithRequest<TResponse>(object request, IEnumerable<UploadFile> files) + { + throw new NotImplementedException(); + } + + public TResponse PostFilesWithRequest<TResponse>(string relativeOrAbsoluteUrl, object request, IEnumerable<UploadFile> files) + { + throw new NotImplementedException(); + } + + public TResponse Send<TResponse>(object request) + { + httpReq.HttpMethod = HttpMethods.Post; + httpReq.Dto = request; + + if (ApplyRequestFilters<TResponse>(request)) return default(TResponse); + + this.PopulateRequestMetadata(request); + + httpReq.HttpMethod = HttpMethods.Post; + var response = ServiceController.Execute(request, httpReq); + + if (ApplyResponseFilters<TResponse>(response)) return (TResponse)response; + + return (TResponse)response; + } + + public List<TResponse> SendAll<TResponse>(IEnumerable<object> requests) + { + throw new NotImplementedException(); + } + + public void Publish(object requestDto) + { + SendOneWay(requestDto); + } + + public void PublishAll(IEnumerable<object> requestDtos) + { + throw new NotImplementedException(); + } + + public Task<TResponse> SendAsync<TResponse>(object requestDto, CancellationToken token = default) + { + var tcs = new TaskCompletionSource<TResponse>(); + var response = default(TResponse); + try + { + try + { + if (ApplyRequestFilters<TResponse>(requestDto)) + { + tcs.SetResult(default(TResponse)); + return tcs.Task; + } + } + catch (Exception ex) + { + tcs.SetException(ex); + return tcs.Task; + } + + response = this.Send<TResponse>(requestDto); + + try + { + if (ApplyResponseFilters<TResponse>(requestDto)) + { + tcs.SetResult(response); + return tcs.Task; + } + } + catch (Exception ex) + { + tcs.SetException(ex); + return tcs.Task; + } + + tcs.SetResult(response); + return tcs.Task; + } + catch (Exception ex) + { + Console.WriteLine("Error: " + ex.Message); + + tcs.SetException(ex); + return tcs.Task; + } + } + + public Task<List<TResponse>> SendAllAsync<TResponse>(IEnumerable<object> requests, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PublishAsync(object requestDto, CancellationToken token = default) + { + return SendAsync<byte[]>(requestDto, token); + } + + public Task PublishAllAsync(IEnumerable<object> requestDtos, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> GetAsync<TResponse>(IReturn<TResponse> requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> GetAsync<TResponse>(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task GetAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> DeleteAsync<TResponse>(IReturn<TResponse> requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> DeleteAsync<TResponse>(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task DeleteAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PostAsync<TResponse>(IReturn<TResponse> requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PostAsync<TResponse>(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PostAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PutAsync<TResponse>(IReturn<TResponse> requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PutAsync<TResponse>(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PutAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PatchAsync<TResponse>(IReturn<TResponse> requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PatchAsync<TResponse>(object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task PatchAsync(IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> CustomMethodAsync<TResponse>(string httpVerb, IReturn<TResponse> requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> CustomMethodAsync<TResponse>(string httpVerb, object requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task CustomMethodAsync(string httpVerb, IReturnVoid requestDto, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> GetAsync<TResponse>(string relativeOrAbsoluteUrl, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> DeleteAsync<TResponse>(string relativeOrAbsoluteUrl, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PostAsync<TResponse>(string relativeOrAbsoluteUrl, object request, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> PutAsync<TResponse>(string relativeOrAbsoluteUrl, object request, CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> CustomMethodAsync<TResponse>(string httpVerb, string relativeOrAbsoluteUrl, object request, + CancellationToken token = default) + { + throw new NotImplementedException(); + } + + public Task<TResponse> SendAsync<TResponse>(string httpMethod, string absoluteUrl, object request, CancellationToken token = default) + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/EndpointHandlerBaseTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/EndpointHandlerBaseTests.cs index 027a2dd5b1e..686aec6644b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/EndpointHandlerBaseTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/EndpointHandlerBaseTests.cs @@ -2,40 +2,46 @@ using System.Collections; using System.Linq; using System.Net.NetworkInformation; -using Moq; using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Extensions; +using ServiceStack.Host; +using ServiceStack.Host.Handlers; +using ServiceStack.Testing; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Support.Tests { [TestFixture] public class EndpointHandlerBaseTests { - class TestHandler : EndpointHandlerBase + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() { - public override object CreateRequest(ServiceHost.IHttpRequest request, string operationName) - { - throw new NotImplementedException(); - } + appHost = new BasicAppHost().Init(); + } - public override object GetResponse(IHttpRequest httpReq, IHttpResponse httpRes, object request) - { - throw new NotImplementedException(); - } + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + class TestHandler : ServiceStackHandlerBase + { } [Test, TestCaseSource(typeof(EndpointHandlerBaseTests), "EndpointExpectations")] - public void GetEndpointAttributes_AcceptsUserHostAddressFormats(string format, EndpointAttributes expected) + public void GetEndpointAttributes_AcceptsUserHostAddressFormats(string format, RequestAttributes expected) { var handler = new TestHandler(); - var request = new Mock<IHttpRequest>(); - request.Expect(req => req.UserHostAddress).Returns(format); - request.Expect(req => req.IsSecureConnection).Returns(false); - request.Expect(req => req.HttpMethod).Returns("GET"); + var request = new BasicRequest { + UserHostAddress = format, + IsSecureConnection = false, + Verb = "GET" + }; - Assert.AreEqual(expected | EndpointAttributes.HttpGet | EndpointAttributes.InSecure, request.Object.GetAttributes()); + Assert.AreEqual(expected | RequestAttributes.HttpGet | RequestAttributes.InSecure, request.GetAttributes()); } public static IEnumerable EndpointExpectations @@ -51,31 +57,31 @@ public static IEnumerable EndpointExpectations //this covers all the different flavors of ipv6 address -- scoped, link local, etc foreach (var address in ipv6Addresses) { - yield return new TestCaseData(address.ToString(), EndpointAttributes.LocalSubnet); - yield return new TestCaseData("[" + address + "]:57", EndpointAttributes.LocalSubnet); + yield return new TestCaseData(address.ToString(), RequestAttributes.LocalSubnet); + yield return new TestCaseData("[" + address + "]:57", RequestAttributes.LocalSubnet); // HttpListener Format w/Port - yield return new TestCaseData("[{0}]:8080".Fmt(address), EndpointAttributes.LocalSubnet); + yield return new TestCaseData("[{0}]:8080".Fmt(address), RequestAttributes.LocalSubnet); } - yield return new TestCaseData("fe80::100:7f:fffe%10", EndpointAttributes.LocalSubnet); - yield return new TestCaseData("[fe80::100:7f:fffe%10]:57", EndpointAttributes.LocalSubnet); - yield return new TestCaseData("[fe80::100:7f:fffe%10]:8080", EndpointAttributes.LocalSubnet); + yield return new TestCaseData("fe80::100:7f:fffe%10", RequestAttributes.LocalSubnet); + yield return new TestCaseData("[fe80::100:7f:fffe%10]:57", RequestAttributes.LocalSubnet); + yield return new TestCaseData("[fe80::100:7f:fffe%10]:8080", RequestAttributes.LocalSubnet); //ipv6 loopback - yield return new TestCaseData("::1", EndpointAttributes.Localhost); - yield return new TestCaseData("[::1]:83", EndpointAttributes.Localhost); + yield return new TestCaseData("::1", RequestAttributes.Localhost); + yield return new TestCaseData("[::1]:83", RequestAttributes.Localhost); //ipv4 - yield return new TestCaseData("192.168.100.2", EndpointAttributes.External); - yield return new TestCaseData("192.168.100.2:47", EndpointAttributes.External); + yield return new TestCaseData("192.168.100.2", RequestAttributes.External); + yield return new TestCaseData("192.168.100.2:47", RequestAttributes.External); //ipv4 loopback - yield return new TestCaseData("127.0.0.1", EndpointAttributes.Localhost); - yield return new TestCaseData("127.0.0.1:20", EndpointAttributes.Localhost); + yield return new TestCaseData("127.0.0.1", RequestAttributes.Localhost); + yield return new TestCaseData("127.0.0.1:20", RequestAttributes.Localhost); //ipv4 in X-FORWARDED-FOR HTTP Header format - yield return new TestCaseData("192.168.100.2, 192.168.0.1", EndpointAttributes.External); - yield return new TestCaseData("192.168.100.2, 192.168.0.1, 10.1.1.1", EndpointAttributes.External); + yield return new TestCaseData("192.168.100.2, 192.168.0.1", RequestAttributes.External); + yield return new TestCaseData("192.168.100.2, 192.168.0.1, 10.1.1.1", RequestAttributes.External); } } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/GithubGateway.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/GithubGateway.cs new file mode 100644 index 00000000000..517e2925ed6 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/GithubGateway.cs @@ -0,0 +1,324 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using ServiceStack.DataAnnotations; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support +{ + public class GithubRepo + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Homepage { get; set; } + public string Language { get; set; } + public int Watchers_Count { get; set; } + public int Stargazes_Count { get; set; } + public int Forks_Count { get; set; } + public int Open_Issues_Count { get; set; } + public int Size { get; set; } + public string Full_Name { get; set; } + public DateTime Created_at { get; set; } + public DateTime? Pushed_At { get; set; } + public DateTime? Updated_At { get; set; } + + public bool Has_issues { get; set; } + public bool Has_Downloads { get; set; } + public bool Has_Wiki { get; set; } + public bool Has_Pages { get; set; } + public bool Fork { get; set; } + + public GithubUser Owner { get; set; } + public string Svn_Url { get; set; } + public string Mirror_Url { get; set; } + public string Url { get; set; } + public string Ssh_Url { get; set; } + public string Html_Url { get; set; } + public string Clone_Url { get; set; } + public string Git_Url { get; set; } + public bool Private { get; set; } + } + + public abstract class GithubUser + { + public int Id { get; set; } + public string Login { get; set; } + public string Avatar_Url { get; set; } + public string Url { get; set; } + public int? Followers { get; set; } + public int? Following { get; set; } + public string Type { get; set; } + public int? Public_Gists { get; set; } + public string Location { get; set; } + public string Company { get; set; } + public string Html_Url { get; set; } + public int? Public_Repos { get; set; } + public DateTime? Created_At { get; set; } + public string Blog { get; set; } + public string Email { get; set; } + public string Name { get; set; } + public bool? Hireable { get; set; } + public string Gravatar_Id { get; set; } + public string Bio { get; set; } + } + + public class GithubOrg + { + public int Id { get; set; } + public string Avatar_Url { get; set; } + public string Url { get; set; } + public string Login { get; set; } + } + + public class GithubByUser + { + public string Name { get; set; } + public string Email { get; set; } + public DateTime Date { get; set; } + } + + public class GithubCommitResult + { + public string Sha { get; set; } + public GithubCommit Commit { get; set; } + public GithubUser Author { get; set; } + public GithubUser Committer { get; set; } + } + + public class GithubCommit + { + public string Id { get; set; } + public string Message { get; set; } + public DateTime Date { get; set; } + public string Name { get; set; } + public int Comment_Count { get; set; } + public GithubByUser Committer { get; set; } + public GithubByUser Author { get; set; } + + public bool? ShouldSerialize(string fieldName) + { + return fieldName != "Committer" && fieldName != "Author"; + } + } + + public class GithubContent + { + [PrimaryKey] + public string Sha { get; set; } + public string Path { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public int Size { get; set; } + public string Download_Url { get; set; } + } + + public class GithubContributor + { + public int Id { get; set; } + public string Login { get; set; } + public int Contributions { get; set; } + public string Type { get; set; } + + public string Avatar_Url { get; set; } + public string Gravatar_Id { get; set; } + public string Url { get; set; } + public bool? Site_Admin { get; set; } + } + + public class GithubSubscriber + { + public int Id { get; set; } + public string Login { get; set; } + public int Contributions { get; set; } + public string Type { get; set; } + + public string Avatar_Url { get; set; } + public string Gravatar_Id { get; set; } + public string Url { get; set; } + public bool? Site_Admin { get; set; } + } + + public class GithubComment + { + public int Id { get; set; } + public string Body { get; set; } + public DateTime Created_At { get; set; } + public DateTime Updated_At { get; set; } + public GithubUser User { get; set; } + public string Url { get; set; } + public string Commit_Id { get; set; } + + public string Position { get; set; } + public string Line { get; set; } + public string Path { get; set; } + } + + public class GithubRelease + { + public int Id { get; set; } + public string Name { get; set; } + public string Tag_Name { get; set; } + public string Target_Commitish { get; set; } + public string Body { get; set; } + + public bool Draft { get; set; } + public bool PreRelease { get; set; } + + public DateTime Created_At { get; set; } + public DateTime Published_At { get; set; } + public GithubUser Author { get; set; } + public string Url { get; set; } + public string Tarball_Url { get; set; } + public string Zipball_Url { get; set; } + } + + public partial class GithubGateway + { + public const string GithubApiBaseUrl = "https://api.github.com/"; + public static string UserAgent = typeof(GithubGateway).Namespace.SplitOnFirst('.').First(); + + public GithubGateway() + { + ClientConfig.ConfigureTls12(); + } + + public string Username { get; set; } + public string Password { get; set; } + + public List<GithubOrg> GetUserOrgs(string githubUsername) + { + return GetJson<List<GithubOrg>>("users/{0}/orgs", githubUsername); + } + + public List<GithubRepo> GetUserRepos(string githubUsername) + { + return GetJson<List<GithubRepo>>("users/{0}/repos", githubUsername); + } + + public List<GithubRepo> GetOrgRepos(string githubOrgName) + { + return GetJson<List<GithubRepo>>("orgs/{0}/repos", githubOrgName); + } + + public List<GithubRepo> GetAllUserAndOrgsReposFor(string githubUsername) + { + var map = new Dictionary<int, GithubRepo>(); + GetUserRepos(githubUsername).ForEach(x => map[x.Id] = x); + GetUserOrgs(githubUsername).ForEach(org => + GetOrgRepos(org.Login) + .ForEach(repo => map[repo.Id] = repo)); + + return map.Values.ToList(); + } + + public IEnumerable<GithubCommitResult> GetRepoCommits(string githubUser, string githubRepo) + { + return StreamJsonCollection<GithubCommitResult>("repos/{0}/{1}/commits", githubUser, githubRepo); + } + + public List<GithubContent> GetRepoContents(string githubUser, string githubRepo) + { + return GetJson<List<GithubContent>>("repos/{0}/{1}/contents", githubUser, githubRepo); + } + + public List<GithubContributor> GetRepoContributors(string githubUser, string githubRepo) + { + return GetJson<List<GithubContributor>>("repos/{0}/{1}/contributors", githubUser, githubRepo); + } + + public List<GithubSubscriber> GetRepoSubscribers(string githubUser, string githubRepo) + { + return GetJson<List<GithubSubscriber>>("repos/{0}/{1}/subscribers", githubUser, githubRepo); + } + + public List<GithubComment> GetRepoComments(string githubUser, string githubRepo) + { + return GetJson<List<GithubComment>>("repos/{0}/{1}/comments", githubUser, githubRepo); + } + + public List<GithubRelease> GetRepoReleases(string githubUser, string githubRepo) + { + return GetJson<List<GithubRelease>>("repos/{0}/{1}/releases", githubUser, githubRepo); + } + + public T GetJson<T>(string route, params object[] routeArgs) + { + return GithubApiBaseUrl.CombineWith(route.Fmt(routeArgs)) + .GetJsonFromUrl(req => req.With(c => { + c.UserAgent = UserAgent; + if (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password)) + c.SetAuthBasic(Username, Password); + })) + .FromJson<T>(); + } + + public IEnumerable<T> StreamJsonCollection<T>(string route, params object[] routeArgs) + { + List<T> results; + var nextUrl = GithubApiBaseUrl.CombineWith(route.Fmt(routeArgs)); + + do + { + results = nextUrl + .GetJsonFromUrl( + req => req.With(c => { + c.UserAgent = UserAgent; + if (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password)) + c.SetAuthBasic(Username, Password); + }), + responseFilter: res => { + var links = ParseLinkUrls(res.GetHeader("Link")); + links.TryGetValue("next", out nextUrl); + }) + .FromJson<List<T>>(); + + foreach (var result in results) + { + yield return result; + } + + } while (results.Count > 0 && nextUrl != null); + } + + public static Dictionary<string, string> ParseLinkUrls(string linkHeader) + { + var map = new Dictionary<string, string>(); + var links = linkHeader; + + while (!string.IsNullOrEmpty(links)) + { + var urlStartPos = links.IndexOf('<'); + var urlEndPos = links.IndexOf('>'); + + if (urlStartPos == -1 || urlEndPos == -1) + break; + + var url = links.Substring(urlStartPos + 1, urlEndPos - urlStartPos - 1); + var parts = links.Substring(urlEndPos).SplitOnFirst(','); + + var relParts = parts[0].Split(';'); + foreach (var relPart in relParts) + { + var keyValueParts = relPart.SplitOnFirst('='); + if (keyValueParts.Length < 2) + continue; + + var name = keyValueParts[0].Trim(); + var value = keyValueParts[1].Trim().Trim('"'); + + if (name == "rel") + { + map[value] = url; + } + } + + links = parts.Length > 1 ? parts[1] : null; + } + + return map; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/ExampleAppHostHttpListener.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/ExampleAppHostHttpListener.cs index 2d7351dbd66..2d2590ad5f1 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/ExampleAppHostHttpListener.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/ExampleAppHostHttpListener.cs @@ -1,28 +1,22 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net; using System.Runtime.Serialization; using System.Threading; +using System.Threading.Tasks; using Funq; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; using ServiceStack.Configuration; +using ServiceStack.Data; using ServiceStack.DataAnnotations; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.Text; +using ServiceStack.ProtoBuf; using ServiceStack.WebHost.Endpoints.Tests.IntegrationTests; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host { - [Route("/factorial/{ForNumber}")] [DataContract] public class GetFactorial @@ -51,27 +45,54 @@ public static long GetFactorial(long n) } } - [DataContract] - public class AlwaysThrows { } + public class TestProgress : IReturn<List<Movie>> { } + public class TestProgressString : IReturn<string> { } + public class TestProgressBytes : IReturn<byte[]> { } - [DataContract] - public class AlwaysThrowsResponse : IHasResponseStatus - { - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } + public class TestProgressBytesHttpResult : IReturn<byte[]> { } + public class TestProgressBinaryFile : IReturn<byte[]> { } + public class TestProgressTextFile : IReturn<string> { } - public class AlwaysThrowsService : ServiceInterface.Service - { - public object Any(AlwaysThrows request) - { - throw new ArgumentException("This service always throws an error"); - } - } + public class DownloadProgressService : Service + { + public object Any(TestProgress request) + { + return ResetMoviesService.Top5Movies; + } + + public string Any(TestProgressString request) + { + return ResetMoviesService.Top5Movies.ToJson(); + } + + public object Any(TestProgressBytes request) + { + return ResetMoviesService.Top5Movies.ToJson().ToUtf8Bytes(); + } + + public object Any(TestProgressBytesHttpResult request) + { + return new HttpResult(ResetMoviesService.Top5Movies.ToJson().ToUtf8Bytes(), "application/octet-stream"); + } + public object Any(TestProgressBinaryFile request) + { + var path = Path.GetTempFileName(); + File.WriteAllBytes(path, ResetMoviesService.Top5Movies.ToJson().ToUtf8Bytes()); + return new HttpResult(new FileInfo(path), "application/octet-stream"); + } - [Route("/movies", "POST,PUT")] - [Route("/movies/{Id}")] + public object Any(TestProgressTextFile request) + { + var path = Path.GetTempFileName(); + File.WriteAllText(path, ResetMoviesService.Top5Movies.ToJson()); + return new HttpResult(new FileInfo(path), "application/json"); + } + } + + + [Route("/all-movies", "POST,PUT")] + [Route("/all-movies/{Id}")] [DataContract] public class Movie { @@ -142,7 +163,7 @@ public class MovieResponse } - public class MovieService : ServiceInterface.Service + public class MovieService : Service { public IDbConnectionFactory DbFactory { get; set; } @@ -151,9 +172,12 @@ public class MovieService : ServiceInterface.Service /// </summary> public object Get(Movie movie) { - return new MovieResponse { - Movie = DbFactory.Run(db => db.GetById<Movie>(movie.Id)) - }; + using (var db = DbFactory.Open()) + { + return new MovieResponse { + Movie = db.SingleById<Movie>(movie.Id) + }; + } } /// <summary> @@ -161,20 +185,23 @@ public object Get(Movie movie) /// </summary> public object Post(Movie movie) { - var newMovieId = DbFactory.Run(db => { - db.Insert(movie); - return db.GetLastInsertId(); - }); - - var newMovie = new MovieResponse { - Movie = DbFactory.Run(db => db.GetById<Movie>(newMovieId)) - }; - return new HttpResult(newMovie) { - StatusCode = HttpStatusCode.Created, - Headers = { - { HttpHeaders.Location, this.RequestContext.AbsoluteUri.WithTrailingSlash() + newMovieId } - } - }; + using (var db = DbFactory.Open()) + { + db.Save(movie); + + var newMovie = new MovieResponse + { + Movie = db.SingleById<Movie>(movie.Id) + }; + + return new HttpResult(newMovie) + { + StatusCode = HttpStatusCode.Created, + Headers = { + { HttpHeaders.Location, this.Request.AbsoluteUri.WithTrailingSlash() + movie.Id } + } + }; + } } /// <summary> @@ -182,8 +209,11 @@ public object Post(Movie movie) /// </summary> public object Put(Movie movie) { - DbFactory.Run(db => db.Save(movie)); - return new MovieResponse(); + using (var db = DbFactory.Open()) + { + db.Save(movie); + return new MovieResponse(); + } } /// <summary> @@ -191,15 +221,18 @@ public object Put(Movie movie) /// </summary> public object Delete(Movie request) { - DbFactory.Run(db => db.DeleteById<Movie>(request.Id)); - return new MovieResponse(); + using (var db = DbFactory.Open()) + { + db.DeleteById<Movie>(request.Id); + return new MovieResponse(); + } } } [DataContract] - [Route("/movies", "GET")] - [Route("/movies/genres/{Genre}")] + [Route("/all-movies", "GET")] + [Route("/all-movies/genres/{Genre}")] public class Movies { [DataMember] @@ -221,7 +254,7 @@ public MoviesResponse() public List<Movie> Movies { get; set; } } - public class MoviesService : ServiceInterface.Service + public class MoviesService : Service { /// <summary> /// GET /movies @@ -255,7 +288,7 @@ public MoviesZipResponse() public List<Movie> Movies { get; set; } } - public class MoviesZipService : ServiceInterface.Service + public class MoviesZipService : Service { public IDbConnectionFactory DbFactory { get; set; } @@ -264,15 +297,19 @@ public object Get(MoviesZip request) return Post(request); } - public object Post(MoviesZip request) + public Task<object> Post(MoviesZip request) { - var response = new MoviesZipResponse { - Movies = request.Genre.IsNullOrEmpty() - ? DbFactory.Run(db => db.Select<Movie>()) - : DbFactory.Run(db => db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%")) - }; - - return RequestContext.ToOptimizedResult(response); + using (var db = DbFactory.Open()) + { + var response = new MoviesZipResponse + { + Movies = request.Genre.IsNullOrEmpty() + ? db.Select<Movie>() + : db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%") + }; + + return Request.ToOptimizedResultAsync(response); + } } } @@ -294,7 +331,7 @@ public ResetMoviesResponse() public ResponseStatus ResponseStatus { get; set; } } - public class ResetMoviesService : ServiceInterface.Service + public class ResetMoviesService : Service { public static List<Movie> Top5Movies = new List<Movie> { @@ -355,7 +392,7 @@ public class PageElementResponseDTO public string PageElementResponse { get; set; } } - public class InboxPostResponseRequestService : ServiceInterface.Service + public class InboxPostResponseRequestService : Service { public object Any(InboxPostResponseRequest request) { @@ -377,7 +414,7 @@ public class InboxPost public int Id { get; set; } } - public class InboxPostService : ServiceInterface.Service + public class InboxPostService : Service { public object Any(InboxPost request) { @@ -392,7 +429,7 @@ public object Any(InboxPost request) [Route("/long_running")] public class LongRunning { } - public class LongRunningService : ServiceInterface.Service + public class LongRunningService : Service { public object Any(LongRunning request) { @@ -418,18 +455,16 @@ public ExampleAppHostHttpListener() public override void Configure(Container container) { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); - //Signal advanced web browsers what HTTP Methods you accept - base.SetConfig(new EndpointHostConfig { + base.SetConfig(new HostConfig { GlobalResponseHeaders = { { "Access-Control-Allow-Origin", "*" }, { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, }, WsdlServiceNamespace = "http://www.servicestack.net/types", - LogFactory = new ConsoleLogFactory(), DebugMode = true, + PreferredContentTypes = { MimeTypes.ProtoBuf }, }); this.RegisterRequestBinder<CustomRequestBinder>( @@ -441,21 +476,19 @@ public override void Configure(Container container) .Add<Movie>("/custom-movies", "POST,PUT") .Add<Movie>("/custom-movies/{Id}") .Add<GetFactorial>("/fact/{ForNumber}") - .Add<MoviesZip>("/movies.zip") + .Add<MoviesZip>("/all-movies.zip") .Add<GetHttpResult>("/gethttpresult") ; - container.Register<IResourceManager>(new ConfigurationResourceManager()); + container.Register<IAppSettings>(new AppSettings()); //var appSettings = container.Resolve<IResourceManager>(); - container.Register(c => new ExampleConfig(c.Resolve<IResourceManager>())); + container.Register(c => new ExampleConfig(c.Resolve<IAppSettings>())); //var appConfig = container.Resolve<ExampleConfig>(); container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - ":memory:", false, - SqliteOrmLiteDialectProvider.Instance)); + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); var resetMovies = container.Resolve<ResetMoviesService>(); resetMovies.Post(null); @@ -470,15 +503,18 @@ public override void Configure(Container container) Plugins.Add(new ProtoBufFormat()); Plugins.Add(new RequestInfoFeature()); + + ContentTypes.Register("application/x-custom+json", + (req, dto,stream) => stream.Write("{\"custom\":\"json\"}"), + (type,stream) => type.CreateInstance()); } } - public class ExampleAppHostHttpListenerLongRunning - : AppHostHttpListenerLongRunningBase + public class ExampleAppHostHttpListenerPool : AppHostHttpListenerPoolBase { //private static ILog log; - public ExampleAppHostHttpListenerLongRunning() + public ExampleAppHostHttpListenerPool() : base("ServiceStack Examples", 500, typeof(GetFactorialService).Assembly) { LogManager.LogFactory = new DebugLogFactory(); @@ -489,10 +525,8 @@ public ExampleAppHostHttpListenerLongRunning() public override void Configure(Container container) { - EndpointHostConfig.Instance.GlobalResponseHeaders.Clear(); - //Signal advanced web browsers what HTTP Methods you accept - base.SetConfig(new EndpointHostConfig + base.SetConfig(new HostConfig { GlobalResponseHeaders = { @@ -500,7 +534,6 @@ public override void Configure(Container container) { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, }, WsdlServiceNamespace = "http://www.servicestack.net/types", - LogFactory = new ConsoleLogFactory(), DebugMode = true, }); @@ -513,21 +546,17 @@ public override void Configure(Container container) .Add<Movie>("/custom-movies", "POST,PUT") .Add<Movie>("/custom-movies/{Id}") .Add<GetFactorial>("/fact/{ForNumber}") - .Add<MoviesZip>("/movies.zip") + .Add<MoviesZip>("/all-movies.zip") .Add<GetHttpResult>("/gethttpresult") ; - container.Register<IResourceManager>(new ConfigurationResourceManager()); - - //var appSettings = container.Resolve<IResourceManager>(); + container.Register<IAppSettings>(new AppSettings()); - container.Register(c => new ExampleConfig(c.Resolve<IResourceManager>())); + container.Register(c => new ExampleConfig(c.Resolve<IAppSettings>())); //var appConfig = container.Resolve<ExampleConfig>(); container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - ":memory:", false, - SqliteOrmLiteDialectProvider.Instance)); + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); var resetMovies = container.Resolve<ResetMoviesService>(); resetMovies.Post(null); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/IocAppHost.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/IocAppHost.cs deleted file mode 100644 index 874376c373a..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/IocAppHost.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections.Generic; -using Funq; -using ServiceStack.Common; -using ServiceStack.Configuration; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints.Tests.Support.Services; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host -{ - public class IocAppHost : AppHostHttpListenerBase - { - public IocAppHost() - : base("IocApp Service", typeof(IocService).Assembly) - { - Instance = null; - } - - private IocAdapter iocAdapter; - - public override void Configure(Container container) - { - container.Adapter = iocAdapter = new IocAdapter(); - container.Register(c => new FunqDepCtor()); - container.Register(c => new FunqDepProperty()); - container.Register(c => new FunqDepDisposableProperty()); - - container.Register(c => new FunqSingletonScope()).ReusedWithin(ReuseScope.Default); - container.Register(c => new FunqRequestScope()).ReusedWithin(ReuseScope.Request); - container.Register(c => new FunqNoneScope()).ReusedWithin(ReuseScope.None); - container.Register(c => new FunqRequestScopeDepDisposableProperty()).ReusedWithin(ReuseScope.Request); - - container.Register(c => new FunqSingletonScopeDisposable()).ReusedWithin(ReuseScope.Default); - container.Register(c => new FunqRequestScopeDisposable()).ReusedWithin(ReuseScope.Request); - container.Register(c => new FunqNoneScopeDisposable()).ReusedWithin(ReuseScope.None); - - Routes.Add<Ioc>("/ioc"); - Routes.Add<IocScope>("/iocscope"); - } - - public override void Release(object instance) - { - iocAdapter.Release(instance); - } - } - - public class IocAdapter : IContainerAdapter, IRelease - { - public T TryResolve<T>() - { - if (typeof(T) == typeof(IRequestContext)) - throw new ArgumentException("should not ask for IRequestContext"); - - if (typeof(T) == typeof(AltDepProperty)) - return (T)(object)new AltDepProperty(); - if (typeof(T) == typeof(AltDepDisposableProperty)) - return (T)(object)new AltDepDisposableProperty(); - if (typeof(T) == typeof(AltRequestScopeDepDisposableProperty)) - return (T)(object)HostContext.Instance.GetOrCreate(() => new AltRequestScopeDepDisposableProperty()); - - return default(T); - } - - public T Resolve<T>() - { - if (typeof(T) == typeof(AltDepCtor)) - return (T)(object)new AltDepCtor(); - - return default(T); - } - - public void Release(object instance) - { - var disposable = instance as IDisposable; - if (disposable != null) - disposable.Dispose(); - } - } - - - public class IocRequestFilterAttribute : Attribute, IHasRequestFilter - { - public FunqSingletonScope FunqSingletonScope { get; set; } - public FunqRequestScope FunqRequestScope { get; set; } - public FunqNoneScope FunqNoneScope { get; set; } - public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } - public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } - - public int Priority { get; set; } - - public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto) - { - } - - public IHasRequestFilter Copy() - { - return (IHasRequestFilter) this.MemberwiseClone(); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestAppHost.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestAppHost.cs index cf11d8cf83d..983355e3186 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestAppHost.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestAppHost.cs @@ -1,3 +1,4 @@ +using System.Reflection; using Funq; using ServiceStack.WebHost.Endpoints.Tests.Support.Services; @@ -10,8 +11,9 @@ public class Foo : IFoo { } public class TestAppHost : AppHostBase { - public TestAppHost() - : base("Example Service", typeof(Nested).Assembly) + public TestAppHost(params Assembly[] assembliesWithServices) + : base("Example Service", + assembliesWithServices.Length > 0 ? assembliesWithServices : new[] { typeof(Nested).Assembly }) { Instance = null; } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs index f790aa6f3c0..8eb83efdaeb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Host/TestConfigAppHostHttpListener.cs @@ -1,6 +1,5 @@ using System.Runtime.Serialization; using Funq; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Host { @@ -25,7 +24,7 @@ public class BclDtoResponse public string Password { get; set; } } - public class BclDtoService : ServiceInterface.Service + public class BclDtoService : Service { public object Any(BclDto request) { @@ -47,7 +46,7 @@ public TestConfigAppHostHttpListener() public override void Configure(Container container) { - SetConfig(new EndpointHostConfig + SetConfig(new HostConfig { UseBclJsonSerializers = true, }); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs index 29bb814a201..672b2075658 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomFormData.cs @@ -1,7 +1,8 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs index 5bdc36a94a3..08083217010 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/CustomRequestBinder.cs @@ -1,8 +1,4 @@ -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations { [Route("/customrequestbinder")] public class CustomRequestBinder @@ -17,7 +13,7 @@ public class CustomRequestBinderResponse public ResponseStatus ResponseStatus { get; set; } } - public class CustomRequestBinderService : ServiceInterface.Service + public class CustomRequestBinderService : Service { public object Any(CustomRequestBinder request) { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/GetCustomer.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/GetCustomer.cs index 5bf30478e97..9a79661013b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/GetCustomer.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/GetCustomer.cs @@ -1,10 +1,11 @@ +using System; using System.Runtime.Serialization; using ServiceStack.WebHost.Endpoints.Tests.Support.Types; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations { [DataContract] - public class GetCustomer + public class GetCustomer : IReturn<GetCustomerResponse> { [DataMember] public long CustomerId { get; set; } @@ -15,5 +16,8 @@ public class GetCustomerResponse { [DataMember] public Customer Customer { get; set; } + + [DataMember] + public DateTime Created { get; set; } } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfComplexTypes.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfComplexTypes.cs index b6b5d90b326..63466bc5870 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfComplexTypes.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Operations/RequestOfComplexTypes.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; +using ServiceStack.Common; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Operations { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs index 652ca3981af..b8a36ca9192 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/ServiceClientTestBase.cs @@ -1,18 +1,17 @@ using System; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; namespace ServiceStack.WebHost.Endpoints.Tests.Support { public abstract class ServiceClientTestBase : IDisposable { - private const string BaseUrl = "http://127.0.0.1:8083/"; + protected const string BaseUrl = "http://127.0.0.1:8083/"; private AppHostHttpListenerBase appHost; public abstract AppHostHttpListenerBase CreateListener(); - [TestFixtureSetUp] + [OneTimeSetUp] public virtual void TestFixtureSetUp() { appHost = CreateListener(); @@ -20,7 +19,7 @@ public virtual void TestFixtureSetUp() appHost.Start(BaseUrl); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { Dispose(); @@ -30,7 +29,6 @@ public void Dispose() { if (appHost == null) return; appHost.Dispose(); - appHost = null; } public void Send<TRes>(object request, Action<TRes> validate) diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs index a7383045bb8..dff8763b6ee 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/CustomFormDataService.cs @@ -1,21 +1,18 @@ -using ServiceStack.ServiceHost; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - public class CustomFormDataService : ServiceInterface.Service - { - //Parsing: &first-name=tom&item-0=blah&item-1-delete=1 - public object Post(CustomFormData request) - { - var httpReq = base.RequestContext.Get<IHttpRequest>(); - - return new CustomFormDataResponse - { - FirstName = httpReq.FormData["first-name"], - Item0 = httpReq.FormData["item-0"], - Item1Delete = httpReq.FormData["item-1-delete"] - }; - } - } + public class CustomFormDataService : Service + { + //Parsing: &first-name=tom&item-0=blah&item-1-delete=1 + public object Post(CustomFormData request) + { + return new CustomFormDataResponse + { + FirstName = Request.FormData["first-name"], + Item0 = Request.FormData["item-0"], + Item1Delete = Request.FormData["item-1-delete"] + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EchoService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EchoService.cs new file mode 100644 index 00000000000..e3b6b357ae1 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EchoService.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + [Route("/echorequestinfo")] + public class EchoRequestInfo : IReturn<EchoRequestInfoResponse> { } + + public class EchoRequestInfoResponse + { + public Dictionary<string, string> Headers { get; set; } + } + + public class EchoService : Service + { + public object Any(EchoRequestInfo request) + { + return new EchoRequestInfoResponse + { + Headers = base.Request.Headers.ToDictionary(), + }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EndpointAccessService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EndpointAccessService.cs index 8402673b967..cab8a5d6e01 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EndpointAccessService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/EndpointAccessService.cs @@ -1,7 +1,4 @@ -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { public class GetsOnly { } public class PostsOnly { } @@ -22,7 +19,7 @@ public class InternalOnly { } public class ReturnsHttpResult { } - public class EndpointAccessService : ServiceInterface.Service + public class EndpointAccessService : Service { public Response Get(GetsOnly request) { diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FailingService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FailingService.cs index 8e60f999809..f9193c61d99 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FailingService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FailingService.cs @@ -1,5 +1,4 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { @@ -9,14 +8,14 @@ public class FailingRequest { } [DataContract] public class FailingRequestResponse { } - public class FailingService : IService<FailingRequest> + public class FailingService : IService { private void ThisMethodAlwaysThrowsAnError(FailingRequest request) { throw new System.ArgumentException("Failure"); } - public object Execute(FailingRequest request) + public object Any(FailingRequest request) { ThisMethodAlwaysThrowsAnError(request); return new FailingRequestResponse(); diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FileUploadService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FileUploadService.cs index 74118d33916..e6d366e2cd6 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FileUploadService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/FileUploadService.cs @@ -1,87 +1,138 @@ using System; +using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - [Route("/fileuploads/{RelativePath*}")] - [Route("/fileuploads", HttpMethods.Post)] - public class FileUpload - { - [DataMember] - public string RelativePath { get; set; } + [DataContract] + [Route("/fileuploads/{RelativePath*}")] + [Route("/fileuploads", HttpMethods.Post)] + public class FileUpload : IReturn<FileUploadResponse> + { + [DataMember] + public string RelativePath { get; set; } [DataMember] public string CustomerName { get; set; } [DataMember] - public int CustomerId { get; set; } - } + public int? CustomerId { get; set; } + + [DataMember] + public DateTime? CreatedDate { get; set; } + } - [DataContract] - public class FileUploadResponse : IHasResponseStatus - { - [DataMember] - public string FileName { get; set; } + [DataContract] + public class FileUploadResponse : IHasResponseStatus + { + [DataMember] + public string Name { get; set; } - [DataMember] - public long ContentLength { get; set; } + [DataMember] + public string FileName { get; set; } - [DataMember] - public string ContentType { get; set; } + [DataMember] + public long ContentLength { get; set; } - [DataMember] - public string Contents { get; set; } + [DataMember] + public string ContentType { get; set; } - [DataMember] - public ResponseStatus ResponseStatus { get; set; } + [DataMember] + public string Contents { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } [DataMember] public string CustomerName { get; set; } [DataMember] - public int CustomerId { get; set; } - } - - public class FileUploadService : ServiceInterface.Service - { - public object Get(FileUpload request) - { - if (request.RelativePath.IsNullOrEmpty()) - throw new ArgumentNullException("RelativePath"); - - var filePath = ("~/" + request.RelativePath).MapProjectPath(); - if (!File.Exists(filePath)) - throw new FileNotFoundException(request.RelativePath); - - var result = new HttpResult(new FileInfo(filePath)); - return result; - } - - public object Post(FileUpload request) - { - if (this.RequestContext.Files.Length == 0) - throw new FileNotFoundException("UploadError", "No such file exists"); - - if (request.RelativePath == "ThrowError") - throw new NotSupportedException("ThrowError"); - - var file = this.RequestContext.Files[0]; - return new FileUploadResponse - { - FileName = file.FileName, - ContentLength = file.ContentLength, - ContentType = file.ContentType, - Contents = new StreamReader(file.InputStream).ReadToEnd(), + public int? CustomerId { get; set; } + + [DataMember] + public DateTime? CreatedDate { get; set; } + } + + [Route("/multi-fileuploads", HttpMethods.Post)] + public class MultipleFileUpload : IReturn<MultipleFileUploadResponse> + { + public string RelativePath { get; set; } + public string CustomerName { get; set; } + public int? CustomerId { get; set; } + public DateTime? CreatedDate { get; set; } + } + + public class MultipleFileUploadResponse : IHasResponseStatus + { + public List<FileUploadResponse> Results { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class FileUploadService : Service + { + public object Get(FileUpload request) + { + if (request.RelativePath.IsNullOrEmpty()) + throw new ArgumentNullException("RelativePath"); + + var filePath = ("~/" + request.RelativePath).MapProjectPlatformPath(); + if (!File.Exists(filePath)) + throw new FileNotFoundException(request.RelativePath); + + var result = new HttpResult(new FileInfo(filePath)); + return result; + } + + public object Post(FileUpload request) + { + if (this.Request.Files.Length == 0) + throw new FileNotFoundException("UploadError", "No such file exists"); + + if (request.RelativePath == "ThrowError") + throw new NotSupportedException("ThrowError"); + + var file = this.Request.Files[0]; + return new FileUploadResponse + { + Name = file.Name, + FileName = file.FileName, + ContentLength = file.ContentLength, + ContentType = file.ContentType, + Contents = file.InputStream.ReadToEnd(), + CustomerId = request.CustomerId, + CustomerName = request.CustomerName, + CreatedDate = request.CreatedDate + }; + } + + public object Put(FileUpload request) + { + return new FileUploadResponse + { CustomerId = request.CustomerId, - CustomerName = request.CustomerName - }; - } - } + CustomerName = request.CustomerName, + CreatedDate = request.CreatedDate + }; + } + + public object Post(MultipleFileUpload request) + { + return new MultipleFileUploadResponse + { + Results = this.Request.Files.Map(file => new FileUploadResponse + { + Name = file.Name, + FileName = file.FileName, + ContentLength = file.ContentLength, + ContentType = file.ContentType, + Contents = file.InputStream.ReadToEnd(), + CustomerId = request.CustomerId, + CustomerName = request.CustomerName, + CreatedDate = request.CreatedDate + }) + }; + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/GetCustomerService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/GetCustomerService.cs index 4110e721b4d..4fff72eb12a 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/GetCustomerService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/GetCustomerService.cs @@ -1,21 +1,22 @@ +using System; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; using ServiceStack.WebHost.Endpoints.Tests.Support.Types; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - public class GetCustomerService - : TestServiceBase<GetCustomer> - { - protected override object Run(GetCustomer request) - { - return new GetCustomerResponse - { - Customer = new Customer - { - Id = request.CustomerId - } - }; - } - } - + public class GetCustomerService + : TestServiceBase<GetCustomer> + { + protected override object Run(GetCustomer request) + { + return new GetCustomerResponse + { + Customer = new Customer + { + Id = request.CustomerId + }, + Created = DateTime.UtcNow, + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HeadersService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HeadersService.cs index 2e15908f684..8b52cabd6a3 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HeadersService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HeadersService.cs @@ -1,40 +1,36 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - public class Headers - { - [DataMember] - public string Name { get; set; } - } + [DataContract] + public class Headers + { + [DataMember] + public string Name { get; set; } + } - [DataContract] - public class HeadersResponse - { - [DataMember] - public string Value { get; set; } - } + [DataContract] + public class HeadersResponse + { + [DataMember] + public string Value { get; set; } + } - public class HeadersService - : TestServiceBase<Headers>, IRequiresRequestContext, IRequiresHttpRequest - { - public IRequestContext RequestContext { get; set; } - public IHttpRequest HttpRequest { get; set; } + public class HeadersService + : TestServiceBase<Headers>, IRequiresRequest + { + public IRequest Request { get; set; } - protected override object Run(Headers request) - { - var header = RequestContext.GetHeader(request.Name); - if (header != HttpRequest.Headers[request.Name]) - throw new NullReferenceException(); - - return new HeadersResponse - { - Value = header - }; - } - } + protected override object Run(Headers request) + { + var header = Request.GetHeader(request.Name); + return new HeadersResponse + { + Value = header + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HelloService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HelloService.cs index ab2ecd87739..358cf5ec761 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HelloService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HelloService.cs @@ -1,33 +1,28 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - /// Create the name of your Web Service (i.e. the Request DTO) - [DataContract] - [Route("/hello")] //Optional: Define an alternate REST-ful url for this service - [Route("/hello/{Name}")] - public class Hello - { - [DataMember] - public string Name { get; set; } - } + /// Create the name of your Web Service (i.e. the Request DTO) + [DataContract] + [Route("/hello")] //Optional: Define an alternate REST-ful url for this service + [Route("/hello/{Name}")] + public class Hello : IReturn<HelloResponse> + { + [DataMember] + public string Name { get; set; } + } - /// Define your Web Service response (i.e. Response DTO) - [DataContract] - public class HelloResponse - { - [DataMember] - public string Result { get; set; } - } - - /// Create your Web Service implementation - public class HelloService : IService<Hello> - { - public object Execute(Hello request) - { - return new HelloResponse { Result = "Hello, " + request.Name }; - } - } + /// Define your Web Service response (i.e. Response DTO) + [DataContract] + public class HelloResponse + { + [DataMember] + public string Result { get; set; } + } + /// Create your Web Service implementation + public class HelloService : IService + { + public object Any(Hello request) => new HelloResponse { Result = "Hello, " + request.Name }; + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpErrorService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpErrorService.cs index c43fdb7348f..0383f20a6f6 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpErrorService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpErrorService.cs @@ -1,65 +1,179 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using System.Threading; +using ServiceStack.Model; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - [Route("/errors")] - [Route("/errors/{Type}")] - [Route("/errors/{Type}/{StatusCode}")] - [Route("/errors/{Type}/{StatusCode}/{Message}")] - public class HttpError - { - [DataMember] - public string Type { get; set; } - - [DataMember] - public string Message { get; set; } - - [DataMember] - public int? StatusCode { get; set; } - } - - [DataContract] - public class HttpErrorResponse - : IHasResponseStatus - { - public HttpErrorResponse() - { - this.ResponseStatus = new ResponseStatus(); - } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class HttpErrorService : ServiceInterface.Service - { - public object Any(HttpError request) - { - if (request.Type.IsNullOrEmpty()) - throw new ArgumentNullException("Type"); - - var ex = new Exception(request.Message); - switch (request.Type) - { - case "FileNotFoundException": - ex = new FileNotFoundException(request.Message); - break; - } - - if (!request.StatusCode.HasValue) - throw ex; - - var httpStatus = (HttpStatusCode)request.StatusCode.Value; - throw new Common.Web.HttpError(httpStatus, ex); - } - } + [DataContract] + [Route("/errors")] + [Route("/errors/{Type}")] + [Route("/errors/{Type}/{StatusCode}")] + [Route("/errors/{Type}/{StatusCode}/{Message}")] + public class ThrowHttpError : IReturn<ThrowHttpErrorResponse> + { + [DataMember] + public string Type { get; set; } + + [DataMember] + public string Message { get; set; } + + [DataMember] + public int? StatusCode { get; set; } + } + + [DataContract] + [Route("/errors")] + [Route("/errors/{Type}")] + [Route("/errors/{Type}/{StatusCode}")] + [Route("/errors/{Type}/{StatusCode}/{Message}")] + public class ThrowHttpErrorNoReturn : IReturnVoid + { + [DataMember] + public string Type { get; set; } + + [DataMember] + public string Message { get; set; } + + [DataMember] + public int? StatusCode { get; set; } + } + + [DataContract] + public class ThrowHttpErrorResponse + : IHasResponseStatus + { + public ThrowHttpErrorResponse() + { + this.ResponseStatus = new ResponseStatus(); + } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + [Route("/throw404")] + public class Throw404 { } + + [Route("/throw404description")] + public class Throw404Description { } + + [Route("/throwcustom404")] + public class ThrowCustom404 { } + + [Route("/return404")] + public class Return404 { } + + [Route("/return404result")] + public class Return404Result { } + + [Route("/throwwebex")] + public class ThrowWebServiceException : IHasResponseStatus + { + public int? StatusCode { get; set; } + public string StatusDescription { get; set; } + public string Message { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + + public class Custom404Exception : Exception, IResponseStatusConvertible, IHasStatusCode + { + public Custom404Exception(string message) : base(message) { } + + public ResponseStatus ToResponseStatus() + { + return new ResponseStatus + { + ErrorCode = GetType().Name, + Message = this.Message, + Errors = new List<ResponseError> + { + new ResponseError + { + ErrorCode = "FieldErrorCode", + Message = "FieldMessage", + FieldName = "FieldName", + } + } + }; + } + + public int StatusCode + { + get { return (int)HttpStatusCode.NotFound; } + } + } + + public class HttpErrorService : Service + { + public static int DisposeCounter = 0; + + public object Any(ThrowHttpError request) + { + if (request.Type.IsNullOrEmpty()) + throw new ArgumentNullException("Type"); + + var ex = new Exception(request.Message); + switch (request.Type) + { + case "FileNotFoundException": + ex = new FileNotFoundException(request.Message); + break; + } + + if (!request.StatusCode.HasValue) + throw ex; + + var httpStatus = (HttpStatusCode)request.StatusCode.Value; + throw new HttpError(httpStatus, ex); + } + + public object Any(Throw404 request) + { + throw HttpError.NotFound("Custom Status Description"); + } + + public object Any(Throw404Description request) + { + throw new HttpError(HttpStatusCode.NotFound) + { + StatusDescription = "Custom Status Description" + }; + } + + public object Any(ThrowCustom404 request) + { + throw new Custom404Exception("Custom Status Description"); + } + + public object Any(Return404 request) + { + return HttpError.NotFound("Custom Status Description"); + } + + public object Any(Return404Result request) + { + return new HttpResult(HttpStatusCode.NotFound, "Custom Status Description"); + } + + public object Any(ThrowWebServiceException request) + { + throw new WebServiceException(request.Message ?? "Message") + { + StatusCode = request.StatusCode ?? 500, + StatusDescription = request.StatusDescription ?? "StatusDescription", + ResponseDto = request, + }; + } + + public override void Dispose() + { + Interlocked.Increment(ref DisposeCounter); + base.Dispose(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs index 6b51cda50da..3ba4aee6db5 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlAndSecureLocalSubnetRestrictionService.cs @@ -1,22 +1,21 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class HttpPostXmlAndSecureLocalSubnetRestriction { } + [Restrict(RequestAttributes.LocalSubnet | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.Xml)] + [DataContract] + public class HttpPostXmlAndSecureLocalSubnetRestriction { } - [DataContract] - public class HttpPostXmlAndSecureLocalSubnetRestrictionResponse { } + [DataContract] + public class HttpPostXmlAndSecureLocalSubnetRestrictionResponse { } - public class HttpPostXmlAndSecureLocalSubnetRestrictionService - : TestServiceBase<HttpPostXmlAndSecureLocalSubnetRestriction> - { - protected override object Run(HttpPostXmlAndSecureLocalSubnetRestriction request) - { - return new HttpPostXmlAndSecureLocalSubnetRestrictionResponse(); - } - } + public class HttpPostXmlAndSecureLocalSubnetRestrictionService + : TestServiceBase<HttpPostXmlAndSecureLocalSubnetRestriction> + { + protected override object Run(HttpPostXmlAndSecureLocalSubnetRestriction request) + { + return new HttpPostXmlAndSecureLocalSubnetRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs index e593a048810..b47d8f83519 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/HttpPostXmlOrSecureLocalSubnetRestrictionService.cs @@ -1,21 +1,20 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(EndpointAttributes.LocalSubnet | EndpointAttributes.Secure, EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class HttpPostXmlOrSecureLocalSubnetRestriction { } + [Restrict(RequestAttributes.LocalSubnet | RequestAttributes.Secure, RequestAttributes.HttpPost | RequestAttributes.Xml)] + [DataContract] + public class HttpPostXmlOrSecureLocalSubnetRestriction { } - [DataContract] - public class HttpPostXmlOrSecureLocalSubnetRestrictionResponse { } + [DataContract] + public class HttpPostXmlOrSecureLocalSubnetRestrictionResponse { } - public class HttpPostXmlOrSecureLocalSubnetRestrictionService - : TestServiceBase<HttpPostXmlOrSecureLocalSubnetRestriction> - { - protected override object Run(HttpPostXmlOrSecureLocalSubnetRestriction request) - { - return new HttpPostXmlOrSecureLocalSubnetRestrictionResponse(); - } - } + public class HttpPostXmlOrSecureLocalSubnetRestrictionService + : TestServiceBase<HttpPostXmlOrSecureLocalSubnetRestriction> + { + protected override object Run(HttpPostXmlOrSecureLocalSubnetRestriction request) + { + return new HttpPostXmlOrSecureLocalSubnetRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InSecureLiveEnvironmentRestriction.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InSecureLiveEnvironmentRestriction.cs index 8eb4e49e156..b40de274dbc 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InSecureLiveEnvironmentRestriction.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InSecureLiveEnvironmentRestriction.cs @@ -1,21 +1,20 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(EndpointAttributes.External | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class InSecureLiveEnvironmentRestriction { } + [Restrict(RequestAttributes.External | RequestAttributes.InSecure | RequestAttributes.HttpPost | RequestAttributes.Xml)] + [DataContract] + public class InSecureLiveEnvironmentRestriction { } - [DataContract] - public class InSecureLiveEnvironmentRestrictionResponse { } + [DataContract] + public class InSecureLiveEnvironmentRestrictionResponse { } - public class InSecureLiveEnvironmentRestrictionService - : TestServiceBase<InSecureLiveEnvironmentRestriction> - { - protected override object Run(InSecureLiveEnvironmentRestriction request) - { - return new InSecureLiveEnvironmentRestrictionResponse(); - } - } + public class InSecureLiveEnvironmentRestrictionService + : TestServiceBase<InSecureLiveEnvironmentRestriction> + { + protected override object Run(InSecureLiveEnvironmentRestriction request) + { + return new InSecureLiveEnvironmentRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InsecureDevEnvironmentRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InsecureDevEnvironmentRestrictionService.cs index e7bdc59529f..8ce96e6f060 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InsecureDevEnvironmentRestrictionService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InsecureDevEnvironmentRestrictionService.cs @@ -1,22 +1,21 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(EndpointAttributes.InternalNetworkAccess | EndpointAttributes.InSecure | EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class InSecureDevEnvironmentRestriction { } + [Restrict(RequestAttributes.InternalNetworkAccess | RequestAttributes.InSecure | RequestAttributes.HttpPost | RequestAttributes.Xml)] + [DataContract] + public class InSecureDevEnvironmentRestriction { } - [DataContract] - public class InsecureDevEnvironmentRestrictionResponse { } + [DataContract] + public class InsecureDevEnvironmentRestrictionResponse { } - public class InsecureDevEnvironmentRestrictionService - : TestServiceBase<InSecureDevEnvironmentRestriction> - { - protected override object Run(InSecureDevEnvironmentRestriction request) - { - return new InsecureDevEnvironmentRestrictionResponse(); - } - } + public class InsecureDevEnvironmentRestrictionService + : TestServiceBase<InSecureDevEnvironmentRestriction> + { + protected override object Run(InSecureDevEnvironmentRestriction request) + { + return new InsecureDevEnvironmentRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InternalRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InternalRestrictionService.cs index b0fbbc42205..5a206fa4baa 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InternalRestrictionService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/InternalRestrictionService.cs @@ -1,22 +1,34 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(AccessTo = EndpointAttributes.InternalNetworkAccess)] - [DataContract] - public class InternalRestriction { } + [Restrict(AccessTo = RequestAttributes.InternalNetworkAccess)] + public class InternalRestriction { } + + [Restrict(RequestAttributes.Localhost)] + public class LocalhostRestriction { } + + [Restrict(RequestAttributes.LocalSubnet)] + public class LocalSubnetRestriction { } + + [Restrict(RequestAttributes.InProcess)] + public class InProcessRestriction { } + + [Restrict(AccessTo = RequestAttributes.None)] + public class AccessToNoneRestriction { } - [DataContract] - public class IntranetRestrictionResponse { } + public class NetworkRestrictionServices : Service + { + public object Any(InternalRestriction request) => request; + public object Any(InProcessRestriction request) => request; + public object Any(LocalhostRestriction request) => request; + public object Any(LocalSubnetRestriction request) => request; + public object Any(AccessToNoneRestriction request) => request; + } - public class InternalRestrictionService - : TestServiceBase<InternalRestriction> - { - protected override object Run(InternalRestriction request) - { - return new IntranetRestrictionResponse(); - } - } + public class LocalhostRestrictionOnService : IReturn<Response> { } + [Restrict(LocalhostOnly = true)] + public class LocalHostOnService : Service + { + public object Any(LocalhostRestrictionOnService request) => request; + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/IocService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/IocService.cs deleted file mode 100644 index 7e04f992ba5..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/IocService.cs +++ /dev/null @@ -1,304 +0,0 @@ -using System; -using System.Collections.Generic; -using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.Endpoints.Tests.Support.Host; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - public class FunqRequestScope - { - public static int Count = 0; - public FunqRequestScope() { Count++; } - } - - public class FunqSingletonScope - { - public static int Count = 0; - public FunqSingletonScope() { Count++; } - } - - public class FunqNoneScope - { - public static int Count = 0; - public FunqNoneScope() { Count++; } - } - - public class FunqRequestScopeDisposable : IDisposable - { - public static int Count = 0; - public static int DisposeCount = 0; - public FunqRequestScopeDisposable() { Count++; } - - public void Dispose() - { - DisposeCount++; - } - } - - public class FunqSingletonScopeDisposable : IDisposable - { - public static int Count = 0; - public static int DisposeCount = 0; - public FunqSingletonScopeDisposable() { Count++; } - - public void Dispose() - { - DisposeCount++; - } - } - - public class FunqNoneScopeDisposable : IDisposable - { - public static int Count = 0; - public static int DisposeCount = 0; - public FunqNoneScopeDisposable() { Count++; } - - public void Dispose() - { - DisposeCount++; - } - } - - public class FunqRequestScopeDepDisposableProperty : IDisposable - { - public static int Count = 0; - public static int DisposeCount = 0; - public FunqRequestScopeDepDisposableProperty() { Count++; } - public void Dispose() { DisposeCount++; } - } - - public class AltRequestScopeDepDisposableProperty : IDisposable - { - public static int Count = 0; - public static int DisposeCount = 0; - public AltRequestScopeDepDisposableProperty() { Count++; } - public void Dispose() { DisposeCount++; } - } - - public class FunqDepCtor { } - public class AltDepCtor { } - - public class FunqDepProperty { } - public class AltDepProperty { } - - public class FunqDepDisposableProperty : IDisposable - { - public static int DisposeCount = 0; - public void Dispose() { DisposeCount++; } - } - public class AltDepDisposableProperty : IDisposable - { - public static int DisposeCount = 0; - public void Dispose() { DisposeCount++; } - } - - public class Ioc { } - - public class IocResponse : IHasResponseStatus - { - public IocResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Results = new List<string>(); - } - - public List<string> Results { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - - [Route("/action-attr")] - public class ActionAttr : IReturn<IocResponse> {} - - public class ActionLevelAttribute : RequestFilterAttribute - { - public IRequestContext RequestContext { get; set; } - public FunqDepProperty FunqDepProperty { get; set; } - public FunqDepDisposableProperty FunqDepDisposableProperty { get; set; } - public AltDepProperty AltDepProperty { get; set; } - public AltDepDisposableProperty AltDepDisposableProperty { get; set; } - - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) - { - var response = new IocResponse(); - - var deps = new object[] { - FunqDepProperty, FunqDepDisposableProperty, - AltDepProperty, AltDepDisposableProperty - }; - - foreach (var dep in deps) - { - if (dep != null) - response.Results.Add(dep.GetType().Name); - } - - req.Items["action-attr"] = response; - } - } - - - public class IocService : IService, IDisposable, IRequiresRequestContext - { - private readonly FunqDepCtor funqDepCtor; - private readonly AltDepCtor altDepCtor; - - public IocService(FunqDepCtor funqDepCtor, AltDepCtor altDepCtor) - { - this.funqDepCtor = funqDepCtor; - this.altDepCtor = altDepCtor; - } - - public IRequestContext RequestContext { get; set; } - public FunqDepProperty FunqDepProperty { get; set; } - public FunqDepDisposableProperty FunqDepDisposableProperty { get; set; } - public AltDepProperty AltDepProperty { get; set; } - public AltDepDisposableProperty AltDepDisposableProperty { get; set; } - - public object Any(Ioc request) - { - var response = new IocResponse(); - - var deps = new object[] { - funqDepCtor, altDepCtor, - FunqDepProperty, FunqDepDisposableProperty, - AltDepProperty, AltDepDisposableProperty - }; - - foreach (var dep in deps) - { - if (dep != null) - response.Results.Add(dep.GetType().Name); - } - - if (ThrowErrors) throw new ArgumentException("This service has intentionally failed"); - - return response; - } - - [ActionLevel] - public IocResponse Any(ActionAttr request) - { - return RequestContext.Get<IHttpRequest>().Items["action-attr"] as IocResponse; - } - - public static int DisposedCount = 0; - public static bool ThrowErrors = false; - - public void Dispose() - { - DisposedCount++; - } - } - - - public class IocScope - { - public bool Throw { get; set; } - } - - public class IocScopeResponse : IHasResponseStatus - { - public IocScopeResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Results = new Dictionary<string, int>(); - } - - public Dictionary<string, int> Results { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - [IocRequestFilter] - public class IocScopeService : IService, IDisposable - { - public FunqRequestScope FunqRequestScope { get; set; } - public FunqSingletonScope FunqSingletonScope { get; set; } - public FunqNoneScope FunqNoneScope { get; set; } - public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } - public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } - - public object Any(IocScope request) - { - if (request.Throw) - throw new Exception("Exception requested by user"); - - var response = new IocScopeResponse { - Results = { - { typeof(FunqSingletonScope).Name, FunqSingletonScope.Count }, - { typeof(FunqRequestScope).Name, FunqRequestScope.Count }, - { typeof(FunqNoneScope).Name, FunqNoneScope.Count }, - }, - }; - - return response; - } - - public static int DisposedCount = 0; - public static bool ThrowErrors = false; - - public void Dispose() - { - DisposedCount++; - } - } - - public class IocDispose : IReturn<IocDisposeResponse> - { - public bool Throw { get; set; } - } - - public class IocDisposeResponse : IHasResponseStatus - { - public IocDisposeResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Results = new Dictionary<string, int>(); - } - - public Dictionary<string, int> Results { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - public class IocDisposableService : IService, IDisposable - { - public FunqRequestScopeDisposable FunqRequestScopeDisposable { get; set; } - public FunqSingletonScopeDisposable FunqSingletonScopeDisposable { get; set; } - public FunqNoneScopeDisposable FunqNoneScopeDisposable { get; set; } - public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } - public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } - - public object Any(IocDispose request) - { - if (request.Throw) - throw new Exception("Exception requested by user"); - - var response = new IocDisposeResponse - { - Results = { - { typeof(FunqSingletonScopeDisposable).Name, FunqSingletonScopeDisposable.DisposeCount }, - { typeof(FunqRequestScopeDisposable).Name, FunqRequestScopeDisposable.DisposeCount }, - { typeof(FunqNoneScopeDisposable).Name, FunqNoneScopeDisposable.DisposeCount }, - { typeof(FunqRequestScopeDepDisposableProperty).Name, FunqRequestScopeDepDisposableProperty.DisposeCount }, - { typeof(AltRequestScopeDepDisposableProperty).Name, AltRequestScopeDepDisposableProperty.DisposeCount }, - }, - }; - - return response; - } - - public static int DisposeCount = 0; - - public void Dispose() - { - DisposeCount++; - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/LocalSubnetRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/LocalSubnetRestrictionService.cs deleted file mode 100644 index 02e22380914..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/LocalSubnetRestrictionService.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - [Restrict(EndpointAttributes.LocalSubnet)] - [DataContract] - public class LocalSubnetRestriction { } - - [DataContract] - public class LocalSubnetRestrictionResponse { } - - public class LocalSubnetRestrictionService - : TestServiceBase<LocalSubnetRestriction> - { - protected override object Run(LocalSubnetRestriction request) - { - return new LocalSubnetRestrictionResponse(); - } - } - -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/LocalhostRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/LocalhostRestrictionService.cs deleted file mode 100644 index fa86a903fec..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/LocalhostRestrictionService.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Runtime.Serialization; -using ServiceStack.ServiceHost; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services -{ - [Restrict(EndpointAttributes.Localhost)] - [DataContract] - public class LocalhostRestriction { } - - [DataContract] - public class LocalhostRestrictionResponse { } - - public class LocalhostRestrictionService - : TestServiceBase<LocalhostRestriction> - { - protected override object Run(LocalhostRestriction request) - { - return new LocalhostRestrictionResponse(); - } - } - -} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/MessageQueueRestriction.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/MessageQueueRestriction.cs new file mode 100644 index 00000000000..68fe848c80c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/MessageQueueRestriction.cs @@ -0,0 +1,33 @@ +using NUnit.Framework; +using ServiceStack.Messaging; +using ServiceStack.Testing; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + [Restrict(RequestAttributes.MessageQueue)] + public class MessageQueueRestriction : IReturn<MessageQueueRestriction> + { + public int Id { get; set; } + } + + public class MessageQueueRestrictionService : Service + { + public object Any(MessageQueueRestriction request) => request; + } + + [TestFixture] + public class MessageQueueRestrictionTests + { + [Test] + public void Can_access_MQ_Restriction_when_using_ExecuteMessage() + { + using (var appHost = new BasicAppHost(typeof(MessageQueueRestrictionService).Assembly).Init()) + { + var request = new MessageQueueRestriction { Id = 1 }; + var response = appHost.ExecuteMessage(new Message<MessageQueueRestriction>(request)); + Assert.That(((MessageQueueRestriction)response).Id, Is.EqualTo(1)); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/NestedService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/NestedService.cs index 28e0c0c25a7..b79ccfde3e5 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/NestedService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/NestedService.cs @@ -2,18 +2,18 @@ namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - public class Nested { } - [DataContract] - public class NestedResponse { } + [DataContract] + public class Nested { } + [DataContract] + public class NestedResponse { } - public class NestedService - : TestServiceBase<Nested> - { - protected override object Run(Nested request) - { - return new NestedResponse(); - } - } + public class NestedService + : TestServiceBase<Nested> + { + protected override object Run(Nested request) + { + return new NestedResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/RequestFilter.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/RequestFilter.cs index b60cf9f183e..dcb05e313a1 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/RequestFilter.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/RequestFilter.cs @@ -1,38 +1,37 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; +using ServiceStack.Web; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - public class RequestFilter - { - [DataMember] - public int StatusCode { get; set; } + [DataContract] + public class RequestFilter + { + [DataMember] + public int StatusCode { get; set; } - [DataMember] - public string HeaderName { get; set; } + [DataMember] + public string HeaderName { get; set; } - [DataMember] - public string HeaderValue { get; set; } - } + [DataMember] + public string HeaderValue { get; set; } + } - [DataContract] - public class RequestFilterResponse - { - [DataMember] - public string Value { get; set; } - } + [DataContract] + public class RequestFilterResponse + { + [DataMember] + public string Value { get; set; } + } - public class StatusCodeService - : TestServiceBase<RequestFilter>, IRequiresRequestContext - { - public IRequestContext RequestContext { get; set; } - - protected override object Run(RequestFilter request) - { - return new RequestFilterResponse(); - } - } + public class StatusCodeService + : TestServiceBase<RequestFilter>, IRequiresRequest + { + public IRequest Request { get; set; } + protected override object Run(RequestFilter request) + { + return new RequestFilterResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureDevEnvironmentRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureDevEnvironmentRestrictionService.cs index ee493630b94..79abd37e46d 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureDevEnvironmentRestrictionService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureDevEnvironmentRestrictionService.cs @@ -1,23 +1,20 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { + [Restrict(RequestAttributes.InternalNetworkAccess | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.Xml)] + [DataContract] + public class SecureDevEnvironmentRestriction { } - [Restrict(EndpointAttributes.InternalNetworkAccess | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class SecureDevEnvironmentRestriction { } - - [DataContract] - public class SecureDevEnvironmentRestrictionResponse { } - - public class SecureDevEnvironmentRestrictionService - : TestServiceBase<SecureDevEnvironmentRestriction> - { - protected override object Run(SecureDevEnvironmentRestriction request) - { - return new SecureDevEnvironmentRestrictionResponse(); - } - } + [DataContract] + public class SecureDevEnvironmentRestrictionResponse { } + public class SecureDevEnvironmentRestrictionService + : TestServiceBase<SecureDevEnvironmentRestriction> + { + protected override object Run(SecureDevEnvironmentRestriction request) + { + return new SecureDevEnvironmentRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLiveEnvironmentRestriction.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLiveEnvironmentRestriction.cs index 46269285922..692c56a6d70 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLiveEnvironmentRestriction.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLiveEnvironmentRestriction.cs @@ -1,21 +1,20 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(EndpointAttributes.External | EndpointAttributes.Secure | EndpointAttributes.HttpPost | EndpointAttributes.Xml)] - [DataContract] - public class SecureLiveEnvironmentRestriction { } + [Restrict(RequestAttributes.External | RequestAttributes.Secure | RequestAttributes.HttpPost | RequestAttributes.Xml)] + [DataContract] + public class SecureLiveEnvironmentRestriction { } - [DataContract] - public class SecureLiveEnvironmentRestrictionResponse { } + [DataContract] + public class SecureLiveEnvironmentRestrictionResponse { } - public class SecureLiveEnvironmentRestrictionService - : TestServiceBase<SecureLiveEnvironmentRestriction> - { - protected override object Run(SecureLiveEnvironmentRestriction request) - { - return new SecureLiveEnvironmentRestrictionResponse(); - } - } + public class SecureLiveEnvironmentRestrictionService + : TestServiceBase<SecureLiveEnvironmentRestriction> + { + protected override object Run(SecureLiveEnvironmentRestriction request) + { + return new SecureLiveEnvironmentRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLocalSubnetRestrictionService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLocalSubnetRestrictionService.cs index 97e3247293b..8521209a6fb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLocalSubnetRestrictionService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SecureLocalSubnetRestrictionService.cs @@ -1,22 +1,21 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [Restrict(EndpointAttributes.Secure | EndpointAttributes.LocalSubnet)] - [DataContract] - public class SecureLocalSubnetRestriction { } + [Restrict(RequestAttributes.Secure | RequestAttributes.LocalSubnet)] + [DataContract] + public class SecureLocalSubnetRestriction { } - [DataContract] - public class SecureLocalSubnetRestrictionResponse { } + [DataContract] + public class SecureLocalSubnetRestrictionResponse { } - public class SecureLocalSubnetRestrictionService - : TestServiceBase<SecureLocalSubnetRestriction> - { - protected override object Run(SecureLocalSubnetRestriction request) - { - return new SecureLocalSubnetRestrictionResponse(); - } - } + public class SecureLocalSubnetRestrictionService + : TestServiceBase<SecureLocalSubnetRestriction> + { + protected override object Run(SecureLocalSubnetRestriction request) + { + return new SecureLocalSubnetRestrictionResponse(); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SendVerbService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SendVerbService.cs new file mode 100644 index 00000000000..d99a2876cf0 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/SendVerbService.cs @@ -0,0 +1,73 @@ +namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services +{ + public class SendVerbResponse + { + public int Id { get; set; } + public string PathInfo { get; set; } + public string RequestMethod { get; set; } + } + + public class SendDefault : IReturn<SendVerbResponse> + { + public int Id { get; set; } + } + + [Route("/sendrestget/{Id}", "GET")] + public class SendRestGet : IReturn<SendVerbResponse>, IGet + { + public int Id { get; set; } + } + + public class SendGet : IReturn<SendVerbResponse>, IGet + { + public int Id { get; set; } + } + + public class SendPost : IReturn<SendVerbResponse>, IPost + { + public int Id { get; set; } + } + + public class SendPut : IReturn<SendVerbResponse>, IPut + { + public int Id { get; set; } + } + + public class SendVerbService : Service + { + public object Any(SendDefault request) + { + return CreateResponse(request.Id); + } + + public object Get(SendRestGet request) + { + return CreateResponse(request.Id); + } + + public object Any(SendGet request) + { + return CreateResponse(request.Id); + } + + public object Any(SendPost request) + { + return CreateResponse(request.Id); + } + + public object Any(SendPut request) + { + return CreateResponse(request.Id); + } + + private object CreateResponse(int requestId) + { + return new SendVerbResponse + { + Id = requestId, + PathInfo = base.Request.PathInfo, + RequestMethod = base.Request.Verb + }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestAsyncService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestAsyncService.cs index c56a469b0b6..2d511653a32 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestAsyncService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestAsyncService.cs @@ -1,53 +1,74 @@ -using System; +using System.Net; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - public class TestAsync { } - - [DataContract] - public class TestAsyncResponse - { - [DataMember] - public IFoo Foo { get; set; } - - [DataMember] - public int ExecuteTimes { get; set; } - - [DataMember] - public int ExecuteAsyncTimes { get; set; } - } - - public class TestAsyncService - : IService<TestAsync>, IAsyncService<TestAsync> - { - private readonly IFoo foo; - - public static int ExecuteTimes { get; private set; } - public static int ExecuteAsyncTimes { get; private set; } - - public static void ResetStats() - { - ExecuteTimes = 0; - ExecuteAsyncTimes = 0; - } - - public TestAsyncService(IFoo foo) - { - this.foo = foo; - } - - public object Execute(TestAsync request) - { - return new TestAsyncResponse { Foo = this.foo, ExecuteTimes = ++ExecuteTimes }; - } - - public object ExecuteAsync(TestAsync request) - { - return new TestAsyncResponse { Foo = this.foo, ExecuteAsyncTimes = ++ExecuteAsyncTimes }; - } - } + [DataContract] + public class TestAsync { } + + [DataContract] + public class TestAsyncResponse + { + [DataMember] + public IFoo Foo { get; set; } + + [DataMember] + public int ExecuteTimes { get; set; } + + [DataMember] + public int ExecuteAsyncTimes { get; set; } + } + + [Route("/returnsvoid")] + [DataContract] + public class ReturnsVoid : IReturnVoid + { + [DataMember] + public string Message { get; set; } + } + + [Route("/returnswebresponse")] + [DataContract] + public class ReturnsWebResponse : IReturn<HttpWebResponse> + { + [DataMember] + public string Message { get; set; } + } + + public class TestAsyncService : IService + { + private readonly IFoo foo; + + public static int ExecuteTimes { get; private set; } + public static int ExecuteAsyncTimes { get; private set; } + public static string ReturnVoidMessage; + public static string ReturnWebResponseMessage; + + public static void ResetStats() + { + ExecuteTimes = 0; + ExecuteAsyncTimes = 0; + } + + public TestAsyncService(IFoo foo) + { + this.foo = foo; + } + + public object Any(TestAsync request) + { + return new TestAsyncResponse { Foo = this.foo, ExecuteTimes = ++ExecuteTimes }; + } + + public void Any(ReturnsVoid request) + { + ReturnVoidMessage = request.Message; + } + + public void Any(ReturnsWebResponse request) + { + ReturnWebResponseMessage = request.Message; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestRestService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestRestService.cs index e56d7c0ac60..e711449105f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestRestService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestRestService.cs @@ -1,62 +1,55 @@ -using System; -using System.ComponentModel.DataAnnotations; -using ServiceStack.Common; -using ServiceStack.DataAnnotations; -using ServiceStack.ServiceInterface; -using ServiceStack.Text; -using ServiceStack.ServiceHost; +using ServiceStack.Text; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - public class TestRestService<TRequest> : IService - where TRequest : class - { - public object Get(TRequest request) - { - return Run(request, ApplyTo.Get); - } - - public object Put(TRequest request) - { - return Run(request, ApplyTo.Put); - } - - public object Post(TRequest request) - { - return Run(request, ApplyTo.Post); - } - - public object Patch(TRequest request) - { - return Run(request, ApplyTo.Patch); - } - - public object Delete(TRequest request) - { - return Run(request, ApplyTo.Delete); - } - - public object Head(TRequest request) - { - return Run(request, ApplyTo.Head); - } - - public object Options(TRequest request) - { - return Run(request, ApplyTo.Options); - } - - protected virtual object Run(TRequest request, ApplyTo method) - { - return request.AsTypeString(); - } - } - - public static class ObjectExtensions - { - public static string AsTypeString(this object request) - { + public class TestRestService<TRequest> : IService + { + public object Get(TRequest request) + { + return Run(request, ApplyTo.Get); + } + + public object Put(TRequest request) + { + return Run(request, ApplyTo.Put); + } + + public object Post(TRequest request) + { + return Run(request, ApplyTo.Post); + } + + public object Patch(TRequest request) + { + return Run(request, ApplyTo.Patch); + } + + public object Delete(TRequest request) + { + return Run(request, ApplyTo.Delete); + } + + public object Head(TRequest request) + { + return Run(request, ApplyTo.Head); + } + + public object Options(TRequest request) + { + return Run(request, ApplyTo.Options); + } + + protected virtual object Run(TRequest request, ApplyTo method) + { + return request.AsTypeString(); + } + } + + public static class ObjectExtensions + { + public static string AsTypeString(this object request) + { return request.GetType().ToTypeString() + "\n" + request.Dump(); } - } + } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestService.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestService.cs index 425a5141413..5ed156e4d54 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestService.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestService.cs @@ -1,52 +1,40 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - [DataContract] - public class Test { } - - [DataContract] - public class TestResponse - { - [DataMember] - public IFoo Foo { get; set; } - - [DataMember] - public int ExecuteTimes { get; set; } - - [DataMember] - public int ExecuteAsyncTimes { get; set; } - } - - public class TestService - : IService<Test> /*Removed:, IAsyncService<Test>*/ - { - private readonly IFoo foo; - - public static int ExecuteTimes { get; private set; } - public static int ExecuteAsyncTimes { get; private set; } - - public static void ResetStats() - { - ExecuteTimes = 0; - ExecuteAsyncTimes = 0; - } - - public TestService(IFoo foo) - { - this.foo = foo; - } - - public object Execute(Test request) - { - return new TestResponse { Foo = this.foo, ExecuteTimes = ++ExecuteTimes }; - } - - public TestResponse ExecuteAsync(Test request) - { - return new TestResponse { Foo = this.foo, ExecuteAsyncTimes = ++ExecuteAsyncTimes }; - } - } + [DataContract] + public class Test { } + + [DataContract] + public class TestResponse + { + [DataMember] + public IFoo Foo { get; set; } + + [DataMember] + public int ExecuteTimes { get; set; } + } + + public class TestService : IService + { + private readonly IFoo foo; + + public static int ExecuteTimes { get; private set; } + + public static void ResetStats() + { + ExecuteTimes = 0; + } + + public TestService(IFoo foo) + { + this.foo = foo; + } + + public object Any(Test request) + { + return new TestResponse { Foo = this.foo, ExecuteTimes = ++ExecuteTimes }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestServiceBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestServiceBase.cs index 46d476d7c10..ceb95bfbb91 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestServiceBase.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Services/TestServiceBase.cs @@ -1,15 +1,13 @@ -using ServiceStack.ServiceHost; - namespace ServiceStack.WebHost.Endpoints.Tests.Support.Services { - public abstract class TestServiceBase<TRequest> - : IService<TRequest> - { - protected abstract object Run(TRequest request); + public abstract class TestServiceBase<TRequest> + : IService + { + protected abstract object Run(TRequest request); - public object Execute(TRequest request) - { - return Run(request); - } - } + public object Any(TRequest request) + { + return Run(request); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/TestBase.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/TestBase.cs deleted file mode 100644 index 70c938031a7..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/TestBase.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; - -namespace ServiceStack.WebHost.Endpoints.Tests.Support -{ - public abstract class MetadataTestBase - { - public ServiceMetadata Metadata { get; set; } - - protected MetadataTestBase() - { - Metadata = new ServiceMetadata(); - var dummyServiceType = GetType(); - Metadata.Add(dummyServiceType, typeof(GetCustomer), typeof(GetCustomerResponse)); - Metadata.Add(dummyServiceType, typeof(GetCustomers), typeof(GetCustomersResponse)); - Metadata.Add(dummyServiceType, typeof(StoreCustomer), null); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Types/KeyAttribute.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Types/KeyAttribute.cs index 5f7c32835a1..947722e913c 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Types/KeyAttribute.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/Support/Types/KeyAttribute.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace ServiceStack.WebHost.Endpoints.Tests.Support.Types { @@ -13,7 +10,7 @@ namespace ServiceStack.WebHost.Endpoints.Tests.Support.Types /// <typeparamref name="RouteInferenceStrategies"/> available at runtime. /// </summary> [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] - sealed class KeyAttribute : Attribute + sealed class KeyAttribute : AttributeBase { } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SwaggerFeatureTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SwaggerFeatureTests.cs deleted file mode 100644 index 9be724c7f39..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/SwaggerFeatureTests.cs +++ /dev/null @@ -1,580 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Service; -using ServiceStack.Api.Swagger; -using ServiceStack.ServiceInterface.Cors; -using ServiceStack.Text; - -namespace ServiceStack.WebHost.Endpoints.Tests -{ - [ServiceHost.Api("Service Description")] - [Route("/swagger/{Name}", "GET", Summary = @"GET Summary", Notes = "GET Notes")] - [Route("/swagger/{Name}", "POST", Summary = @"POST Summary", Notes = "POST Notes")] - public class SwaggerFeatureRequest - { - [ApiMember(Name="Name", Description = "Name Description", - ParameterType = "path", DataType = SwaggerType.String, IsRequired = true)] - public string Name { get; set; } - } - - [ServiceHost.Api] - [Route("/swaggerGetList/{Name}", "GET")] - public class SwaggerGetListRequest : IReturn<List<SwaggerFeatureResponse>> - { - public string Name { get; set; } - } - - [ServiceHost.Api] - [Route("/swaggerGetArray/{Name}", "GET")] - public class SwaggerGetArrayRequest : IReturn<SwaggerFeatureResponse[]> - { - public string Name { get; set; } - } - - [ServiceHost.Api] - [Route("/swaggerModels/{UrlParam}", "POST")] - public class SwaggerModelsRequest : IReturn<SwaggerFeatureResponse> - { - [ApiMember(Name = "UrlParam", Description = "URL parameter", - ParameterType = "path", DataType = SwaggerType.String, IsRequired = true)] - public string UrlParam { get; set; } - - [ApiMember(Name = "RequestBody", Description = "The request body", - ParameterType = "body", DataType = "SwaggerModelsRequest", IsRequired = true)] - [System.ComponentModel.Description("Name description")] - public string Name { get; set; } - - [System.ComponentModel.Description("NestedModel description")] - public SwaggerNestedModel NestedModel { get; set;} - - public List<SwaggerNestedModel2> ListProperty { get; set; } - - public SwaggerNestedModel3[] ArrayProperty { get; set; } - - public byte ByteProperty { get; set; } - - public long LongProperty { get; set; } - - public float FloatProperty { get; set; } - - public double DoubleProperty { get; set; } - - public decimal DecimalProperty { get; set; } - - public DateTime DateProperty { get; set; } - } - - public class SwaggerNestedModel - { - [System.ComponentModel.Description("NestedProperty description")] - public bool NestedProperty { get; set;} - } - - public class SwaggerNestedModel2 - { - [System.ComponentModel.Description("NestedProperty2 description")] - public bool NestedProperty2 { get; set;} - } - - public class SwaggerNestedModel3 - { - [System.ComponentModel.Description("NestedProperty3 description")] - public bool NestedProperty3 { get; set;} - } - - [ServiceHost.Api] - [Route("/swagger2/NameIsNotSetRequest", "GET")] - public class NameIsNotSetRequest - { - [ApiMember] - public string Name { get; set; } - } - - - [ServiceHost.Api("test")] - [Route("/swg3/conference/count", "GET")] - public class MultipleTestRequest : IReturn<int> - { - [ApiMember] - public string Name { get; set; } - } - - [ServiceHost.Api] - [Route("/swg3/conference/{Name}/conferences", "POST")] - [Route("/swgb3/conference/{Name}/conferences", "POST")] - public class MultipleTest2Request : IReturn<object> - { - [ApiMember] - public string Name { get; set; } - } - - [ServiceHost.Api] - [Route("/swg3/conference/{Name}/conferences", "DELETE")] - public class MultipleTest3Request : IReturn<object> - { - [ApiMember] - public string Name { get; set; } - } - - [ServiceHost.Api] - [Route("/swg3/conference", "GET")] - public class MultipleTest4Request : IReturn<object> - { - [ApiMember] - public string Name { get; set; } - } - - public class NullableResponse - { - [System.ComponentModel.Description("NestedProperty2 description")] - public bool NestedProperty2 { get; set; } - - public int? Optional { get; set; } - } - - [ServiceHost.Api] - [Route("/swgnull/", "GET")] - public class NullableInRequest : IReturn<NullableResponse> - { - [ApiMember] - public int? Position { get; set; } - } - - public class NullableService : ServiceInterface.Service - { - public object Get(NullableInRequest request) - { - return null; - } - } - - - public class SwaggerFeatureResponse - { - public bool IsSuccess { get; set; } - } - - public class MultipleTestRequestService : ServiceInterface.Service - { - public object Get(MultipleTestRequest request) - { - return null; - } - - public object Post(MultipleTest2Request request) - { - return null; - } - - public object Delete(MultipleTest3Request request) - { - return null; - } - } - public class MultipleTest2RequestService : ServiceInterface.Service - { - public object Get(MultipleTest4Request request) - { - return null; - } - } - - - public class SwaggerFeatureService : ServiceInterface.Service - { - public object Get(SwaggerFeatureRequest request) - { - return new SwaggerFeatureResponse { IsSuccess = true }; - } - - public object Post(SwaggerFeatureRequest request) - { - return new SwaggerFeatureResponse { IsSuccess = true }; - } - - public object Get(NameIsNotSetRequest request) - { - return 0; - } - - public object Post(SwaggerModelsRequest request) - { - return new SwaggerFeatureResponse { IsSuccess = true }; - } - - public object Get(SwaggerGetListRequest request) - { - return new List<SwaggerFeatureResponse> { new SwaggerFeatureResponse { IsSuccess = true } }; - } - - public object Get(SwaggerGetArrayRequest request) - { - return new[] { new SwaggerFeatureResponse { IsSuccess = true } }; - } - } - - - - [TestFixture] - public class SwaggerFeatureServiceTests - { - private const string BaseUrl = "http://localhost:8024"; - private const string ListeningOn = BaseUrl + "/"; - - public class SwaggerFeatureAppHostHttpListener - : AppHostHttpListenerBase - { - - public SwaggerFeatureAppHostHttpListener() - : base("Swagger Feature Tests", typeof(SwaggerFeatureServiceTests).Assembly) { } - - public override void Configure(Funq.Container container) - { - Plugins.Add(new SwaggerFeature()); - - SetConfig(new EndpointHostConfig - { - DebugMode = true //Show StackTraces for easier debugging - }); - } - } - - SwaggerFeatureAppHostHttpListener appHost; - - [TestFixtureSetUp] - public void OnTestFixtureSetUp() - { - appHost = new SwaggerFeatureAppHostHttpListener(); - appHost.Init(); - appHost.Start(ListeningOn); - } - - [TestFixtureTearDown] - public void OnTestFixtureTearDown() - { - appHost.Dispose(); - } - - static IRestClient[] RestClients = - { - new JsonServiceClient(ListeningOn) - //new XmlServiceClient(ServiceClientBaseUri), - }; - - [Test, Explicit] - public void RunFor5Mins() - { - appHost.LoadPlugin(new CorsFeature("http://localhost:50000")); - - Debug.WriteLine(ListeningOn + "resources"); - Thread.Sleep(TimeSpan.FromMinutes(5)); - } - - [Test, TestCaseSource("RestClients")] - public void Should_get_default_name_from_property(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swagger2/NameIsNotSetRequest"); - - var p = resource.Apis.SelectMany(t => t.Operations).SelectMany(t => t.Parameters); - Assert.That(p.Count(), Is.EqualTo(1)); - Assert.That(p.FirstOrDefault(t=>t.Name == "Name"), Is.Not.Null); - } - - [Test, TestCaseSource("RestClients")] - public void Should_group_similar_services(IRestClient client) - { - var resources = client.Get<ResourcesResponse>("/resources"); - resources.PrintDump(); - - var swagger = resources.Apis.Where(t => t.Path.Contains("/resource/swg3")); - Assert.That(swagger.Count(), Is.EqualTo(1)); - } - - [Test, TestCaseSource("RestClients")] - public void Should_distinct_base_path(IRestClient client) - { - var resources = client.Get<ResourcesResponse>("/resources"); - resources.PrintDump(); - - var swagger = resources.Apis.Where(t => t.Path.Contains("/resource/swgb3")); - Assert.That(swagger.Count(), Is.EqualTo(1)); - } - - [Test, TestCaseSource("RestClients")] - public void Should_list_services(IRestClient client) - { - var resources = client.Get<ResourcesResponse>("/resources"); - Assert.That(resources.BasePath, Is.EqualTo(BaseUrl)); - Assert.That(resources.SwaggerVersion, Is.EqualTo("1.1")); - Assert.That(resources.Apis, Is.Not.Null); - - var swagger = resources.Apis.FirstOrDefault(t => t.Path == "/resource/swagger"); - Assert.That(swagger, Is.Not.Null); - Assert.That(swagger.Description, Is.EqualTo("Service Description")); - } - - [Test, TestCaseSource("RestClients")] - public void Should_use_webhosturl_as_resources_base_path_when_configured(IRestClient client) - { - const string webHostUrl = "https://host.example.com/_api"; - try - { - appHost.Config.WebHostUrl = webHostUrl; - - var resources = client.Get<ResourcesResponse>("/resources"); - resources.PrintDump(); - - Assert.That(resources.BasePath, Is.EqualTo(webHostUrl)); - } - finally - { - appHost.Config.WebHostUrl = null; - } - } - - [Test, TestCaseSource("RestClients")] - public void Should_use_webhosturl_as_resource_base_path_when_configured(IRestClient client) - { - const string webHostUrl = "https://host.example.com/_api"; - try - { - appHost.Config.WebHostUrl = webHostUrl; - - var resource = client.Get<ResourceResponse>("/resource/swagger"); - resource.PrintDump(); - - Assert.That(resource.BasePath, Is.EqualTo(webHostUrl)); - } - finally - { - appHost.Config.WebHostUrl = null; - } - } - - [Test, TestCaseSource("RestClients")] - public void Should_use_https_for_resources_basepath_when_usehttpslinks_config_is_true(IRestClient client) - { - try - { - appHost.Config.UseHttpsLinks = true; - - var resources = client.Get<ResourcesResponse>("/resources"); - resources.PrintDump(); - - Assert.That(resources.BasePath.ToLowerInvariant(), Is.StringStarting("https")); - } - finally - { - appHost.Config.UseHttpsLinks = false; - } - } - - [Test, TestCaseSource("RestClients")] - public void Should_use_https_for_resource_basepath_when_usehttpslinks_config_is_true(IRestClient client) - { - try - { - appHost.Config.UseHttpsLinks = true; - - var resource = client.Get<ResourceResponse>("/resource/swagger"); - resource.PrintDump(); - - Assert.That(resource.BasePath.ToLowerInvariant(), Is.StringStarting("https")); - } - finally - { - appHost.Config.UseHttpsLinks = false; - } - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_service_parameters(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swagger"); - Assert.That(resource.BasePath, Is.EqualTo(BaseUrl)); - Assert.That(resource.ResourcePath, Is.EqualTo("/swagger")); - Assert.That(resource.Apis, Is.Not.Empty); - - resource.Apis.PrintDump(); - - var operations = new List<MethodOperation>(); - foreach(var api in resource.Apis) operations.AddRange(api.Operations); - - var getOperation = operations.Single(t => t.HttpMethod == "GET"); - Assert.That(getOperation.Summary, Is.EqualTo("GET Summary")); - Assert.That(getOperation.Notes, Is.EqualTo("GET Notes")); - Assert.That(getOperation.HttpMethod, Is.EqualTo("GET")); - - Assert.That(getOperation.Parameters, Is.Not.Empty); - var p1 = getOperation.Parameters[0]; - Assert.That(p1.Name, Is.EqualTo("Name")); - Assert.That(p1.Description, Is.EqualTo("Name Description")); - Assert.That(p1.DataType, Is.EqualTo("string")); - Assert.That(p1.ParamType, Is.EqualTo("path")); - Assert.That(p1.Required, Is.EqualTo(true)); - - - var postOperation = operations.Single(t => t.HttpMethod == "POST"); - Assert.That(postOperation.Summary, Is.EqualTo("POST Summary")); - Assert.That(postOperation.Notes, Is.EqualTo("POST Notes")); - Assert.That(postOperation.HttpMethod, Is.EqualTo("POST")); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_response_class_name(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerModels"); - Assert.That(resource.Apis, Is.Not.Empty); - - var postOperation = resource.Apis.SelectMany(api => api.Operations).Single(t => t.HttpMethod == "POST"); - postOperation.PrintDump(); - Assert.That(postOperation.ResponseClass, Is.EqualTo(typeof(SwaggerFeatureResponse).Name)); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_list_response_type_info(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerGetList"); - Assert.That(resource.Apis, Is.Not.Empty); - - var operation = resource.Apis.SelectMany(api => api.Operations).Single(t => t.HttpMethod == "GET"); - operation.PrintDump(); - Assert.That(operation.ResponseClass, Is.EqualTo("List[SwaggerFeatureResponse]")); - Assert.That(resource.Models.ContainsKey("SwaggerFeatureResponse")); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_array_response_type_info(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerGetArray"); - Assert.That(resource.Apis, Is.Not.Empty); - - var operation = resource.Apis.SelectMany(api => api.Operations).Single(t => t.HttpMethod == "GET"); - operation.PrintDump(); - Assert.That(operation.ResponseClass, Is.EqualTo("List[SwaggerFeatureResponse]")); - Assert.That(resource.Models.ContainsKey("SwaggerFeatureResponse")); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_response_model(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerModels"); - Assert.That(resource.Models, Is.Not.Empty); - - Assert.That(resource.Models.ContainsKey(typeof(SwaggerFeatureResponse).Name), Is.True); - var responseClassModel = resource.Models[typeof(SwaggerFeatureResponse).Name]; - responseClassModel.PrintDump(); - - Assert.That(responseClassModel.Id, Is.EqualTo(typeof(SwaggerFeatureResponse).Name)); - Assert.That(responseClassModel.Properties, Is.Not.Empty); - Assert.That(responseClassModel.Properties.ContainsKey("IsSuccess"), Is.True); - Assert.That(responseClassModel.Properties["IsSuccess"].Type, Is.EqualTo(SwaggerType.Boolean)); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_request_body_model(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerModels"); - Assert.That(resource.Models, Is.Not.Empty); - resource.Models.PrintDump(); - - Assert.That(resource.Models.ContainsKey(typeof(SwaggerModelsRequest).Name), Is.True); - var requestClassModel = resource.Models[typeof(SwaggerModelsRequest).Name]; - - Assert.That(requestClassModel.Id, Is.EqualTo(typeof(SwaggerModelsRequest).Name)); - Assert.That(requestClassModel.Properties, Is.Not.Empty); - - Assert.That(requestClassModel.Properties.ContainsKey("UrlParam"), Is.False); - - Assert.That(requestClassModel.Properties.ContainsKey("Name"), Is.True); - Assert.That(requestClassModel.Properties["Name"].Type, Is.EqualTo(SwaggerType.String)); - Assert.That(requestClassModel.Properties["Name"].Description, Is.EqualTo("Name description")); - - Assert.That(requestClassModel.Properties.ContainsKey("ByteProperty")); - Assert.That(requestClassModel.Properties["ByteProperty"].Type, Is.EqualTo(SwaggerType.Byte)); - Assert.That(resource.Models.ContainsKey(typeof(byte).Name), Is.False); - - Assert.That(requestClassModel.Properties.ContainsKey("LongProperty")); - Assert.That(requestClassModel.Properties["LongProperty"].Type, Is.EqualTo(SwaggerType.Long)); - Assert.That(resource.Models.ContainsKey(typeof(long).Name), Is.False); - - Assert.That(requestClassModel.Properties.ContainsKey("FloatProperty")); - Assert.That(requestClassModel.Properties["FloatProperty"].Type, Is.EqualTo(SwaggerType.Float)); - Assert.That(resource.Models.ContainsKey(typeof(float).Name), Is.False); - - Assert.That(requestClassModel.Properties.ContainsKey("DoubleProperty")); - Assert.That(requestClassModel.Properties["DoubleProperty"].Type, Is.EqualTo(SwaggerType.Double)); - Assert.That(resource.Models.ContainsKey(typeof(double).Name), Is.False); - - // Swagger has no concept of a "decimal" type - Assert.That(requestClassModel.Properties.ContainsKey("DecimalProperty")); - Assert.That(requestClassModel.Properties["DecimalProperty"].Type, Is.EqualTo(SwaggerType.Double)); - Assert.That(resource.Models.ContainsKey(typeof(decimal).Name), Is.False); - - Assert.That(requestClassModel.Properties.ContainsKey("DateProperty")); - Assert.That(requestClassModel.Properties["DateProperty"].Type, Is.EqualTo(SwaggerType.Date)); - Assert.That(resource.Models.ContainsKey(typeof(DateTime).Name), Is.False); - - Assert.That(requestClassModel.Properties.ContainsKey("NestedModel"), Is.True); - Assert.That(requestClassModel.Properties["NestedModel"].Type, Is.EqualTo("SwaggerNestedModel")); - Assert.That(requestClassModel.Properties["NestedModel"].Description, Is.EqualTo("NestedModel description")); - - Assert.That(resource.Models.ContainsKey(typeof(SwaggerNestedModel).Name), Is.True); - var nestedClassModel = resource.Models[typeof(SwaggerNestedModel).Name]; - - Assert.That(nestedClassModel.Properties.ContainsKey("NestedProperty"), Is.True); - Assert.That(nestedClassModel.Properties["NestedProperty"].Type, Is.EqualTo(SwaggerType.Boolean)); - Assert.That(nestedClassModel.Properties["NestedProperty"].Description, Is.EqualTo("NestedProperty description")); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_list_property_model(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerModels"); - Assert.That(resource.Models.ContainsKey(typeof(SwaggerModelsRequest).Name), Is.True); - var requestClassModel = resource.Models[typeof(SwaggerModelsRequest).Name]; - - Assert.That(requestClassModel.Properties.ContainsKey("ListProperty"), Is.True); - Assert.That(requestClassModel.Properties["ListProperty"].Type, Is.EqualTo(SwaggerType.Array)); - Assert.That(requestClassModel.Properties["ListProperty"].Items["$ref"], Is.EqualTo(typeof(SwaggerNestedModel2).Name)); - Assert.That(resource.Models.ContainsKey(typeof(SwaggerNestedModel2).Name), Is.True); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_array_property_model(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swaggerModels"); - Assert.That(resource.Models.ContainsKey(typeof(SwaggerModelsRequest).Name), Is.True); - var requestClassModel = resource.Models[typeof(SwaggerModelsRequest).Name]; - - Assert.That(requestClassModel.Properties.ContainsKey("ArrayProperty"), Is.True); - Assert.That(requestClassModel.Properties["ArrayProperty"].Type, Is.EqualTo(SwaggerType.Array)); - Assert.That(requestClassModel.Properties["ArrayProperty"].Items["$ref"], Is.EqualTo(typeof(SwaggerNestedModel3).Name)); - Assert.That(resource.Models.ContainsKey(typeof(SwaggerNestedModel3).Name), Is.True); - } - - [Test, TestCaseSource("RestClients")] - public void Should_retrieve_valid_nullable_fields(IRestClient client) - { - var resource = client.Get<ResourceResponse>("/resource/swgnull"); - Assert.That(resource.Models.ContainsKey(typeof(NullableInRequest).Name), Is.True); - var requestClassModel = resource.Models[typeof(NullableInRequest).Name]; - - Assert.That(requestClassModel.Properties.ContainsKey("Position"), Is.True); - Assert.That(requestClassModel.Properties["Position"].Type, Is.EqualTo(SwaggerType.Int)); - Assert.That(resource.Models.ContainsKey(typeof(NullableResponse).Name), Is.True); - - var responseModel = resource.Models[typeof (NullableResponse).Name]; - Assert.That(responseModel.Properties.ContainsKey("Optional"), Is.True); - Assert.That(responseModel.Properties["Optional"].Required, Is.False); - Assert.That(responseModel.Properties["Optional"].Type, Is.EqualTo(SwaggerType.Int)); - Assert.That(responseModel.Properties["NestedProperty2"].Required, Is.True); - } - } -} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs index 7b71182cd8b..3b34018491f 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/SyncRestClientTests.cs @@ -1,13 +1,8 @@ using System; using System.Collections.Generic; -using System.Net; using NUnit.Framework; -using ServiceStack.Common.Extensions; using ServiceStack.Logging; -using ServiceStack.Logging.Support.Logging; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceModel.Serialization; +using ServiceStack.Serialization; using ServiceStack.Text; using ServiceStack.WebHost.Endpoints.Tests.Support.Host; @@ -28,7 +23,7 @@ protected SyncRestClientTests(int port) ListeningOn += port + "/"; } - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { LogManager.LogFactory = new ConsoleLogFactory(); @@ -38,7 +33,7 @@ public void OnTestFixtureSetUp() appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { Dispose(); @@ -46,9 +41,7 @@ public void OnTestFixtureTearDown() public void Dispose() { - if (appHost == null) return; appHost.Dispose(); - appHost = null; } protected abstract IRestClient CreateRestClient(); @@ -71,7 +64,7 @@ public void Can_GET_GetFactorial_using_RestClient(string path) Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(3))); } - [TestCase("movies")] + [TestCase("all-movies")] [TestCase("custom-movies")] public void Can_GET_Movies_using_RestClient(string path) { @@ -83,7 +76,7 @@ public void Can_GET_Movies_using_RestClient(string path) Assert.That(response.Movies.EquivalentTo(ResetMoviesService.Top5Movies)); } - [TestCase("movies/1")] + [TestCase("all-movies/1")] [TestCase("custom-movies/1")] public void Can_GET_single_Movie_using_RestClient(string path) { @@ -95,13 +88,13 @@ public void Can_GET_single_Movie_using_RestClient(string path) Assert.That(response.Movie.Id, Is.EqualTo(1)); } - [TestCase("movies")] + [TestCase("all-movies")] [TestCase("custom-movies")] public void Can_POST_to_add_new_Movie_using_RestClient(string path) { var restClient = CreateRestClient(); - var newMovie = new Movie { + var newMovie = new Support.Host.Movie { ImdbId = "tt0450259", Title = "Blood Diamond", Rating = 8.0m, @@ -126,8 +119,8 @@ public void Can_Deserialize_Xml_MovieResponse() try { var xml = "<MovieResponse xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.servicestack.net/types\"><Movie><Director>Edward Zwick</Director><Genres xmlns:d3p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"><d3p1:string>Adventure</d3p1:string><d3p1:string>Drama</d3p1:string><d3p1:string>Thriller</d3p1:string></Genres><Id>6</Id><ImdbId>tt0450259</ImdbId><Rating>8</Rating><ReleaseDate>2007-01-26T00:00:00+00:00</ReleaseDate><TagLine>A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.</TagLine><Title>Blood Diamond</Title></Movie></MovieResponse>"; - var response = DataContractDeserializer.Instance.Parse<MovieResponse>(xml); - var toXml = DataContractSerializer.Instance.Parse(response); + var response = DataContractSerializer.Instance.DeserializeFromString<MovieResponse>(xml); + var toXml = DataContractSerializer.Instance.SerializeToString(response); Console.WriteLine("XML: " + toXml); } catch (Exception ex) @@ -137,13 +130,14 @@ public void Can_Deserialize_Xml_MovieResponse() } } - [TestCase("movies", "movies/")] + [TestCase("all-movies", "all-movies/")] [TestCase("custom-movies", "custom-movies/")] public void Can_DELETE_Movie_using_RestClient(string postPath, string deletePath) { var restClient = CreateRestClient(); - var newMovie = new Movie { + var newMovie = new Support.Host.Movie + { ImdbId = "tt0450259", Title = "Blood Diamond", Rating = 8.0m, @@ -177,9 +171,7 @@ public void Can_PUT_complex_type_with_custom_path() } }; - var response = client.Put<InboxPostResponseRequestResponse>( - "inbox/123/responses", - request); + var response = client.Put<InboxPostResponseRequestResponse>("inbox/123/responses", request); Assert.That(response.Id, Is.EqualTo(request.Id)); Assert.That(response.Responses[0].PageElementId, @@ -193,11 +185,7 @@ public void Does_throw_400_for_Argument_exceptions() try { - var response = client.Put<InboxPostResponseRequestResponse>( - "inbox/123/responses", - new InboxPostResponseRequest()); - - response.PrintDump(); + var response = client.Put<InboxPostResponseRequestResponse>("inbox/123/responses", new InboxPostResponseRequest()); Assert.Fail("Should throw"); } @@ -214,11 +202,7 @@ public void Does_throw_400_for_Argument_exceptions_without_response_DTOs() try { - var response = client.Put<InboxPost>( - "inbox/123/responses", - new InboxPost { Throw = true }); - - response.PrintDump(); + var response = client.Put<InboxPost>("inbox/123/responses", new InboxPost { Throw = true }); Assert.Fail("Should throw"); } @@ -246,14 +230,43 @@ public void Can_use_response_filters() { var isActioncalledGlobal = false; var isActioncalledLocal = false; - ServiceClientBase.HttpWebResponseFilter = r => isActioncalledGlobal = true; + ServiceClientBase.GlobalResponseFilter = r => isActioncalledGlobal = true; var restClient = (JsonServiceClient)CreateRestClient(); - restClient.LocalHttpWebResponseFilter = r => isActioncalledLocal = true; - restClient.Get<MoviesResponse>("movies"); + restClient.ResponseFilter = r => isActioncalledLocal = true; + restClient.Get<MoviesResponse>("all-movies"); + Assert.That(isActioncalledGlobal, Is.True); + Assert.That(isActioncalledLocal, Is.True); + + ServiceClientBase.GlobalResponseFilter = null; + } + } + + [TestFixture] + public class JsonSyncRestHttpClientTests : SyncRestClientTests + { + public JsonSyncRestHttpClientTests() + : base(8090) + { + } + + protected override IRestClient CreateRestClient() + { + return new JsonHttpClient(ListeningOn); + } + + [Test] + public void Can_use_response_filters() + { + var isActioncalledGlobal = false; + var isActioncalledLocal = false; + JsonHttpClient.GlobalResponseFilter = r => isActioncalledGlobal = true; + var restClient = (JsonHttpClient)CreateRestClient(); + restClient.ResponseFilter = r => isActioncalledLocal = true; + restClient.Get<MoviesResponse>("all-movies"); Assert.That(isActioncalledGlobal, Is.True); Assert.That(isActioncalledLocal, Is.True); - ServiceClientBase.HttpWebResponseFilter = null; + JsonHttpClient.GlobalResponseFilter = null; } } @@ -275,7 +288,7 @@ protected override IRestClient CreateRestClient() public class XmlSyncRestClientTests : SyncRestClientTests { public XmlSyncRestClientTests() - : base(8092) + : base(8094) { } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs index 7d4da4808d8..edb2da67b50 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/TodoListTests.cs @@ -1,11 +1,8 @@ using System.Collections.Generic; using Funq; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Host; using ServiceStack.WebHost.Endpoints; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -59,7 +56,7 @@ public class TodoListResponse } [DefaultRequest(typeof(TodoList))] - public class TodoListService : ServiceInterface.Service + public class TodoListService : Service { public object Get(TodoList request) { @@ -104,7 +101,7 @@ public override void Configure(Container container) {} new Todo { Id = 3, Name = "Todo3", Content = "Content3", Done = false}, }; - [TestFixtureSetUp] + [OneTimeSetUp] public void OnTestFixtureSetUp() { appHost = new TodoListAppHostHttpListener(); @@ -112,7 +109,7 @@ public void OnTestFixtureSetUp() appHost.Start(ListeningOn); } - [TestFixtureTearDown] + [OneTimeTearDown] public void OnTestFixtureTearDown() { appHost.Dispose(); @@ -130,7 +127,7 @@ public void Can_Send_TodoList() public void Can_Post_TodoList() { var serviceClient = new JsonServiceClient(ListeningOn); - var response = serviceClient.Post<TodoListResponse>("/todolist", new TodoList(Todos)); + var response = serviceClient.Post<TodoListResponse>("/todolist", new TodoList(Todos)); Assert.That(response.Results, Is.EquivalentTo(Todos)); } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/TypedFilterTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/TypedFilterTests.cs new file mode 100644 index 00000000000..a8a83d6ff12 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/TypedFilterTests.cs @@ -0,0 +1,118 @@ +using NUnit.Framework; +using ServiceStack.Host; +using ServiceStack.Testing; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [TestFixture] + public class TypedFilterTests + { + private class Dto : IReturn<Dto> + { + public bool RequestFilter { get; set; } + public bool ResponseFilter { get; set; } + } + + private class DtoService : Service + { + public object Any(Dto r) => r; + } + + private interface IDependency { } + private class Dependency : IDependency { } + + private class TypedRequestFilter : ITypedFilter<Dto> + { + public TypedRequestFilter(IDependency dependency) => Dependency = dependency; + + public IDependency Dependency { get; } + + public void Invoke(IRequest req, IResponse res, Dto dto) => dto.RequestFilter = true; + } + + private class TypedResponseFilter : ITypedFilter<Dto> + { + public TypedResponseFilter(IDependency dependency) => Dependency = dependency; + + public IDependency Dependency { get; } + + public void Invoke(IRequest req, IResponse res, Dto dto) => dto.ResponseFilter = true; + } + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void OnTestFixtureSetup() + { + appHost = new BasicAppHost(typeof(DtoService).Assembly) + { + ConfigureContainer = c => + { + c.RegisterAutoWiredAs<Dependency, IDependency>(); + c.RegisterAutoWired<TypedRequestFilter>(); + c.RegisterAutoWired<TypedResponseFilter>(); + } + }; + appHost.RegisterTypedRequestFilter(c => c.Resolve<TypedRequestFilter>()); + appHost.RegisterTypedResponseFilter(c => c.Resolve<TypedResponseFilter>()); + appHost.Init(); + } + + [OneTimeTearDown] + public void OnTestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Request_filter_auto_wired() + { + // Arrange + var filter = appHost.GetContainer().Resolve<TypedRequestFilter>(); + + // Assert + Assert.NotNull(filter.Dependency); + } + + [Test] + public void Response_filter_auto_wired() + { + // Arrange + var filter = appHost.GetContainer().Resolve<TypedResponseFilter>(); + + // Assert + Assert.NotNull(filter.Dependency); + } + + [Test] + public void Request_filter_executed() + { + // Arrange + var dto = new Dto(); + var request = new BasicRequest(dto); + + // Act + var response = appHost.ServiceController.Execute(dto, request, true) as Dto; + + // Assert + Assert.NotNull(response); + Assert.IsTrue(response.RequestFilter); + } + + [Test] + public void Response_filter_executed() + { + // Arrange + var dto = new Dto(); + var request = new BasicRequest(dto); + + // Act + var response = appHost.ServiceController.Execute(dto, request, true) as Dto; + + // Assert + Assert.NotNull(response); + Assert.IsTrue(response.ResponseFilter); + } + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UniqueRequestTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UniqueRequestTests.cs index c368665e198..292e582369b 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/UniqueRequestTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UniqueRequestTests.cs @@ -1,10 +1,12 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using Funq; using NUnit.Framework; using ServiceStack.Common; -using ServiceStack.MiniProfiler.UI; -using ServiceStack.ServiceHost; using ServiceStack.Text; +#if !NETCORE +using ServiceStack.MiniProfiler.UI; +#endif namespace ServiceStack.WebHost.Endpoints.Tests { @@ -14,12 +16,39 @@ public class ById public string Id { get; set; } } + [Route("/collections")] + public class Collections : IReturn<Collections> + { + public int[] Ids { get; set; } + public List<string> Names { get; set; } + } + public class UniqueRequestService : IService { public string Get(ById byId) { return byId.Id; } + + public object Any(Collections request) + { + return request; + } + } + + [Route("/head-test/{Id}")] + public class HeadTest + { + public string Id { get; set; } + } + + public class HeadTestService : Service + { + public void Any(HeadTest request) + { + Response.AddHeader("Id", request.Id); + Response.EndRequest(); + } } public class UniqueRequestAppHost : AppHostHttpListenerBase @@ -31,10 +60,10 @@ public override void Configure(Container container) {} [TestFixture] public class UniqueRequestTests { - private const string BaseUri = "http://localhost:8000"; + private const string BaseUri = "http://localhost:8001"; private UniqueRequestAppHost appHost; - [TestFixtureSetUp] + [OneTimeSetUp] public void TestFixtureSetUp() { appHost = new UniqueRequestAppHost(); @@ -42,11 +71,10 @@ public void TestFixtureSetUp() appHost.Start(BaseUri + "/"); } - [TestFixtureTearDown] + [OneTimeTearDown] public void TestFixtureTearDown() { appHost.Dispose(); - appHost = null; } [Test] @@ -57,5 +85,86 @@ public void Can_handle_encoded_chars() response = BaseUri.CombineWith("request/123%7C456").GetStringFromUrl(); Assert.That(response, Is.EqualTo("123|456")); } + + [Test] + public void Can_handle_collections_with_ServiceClient() + { + var client = new JsonServiceClient(BaseUri); + var request = new Collections { + Ids = new[] {1, 2, 3}, + Names = new List<string> {"A", "B", "C"}, + }; + var response = client.Get(request); + + Assert.That(response.Ids, Is.EquivalentTo(request.Ids)); + Assert.That(response.Names, Is.EquivalentTo(request.Names)); + } + + [Test] + public void Can_handle_collections_with_HttpClient() + { + var url = BaseUri.CombineWith("collections") + .AddQueryParam("Ids", "1,2,3") + .AddQueryParam("Names", "A,B,C"); + + var response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + + url = BaseUri.CombineWith("collections") + .AddQueryParam("Ids", "1") + .AddQueryParam("Ids", "2") + .AddQueryParam("Ids", "3") + .AddQueryParam("Names", "A") + .AddQueryParam("Names", "B") + .AddQueryParam("Names", "C"); + + response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + } + + [Test] + public void Can_handle_collections_with_HttpClient_on_predefined_route() + { + var url = BaseUri.CombineWith("json/reply/Collections") + .AddQueryParam("Ids", "1,2,3") + .AddQueryParam("Names", "A,B,C"); + + var response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + + url = BaseUri.CombineWith("json/reply/Collections") + .AddQueryParam("Ids", "1") + .AddQueryParam("Ids", "2") + .AddQueryParam("Ids", "3") + .AddQueryParam("Names", "A") + .AddQueryParam("Names", "B") + .AddQueryParam("Names", "C"); + + response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + } + + [Test] + public void Does_populate_Head_requests() + { + var json = BaseUri.CombineWith("json", "reply", nameof(HeadTest)) + .AddQueryParam("Id", 1) + .SendStringToUrl(method:HttpMethods.Head, responseFilter: res => { + Assert.That(res.GetHeader("Id"), Is.EqualTo("1")); + }); + Assert.That(json, Is.Empty); + } } } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UnitTestExample.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UnitTestExample.cs new file mode 100644 index 00000000000..3f2ab0eb435 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UnitTestExample.cs @@ -0,0 +1,226 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using Funq; +using NUnit.Framework; +using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; +using ServiceStack.OrmLite; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + // Request DTOs + public class FindRockstars + { + public int? Aged { get; set; } + public bool? Alive { get; set; } + } + + public class GetStatus + { + public string LastName { get; set; } + } + + public enum LivingStatus + { + Alive, + Dead + } + + // Types + public class Rockstar + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int? Age { get; set; } + public DateTime DateOfBirth { get; set; } + public DateTime? DateDied { get; set; } + public LivingStatus LivingStatus { get; set; } + } + + public class RockstarStatus + { + public int Age { get; set; } + public bool Alive { get; set; } + } + + public class PagingTest + { + public int Id { get; set; } + public string Name { get; set; } + public int Value { get; set; } + } + + // Implementation + public class SimpleService : Service + { + public IRockstarRepository RockstarRepository { get; set; } + + public List<Rockstar> Get(FindRockstars request) + { + return request.Aged.HasValue + ? Db.Select<Rockstar>(q => q.Age == request.Aged.Value) + : Db.Select<Rockstar>(); + } + + public RockstarStatus Get(GetStatus request) + { + var rockstar = RockstarRepository.GetByLastName(request.LastName); + if (rockstar == null) + throw HttpError.NotFound("'{0}' is not a Rockstar".Fmt(request.LastName)); + + var status = new RockstarStatus + { + Alive = RockstarRepository.IsAlive(request.LastName) + }.PopulateWith(rockstar); //Populates with matching fields + + return status; + } + } + + //Custom Repository + public interface IRockstarRepository + { + Rockstar GetByLastName(string lastName); + bool IsAlive(string lastName); + } + + public class RockstarRepository : RepositoryBase, IRockstarRepository + { + public Rockstar GetByLastName(string lastName) + { + return Db.Single<Rockstar>(q => q.LastName == lastName); + } + + readonly HashSet<string> fallenLegends = new HashSet<string> { + "Hendrix", "Hendrix", "Cobain", "Presley", "Jackson" + }; + + public bool IsAlive(string lastName) + { + return !fallenLegends.Contains(lastName); + } + } + + //Use base class to keep common boilerplate + public class RepositoryBase : IDisposable + { + public IDbConnectionFactory DbFactory { get; set; } + + IDbConnection db; + protected IDbConnection Db + { + get { return db ?? (db = DbFactory.Open()); } + } + + public void Dispose() + { + if (db != null) + db.Dispose(); + } + } + + [TestFixture] + public class UnitTestExample + { + public static List<Rockstar> SeedData = new[] { + new Rockstar { Id = 1, FirstName = "Jimi", LastName = "Hendrix", Age = 27, DateOfBirth = new DateTime(1942, 11, 27), DateDied = new DateTime(1970, 09, 18), }, + new Rockstar { Id = 2, FirstName = "Jim", LastName = "Morrison", Age = 27, DateOfBirth = new DateTime(1943, 12, 08), DateDied = new DateTime(1971, 07, 03), }, + new Rockstar { Id = 3, FirstName = "Kurt", LastName = "Cobain", Age = 27, DateOfBirth = new DateTime(1967, 02, 20), DateDied = new DateTime(1994, 04, 05), }, + new Rockstar { Id = 4, FirstName = "Elvis", LastName = "Presley", Age = 42, DateOfBirth = new DateTime(1935, 01, 08), DateDied = new DateTime(1977, 08, 16), }, + new Rockstar { Id = 5, FirstName = "David", LastName = "Grohl", Age = 44, DateOfBirth = new DateTime(1969, 01, 14), }, + new Rockstar { Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48, DateOfBirth = new DateTime(1964, 12, 23), }, + new Rockstar { Id = 7, FirstName = "Michael", LastName = "Jackson", Age = 50, DateOfBirth = new DateTime(1958, 08, 29), DateDied = new DateTime(2009, 06, 05), }, + }.ToList(); + + private ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost().Init(); + var container = appHost.Container; + + container.Register<IDbConnectionFactory>( + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + container.RegisterAutoWiredAs<RockstarRepository, IRockstarRepository>(); + + container.RegisterAutoWired<SimpleService>(); + + using (var db = container.Resolve<IDbConnectionFactory>().Open()) + { + db.DropAndCreateTable<Rockstar>(); + db.InsertAll(SeedData); + } + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Using_in_memory_database() + { + var service = appHost.Container.Resolve<SimpleService>(); //Resolve auto-wired service + + var rockstars = service.Get(new FindRockstars { Aged = 27 }); + + Assert.That(rockstars.Count, Is.EqualTo(SeedData.Count(x => x.Age == 27))); + + var status = service.Get(new GetStatus { LastName = "Vedder" }); + Assert.That(status.Age, Is.EqualTo(48)); + Assert.That(status.Alive, Is.True); + + status = service.Get(new GetStatus { LastName = "Hendrix" }); + Assert.That(status.Age, Is.EqualTo(27)); + Assert.That(status.Alive, Is.False); + + Assert.Throws<HttpError>(() => + service.Get(new GetStatus { LastName = "Unknown" })); + } + + public class RockstarRepositoryMock : IRockstarRepository + { + public Rockstar GetByLastName(string lastName) + { + return lastName == "Vedder" + ? new Rockstar { Id = 6, FirstName = "Eddie", LastName = "Vedder", Age = 48 } + : null; + } + + public bool IsAlive(string lastName) + { + return lastName == "Grohl" || lastName == "Vedder"; + } + } + + [Test] + public void Using_manual_dependency_injection() + { + var service = new SimpleService + { + RockstarRepository = new RockstarRepositoryMock() + }; + + var status = service.Get(new GetStatus { LastName = "Vedder" }); + Assert.That(status.Age, Is.EqualTo(48)); + Assert.That(status.Alive, Is.True); + + Assert.Throws<HttpError>(() => + service.Get(new GetStatus { LastName = "Hendrix" })); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/BasicEncryptedMessagesTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/BasicEncryptedMessagesTests.cs new file mode 100644 index 00000000000..ae76319781b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/BasicEncryptedMessagesTests.cs @@ -0,0 +1,126 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +using System; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class BasicEncryptedMessagesAppHost : AppSelfHostBase +{ + public BasicEncryptedMessagesAppHost() + : base(nameof(BasicEncryptedMessagesAppHost), typeof(BasicEncryptedMessagesService).Assembly) { } + + public override void Configure(Container container) + { + RequestConverters.Add((req, requestDto) => { + if (!(requestDto is BasicEncryptedMessage encRequest)) + return null; + + var requestType = Metadata.GetOperationType(encRequest.OperationName); + var decryptedJson = RsaUtils.Decrypt(encRequest.EncryptedBody, SecureConfig.PrivateKeyXml); + var request = JsonSerializer.DeserializeFromString(decryptedJson, requestType); + + req.Items["_encrypt"] = encRequest; + + return Task.FromResult(request); + }); + + ResponseConverters.Add((req, response) => { + if (!req.Items.ContainsKey("_encrypt")) + return TypeConstants.EmptyTask; + + var encResponse = RsaUtils.Encrypt(response.ToJson(), SecureConfig.PublicKeyXml); + return Task.FromResult((object)new BasicEncryptedMessageResponse + { + OperationName = response.GetType().Name, + EncryptedBody = encResponse + }); + }); + } +} + +public class BasicEncryptedMessage : IReturn<BasicEncryptedMessageResponse> +{ + public string OperationName { get; set; } + public string EncryptedBody { get; set; } +} + +public class BasicEncryptedMessageResponse +{ + public string OperationName { get; set; } + public string EncryptedBody { get; set; } + + public ResponseStatus ResponseStatus { get; set; } +} + +public class BasicEncryptedMessagesService : Service +{ + public object Any(BasicEncryptedMessage request) + { + throw new NotImplementedException("Dummy method so EncryptedMessage is treated as a Service"); + } +} + +[TestFixture] +public class BasicEncryptedMessagesTests +{ + private readonly ServiceStackHost appHost; + + public BasicEncryptedMessagesTests() + { + appHost = new BasicEncryptedMessagesAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Generate_Key_Pair() + { + var keyPair = RsaUtils.CreatePublicAndPrivateKeyPair(); + + "Public Key: {0}\n".Print(keyPair.PublicKey); + "Private Key: {0}\n".Print(keyPair.PrivateKey); + } + + [Test] + public void Can_Encryt_and_Decrypt_String() + { + var request = new HelloSecure { Name = "World" }; + var requestJson = request.ToJson(); + var encRequest = RsaUtils.Encrypt(requestJson, SecureConfig.PublicKeyXml); + + var decJson = RsaUtils.Decrypt(encRequest, SecureConfig.PrivateKeyXml); + + Assert.That(decJson, Is.EqualTo(requestJson)); + } + + [Test] + public void Can_Send_Encrypted_Message() + { + var client = new JsonServiceClient(Config.AbsoluteBaseUri); + + var request = new HelloSecure { Name = "World" }; + var encRequest = RsaUtils.Encrypt(request.ToJson(), SecureConfig.PublicKeyXml); + + var encResponse = client.Post(new BasicEncryptedMessage + { + OperationName = typeof(HelloSecure).Name, + EncryptedBody = encRequest + }); + + var responseJson = RsaUtils.Decrypt(encResponse.EncryptedBody, SecureConfig.PrivateKeyXml); + var response = responseJson.FromJson<HelloSecureResponse>(); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs new file mode 100644 index 00000000000..0814b1fed7b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs @@ -0,0 +1,699 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +using System; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class EncryptedMessagesAppHost : AppSelfHostBase +{ + public EncryptedMessagesAppHost() + : base(nameof(EncryptedMessagesAppHost), typeof(SecureServices).Assembly) + { } + + public override void Configure(Container container) + { + Plugins.Add(new EncryptedMessagesFeature + { + PrivateKey = SecureConfig.PrivateKeyXml.ToPrivateRSAParameters(), + FallbackPrivateKeys = { + SecureConfig.FallbackPrivateKeyXml.ToPrivateRSAParameters() + }, + }); + + var apiKeyAuth = new ApiKeyAuthProvider(AppSettings); + var jwtAuth = new JwtAuthProvider(AppSettings) { + AuthKey = AesUtils.CreateKey(), + UseTokenCookie = false, // only works with non HTTP Cookies + }; + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(AppSettings), + apiKeyAuth, + jwtAuth, + })); + + container.Register<IAuthRepository>(c => new InMemoryAuthRepository()); + var authRepo = container.Resolve<IAuthRepository>(); + + var userAuth = authRepo.CreateUserAuth( + new UserAuth { Email = "test@gmail.com" }, "p@55word"); + + var apiKeys = apiKeyAuth.GenerateNewApiKeys(userAuth.Id.ToString(), "live"); + var apiKeyRepo = (IManageApiKeys) authRepo; + apiKeyRepo.StoreAll(apiKeys); + LiveApiKey = apiKeys[0]; + + JwtBearerToken = jwtAuth.CreateJwtBearerToken(new AuthUserSession { + UserAuthId = userAuth.Id.ToString(), + Email = userAuth.Email, + IsAuthenticated = true, + }); + } + + public ApiKey LiveApiKey { get; set; } + + public string JwtBearerToken { get; set; } +} + +public class JsonServiceClientEncryptedMessagesTests : EncryptedMessagesTests +{ + protected override IJsonServiceClient CreateClient() + { + return new JsonServiceClient(Config.AbsoluteBaseUri); + } +} + +public class JsonHttpClientEncryptedMessagesTests : EncryptedMessagesTests +{ + protected override IJsonServiceClient CreateClient() + { + return new JsonHttpClient(Config.AbsoluteBaseUri); + } +} + +#if NET6_0_OR_GREATER +public class JsonApiClientEncryptedMessagesTests : EncryptedMessagesTests +{ + protected override IJsonServiceClient CreateClient() + { + return new JsonApiClient(Config.AbsoluteBaseUri); + } +} +#endif + +public abstract class EncryptedMessagesTests +{ + private readonly ServiceStackHost appHost; + + public ApiKey LiveApiKey => ((EncryptedMessagesAppHost)appHost).LiveApiKey; + public string JwtBearerToken => ((EncryptedMessagesAppHost)appHost).JwtBearerToken; + + protected EncryptedMessagesTests() + { + appHost = new EncryptedMessagesAppHost() + .Init() + .Start(Config.AbsoluteBaseUri); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + ((IClearable)appHost.TryResolve<IAuthRepository>()).Clear(); //Flush InMemoryAuthProvider + appHost.Dispose(); + } + + protected abstract IJsonServiceClient CreateClient(); + + [Test] + public void Can_Send_Encrypted_Message_with_ServiceClients() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get(new GetPublicKey())); + + var response = encryptedClient.Send(new HelloSecure { Name = "World" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Can_Send_Secure_Restricted_Encrypted_Message_with_ServiceClients() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get(new GetPublicKey())); + + var response = encryptedClient.Send(new HelloSecureRestricted { Name = "World" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Can_Send_Encrypted_OneWay_Message_with_ServiceClients() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get(new GetPublicKey())); + + encryptedClient.Send(new HelloOneWay { Name = "World" }); + + Assert.That(HelloOneWay.LastName, Is.EqualTo("World")); + } + + [Test] + public void Can_Send_Encrypted_EmptyRequest_with_ServiceClients() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get(new GetPublicKey())); + + var response = encryptedClient.Delete(new EncryptedDelete()); + + Assert.That(response, Is.Not.Null); + } + + [Test] + public void Can_authenticate_and_call_authenticated_Service() + { + try + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var authResponse = encryptedClient.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "test@gmail.com", + Password = "p@55word", + }); + + var encryptedClientCookies = client.GetCookieValues(); + Assert.That(encryptedClientCookies.Count, Is.EqualTo(0)); + + var response = encryptedClient.Send(new HelloAuthenticated + { + SessionId = authResponse.SessionId, + }); + + Assert.That(response.IsAuthenticated); + Assert.That(response.Email, Is.EqualTo("test@gmail.com")); + Assert.That(response.SessionId, Is.EqualTo(authResponse.SessionId)); + + encryptedClientCookies = client.GetCookieValues(); + Assert.That(encryptedClientCookies.Count, Is.EqualTo(0)); + } + catch (Exception ex) + { + throw ex; + } + } + + [Test] + public void Does_populate_Request_metadata() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var authResponse = encryptedClient.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "test@gmail.com", + Password = "p@55word", + }); + + var encryptedClientCookies = client.GetCookieValues(); + Assert.That(encryptedClientCookies.Count, Is.EqualTo(0)); + + encryptedClient.Version = 1; + encryptedClient.SessionId = authResponse.SessionId; + + var response = encryptedClient.Send(new HelloAuthenticated()); + Assert.That(response.SessionId, Is.EqualTo(encryptedClient.SessionId)); + Assert.That(response.Version, Is.EqualTo(encryptedClient.Version)); + + encryptedClientCookies = client.GetCookieValues(); + Assert.That(encryptedClientCookies.Count, Is.EqualTo(0)); + + client.SessionId = authResponse.SessionId; + client.Version = 2; + + response = client.Send(new HelloAuthenticated()); + Assert.That(response.SessionId, Is.EqualTo(client.SessionId)); + Assert.That(response.Version, Is.EqualTo(client.Version)); + } + + [Test] + public void Can_Authenticate_then_call_AuthOnly_Services_with_ServiceClients_Temp() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var authResponse = encryptedClient.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "test@gmail.com", + Password = "p@55word", + }); + + client.SetCookie("ss-id", authResponse.SessionId); + var response = client.Get(new HelloAuthSecure { Name = "World" }); + } + + [Test] + public void Can_Authenticate_then_call_AuthOnly_Services_with_ServiceClients_Perm() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var authResponse = encryptedClient.Send(new Authenticate + { + provider = CredentialsAuthProvider.Name, + UserName = "test@gmail.com", + Password = "p@55word", + RememberMe = true, + }); + + client.SetCookie("ss-pid", authResponse.SessionId); + client.SetCookie("ss-opt", "perm"); + var response = client.Get(new HelloAuthSecure { Name = "World" }); + } + + [Test] + public void Can_Authenticate_with_ApiKey_then_call_AuthOnly_Services_with_ServiceClients() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + encryptedClient.BearerToken = LiveApiKey.Id; + + var response = encryptedClient.Get(new HelloAuthenticated()); + } + + [Test] + public void Can_Authenticate_with_JWT_then_call_AuthOnly_Services_with_ServiceClients() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + encryptedClient.BearerToken = JwtBearerToken; + + var response = encryptedClient.Get(new HelloAuthenticated()); + } + + [Test] + public void Does_handle_Exceptions() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + try + { + var response = encryptedClient.Send(new HelloSecure()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ResponseStatus.ErrorCode, Is.EqualTo(nameof(ArgumentNullException))); + Assert.That(ex.ResponseStatus.Message, Is.EqualTo($"Value cannot be null.{Environment.NewLine}Parameter name: Name") + .Or.EqualTo("Value cannot be null. (Parameter 'Name')")); + } + + try + { + var response = encryptedClient.Send(new HelloAuthenticated()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(ex.StatusDescription, Is.EqualTo("Unauthorized")); + } + } + + [Test] + public void Can_call_GET_only_Services() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var response = encryptedClient.Get(new GetSecure { Name = "World" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Can_send_large_messages() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var request = new LargeMessage + { + Messages = 100.Times(i => new HelloSecure { Name = "Name" + i }) + }; + + var response = encryptedClient.Send(request); + + Assert.That(response.Messages.Count, Is.EqualTo(request.Messages.Count)); + } + + [Test] + public void Can_send_auto_batched_requests() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var names = new[] { "Foo", "Bar", "Baz" }; + var requests = names.Map(x => new HelloSecure { Name = x }); + + var responses = encryptedClient.SendAll(requests); + var responseNames = responses.Map(x => x.Result); + + Assert.That(responseNames, Is.EqualTo(names.Map(x => "Hello, {0}!".Fmt(x)))); + } + + [Test] + public void Can_send_PublishAll_requests() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get<string>("/publickey")); + + var names = new[] { "Foo", "Bar", "Baz" }; + var requests = names.Map(x => new HelloSecure { Name = x }); + + encryptedClient.PublishAll(requests); + } + + [Test] + public void Can_Send_Encrypted_Message() + { + var client = CreateClient(); + + var request = new HelloSecure { Name = "World" }; + + AesUtils.CreateCryptAuthKeysAndIv(out var cryptKey, out var authKey, out var iv); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var timestamp = DateTime.UtcNow.ToUnixTime(); + var requestBody = timestamp + " POST " + nameof(HelloSecure) + " " + request.ToJson(); + + var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + var encryptedMessage = new EncryptedMessage + { + EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), + EncryptedBody = Convert.ToBase64String(authEncryptedBytes), + }; + + var encResponse = client.Post(encryptedMessage); + + authEncryptedBytes = Convert.FromBase64String(encResponse.EncryptedBody); + + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("Invalid EncryptedBody"); + + var decryptedBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + + var responseJson = decryptedBytes.FromUtf8Bytes(); + var response = responseJson.FromJson<HelloSecureResponse>(); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Does_throw_on_old_messages() + { + var client = CreateClient(); + + var request = new HelloSecure { Name = "World" }; + + AesUtils.CreateCryptAuthKeysAndIv(out var cryptKey, out var authKey, out var iv); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var timestamp = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(21)).ToUnixTime(); + + var requestBody = timestamp + " POST " + nameof(HelloSecure) + " " + request.ToJson(); + + var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + try + { + var encryptedMessage = new EncryptedMessage + { + EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), + EncryptedBody = Convert.ToBase64String(authEncryptedBytes), + }; + var encResponse = client.Post(encryptedMessage); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.StatusDescription.Print(); + + var errorResponse = (EncryptedMessageResponse)ex.ResponseDto; + + authEncryptedBytes = Convert.FromBase64String(errorResponse.EncryptedBody); + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("EncryptedBody is Invalid"); + + var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + var responseJson = responseBytes.FromUtf8Bytes(); + var response = responseJson.FromJson<ErrorResponse>(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("Request too old")); + } + } + + [Test] + public void Does_throw_on_replayed_messages() + { + var client = CreateClient(); + + var request = new HelloSecure { Name = "World" }; + + AesUtils.CreateKeyAndIv(out var cryptKey, out var iv); + + byte[] authKey = AesUtils.CreateKey(); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var timestamp = DateTime.UtcNow.ToUnixTime(); + var requestBody = timestamp + " POST " + nameof(HelloSecure) + " " + request.ToJson(); + + var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + var encryptedMessage = new EncryptedMessage + { + EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), + EncryptedBody = Convert.ToBase64String(authEncryptedBytes), + }; + + var encResponse = client.Post(encryptedMessage); + + try + { + client.Post(encryptedMessage); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.StatusDescription.Print(); + + var errorResponse = (EncryptedMessageResponse)ex.ResponseDto; + + authEncryptedBytes = Convert.FromBase64String(errorResponse.EncryptedBody); + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("EncryptedBody is Invalid"); + + var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + var responseJson = responseBytes.FromUtf8Bytes(); + var response = responseJson.FromJson<ErrorResponse>(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("Nonce already seen")); + } + } + + [Test] + public void Can_send_encrypted_messages_with_old_registered_PublicKey() + { + var client = CreateClient(); + var encryptedClient = client.GetEncryptedClient(SecureConfig.FallbackPublicKeyXml); + + var response = encryptedClient.Send(new HelloSecure { Name = "Fallback Key" }); + + Assert.That(response.Result, Is.EqualTo("Hello, Fallback Key!")); + } + + [Test] + public void Fails_when_sending_invalid_KeyId() + { + var client = CreateClient(); + var encryptedClient = (EncryptedServiceClient)client.GetEncryptedClient(SecureConfig.FallbackPublicKeyXml); + encryptedClient.KeyId = "AAAAAA"; + + try + { + var response = encryptedClient.Send(new HelloSecure { Name = "Fallback Key" }); + Assert.Fail("Should Throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.NotFound)); + Assert.That(ex.StatusDescription, Is.EqualTo("KeyNotFoundException")); + Assert.That(ex.ResponseStatus.Message, Does.StartWith(EncryptedMessagesFeature.ErrorKeyNotFound.Substring(0,10))); + } + } +} + +public class CryptUtilsTests +{ + [Test] + public void Can_Encrypt_and_Decrypt_with_AES() + { + var msg = new HelloSecure { Name = "World" }; + + AesUtils.CreateKeyAndIv(out var cryptKey, out var iv); + + var encryptedText = AesUtils.Encrypt(msg.ToJson(), cryptKey, iv); + + var decryptedJson = AesUtils.Decrypt(encryptedText, cryptKey, iv); + + var decryptedMsg = decryptedJson.FromJson<HelloSecure>(); + + Assert.That(decryptedMsg.Name, Is.EqualTo(msg.Name)); + } + + [Test] + public void Can_Encrypt_and_Decrypt_with_AES_bytes() + { + var msg = new HelloSecure { Name = "World" }; + + AesUtils.CreateKeyAndIv(out var cryptKey, out var iv); + + var encryptedBytes = AesUtils.Encrypt(msg.ToJson().ToUtf8Bytes(), cryptKey, iv); + + var msgBytes = AesUtils.Decrypt(encryptedBytes, cryptKey, iv); + + var decryptedMsg = msgBytes.FromUtf8Bytes().FromJson<HelloSecure>(); + + Assert.That(decryptedMsg.Name, Is.EqualTo(msg.Name)); + } + + [Test] + public void Does_Hybrid_RSA_Crypt_and_Auth_AES_with_HMAC_SHA256() + { + var request = new HelloSecure { Name = "World" }; + var timestamp = DateTime.UtcNow.ToUnixTime(); + var msg = timestamp + " POST " + request.GetType().Name + " " + request.ToJson(); + var msgBytes = msg.ToUtf8Bytes(); + + AesUtils.CreateCryptAuthKeysAndIv(out var cryptKey, out var authKey, out var iv); + + var encryptedBytes = AesUtils.Encrypt(msgBytes, cryptKey, iv); + + var decryptedBytes = AesUtils.Decrypt(encryptedBytes, cryptKey, iv); + Assert.That(decryptedBytes, Is.EquivalentTo(msgBytes)); + + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var decryptedMsg = ValidateAndDecrypt(authRsaEncCryptAuthKeys, authEncryptedBytes); + + var parts = decryptedMsg.SplitOnFirst(' '); + Assert.That(long.Parse(parts[0]), Is.EqualTo(timestamp)); + + parts = parts[1].SplitOnFirst(' '); + Assert.That(parts[0], Is.EqualTo("POST")); + + parts = parts[1].SplitOnFirst(' '); + Assert.That(parts[0], Is.EqualTo(request.GetType().Name)); + + var decryptedJson = parts[1]; + var decryptedRequest = decryptedJson.FromJson<HelloSecure>(); + + Assert.That(decryptedRequest.Name, Is.EqualTo(request.Name)); + } + + private static string ValidateAndDecrypt(byte[] authRsaEncCryptKey, byte[] authEncryptedBytes) + { + byte[] iv = new byte[AesUtils.BlockSizeBytes]; + const int tagLength = HmacUtils.KeySizeBytes; + byte[] rsaEncCryptAuthKeys = new byte[authRsaEncCryptKey.Length - iv.Length - tagLength]; + + Buffer.BlockCopy(authRsaEncCryptKey, 0, iv, 0, iv.Length); + Buffer.BlockCopy(authRsaEncCryptKey, iv.Length, rsaEncCryptAuthKeys, 0, rsaEncCryptAuthKeys.Length); + + var cryptAuthKeys = RsaUtils.Decrypt(rsaEncCryptAuthKeys, SecureConfig.PrivateKeyXml); + + byte[] cryptKey = new byte[AesUtils.KeySizeBytes]; + byte[] authKey = new byte[AesUtils.KeySizeBytes]; + + Buffer.BlockCopy(cryptAuthKeys, 0, cryptKey, 0, cryptKey.Length); + Buffer.BlockCopy(cryptAuthKeys, cryptKey.Length, authKey, 0, authKey.Length); + + if (!HmacUtils.Verify(authRsaEncCryptKey, authKey)) + throw new Exception("authRsaEncCryptKey is Invalid"); + + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("authEncryptedBytes is Invalid"); + + var msgBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + + return msgBytes.FromUtf8Bytes(); + } + + //Alternate approach use Master Key with SHA-512 to create Crypt + Auth Keys + + [Test] + public void Does_Hybrid_RSA_SHA512_AES_MasterKey_and_HmacSha256() + { + var request = new HelloSecure { Name = "World" }; + var msgBytes = request.ToJson().ToUtf8Bytes(); + + AesUtils.CreateKeyAndIv(out var masterKey, out var iv); + + var sha512KeyBytes = masterKey.ToSha512HashBytes(); + + var cryptKey = new byte[sha512KeyBytes.Length / 2]; + var authKey = new byte[sha512KeyBytes.Length / 2]; + + Buffer.BlockCopy(sha512KeyBytes, 0, cryptKey, 0, cryptKey.Length); + Buffer.BlockCopy(sha512KeyBytes, cryptKey.Length, authKey, 0, authKey.Length); + + var encryptedBytes = AesUtils.Encrypt(msgBytes, cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + var aesKeyNonceBytes = iv.Combine(masterKey); + var rsaEncAesKeyNonceBytes = RsaUtils.Encrypt(aesKeyNonceBytes, SecureConfig.PublicKeyXml); + + var json = ValidateAndDecryptWithMasterKey(rsaEncAesKeyNonceBytes, authEncryptedBytes); + + var fromJson = json.FromJson<HelloSecure>(); + + Assert.That(fromJson.Name, Is.EqualTo(request.Name)); + } + + private static string ValidateAndDecryptWithMasterKey(byte[] rsaEncAesKeyNonceBytes, byte[] authEncryptedBytes) + { + var aesKeyNonceBytes = RsaUtils.Decrypt(rsaEncAesKeyNonceBytes, SecureConfig.PrivateKeyXml); + + var aesKey = new byte[AesUtils.KeySizeBytes]; + var iv = new byte[AesUtils.BlockSizeBytes]; + + Buffer.BlockCopy(aesKeyNonceBytes, 0, iv, 0, iv.Length); + Buffer.BlockCopy(aesKeyNonceBytes, iv.Length, aesKey, 0, aesKey.Length); + + var sha512HashBytes = aesKey.ToSha512HashBytes(); + var cryptKey = new byte[sha512HashBytes.Length / 2]; + var authKey = new byte[sha512HashBytes.Length / 2]; + + Buffer.BlockCopy(sha512HashBytes, 0, cryptKey, 0, cryptKey.Length); + Buffer.BlockCopy(sha512HashBytes, cryptKey.Length, authKey, 0, authKey.Length); + + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("Verification Failed"); + + var msgBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + + var json = msgBytes.FromUtf8Bytes(); + return json; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderNoCookiesTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderNoCookiesTests.cs new file mode 100644 index 00000000000..c1474386a4c --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderNoCookiesTests.cs @@ -0,0 +1,761 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Data; +using ServiceStack.Host; +using ServiceStack.OrmLite; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class JwtAuthProviderRsaEncryptedNoCookiesTests : JwtAuthProviderNoCookiesTests +{ + protected override JwtAuthProvider CreateJwtAuthProvider() + { + var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + var publicKey = privateKey.ToPublicRsaParameters(); + var privateKeyXml = privateKey.ToPrivateKeyXml(); + var publicKeyXml = privateKey.ToPublicKeyXml(); + + return new JwtAuthProvider + { + UseTokenCookie = false, + HashAlgorithm = "RS256", + PrivateKeyXml = privateKeyXml, + EncryptPayload = true, + RequireSecureConnection = false, + }; + } +} + +public class JwtAuthProviderRsaNoCookiesTests : JwtAuthProviderNoCookiesTests +{ + protected override JwtAuthProvider CreateJwtAuthProvider() + { + var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + var publicKey = privateKey.ToPublicRsaParameters(); + var privateKeyXml = privateKey.ToPrivateKeyXml(); + var publicKeyXml = privateKey.ToPublicKeyXml(); + + return new JwtAuthProvider + { + UseTokenCookie = false, + HashAlgorithm = "RS256", + PrivateKeyXml = privateKeyXml, + RequireSecureConnection = false, + }; + } +} + +public class JwtAuthProviderHS256NoCookiesTests : JwtAuthProviderNoCookiesTests +{ + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + + protected override JwtAuthProvider CreateJwtAuthProvider() => new() { + UseTokenCookie = false, + AuthKey = AuthKey, + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + }; + + [Test] + public void Can_manually_create_an_authenticated_UserSession_in_Token() + { + var jwtProvider = CreateJwtAuthProvider(); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + IsAuthenticated = true, + }, + issuer: jwtProvider.Issuer, + expireIn: jwtProvider.ExpireTokensIn, + audiences: jwtProvider.Audiences, + roles: new[] {"TheRole"}, + permissions: new[] {"ThePermission"}); + + var jwtToken = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm()); + + var client = GetClient(); + + try + { + client.Send(new HelloJwt { Name = "no jwt" }); + Assert.Fail("should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + + client.SetTokenCookie(jwtToken); + var response = client.Send(new HelloJwt { Name = "from Custom JWT" }); + Assert.That(response.Result, Is.EqualTo("Hello, from Custom JWT")); + } + + [Test] + public void Can_authenticate_using_JWT_with_QueryString() + { + var client = GetClientWithBasicAuthCredentials(); + + var authResponse = client.Post(new Authenticate()); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + var request = new Secured { Name = "test" }; + var url = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .AddQueryParam(Keywords.TokenCookie, authResponse.BearerToken); + + var response = url.PostJsonToUrl("{}") + .FromJson<SecuredResponse>(); + + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Requires_full_Signature_to_Authenticate() + { + var client = GetClientWithBasicAuthCredentials(); + + var authResponse = client.Post(new Authenticate()); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + var jwtProvider = (JwtAuthProvider) AuthenticateService.GetJwtAuthProvider(); + // Ensure minimum signature example + // jwtProvider.ValidateToken = (js,req) => + // req.GetJwtToken().LastRightPart('.').FromBase64UrlSafe().Length >= 32; + + var req = new BasicHttpRequest { + Headers = {[HttpHeaders.Authorization] = "Bearer " + authResponse.BearerToken} + }; + + Assert.That(jwtProvider.IsJwtValid(req)); + + var startSigPos = authResponse.BearerToken.LastIndexOf('.') + 1; + for (var i = startSigPos; i < authResponse.BearerToken.Length; i++) + { + req.Headers[HttpHeaders.Authorization] = "Bearer " + authResponse.BearerToken.Substring(0, i); + Assert.That(jwtProvider.IsJwtValid(req), Is.False); + } + } + + [Test] + public void Can_authenticate_using_JWT_with_FormData() + { + var client = GetClientWithBasicAuthCredentials(); + + var authResponse = client.Post(new Authenticate()); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + var request = new Secured { Name = "test" }; + var url = Config.ListeningOn.CombineWith(request.ToGetUrl()); + + var response = url.PostToUrl(new Dictionary<string,string> { + { Keywords.TokenCookie, authResponse.BearerToken } + }, accept: MimeTypes.Json) + .FromJson<SecuredResponse>(); + + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_authenticate_using_JWT_with_IHasBearerToken() + { + var authClient = GetClientWithBasicAuthCredentials(); + + var authResponse = authClient.Post(new Authenticate()); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + var client = GetClient(); + var request = new HelloJwt { BearerToken = authResponse.BearerToken, Name = "IHasBearerToken" }; + var response = client.Get(request); + + Assert.That(response.Result, Is.EqualTo("Hello, IHasBearerToken")); + } + + [Test] + public void Does_escape_JWT_with_slashes() + { + var jwtHeader = new JsonObject { + ["typ"] = "JWT", + ["alg"] = "HS256", + }; + var jwtPayload = new JsonObject { + ["iss"] = "ssjwt", + ["iat"] = "1635952233", + ["exp"] = "1635955833", + ["name"] = "Robin Doe", + ["preferred_username"] = "domainname\\robindoe", + }; + + var jwtProvider = new JwtAuthProvider { + AuthKey = AesUtils.CreateKey() + }; + var jwt = JwtAuthProvider.CreateJwt(jwtHeader, jwtPayload, jwtProvider.GetHashAlgorithm()); + + JsonObject validJwt = jwtProvider.GetVerifiedJwtPayload(jwt); + Assert.That(validJwt["preferred_username"], Is.EqualTo("domainname\\robindoe")); + + var session = new AuthUserSession(); + session.PopulateFromMap(validJwt); + Assert.That(session.UserName, Is.EqualTo("domainname\\robindoe")); + } +} + +public class JwtAuthProviderHS256HttpClientNoCookiesTests : JwtAuthProviderHS256NoCookiesTests +{ + protected override IJsonServiceClient GetClient() + { + return new JsonHttpClient(Config.ListeningOn); + } + + protected override IJsonServiceClient GetClientWithBasicAuthCredentials() + { + return new JsonHttpClient(Config.ListeningOn) + { + UserName = Username, + Password = Password, + }; + } +} + +public abstract class JwtAuthProviderNoCookiesTests +{ + public const string Username = "cookieless"; + public const string Password = "p@55word"; + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(JwtAuthProviderTests), typeof(JwtServices).Assembly) { } + + public virtual JwtAuthProvider JwtAuthProvider { get; set; } + + public override void Configure(Container container) + { + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + + container.Register<IDbConnectionFactory>(dbFactory); + container.Register<IAuthRepository>(c => + new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()) + { + UseDistinctRoleTables = true + }); + + //Create UserAuth RDBMS Tables + container.Resolve<IAuthRepository>().InitSchema(); + + //Also store User Sessions in SQL Server + container.RegisterAs<OrmLiteCacheClient, ICacheClient>(); + container.Resolve<ICacheClient>().InitSchema(); + + // just for testing, create a privateKeyXml on every instance + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + JwtAuthProvider, + })); + + Plugins.Add(new RegistrationFeature()); + + var authRepo = GetAuthRepository(); + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + } + } + + protected abstract JwtAuthProvider CreateJwtAuthProvider(); + + protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn); + + protected virtual IJsonServiceClient GetClientWithBasicAuthCredentials() => new JsonServiceClient(Config.ListeningOn) + { + UserName = Username, + Password = Password, + }; + + protected virtual IJsonServiceClient GetClientWithRefreshToken(string refreshToken = null, string accessToken = null, bool useTokenCookie = false) + { + if (refreshToken == null) + { + refreshToken = GetRefreshToken(); + } + + var client = GetClient(); + if (client is JsonServiceClient serviceClient) + { + serviceClient.RefreshToken = refreshToken; + if (!useTokenCookie) + serviceClient.BearerToken = accessToken; + return serviceClient; + } + + if (client is JsonHttpClient httpClient) + { + httpClient.RefreshToken = refreshToken; + if (!useTokenCookie) + httpClient.BearerToken = accessToken; + return httpClient; + } + + throw new NotSupportedException(client.GetType().Name); + } + + private static string CreateExpiredToken() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name); + jwtProvider.CreatePayloadFilter = (jwtPayload, session) => + jwtPayload["exp"] = DateTime.UtcNow.AddSeconds(-1).ToUnixTime().ToString(); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + jwtProvider.CreatePayloadFilter = null; + return token; + } + + private readonly ServiceStackHost appHost; + + public JwtAuthProviderNoCookiesTests() + { + appHost = new AppHost + { + JwtAuthProvider = CreateJwtAuthProvider() + } + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private string GetRefreshToken() + { + var authClient = GetClient(); + var refreshToken = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }) + .RefreshToken; + return refreshToken; + } + + [Test] + public void Can_ConvertSessionToToken() + { + var authClient = GetClient(); + var authResponse = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + RememberMe = true, + }); + Assert.That(authResponse.SessionId, Is.Not.Null); + Assert.That(authResponse.UserName, Is.EqualTo(Username)); + Assert.That(authResponse.BearerToken, Is.Not.Null); + + var jwtToken = authClient.GetTokenCookie(); //From ss-tok Cookie + Assert.That(jwtToken, Is.Null); + + var response = authClient.Send(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + + authClient.Send(new ConvertSessionToToken()); + jwtToken = authClient.GetTokenCookie(); //From ss-tok Cookie + Assert.That(jwtToken, Is.Not.Null); + + response = authClient.Send(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + } + + [Test] + public void Invalid_RefreshToken_throws_RefreshTokenException() + { + var client = GetClientWithRefreshToken("Invalid.Refresh.Token"); + try + { + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.Fail("Should throw"); + } + catch (RefreshTokenException ex) + { + ex.Message.Print(); + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + } + } + + [Test] + public async Task Invalid_RefreshToken_throws_RefreshTokenException_Async() + { + var client = GetClientWithRefreshToken("Invalid.Refresh.Token"); + try + { + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.Fail("Should throw"); + } + catch (RefreshTokenException ex) + { + ex.Message.Print(); + Assert.That(ex.StatusCode, Is.EqualTo(400)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(ArgumentException))); + } + } + + [Test] + public void Only_returns_Tokens_on_Requests_that_Authenticate_the_user() + { + var authClient = GetClient(); + var refreshToken = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }).RefreshToken; + + Assert.That(refreshToken, Is.Not.Null); //On Auth using non IAuthWithRequest + + var postAuthRefreshToken = authClient.Send(new Authenticate()).RefreshToken; + Assert.That(postAuthRefreshToken, Is.Null); //After Auth + } + + [Test] + public void Can_Auto_reconnect_with_just_RefreshToken() + { + var client = GetClientWithRefreshToken(); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Auto_reconnect_with_just_RefreshToken_with_UseTokenCookie() + { + var client = GetClientWithRefreshToken(useTokenCookie:true); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Auto_reconnect_with_RefreshToken_after_expired_token() + { + var client = GetClientWithRefreshToken(GetRefreshToken(), CreateExpiredToken()); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public async Task Can_Auto_reconnect_with_RefreshToken_after_expired_token_Async() + { + var client = GetClientWithRefreshToken(GetRefreshToken(), CreateExpiredToken()); + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Auto_reconnect_with_RefreshToken_in_OnAuthenticationRequired_after_expired_token() + { + var client = GetClient(); + if (!(client is JsonServiceClient serviceClient)) //OnAuthenticationRequired not implemented in JsonHttpClient + return; + + var called = 0; + serviceClient.BearerToken = CreateExpiredToken(); + + serviceClient.OnAuthenticationRequired = () => + { + called++; + var authClient = GetClient(); + serviceClient.BearerToken = authClient.Send(new GetAccessToken + { + RefreshToken = GetRefreshToken(), + }).AccessToken; + }; + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + Assert.That(called, Is.EqualTo(1)); + } + + [Test] + public void Does_return_token_on_subsequent_BasicAuth_Authentication_requests() + { + var client = GetClientWithBasicAuthCredentials(); + + var response = client.Post(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + + response = client.Post(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + } + + [Test] + public async Task Does_return_token_on_subsequent_BasicAuth_Authentication_requests_Async() + { + var client = GetClientWithBasicAuthCredentials(); + + var response = await client.PostAsync(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + + response = await client.PostAsync(new Authenticate()); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + } + + [Test] + public void Does_return_token_on_subsequent_Credentials_Authentication_requests() + { + var client = GetClient(); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + RememberMe = true, + }); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + + response = client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + RememberMe = true, + }); + Assert.That(response.BearerToken, Is.Not.Null); + Assert.That(response.RefreshToken, Is.Not.Null); + + response = client.Post(new Authenticate()); + Assert.That(response.BearerToken, Is.Null); + Assert.That(response.RefreshToken, Is.Null); + } + + [Test] + public void Can_validate_valid_token() + { + var authClient = GetClient(); + var jwt = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }).BearerToken; + + var jwtProvider = AuthenticateService.GetJwtAuthProvider(); + Assert.That(jwtProvider.IsJwtValid(jwt)); + + var jwtPayload = jwtProvider.GetValidJwtPayload(jwt); + Assert.That(jwtPayload, Is.Not.Null); + Assert.That(jwtPayload["preferred_username"], Is.EqualTo(Username)); + } + + [Test] + public void Does_not_validate_invalid_token() + { + var expiredJwt = CreateExpiredToken(); + + var jwtProvider = AuthenticateService.GetJwtAuthProvider(); + Assert.That(jwtProvider.IsJwtValid(expiredJwt), Is.False); + + Assert.That(jwtProvider.GetValidJwtPayload(expiredJwt), Is.Null); + } + + [Test] + public void Does_validate_multiple_audiences() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name); + + string CreateJwtWithAudiences(params string[] audiences) + { + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + IsAuthenticated = true, + }, + issuer: jwtProvider.Issuer, + expireIn: jwtProvider.ExpireTokensIn, + audiences: audiences); + + var jwtToken = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm()); + return jwtToken; + } + + jwtProvider.Audiences = new List<string> { "foo", "bar" }; + var jwtNoAudience = CreateJwtWithAudiences(); + Assert.That(jwtProvider.IsJwtValid(jwtNoAudience)); + + var jwtWrongAudience = CreateJwtWithAudiences("qux"); + Assert.That(!jwtProvider.IsJwtValid(jwtWrongAudience)); + + var jwtPartialAudienceMatch = CreateJwtWithAudiences("bar","qux"); + Assert.That(jwtProvider.IsJwtValid(jwtPartialAudienceMatch)); + + jwtProvider.Audience = "foo"; + Assert.That(!jwtProvider.IsJwtValid(jwtPartialAudienceMatch)); + + jwtProvider.Audience = null; + Assert.That(jwtProvider.IsJwtValid(jwtPartialAudienceMatch)); + } +} + +public class JwtAuthProviderIntegrationNoCookiesTests +{ + public const string Username = "cookieless"; + public const string Password = "p@55word"; + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + + private readonly ServiceStackHost appHost; + + public JwtAuthProviderIntegrationNoCookiesTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(JwtAuthProviderIntegrationTests), typeof(JwtServices).Assembly) { } + + public override void Configure(Container container) + { + // just for testing, create a privateKeyXml on every instance + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + new JwtAuthProvider + { + UseTokenCookie = false, + AuthKey = AuthKey, + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + }, + })); + + Plugins.Add(new RegistrationFeature()); + + container.Register<IAuthRepository>(c => new InMemoryAuthRepository()); + + var authRepo = GetAuthRepository(); + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + + Plugins.Add(new RequestLogsFeature { + EnableSessionTracking = true, + ExcludeRequestDtoTypes = new[] { typeof(Authenticate) }, + }); + } + } + + protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn) { + UserName = Username, + Password = Password, + }; + + protected virtual IJsonServiceClient GetJwtClient() => new JsonServiceClient(Config.ListeningOn) { + BearerToken = GetClient().Post(new Authenticate()).BearerToken + }; + + [Test] + public void Does_track_JWT_Sessions_calling_Authenticate_Services() + { + var client = GetJwtClient(); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var reqLogger = HostContext.TryResolve<IRequestLogger>(); + var lastEntrySession = reqLogger.GetLatestLogs(1)[0]?.Session as AuthUserSession; + Assert.That(lastEntrySession, Is.Not.Null); + Assert.That(lastEntrySession.AuthProvider, Is.EqualTo("jwt")); + Assert.That(lastEntrySession.UserName, Is.EqualTo(Username)); + } + + [Test] + public void Does_track_JWT_Sessions_calling_non_Authenticate_Services() + { + var client = GetJwtClient(); + + var request = new Unsecure { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + var reqLogger = HostContext.TryResolve<IRequestLogger>(); + var lastEntrySession = reqLogger.GetLatestLogs(1)[0]?.Session as AuthUserSession; + Assert.That(lastEntrySession, Is.Not.Null); + Assert.That(lastEntrySession.AuthProvider, Is.EqualTo("jwt")); + Assert.That(lastEntrySession.UserName, Is.EqualTo(Username)); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderRsa256ReaderTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderRsa256ReaderTests.cs new file mode 100644 index 00000000000..025cd5cdf1f --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderRsa256ReaderTests.cs @@ -0,0 +1,144 @@ +using System.Security.Cryptography; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class JwtAuthProviderRsa256ReaderTests +{ + readonly RSAParameters privateKey; + readonly RSAParameters publicKey; + readonly string privateKeyXml; + readonly string publicKeyXml; + + public const string Username = "rsa256reader"; + public const string Password = "p@55word"; + private readonly ServiceStackHost appHost; + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(JwtAuthProviderTests), typeof(JwtServices).Assembly) { } + + public virtual JwtAuthProviderReader JwtAuthProviderReader { get; set; } + + public override void Configure(Container container) + { + // just for testing, create a privateKeyXml on every instance + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + JwtAuthProviderReader, + })); + + Plugins.Add(new RegistrationFeature()); + + container.Register<IAuthRepository>(x => new InMemoryAuthRepository()); + + var authRepo = GetAuthRepository(); + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + } + } + + public JwtAuthProviderRsa256ReaderTests() + { + privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + publicKey = privateKey.ToPublicRsaParameters(); + privateKeyXml = privateKey.ToPrivateKeyXml(); + publicKeyXml = privateKey.ToPublicKeyXml(); + + appHost = new AppHost + { + JwtAuthProviderReader = CreateJwtAuthProviderReader() + } + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + protected JwtAuthProvider CreateJwtAuthProvider() + { + return new() { + HashAlgorithm = "RS256", + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + PrivateKeyXml = privateKeyXml, + }; + } + + protected JwtAuthProviderReader CreateJwtAuthProviderReader() + { + return new() { + HashAlgorithm = "RS256", + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + PublicKeyXml = publicKeyXml, + }; + } + protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn); + + private string CreateJwtToken() + { + var jwtProvider = CreateJwtAuthProvider(); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + IsAuthenticated = true, + }, + issuer: jwtProvider.Issuer, + expireIn: jwtProvider.ExpireTokensIn, + audiences: jwtProvider.Audiences, + roles: new[] {"TheRole"}, + permissions: new[] {"ThePermission"}); + + var jwtToken = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm()); + return jwtToken; + } + + [Test] + public void Can_create_JWT_RSA_Signed_Token_validated_with_Reader() + { + var jwtToken = CreateJwtToken(); + jwtToken.Print(); + + var jwtAuth = CreateJwtAuthProviderReader(); + + // JWT Signature is Verified + var jwtBody = jwtAuth.GetVerifiedJwtPayload(null, jwtToken.Split('.')); + Assert.That(jwtBody, Is.Not.Null); + Assert.That(jwtBody["sub"], Is.EqualTo("1")); + + // JWT is Valid + var invalidError = jwtAuth.GetInvalidJwtPayloadError(jwtBody); + Assert.That(invalidError, Is.Null); + + Assert.That(jwtAuth.IsJwtValid(jwtToken)); + } + + [Test] + public void Can_Authenticate_with_Reader() + { + var authClient = GetClient(); + authClient.BearerToken = CreateJwtToken(); + + var response = authClient.Send(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderTests.cs new file mode 100644 index 00000000000..fd80d7e2925 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtAuthProviderTests.cs @@ -0,0 +1,952 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Data; +using ServiceStack.Host; +using ServiceStack.OrmLite; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class JwtAuthProviderRsaEncryptedTests : JwtAuthProviderTests +{ + protected override JwtAuthProvider CreateJwtAuthProvider() + { + var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + var publicKey = privateKey.ToPublicRsaParameters(); + var privateKeyXml = privateKey.ToPrivateKeyXml(); + var publicKeyXml = privateKey.ToPublicKeyXml(); + + return new JwtAuthProvider + { + HashAlgorithm = "RS256", + PrivateKeyXml = privateKeyXml, + EncryptPayload = true, + RequireSecureConnection = false, + }; + } +} + +public class JwtAuthProviderRsaTests : JwtAuthProviderTests +{ + protected override JwtAuthProvider CreateJwtAuthProvider() + { + var privateKey = RsaUtils.CreatePrivateKeyParams(RsaKeyLengths.Bit2048); + var publicKey = privateKey.ToPublicRsaParameters(); + var privateKeyXml = privateKey.ToPrivateKeyXml(); + var publicKeyXml = privateKey.ToPublicKeyXml(); + + return new JwtAuthProvider + { + HashAlgorithm = "RS256", + PrivateKeyXml = privateKeyXml, + RequireSecureConnection = false, + }; + } +} + +public class JwtAuthProviderHS256Tests : JwtAuthProviderTests +{ + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + + protected override JwtAuthProvider CreateJwtAuthProvider() => new() { + AuthKey = AuthKey, + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + }; + + [Test] + public void Can_manually_create_an_authenticated_UserSession_in_Token() + { + var jwtProvider = CreateJwtAuthProvider(); + + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + IsAuthenticated = true, + }, + issuer: jwtProvider.Issuer, + expireIn: jwtProvider.ExpireTokensIn, + audiences: jwtProvider.Audiences, + roles: new[] {"TheRole"}, + permissions: new[] {"ThePermission"}); + + var jwtToken = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm()); + + var client = GetClient(); + + try + { + client.Send(new HelloJwt { Name = "no jwt" }); + Assert.Fail("should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + } + + client.SetTokenCookie(jwtToken); + var response = client.Send(new HelloJwt { Name = "from Custom JWT" }); + Assert.That(response.Result, Is.EqualTo("Hello, from Custom JWT")); + } + + [Test] + public void Can_authenticate_using_JWT_with_QueryString() + { + var client = GetClientWithBasicAuthCredentials(); + + var authResponse = client.Post(new Authenticate()); + AssertAuthenticateResponse(client, authResponse); + + var request = new Secured { Name = "test" }; + var url = Config.ListeningOn.CombineWith(request.ToGetUrl()) + .AddQueryParam(Keywords.TokenCookie, client.GetTokenCookie()); + + var response = url.PostJsonToUrl("{}") + .FromJson<SecuredResponse>(); + + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Requires_full_Signature_to_Authenticate() + { + var client = GetClientWithBasicAuthCredentials(); + + var authResponse = client.Post(new Authenticate()); + AssertAuthenticateResponse(client, authResponse); + + var jwtProvider = (JwtAuthProvider) AuthenticateService.GetJwtAuthProvider(); + // Ensure minimum signature example + // jwtProvider.ValidateToken = (js,req) => + // req.GetJwtToken().LastRightPart('.').FromBase64UrlSafe().Length >= 32; + + var bearerToken = client.GetTokenCookie(); + var req = new BasicHttpRequest { + Headers = {[HttpHeaders.Authorization] = "Bearer " + bearerToken} + }; + + Assert.That(jwtProvider.IsJwtValid(req)); + + var startSigPos = bearerToken.LastIndexOf('.') + 1; + for (var i = startSigPos; i < bearerToken.Length; i++) + { + req.Headers[HttpHeaders.Authorization] = "Bearer " + bearerToken.Substring(0, i); + Assert.That(jwtProvider.IsJwtValid(req), Is.False); + } + } + + [Test] + public void Can_authenticate_using_JWT_with_FormData() + { + var client = GetClientWithBasicAuthCredentials(); + + var authResponse = client.Post(new Authenticate()); + AssertAuthenticateResponse(client, authResponse); + + var request = new Secured { Name = "test" }; + var url = Config.ListeningOn.CombineWith(request.ToGetUrl()); + + var response = url.PostToUrl(new Dictionary<string,string> { + { Keywords.TokenCookie, client.GetTokenCookie() } + }, accept: MimeTypes.Json) + .FromJson<SecuredResponse>(); + + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_authenticate_using_JWT_with_IHasBearerToken() + { + var authClient = GetClientWithBasicAuthCredentials(); + + var authResponse = authClient.Post(new Authenticate()); + AssertAuthenticateResponse(authClient, authResponse); + + var client = GetClient(); + var request = new HelloJwt { BearerToken = authClient.GetTokenCookie(), Name = "IHasBearerToken" }; + var response = client.Get(request); + + Assert.That(response.Result, Is.EqualTo("Hello, IHasBearerToken")); + } + + [Test] + public void Does_escape_JWT_with_slashes() + { + var jwtHeader = new JsonObject { + ["typ"] = "JWT", + ["alg"] = "HS256", + }; + var jwtPayload = new JsonObject { + ["iss"] = "ssjwt", + ["iat"] = "1635952233", + ["exp"] = "1635955833", + ["name"] = "Robin Doe", + ["preferred_username"] = "domainname\\robindoe", + }; + + var jwtProvider = new JwtAuthProvider { + AuthKey = AesUtils.CreateKey() + }; + var jwt = JwtAuthProvider.CreateJwt(jwtHeader, jwtPayload, jwtProvider.GetHashAlgorithm()); + + JsonObject validJwt = jwtProvider.GetVerifiedJwtPayload(jwt); + Assert.That(validJwt["preferred_username"], Is.EqualTo("domainname\\robindoe")); + + var session = new AuthUserSession(); + session.PopulateFromMap(validJwt); + Assert.That(session.UserName, Is.EqualTo("domainname\\robindoe")); + } +} + +public class JwtAuthProviderHS256HttpClientTests : JwtAuthProviderHS256Tests +{ + protected override IJsonServiceClient GetClient() + { + return new JsonHttpClient(Config.ListeningOn); + } + + protected override IJsonServiceClient GetClientWithBasicAuthCredentials() + { + return new JsonHttpClient(Config.ListeningOn) + { + UserName = Username, + Password = Password, + }; + } +} + +public abstract class JwtAuthProviderTests +{ + public const string Username = "mythz"; + public const string Password = "p@55word"; + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(JwtAuthProviderTests), typeof(JwtServices).Assembly) { } + + public virtual JwtAuthProvider JwtAuthProvider { get; set; } + + public override void Configure(Container container) + { + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + + container.Register<IDbConnectionFactory>(dbFactory); + container.Register<IAuthRepository>(c => + new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()) + { + UseDistinctRoleTables = true + }); + + //Create UserAuth RDBMS Tables + container.Resolve<IAuthRepository>().InitSchema(); + + //Also store User Sessions in SQL Server + container.RegisterAs<OrmLiteCacheClient, ICacheClient>(); + container.Resolve<ICacheClient>().InitSchema(); + + // just for testing, create a privateKeyXml on every instance + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + JwtAuthProvider, + })); + + Plugins.Add(new RegistrationFeature()); + + var authRepo = GetAuthRepository(); + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + } + } + + protected abstract JwtAuthProvider CreateJwtAuthProvider(); + + protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn); + + protected virtual IJsonServiceClient GetClientWithBasicAuthCredentials() => new JsonServiceClient(Config.ListeningOn) + { + UserName = Username, + Password = Password, + }; + + protected virtual IJsonServiceClient GetClientWithRefreshToken(string refreshToken = null, string accessToken = null, bool useTokenCookie = false) + { + if (refreshToken == null) + refreshToken = GetRefreshToken(); + + var client = GetClient(); + client.SetRefreshTokenCookie(refreshToken); + if (!useTokenCookie) + client.SetTokenCookie(accessToken); + return client; + } + + private static string CreateExpiredToken() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name); + jwtProvider.CreatePayloadFilter = (jwtPayload, session) => + jwtPayload["exp"] = DateTime.UtcNow.AddSeconds(-1).ToUnixTime().ToString(); + + var token = jwtProvider.CreateJwtBearerToken(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com" + }); + + jwtProvider.CreatePayloadFilter = null; + return token; + } + + private readonly ServiceStackHost appHost; + + public JwtAuthProviderTests() + { + appHost = new AppHost + { + JwtAuthProvider = CreateJwtAuthProvider() + } + .Init() + .Start(Config.ListeningOn); + } + + protected static void AssertAuthenticateResponse(IJsonServiceClient client, AuthenticateResponse authResponse) + { + Assert.That(authResponse.BearerToken, Is.Null); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + private string GetRefreshToken() + { + var authClient = GetClient(); + authClient.Send(new Authenticate { + provider = "credentials", + UserName = Username, + Password = Password, + }); + var refreshToken = authClient.GetRefreshTokenCookie(); + Assert.That(refreshToken, Is.Not.Null); + return refreshToken; + } + + [Test] + public void Can_get_TokenCookie() + { + var authClient = GetClient(); + var authResponse = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + Assert.That(authResponse.SessionId, Is.Not.Null); + Assert.That(authResponse.UserName, Is.EqualTo(Username)); + + var response = authClient.Send(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + + var jwtToken = authClient.GetTokenCookie(); //From ss-tok Cookie + Assert.That(jwtToken, Is.Not.Null); + } + + [Test] + public void Can_ConvertSessionToToken() + { + var authClient = GetClient(); + var authResponse = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + RememberMe = true, + }); + Assert.That(authResponse.SessionId, Is.Not.Null); + Assert.That(authResponse.UserName, Is.EqualTo(Username)); + Assert.That(authResponse.BearerToken, Is.Null); + + var jwtToken = authClient.GetTokenCookie(); //From ss-tok Cookie + Assert.That(jwtToken, Is.Not.Null); + + var response = authClient.Send(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + + authClient.Send(new ConvertSessionToToken()); + jwtToken = authClient.GetTokenCookie(); //From ss-tok Cookie + Assert.That(jwtToken, Is.Not.Null); + + response = authClient.Send(new HelloJwt { Name = "from auth service" }); + Assert.That(response.Result, Is.EqualTo("Hello, from auth service")); + } + + [Test] + public void Invalid_RefreshToken_using_TokenCookies_throws_Unauthorized() + { + var client = GetClientWithRefreshToken("Invalid.Refresh.Token"); + try + { + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.Message.Print(); + Assert.That(ex.StatusCode, Is.EqualTo(401)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + } + + [Test] + public async Task Invalid_RefreshToken_using_TokenCookies_throws_Unauthorized_Async() + { + var client = GetClientWithRefreshToken("Invalid.Refresh.Token"); + try + { + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.Message.Print(); + Assert.That(ex.StatusCode, Is.EqualTo(401)); + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + } + + [Test] + public void Only_returns_Tokens_on_Requests_that_Authenticate_the_user() + { + var authClient = GetClient(); + var authResponse = authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + + Assert.That(authClient.GetRefreshTokenCookie(), Is.Not.Null); //On Auth using non IAuthWithRequest + + var postAuthRefreshToken = authClient.Send(new Authenticate()).RefreshToken; + Assert.That(postAuthRefreshToken, Is.Null); //After Auth + } + + [Test] + public void Can_Auto_reconnect_with_just_RefreshToken() + { + var client = GetClientWithRefreshToken(); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Auto_reconnect_with_just_RefreshToken_with_UseTokenCookie() + { + var client = GetClientWithRefreshToken(useTokenCookie:true); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Auto_reconnect_with_RefreshToken_after_expired_token() + { + var client = GetClientWithRefreshToken(GetRefreshToken(), CreateExpiredToken()); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public async Task Can_Auto_reconnect_with_RefreshToken_after_expired_token_Async() + { + var client = GetClientWithRefreshToken(GetRefreshToken(), CreateExpiredToken()); + + var request = new Secured { Name = "test" }; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + } + + [Test] + public void Can_Auto_reconnect_with_RefreshToken_in_OnAuthenticationRequired_after_expired_token() + { + var client = GetClient(); + if (!(client is JsonServiceClient serviceClient)) //OnAuthenticationRequired not implemented in JsonHttpClient + return; + + var called = 0; + serviceClient.BearerToken = CreateExpiredToken(); + + serviceClient.OnAuthenticationRequired = () => + { + called++; + var authClient = GetClient(); + var authResponse = authClient.Send(new GetAccessToken { + RefreshToken = GetRefreshToken(), + }); + serviceClient.BearerToken = authClient.GetTokenCookie(); + }; + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + Assert.That(called, Is.EqualTo(1)); + } + + [Test] + public void Does_return_token_on_subsequent_BasicAuth_Authentication_requests() + { + var client = GetClientWithBasicAuthCredentials(); + + var response = client.Post(new Authenticate()); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + + response = client.Post(new Authenticate()); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + } + + [Test] + public async Task Does_return_token_on_subsequent_BasicAuth_Authentication_requests_Async() + { + var client = GetClientWithBasicAuthCredentials(); + + var response = await client.PostAsync(new Authenticate()); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + + response = await client.PostAsync(new Authenticate()); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + } + + [Test] + public void Does_return_token_on_subsequent_Credentials_Authentication_requests() + { + var client = GetClient(); + + var response = client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + RememberMe = true, + }); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + + response = client.Post(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + RememberMe = true, + }); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + + response = client.Post(new Authenticate()); + Assert.That(client.GetTokenCookie(), Is.Not.Null); + Assert.That(client.GetRefreshTokenCookie(), Is.Not.Null); + } + + [Test] + public void Can_validate_valid_token() + { + var authClient = GetClient(); + authClient.Send(new Authenticate + { + provider = "credentials", + UserName = Username, + Password = Password, + }); + + var jwtProvider = AuthenticateService.GetJwtAuthProvider(); + var jwt = authClient.GetTokenCookie(); + Assert.That(jwtProvider.IsJwtValid(jwt)); + + var jwtPayload = jwtProvider.GetValidJwtPayload(jwt); + Assert.That(jwtPayload, Is.Not.Null); + Assert.That(jwtPayload["preferred_username"], Is.EqualTo(Username)); + } + + [Test] + public void Does_not_validate_invalid_token() + { + var expiredJwt = CreateExpiredToken(); + + var jwtProvider = AuthenticateService.GetJwtAuthProvider(); + Assert.That(jwtProvider.IsJwtValid(expiredJwt), Is.False); + + Assert.That(jwtProvider.GetValidJwtPayload(expiredJwt), Is.Null); + } + + [Test] + public void Does_validate_multiple_audiences() + { + var jwtProvider = (JwtAuthProvider)AuthenticateService.GetAuthProvider(JwtAuthProviderReader.Name); + + string CreateJwtWithAudiences(params string[] audiences) + { + var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm); + var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession + { + UserAuthId = "1", + DisplayName = "Test", + Email = "as@if.com", + IsAuthenticated = true, + }, + issuer: jwtProvider.Issuer, + expireIn: jwtProvider.ExpireTokensIn, + audiences: audiences); + + var jwtToken = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm()); + return jwtToken; + } + + jwtProvider.Audiences = new List<string> { "foo", "bar" }; + var jwtNoAudience = CreateJwtWithAudiences(); + Assert.That(jwtProvider.IsJwtValid(jwtNoAudience)); + + var jwtWrongAudience = CreateJwtWithAudiences("qux"); + Assert.That(!jwtProvider.IsJwtValid(jwtWrongAudience)); + + var jwtPartialAudienceMatch = CreateJwtWithAudiences("bar","qux"); + Assert.That(jwtProvider.IsJwtValid(jwtPartialAudienceMatch)); + + jwtProvider.Audience = "foo"; + Assert.That(!jwtProvider.IsJwtValid(jwtPartialAudienceMatch)); + + jwtProvider.Audience = null; + Assert.That(jwtProvider.IsJwtValid(jwtPartialAudienceMatch)); + } +} + +public class JwtAuthProviderIntegrationTests +{ + public const string Username = "mythz"; + public const string Password = "p@55word"; + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + + private readonly ServiceStackHost appHost; + + public JwtAuthProviderIntegrationTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(JwtAuthProviderIntegrationTests), typeof(JwtServices).Assembly) { } + + public override void Configure(Container container) + { + // just for testing, create a privateKeyXml on every instance + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] + { + new BasicAuthProvider(), + new CredentialsAuthProvider(), + new JwtAuthProvider + { + AuthKey = AuthKey, + RequireSecureConnection = false, + AllowInQueryString = true, + AllowInFormData = true, + }, + })); + + Plugins.Add(new RegistrationFeature()); + + container.Register<IAuthRepository>(c => new InMemoryAuthRepository()); + + var authRepo = GetAuthRepository(); + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + + Plugins.Add(new RequestLogsFeature { + EnableSessionTracking = true, + ExcludeRequestDtoTypes = new[] { typeof(Authenticate) }, + }); + } + } + + protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn) { + UserName = Username, + Password = Password, + }; + + protected virtual IJsonServiceClient GetJwtClient() + { + var authClient = GetClient(); + var authResponse = authClient.Post(new Authenticate()); + return new JsonServiceClient(Config.ListeningOn) { + BearerToken = authClient.GetTokenCookie() + }; + } + + [Test] + public void Does_track_JWT_Sessions_calling_Authenticate_Services() + { + var client = GetJwtClient(); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var reqLogger = HostContext.TryResolve<IRequestLogger>(); + var lastEntrySession = reqLogger.GetLatestLogs(1)[0]?.Session as AuthUserSession; + Assert.That(lastEntrySession, Is.Not.Null); + Assert.That(lastEntrySession.AuthProvider, Is.EqualTo("jwt")); + Assert.That(lastEntrySession.UserName, Is.EqualTo(Username)); + } + + [Test] + public void Does_track_JWT_Sessions_calling_non_Authenticate_Services() + { + var client = GetJwtClient(); + + var request = new Unsecure { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Name, Is.EqualTo(request.Name)); + + var reqLogger = HostContext.TryResolve<IRequestLogger>(); + var lastEntrySession = reqLogger.GetLatestLogs(1)[0]?.Session as AuthUserSession; + Assert.That(lastEntrySession, Is.Not.Null); + Assert.That(lastEntrySession.AuthProvider, Is.EqualTo("jwt")); + Assert.That(lastEntrySession.UserName, Is.EqualTo(Username)); + } +} + +public class JwtAuthProviderTokenCookieTests +{ + public const string Username = "ss-reftok"; + public const string Password = "p@55word"; + private static readonly byte[] AuthKey = AesUtils.CreateKey(); + + private readonly ServiceStackHost appHost; + + public JwtAuthProviderTokenCookieTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(JwtAuthProviderTokenCookieTests), typeof(JwtServices).Assembly) { } + + public override void Configure(Container container) + { + // just for testing, create a privateKeyXml on every instance + Plugins.Add(new AuthFeature(() => new AuthUserSession(), + new IAuthProvider[] { + new CredentialsAuthProvider(), + new JwtAuthProvider + { + AuthKey = AuthKey, + RequireSecureConnection = false, + UseTokenCookie = true, + AllowInQueryString = true, + AllowInFormData = true, + }, + })); + + container.Register<IAuthRepository>(c => new InMemoryAuthRepository()); + + var authRepo = GetAuthRepository(); + authRepo.CreateUserAuth(new UserAuth + { + Id = 1, + UserName = Username, + FirstName = "First", + LastName = "Last", + DisplayName = "Display", + }, Password); + + Plugins.Add(new RequestLogsFeature { + EnableSessionTracking = true, + ExcludeRequestDtoTypes = new[] { typeof(Authenticate) }, + }); + } + } + + [Test] + public void Can_use_RefreshTokenCookie_to_authenticate_and_get_new_AccessToken() + { + string initialAccessToken = null; + var client = new JsonServiceClient(Config.ListeningOn) { + ResponseFilter = res => { + if (initialAccessToken == null) + { + var accessToken = res.Cookies[Keywords.TokenCookie]; + Assert.That(accessToken.Value, Is.Not.Null); + initialAccessToken = accessToken.Value; + var refreshToken = res.Cookies[Keywords.RefreshTokenCookie]; + Assert.That(refreshToken.Value, Is.Not.Null); + } + } + }; + var authResponse = client.Post(new Authenticate { + provider = "credentials", + UserName = Username, + Password = Password + }); + + var request = new Secured { Name = "test" }; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var reqLogger = HostContext.TryResolve<IRequestLogger>(); + var lastEntrySession = reqLogger.GetLatestLogs(1)[0]?.Session as AuthUserSession; + Assert.That(lastEntrySession, Is.Not.Null); + Assert.That(lastEntrySession.AuthProvider, Is.EqualTo("jwt")); + Assert.That(lastEntrySession.UserName, Is.EqualTo(Username)); + + string lastAccessToken = null; + client.ResponseFilter = res => { + var accessToken = res.Cookies[Keywords.TokenCookie]; + lastAccessToken = accessToken.Value; + }; + var i = 0; + do + { + var accessTokenResponse = client.Post(new GetAccessToken()); + ExecUtils.SleepBackOffMultiplier(++i); //need to wait for iat to tick +1s so JWT's are different + } + while (lastAccessToken == initialAccessToken); + } + + [Test] + public void Does_auto_fetch_new_AccessToken_with_RefreshTokenCookie_ServiceClient() => + AssertDoesGetAccessTokenUsingRefreshTokenCookie(new JsonServiceClient(Config.ListeningOn)); + + [Test] + public void Does_auto_fetch_new_AccessToken_with_RefreshTokenCookie_HttpClient() => + AssertDoesGetAccessTokenUsingRefreshTokenCookie(new JsonHttpClient(Config.ListeningOn)); + + private static void AssertDoesGetAccessTokenUsingRefreshTokenCookie(IJsonServiceClient client) + { + var authResponse = client.Post(new Authenticate { + provider = "credentials", + UserName = Username, + Password = Password + }); + + var initialAccessToken = client.GetTokenCookie(); + var initialRefreshToken = client.GetRefreshTokenCookie(); + Assert.That(initialAccessToken, Is.Not.Null); + Assert.That(initialRefreshToken, Is.Not.Null); + + var request = new Secured {Name = "test"}; + var response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var jwtAuthProvider = AuthenticateService.GetRequiredJwtAuthProvider(); + jwtAuthProvider.InvalidateJwtIds.Add(jwtAuthProvider.LastJwtId()); + // JwtAuthProvider.PrintDump(initialAccessToken); + // JwtAuthProvider.PrintDump(initialRefreshToken); + + response = client.Send(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + var latestAccessToken = client.GetTokenCookie(); + Assert.That(latestAccessToken, Is.Not.EqualTo(initialAccessToken)); + } + + [Test] + public async Task Does_auto_fetch_new_AccessToken_with_RefreshTokenCookie_ServiceClient_Async() => + await AssertDoesGetAccessTokenUsingRefreshTokenCookieAsync(new JsonServiceClient(Config.ListeningOn)); + + [Test] + public async Task Does_auto_fetch_new_AccessToken_with_RefreshTokenCookie_HttpClient_Async() => + await AssertDoesGetAccessTokenUsingRefreshTokenCookieAsync(new JsonHttpClient(Config.ListeningOn)); + + private static async Task AssertDoesGetAccessTokenUsingRefreshTokenCookieAsync(IJsonServiceClient client) + { + var authResponse = await client.PostAsync(new Authenticate { + provider = "credentials", + UserName = Username, + Password = Password + }); + + var initialAccessToken = client.GetTokenCookie(); + var initialRefreshToken = client.GetRefreshTokenCookie(); + Assert.That(initialAccessToken, Is.Not.Null); + Assert.That(initialRefreshToken, Is.Not.Null); + + var request = new Secured {Name = "test"}; + var response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + + var jwtAuthProvider = AuthenticateService.GetRequiredJwtAuthProvider(); + jwtAuthProvider.InvalidateJwtIds.Add(jwtAuthProvider.LastJwtId()); + // JwtAuthProvider.PrintDump(initialAccessToken); + // JwtAuthProvider.PrintDump(initialRefreshToken); + + response = await client.SendAsync(request); + Assert.That(response.Result, Is.EqualTo(request.Name)); + var latestAccessToken = client.GetTokenCookie(); + Assert.That(latestAccessToken, Is.Not.EqualTo(initialAccessToken)); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtServices.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtServices.cs new file mode 100644 index 00000000000..c4c4195f731 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/JwtServices.cs @@ -0,0 +1,20 @@ +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class HelloJwt : IReturn<HelloJwtResponse>, IHasBearerToken +{ + public string Name { get; set; } + public string BearerToken { get; set; } +} +public class HelloJwtResponse +{ + public string Result { get; set; } +} + +[Authenticate] +public class JwtServices : Service +{ + public object Any(HelloJwt request) + { + return new HelloJwtResponse { Result = $"Hello, {request.Name}" }; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs new file mode 100644 index 00000000000..7c45f09779b --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs @@ -0,0 +1,162 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Threading.Tasks; + +namespace ServiceStack.WebHost.Endpoints.Tests.UseCases; + +public class SecureConfig +{ + public static string PublicKeyXml = "<RSAKeyValue><Modulus>s1/rrg2UxchL5O4yFKCHTaDQgr8Bfkr1kmPf8TCXUFt4WNgAxRFGJ4ap1Kc22rt/k0BRJmgC3xPIh7Z6HpYVzQroXuYI6+q66zyk0DRHG7ytsoMiGWoj46raPBXRH9Gj5hgv+E3W/NRKtMYXqq60hl1DvtGLUs2wLGv15K9NABc=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; + public static string PrivateKeyXml = "<RSAKeyValue><Modulus>s1/rrg2UxchL5O4yFKCHTaDQgr8Bfkr1kmPf8TCXUFt4WNgAxRFGJ4ap1Kc22rt/k0BRJmgC3xPIh7Z6HpYVzQroXuYI6+q66zyk0DRHG7ytsoMiGWoj46raPBXRH9Gj5hgv+E3W/NRKtMYXqq60hl1DvtGLUs2wLGv15K9NABc=</Modulus><Exponent>AQAB</Exponent><P>6CiNjgn8Ov6nodG56rCOXBoSGksYUf/2C8W23sEBfwfLtKyqTbTk3WolBj8sY8QptjwFBF4eaQiFdVLt3jg08w==</P><Q>xcuu4OGTcSOs5oYqyzsQrOAys3stMauM2RYLIWqw7JGEF1IV9LBwbaW/7foq2dG8saEI48jxcskySlDgq5dhTQ==</Q><DP>KqzhsH13ZyTOjblusox37shAEaNCOjiR8wIKJpJWAxLcyD6BI72f4G+VlLtiHoi9nikURwRCFM6jMbjnztSILw==</DP><DQ>H4CvW7XRy+VItnaL/k5r+3zB1oA51H1kM3clUq8xepw6k5RJVu17GpuZlAeSJ5sWGJxzVAQ/IG8XCWsUPYAgyQ==</DQ><InverseQ>vTLuAT3rSsoEdNwZeH2/JDEWmQ1NGa5PUq1ak1UbDD0snhsfJdLo6at3isRqEtPVsSUK6I07Nrfkd6okGhzGDg==</InverseQ><D>M8abO9lVuSVQqtsKf6O6inDB3wuNPcwbSE8l4/O3qY1Nlq96wWd0DZK0UNqXXdnDQFjPU7uwIH4QYwQMCeoejl3dZlllkyvKVa3jihImDD++qgswX2DmHGDqTIkVABf1NF730gqTmt1kqXoVp5Y+VcO7CZPEygIQyTK4WwYlRjk=</D></RSAKeyValue>"; + + public static string FallbackPublicKeyXml = "<RSAKeyValue><Modulus>pj18q4mUIQbF2AT3oQc+ba+vynhg91M+qdpqF2PQ/ud0kdsEbWu5FtP2RvRsuj7blTnBTnZ1yeXUMZKSCLhuKrkqfA1pomGoigiM6stExi/OqZhoKBDJqNt4QZXzNVKrRBPS7GvCYUcm78AmwivSfJN9nF58QunZxHjvmTsnmNcPOOC5+YJDUI0S68v5sYvVhZquvrgmfyhZW1Is8T+AmL32UfOlzktQCFyASfOhYN1gb3/DwGoli41vN5lWoWNbtf/aJFUOwBoTFignE0tey6X5TXcgIZp5HtloIDqgOQBD0xClOpRwYuMwefw6DYP0/fImodq3H/RSTOhtoXspsQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; + public static string FallbackPrivateKeyXml = "<RSAKeyValue><Modulus>pj18q4mUIQbF2AT3oQc+ba+vynhg91M+qdpqF2PQ/ud0kdsEbWu5FtP2RvRsuj7blTnBTnZ1yeXUMZKSCLhuKrkqfA1pomGoigiM6stExi/OqZhoKBDJqNt4QZXzNVKrRBPS7GvCYUcm78AmwivSfJN9nF58QunZxHjvmTsnmNcPOOC5+YJDUI0S68v5sYvVhZquvrgmfyhZW1Is8T+AmL32UfOlzktQCFyASfOhYN1gb3/DwGoli41vN5lWoWNbtf/aJFUOwBoTFignE0tey6X5TXcgIZp5HtloIDqgOQBD0xClOpRwYuMwefw6DYP0/fImodq3H/RSTOhtoXspsQ==</Modulus><Exponent>AQAB</Exponent><P>5zZpGMnXoOeGrG2Z5auY3dcUgly5735TBn+1ot5um1x9umHSPAIrazNuteZQyD4bNs7z+0WPkCcUiuvVGbuTgepw644WPO36SMQ5gSsgjttNedGWnD8esHl/Pm1/F+IzHjuU2MZ/rZlyFsRu3C+tXgA1uQjtFnLHF+n5qmBa8Uk=</P><Q>uA/rxcOmWbvri+yDT7f/6iHB+JQDiHQM8OAcjHl5FsEb+OM/2WgOvwtr7BdTsPaaFa6VyXyEnWIdZ1F43V5tj+vwYGO26e+AwDIQAb7ma/1rb7J9LXJ4SH1kta/AL4mr4QjS39+M/0ae2IaBiG6gpufl9d86nMY5qOY5OZIrXSk=</Q><DP>PBaf6ZlLOL3y+gzh2hZmfADRi6+dguhJm37FLbaw+B9pbW7OvFmz/wA23X8lr2S0neHa9op1bPk7FX+EulNNWo4bGpyqmtseGJsmdrNGmtnToL0fbyvYRfTNZOQAC6z1q/3ACTZNKEigpdoXFZIudCeJzrTLKPJbW5OrFuRDvkE=</DP><DQ>iG38o8Tmi8LX0ApKNo+7GA9XmGoVyFHEudJUNudfEremhS/kRsBzlbXgk8milhvjkEis7ADox0NPaiKghO0WJsSKkte2X+XPuCYjaTfX0ZmwxcU2NbaQY6LWQDl6KYJRLWb970TjXOA6o2Hnp3ngiHaBJGMHLedcG84yAnNOwyk=</DQ><InverseQ>WkDNqDhQH8UhxWFq4HCgag0aHNKg7FJfjSk/+u0HsJvH8Q1uibXWYfqoPonebPlG+7u7+i//RdrwYA9vWMC2Tud9j3hguZoP6si6hoA2NyFNGxvNjv8zKIX/b2wwjxB4fDVmEHwz+JTuKjbWf3PtbtmcUUus7HTg7nhgDE96+Ek=</InverseQ><D>AIId3lbleGvhQTmzqZ8AbHyt5oozbrInFgUcT62/EvZxc2w2YWDD0Dtt7HXdGr0sNfK3IfaoAcnlehDTCDqLIK+P/xDZ7rSKe8COsL2WHF6DTN6xy9SQT0c7gQTUuWgjLKo8Wfty3NIHPxKo861HX5jiWI7r5Zb6Mtj1T5RAGN4nMVhG35fMQpY7Tph4km3wr8peR64RaE4JCagwpe5AK/12hISwiLPKOClg3P4ddvQY6oOYZ93qrBQsR8Yg+MSeyfOdxu8GMRnQIbyQJy2luhWKN7EJb758/vJHzGYJFZh5UY/X6FTZbs4Wg66vNH+3WBO/qjZPR96dBmL2NK4cOQ==</D></RSAKeyValue>"; +} + +public class HelloSecure : IReturn<HelloSecureResponse> +{ + public string Name { get; set; } +} + +public class HelloSecureResponse +{ + public string Result { get; set; } +} + +public class GetSecure : IReturn<GetSecureResponse> +{ + public string Name { get; set; } +} + +public class GetSecureResponse +{ + public string Result { get; set; } +} + +public class HelloAuthenticated : IReturn<HelloAuthenticatedResponse>, IHasSessionId, IHasBearerToken, IHasVersion +{ + public string SessionId { get; set; } + public string BearerToken { get; set; } + public int Version { get; set; } +} + +public class LargeMessage : IReturn<LargeMessage> +{ + public List<HelloSecure> Messages { get; set; } +} + +[Authenticate] +public class HelloAuthSecure : IReturn<HelloAuthSecureResponse> +{ + public string Name { get; set; } +} + +public class HelloAuthSecureResponse +{ + public string Result { get; set; } +} + +public class HelloAuthenticatedResponse +{ + public int Version { get; set; } + public string SessionId { get; set; } + public string UserName { get; set; } + public string Email { get; set; } + public bool IsAuthenticated { get; set; } + public ResponseStatus ResponseStatus { get; set; } +} + +public class HelloOneWay : IReturnVoid +{ + internal static string LastName; + + public string Name { get; set; } +} + +[Restrict(RequestAttributes.Secure)] +public class HelloSecureRestricted : IReturn<HelloSecureRestrictedResponse> +{ + public string Name { get; set; } +} + +public class HelloSecureRestrictedResponse +{ + public string Result { get; set; } +} + +[DataContract] +[Route("/encrypted/delete/{Id}", "DELETE")] +public class EncryptedDelete : IReturn<EmptyResponse> +{ + [DataMember(Order = 1)] public string Id { get; set; } +} + +public class SecureServices : Service +{ + public async Task<object> Delete(EncryptedDelete request) + { + await Task.Yield(); + return new EmptyResponse(); + } + + public object Get(GetSecure request) + { + if (request.Name == null) + throw new ArgumentNullException("Name"); + + return new GetSecureResponse { Result = $"Hello, {request.Name}!" }; + } + + public object Any(HelloSecure request) + { + if (request.Name == null) + throw new ArgumentNullException("Name"); + + return new HelloSecureResponse { Result = $"Hello, {request.Name}!" }; + } + + public object Any(HelloAuthSecure request) + { + if (request.Name == null) + throw new ArgumentNullException("Name"); + + return new HelloAuthSecureResponse { Result = $"Hello, {request.Name}!" }; + } + + public object Any(HelloSecureRestricted request) + { + if (request.Name == null) + throw new ArgumentNullException("Name"); + + return new HelloSecureRestrictedResponse { Result = $"Hello, {request.Name}!" }; + } + + [Authenticate] + public object Any(HelloAuthenticated request) + { + var session = GetSession(); + + return new HelloAuthenticatedResponse + { + Version = request.Version, + SessionId = session.Id, + UserName = session.UserName, + Email = session.Email, + IsAuthenticated = session.IsAuthenticated, + }; + } + + public object Any(LargeMessage request) + { + return request; + } + + public void Any(HelloOneWay request) + { + HelloOneWay.LastName = request.Name; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UserServiceValidationTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UserServiceValidationTests.cs index e8b261cbfe4..7f66f6a6df5 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/UserServiceValidationTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UserServiceValidationTests.cs @@ -1,24 +1,17 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Net; -using System.Text; using ServiceStack.FluentValidation; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; using NUnit.Framework; -using ServiceStack.ServiceInterface.Validation; using System.Collections; using Funq; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Service; -using ServiceStack.WebHost.Endpoints.Support; +using ServiceStack.Validation; +using ServiceStack.Web; using ServiceStack.WebHost.Endpoints.Tests.Support; namespace ServiceStack.WebHost.Endpoints.Tests { [Route("/uservalidation")] - [Route("/uservalidation/{Id}")] + [Route("/uservalidation/{Id}")] public class UserValidation { public string FirstName { get; set; } @@ -30,27 +23,26 @@ public interface IAddressValidator bool ValidAddress(string address); } - public class UserValidator : AbstractValidator<UserValidation>, IRequiresHttpRequest + public class UserValidator : AbstractValidator<UserValidation>, IRequiresRequest { public IAddressValidator AddressValidator { get; set; } - public IHttpRequest HttpRequest { get; set; } public UserValidator() { - RuleFor(x => x.FirstName).Must(f => - { - if (HttpRequest == null) - Assert.Fail(); - - return true; - }); - RuleFor(x => x.LastName).NotEmpty().WithErrorCode("ShouldNotBeEmpty"); - RuleSet(ApplyTo.Post | ApplyTo.Put, () => + RuleFor(x => x.FirstName).Must(f => + { + if (Request == null) + Assert.Fail(); + + return true; + }); + RuleFor(x => x.LastName).NotEmpty().WithErrorCode("ShouldNotBeEmpty"); + RuleSet(ApplyTo.Post | ApplyTo.Put, () => { RuleFor(x => x.FirstName).NotEmpty().WithMessage("Please specify a first name"); }); } - } + } //Not matching the naming convention ([Request DTO Name] + "Response") public class OperationResponse @@ -58,7 +50,7 @@ public class OperationResponse public UserValidation Result { get; set; } } - public class UserValidationService : ServiceInterface.Service + public class UserValidationService : Service { public object Get(UserValidation request) { @@ -69,7 +61,7 @@ public object Get(UserValidation request) [TestFixture] public class UserServiceValidationTests { - private const string ListeningOn = "http://localhost:82/"; + private const string ListeningOn = "http://localhost:1337/"; public class UserAppHostHttpListener : AppHostHttpListenerBase @@ -80,34 +72,32 @@ public UserAppHostHttpListener() public override void Configure(Container container) { - Plugins.Add(new ValidationFeature()); - container.RegisterValidators(typeof(UserValidator).Assembly); + Plugins.Add(new ValidationFeature()); + container.RegisterValidators(typeof(UserValidator).Assembly); } } - UserAppHostHttpListener appHost; + static UserAppHostHttpListener appHost; - [TestFixtureSetUp] - public void OnTestFixtureSetUp() + [OneTimeSetUp] + public void TestFixtureSetUp() { appHost = new UserAppHostHttpListener(); appHost.Init(); appHost.Start(ListeningOn); } - [TestFixtureTearDown] - public void OnTestFixtureTearDown() + [OneTimeTearDown] + public void TestFixtureTearDown() { appHost.Dispose(); - EndpointHandlerBase.ServiceManager = null; } private static string ExpectedErrorCode = "ShouldNotBeEmpty"; protected static IServiceClient UnitTestServiceClient() { - EndpointHandlerBase.ServiceManager = new ServiceManager(typeof(SecureService).Assembly).Init(); - return new DirectServiceClient(EndpointHandlerBase.ServiceManager); + return new DirectServiceClient(appHost.ServiceController); } public static IEnumerable ServiceClients @@ -118,11 +108,12 @@ public static IEnumerable ServiceClients //be run for all test fixtures, not just this one. return new Func<IServiceClient>[] { - () => UnitTestServiceClient(), - () => new JsonServiceClient(ListeningOn), - () => new JsvServiceClient(ListeningOn), - () => new XmlServiceClient(ListeningOn), - }; + () => UnitTestServiceClient(), + () => new JsonServiceClient(ListeningOn), + () => new JsonHttpClient(ListeningOn), + () => new JsvServiceClient(ListeningOn), + () => new XmlServiceClient(ListeningOn), + }; } } @@ -132,13 +123,13 @@ public void Get_empty_request_throws_validation_exception(Func<IServiceClient> f try { var client = (IRestClient)factory(); - var response = client.Get<OperationResponse>("UserValidation"); + var response = client.Get<OperationResponse>("UserValidation"); Assert.Fail("Should throw Validation Exception"); } catch (WebServiceException ex) { Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); - Assert.That(ex.StatusDescription, Is.EqualTo(ExpectedErrorCode)); + Assert.That(ex.StatusDescription, Is.EqualTo(ExpectedErrorCode)); } } @@ -150,10 +141,11 @@ public static IEnumerable RestClients //be run for all test fixtures, not just this one. return new Func<IServiceClient>[] { - () => new JsonServiceClient(ListeningOn), - () => new JsvServiceClient(ListeningOn), - () => new XmlServiceClient(ListeningOn), - }; + () => new JsonServiceClient(ListeningOn), + () => new JsonHttpClient(ListeningOn), + () => new JsvServiceClient(ListeningOn), + () => new XmlServiceClient(ListeningOn), + }; } } @@ -162,8 +154,14 @@ public void Throws_validation_exception_even_if_AlwaysSendBasicAuthHeader_is_fal { try { - var client = (ServiceClientBase)factory(); - client.AlwaysSendBasicAuthHeader = false; + var client = factory(); + var serviceClient = client as ServiceClientBase; + if (serviceClient != null) + serviceClient.AlwaysSendBasicAuthHeader = false; + var httpClient = client as JsonHttpClient; + if (httpClient != null) + httpClient.AlwaysSendBasicAuthHeader = false; + var response = client.Get<OperationResponse>("UserValidation"); Assert.Fail("Should throw Validation Exception"); } diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationCustomTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationCustomTests.cs new file mode 100644 index 00000000000..383bf1e8156 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationCustomTests.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.FluentValidation.Results; +using ServiceStack.Text; +using ServiceStack.Validation; +using ServiceStack.WebHost.Endpoints.Tests.Support.Services; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [Route("/validation/custom")] + public class CustomValidation + { + public string Name { get; set; } + } + + public class CustomValidationResponse + { + public string Result { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class CustomValidationValidator : AbstractValidator<CustomValidation> + { + public CustomValidationValidator() + { + RuleFor(request => request.Name) + .NotEmpty() + .WithState(x => new Dictionary<string,string> { ["Custom"] = "Dictionary" }); + RuleFor(request => request) + .Custom((request, context) => { + if (request.Name?.StartsWith("A") != true) + { + var propertyName = context.ParentContext.PropertyChain.BuildPropertyName("Name:0"); + var errorMessage = "Incorrect prefix."; + var failure = new ValidationFailure(propertyName, errorMessage) + { + ErrorCode = "NotFound" + }; + context.AddFailure(failure); + } + var nameLength = request.Name?.Length ?? 0; + var firstLetter = request.Name?.Substring(0, 1) ?? ""; + var lastLetter = request.Name?.Substring(nameLength - 1, 1) ?? ""; + if (firstLetter != lastLetter) + { + var propertyName = context.ParentContext.PropertyChain.BuildPropertyName($"Name:0:1 <> Name:{nameLength - 1}:{nameLength}"); + var errorMessage = $"Name inconsistency: {firstLetter} <> {lastLetter}"; + var failure = new ValidationFailure(propertyName, errorMessage) + { + ErrorCode = "Inconsistency" + }; + context.AddFailure(failure); + } + }); + } + } + + [Route("/validation/inline")] + public class InlineValidation : IReturn<InlineValidation> + { + } + + public class InlineModel + { + public string Name { get; set; } + } + public class InlineModelValidator : AbstractValidator<InlineModel> + { + public InlineModelValidator() + { + RuleFor(request => request.Name) + .NotEmpty() + .WithState(x => new { Custom = "State" }); + } + } + + public class CustomValidationService : Service + { + public object Any(CustomValidation request) + { + return new CustomValidationResponse { Result = "Hello, " + request.Name }; + } + + public object Any(InlineValidation request) + { + var validationResult = new InlineModelValidator().Validate(new InlineModel()); + if (!validationResult.IsValid) + throw validationResult.ToException(); + + return request; + } + } + + public class ValidationCustomTests + { + private readonly ServiceStackHost appHost; + public class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ValidationCustomTests), typeof(HelloService).Assembly) { } + + public override void Configure(Funq.Container container) + { + Plugins.Add(new ValidationFeature()); + } + } + + public ValidationCustomTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + [Test] + public void Does_execute_custom_validators() + { + var client = new JsonServiceClient(Config.ListeningOn); + + try + { + using var response = client.Get<HttpWebResponse>(new CustomValidation {Name = "Joan"}); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.GetResponseStatus(); + + Assert.That(status.ErrorCode, Is.EqualTo("NotFound")); + Assert.That(status.Message, Is.EqualTo("Incorrect prefix.")); + Assert.That(status.Errors.Count, Is.EqualTo(2)); + + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotFound")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name:0")); + Assert.That(status.Errors[0].Message, Is.EqualTo("Incorrect prefix.")); + + Assert.That(status.Errors[1].ErrorCode, Is.EqualTo("Inconsistency")); + Assert.That(status.Errors[1].FieldName, Is.EqualTo("Name:0:1 <> Name:3:4")); + Assert.That(status.Errors[1].Message, Is.EqualTo("Name inconsistency: J <> n")); + } + } + + [Test] + public void Does_execute_custom_validators_combined() + { + var client = new JsonServiceClient(Config.ListeningOn); + + try + { + using var response = client.Get<HttpWebResponse>(new CustomValidation()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.GetResponseStatus(); + + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Name' must not be empty.")); + Assert.That(status.Errors.Count, Is.EqualTo(2)); + + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Name' must not be empty.")); + Assert.That(status.Errors[0].Meta["Custom"], Is.EqualTo("Dictionary")); + + Assert.That(status.Errors[1].ErrorCode, Is.EqualTo("NotFound")); + Assert.That(status.Errors[1].FieldName, Is.EqualTo("Name:0")); + Assert.That(status.Errors[1].Message, Is.EqualTo("Incorrect prefix.")); + } + } + + [Test] + public void Does_include_CustomState_for_inline_validation() + { + var client = new JsonServiceClient(Config.ListeningOn); + + try + { + var response = client.Get(new InlineValidation()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + var status = ex.GetResponseStatus(); + status.PrintDump(); + + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Name' must not be empty.")); + Assert.That(status.Errors.Count, Is.EqualTo(1)); + + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Name")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Name' must not be empty.")); + Assert.That(status.Errors[0].Meta["Custom"], Is.EqualTo("State")); + } + } + + } +} diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationExceptionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationExceptionTests.cs new file mode 100644 index 00000000000..1092b3273a3 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationExceptionTests.cs @@ -0,0 +1,174 @@ +using System; +using System.Linq; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.FluentValidation; +using ServiceStack.FluentValidation.Validators; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class TriggerValidators : IReturn<TriggerValidators> + { + public string CreditCard { get; set; } + public string Email { get; set; } + public string Empty { get; set; } + public string Equal { get; set; } + public int ExclusiveBetween { get; set; } + public int GreaterThanOrEqual { get; set; } + public int GreaterThan { get; set; } + public int InclusiveBetween { get; set; } + public string Length { get; set; } + public int LessThanOrEqual { get; set; } + public int LessThan { get; set; } + public string NotEmpty { get; set; } + public string NotEqual { get; set; } + public string Null { get; set; } + public string RegularExpression { get; set; } + public decimal ScalePrecision { get; set; } + } + + public class TriggerValidatorsValidator : AbstractValidator<TriggerValidators> + { + public TriggerValidatorsValidator() + { + RuleFor(x => x.CreditCard).CreditCard(); + RuleFor(x => x.Email).EmailAddress(); + RuleFor(x => x.Empty).Empty(); + RuleFor(x => x.Equal).Equal("Equal"); + RuleFor(x => x.ExclusiveBetween).ExclusiveBetween(10, 20); + RuleFor(x => x.GreaterThanOrEqual).GreaterThanOrEqualTo(10); + RuleFor(x => x.GreaterThan).GreaterThan(10); + RuleFor(x => x.InclusiveBetween).InclusiveBetween(10, 20); + RuleFor(x => x.Length).Length(10); + RuleFor(x => x.LessThanOrEqual).LessThanOrEqualTo(10); + RuleFor(x => x.LessThan).LessThan(10); + RuleFor(x => x.NotEmpty).NotEmpty(); + RuleFor(x => x.NotEqual).NotEqual("NotEqual"); + RuleFor(x => x.Null).Null(); + RuleFor(x => x.RegularExpression).Matches(@"^[a-z]*$"); + RuleFor(x => x.ScalePrecision).SetValidator(new ScalePrecisionValidator(1, 1)); + } + } + + public class ValidatorIssues : IReturn<ValidatorIssues> + { + public DateTime ValidTo { get; set; } + } + + public class ValidatorIssuesValidator : AbstractValidator<ValidatorIssues> + { + public ValidatorIssuesValidator() + { + RuleFor(x => x.ValidTo).GreaterThanOrEqualTo(x => DateTime.UtcNow); + } + } + + public class ValidationRulesTest : IReturn<ValidationRulesTest> + { + public string Id { get; set; } + public string AuthSecret { get; set; } + } + + public class ValidationService : Service + { + public object Any(TriggerValidators request) => request; + public object Any(ValidatorIssues request) => request; + + public object Any(ValidationRulesTest request) => request; + } + + public class ValidationExceptionTests + { + class AppHost : AppSelfHostBase + { + public AppHost() : base(nameof(ValidationExceptionTests), typeof(ValidationExceptionTests).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new ValidationFeature()); + + container.RegisterValidator(typeof(TriggerValidatorsValidator)); + container.RegisterValidator(typeof(ValidatorIssuesValidator)); + } + } + + private readonly ServiceStackHost appHost; + public ValidationExceptionTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + protected virtual JsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn); + + [Test] + public void Triggering_all_validators_returns_right_ErrorCode() + { + var client = GetClient(); + var request = CreateTriggerValidators(); + + try + { + var response = client.Post(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + //ex.ResponseStatus.PrintDump(); + ex.AssertTriggerValidators(); + } + } + + public static TriggerValidators CreateTriggerValidators() + { + var request = new TriggerValidators { + CreditCard = "NotCreditCard", + Email = "NotEmail", + Empty = "NotEmpty", + Equal = "NotEqual", + ExclusiveBetween = 1, + GreaterThan = 1, + GreaterThanOrEqual = 1, + InclusiveBetween = 1, + Length = "Length", + LessThan = 20, + LessThanOrEqual = 20, + NotEmpty = "", + NotEqual = "NotEqual", + Null = "NotNull", + RegularExpression = "FOO", + ScalePrecision = 123.456m + }; + return request; + } + + [Test] + public void Does_handle_reported_issues_correctly() + { + var client = GetClient(); + var request = new ValidatorIssues + { + ValidTo = DateTime.UtcNow.AddDays(-1), + }; + + try + { + var response = client.Post(request); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.ResponseStatus.PrintDump(); + var errors = ex.ResponseStatus.Errors; + Assert.That(errors.First(x => x.FieldName == "ValidTo").ErrorCode, Is.EqualTo("GreaterThanOrEqual")); + } + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationRulesTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationRulesTests.cs new file mode 100644 index 00000000000..5b9ca7b8d80 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ValidationRulesTests.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Funq; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Data; +using ServiceStack.OrmLite; +using ServiceStack.Text; +using ServiceStack.Validation; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class OrmLiteValidationRulesTests : ValidationRulesTests + { + protected override ValidationFeature GetValidationFeature(Container container) => + new ValidationFeature { + ValidationSource = new OrmLiteValidationSource(container.Resolve<IDbConnectionFactory>()), + }; + } + + public class OrmLiteWithCacheValidationRulesTests : ValidationRulesTests + { + protected override ValidationFeature GetValidationFeature(Container container) => + new ValidationFeature { + ValidationSource = new OrmLiteValidationSource( + container.Resolve<IDbConnectionFactory>(), + container.Resolve<MemoryCacheClient>()), + }; + } + + public class MemoryValidationRulesTests : ValidationRulesTests + { + protected override ValidationFeature GetValidationFeature(Container container) => + new ValidationFeature { + ValidationSource = new MemoryValidationSource(), + }; + } + + public abstract class ValidationRulesTests + { + private const string AuthSecret = "secretz"; + + protected abstract ValidationFeature GetValidationFeature(Container container); + + class AppHost : AppSelfHostBase + { + public ValidationFeature ValidationFeature { get; set; } + public AppHost() : base(nameof(ValidationExceptionTests), typeof(ValidationExceptionTests).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + AdminAuthSecret = AuthSecret, + }); + + Plugins.Add(ValidationFeature); + } + } + + private readonly ServiceStackHost appHost; + public ValidationRulesTests() + { + ValidationExtensions.RegisteredDtoValidators.Clear(); + + appHost = new AppHost(); + var container = appHost.Container; + var dbFactory = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider); + container.Register<IDbConnectionFactory>(dbFactory); + container.Register(appHost.GetMemoryCacheClient()); + ((AppHost)appHost).ValidationFeature = GetValidationFeature(container); + + appHost.Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] public void OneTimeTearDown() => appHost.Dispose(); + + protected virtual JsonServiceClient GetClient() => new JsonServiceClient(Config.ListeningOn); + + [Test] + public void Does_only_allow_access_to_Admin_by_Default() + { + var client = new JsonServiceClient(Config.ListeningOn); + try + { + client.Get(new GetValidationRules { Type = nameof(ValidationRulesTest) }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + + client.Get(new GetValidationRules { + Type = nameof(ValidationRulesTest), + AuthSecret = AuthSecret + }); + } + + [Test] + public void Does_now_allow_registering_invalid_validators() + { + (appHost.Resolve<IValidationSource>() as IClearable)?.Clear(); + + var client = GetClient(); + + void saveRules(params ValidationRule[] rules) => client.Post(new ModifyValidationRules { + AuthSecret = AuthSecret, + SaveRules = new List<ValidationRule>(rules) + }); + + void assertThrows(Action fn, Action<WebServiceException> onError) + { + try + { + fn(); + Assert.Fail($"Should throw {nameof(WebServiceException)}"); + } + catch (WebServiceException e) + { + onError(e); + } + } + + assertThrows(() => saveRules(new ValidationRule { + Validator = nameof(ValidateScripts.IsAuthenticated), + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Type))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest) + "NotExists", + Validator = nameof(ValidateScripts.IsAuthenticated), + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Type))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Field = "NotExists", + Validator = nameof(ValidateScripts.IsAuthenticated), + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Field))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Validator = nameof(ValidateScripts.IsAuthenticated) + "NotExists", + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Validator))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Field = nameof(ValidationRulesTest.AuthSecret), + Validator = nameof(ValidateScripts.IsAuthenticated), //should be IPropertyValidator + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Validator))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Validator = nameof(ValidateScripts.Null), //should be ITypeValidator + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Validator))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Field = nameof(ValidationRulesTest.AuthSecret), + Validator = $"[{nameof(ValidateScripts.Null)},{nameof(ValidateScripts.IsAuthenticated)}]", //validate all + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Validator))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Validator = $"[{nameof(ValidateScripts.IsAuthenticated)},{nameof(ValidateScripts.Null)}]", //validate all + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Validator))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Validator = nameof(ValidateScripts.IsAuthenticated), + Condition = "true", + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Condition))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Validator))); + + assertThrows(() => saveRules(new ValidationRule { + Type = nameof(ValidationRulesTest), + Condition = "Invalid (ode" + }), e => Assert.That(e.StatusCode == 400 && + e.GetFieldErrors()[0].FieldName == nameof(ValidationRule.Condition))); + } + + [Test] + public void Can_ModifyValidationRules_suspend_and_delete() + { + (appHost.Resolve<IValidationSource>() as IClearable)?.Clear(); + + var client = GetClient(); + + var noRules = client.Get(new ValidationRulesTest()); + + client.Post(new ModifyValidationRules { + AuthSecret = AuthSecret, + SaveRules = new List<ValidationRule> { + new ValidationRule { Type = nameof(ValidationRulesTest), Validator = nameof(ValidateScripts.IsAuthenticated) }, + } + }); + + static void AssertRule(ValidationRule rule) + { + // Assert.That(rule.CreatedBy, Is.Not.Null); //AuthSecret is null + Assert.That(rule.CreatedDate, Is.Not.Null); + // Assert.That(rule.ModifiedBy, Is.Not.Null); //AuthSecret is null + Assert.That(rule.ModifiedDate, Is.Not.Null); + } + + var typeRules = client.Get(new GetValidationRules { + AuthSecret = AuthSecret, Type = nameof(ValidationRulesTest) + }); + Assert.That(typeRules.Results.Count, Is.EqualTo(1)); + AssertRule(typeRules.Results[0]); + + try + { + var requiresAuth = client.Get(new ValidationRulesTest()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + + var requiresAuthAsAdmin = client.Get(new ValidationRulesTest { + AuthSecret = AuthSecret + }); + + client.Post(new ModifyValidationRules { + AuthSecret = AuthSecret, + SaveRules = new List<ValidationRule> { + new ValidationRule { Type = nameof(ValidationRulesTest), Field = nameof(ValidationRulesTest.Id), Validator = nameof(ValidateScripts.NotNull) }, + } + }); + + typeRules = client.Get(new GetValidationRules { + AuthSecret = AuthSecret, Type = nameof(ValidationRulesTest) + }); + Assert.That(typeRules.Results.Count, Is.EqualTo(2)); + AssertRule(typeRules.Results[0]); + AssertRule(typeRules.Results[1]); + + try + { + requiresAuthAsAdmin = client.Get(new ValidationRulesTest { + AuthSecret = AuthSecret + }); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.GetFieldErrors()[0].ErrorCode, Is.EqualTo("NotNull")); + } + + requiresAuthAsAdmin = client.Get(new ValidationRulesTest { + AuthSecret = AuthSecret, + Id = "Id" + }); + + client.Post(new ModifyValidationRules { + AuthSecret = AuthSecret, + SuspendRuleIds = new[] { + typeRules.Results.First(x => x.Field == nameof(ValidationRulesTest.Id)).Id + } + }); + + typeRules = client.Get(new GetValidationRules { + AuthSecret = AuthSecret, Type = nameof(ValidationRulesTest) + }); + Assert.That(typeRules.Results.First(x => x.Field == nameof(ValidationRulesTest.Id)).SuspendedDate, + Is.Not.Null); + + // Same as not having last rule + try + { + var requiresAuth = client.Get(new ValidationRulesTest()); + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + Assert.That(ex.ErrorCode, Is.EqualTo(nameof(HttpStatusCode.Unauthorized))); + } + + requiresAuthAsAdmin = client.Get(new ValidationRulesTest { + AuthSecret = AuthSecret + }); + + client.Post(new ModifyValidationRules { + AuthSecret = AuthSecret, + DeleteRuleIds = typeRules.Results.Map(x => x.Id).ToArray() + }); + + typeRules = client.Get(new GetValidationRules { + AuthSecret = AuthSecret, Type = nameof(ValidationRulesTest) + }); + Assert.That(typeRules.Results.Count, Is.EqualTo(0)); + + noRules = client.Get(new ValidationRulesTest()); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/VirtualFileSystemMappingTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/VirtualFileSystemMappingTests.cs new file mode 100644 index 00000000000..ebf9e908d6e --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/VirtualFileSystemMappingTests.cs @@ -0,0 +1,205 @@ +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Funq; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.VirtualPath; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class GetMappedFile : IReturn<GetMappedFileResponse> + { + public string VirtualPath { get; set; } + } + + public class GetMappedFileResponse + { + public string VirtualPath { get; set; } + public string FileName { get; set; } + public long FileSize { get; set; } + public string Contents { get; set; } + } + + public class FileSystemMappingService : Service + { + public object Any(GetMappedFile request) + { + var file = base.VirtualFileSources.GetFile(request.VirtualPath); + return new GetMappedFileResponse + { + VirtualPath = request.VirtualPath, + FileName = file.Name, + FileSize = file.Length, + Contents = file.ReadAllText(), + }; + } + } + + public class VirtualFileSystemMappingTests : VirtualFileSystemMappingTestsBase + { + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(VirtualFileSystemMappingTests), typeof(FileSystemMappingService).Assembly) { } + + public override void Configure(Container container) + { + } + + public override List<IVirtualPathProvider> GetVirtualFileSources() + { + var existingSources = base.GetVirtualFileSources(); + existingSources.Add(new FileSystemMapping("vfs1", MapProjectPath("~/App_Data/mount1"))); + existingSources.Add(new FileSystemMapping("vfs2", MapProjectPath("~/App_Data/mount2"))); + return existingSources; + } + } + + protected override ServiceStackHost CreateAppHost() => new AppHost(); + } + + public class VirtualFileSystemMappingPluginTests : VirtualFileSystemMappingTestsBase + { + public class VfsPlugin1 : IPlugin, IPreInitPlugin + { + public void BeforePluginsLoaded(IAppHost appHost) + { + appHost.AddVirtualFileSources.Add(new FileSystemMapping("vfs1", appHost.MapProjectPath("~/App_Data/mount1"))); + } + + public void Register(IAppHost appHost) {} + } + + public class VfsPlugin2 : IPlugin, IPreInitPlugin + { + public void BeforePluginsLoaded(IAppHost appHost) + { + appHost.AddVirtualFileSources.Add(new FileSystemMapping("vfs2", appHost.MapProjectPath("~/App_Data/mount2"))); + } + + public void Register(IAppHost appHost) {} + } + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(VirtualFileSystemMappingPluginTests), typeof(FileSystemMappingService).Assembly) { } + + public override void Configure(Container container) + { + Plugins.Add(new VfsPlugin1()); + Plugins.Add(new VfsPlugin2()); + } + } + + protected override ServiceStackHost CreateAppHost() => new AppHost(); + } + + [TestFixture] + public abstract class VirtualFileSystemMappingTestsBase + { + protected readonly ServiceStackHost appHost; + protected abstract ServiceStackHost CreateAppHost(); + + public VirtualFileSystemMappingTestsBase() + { + appHost = CreateAppHost(); + var dirPath = ClearFolders(); + + Directory.CreateDirectory(dirPath.AppendPath("mount1", "dir1")); + File.WriteAllText(dirPath.AppendPath("mount1", "file.txt"), "MOUNT1"); + File.WriteAllText(dirPath.AppendPath("mount1", "dir1", "nested-file.txt"), "NESTED MOUNT1"); + + Directory.CreateDirectory(dirPath.AppendPath("mount2", "dir2")); + File.WriteAllText(dirPath.AppendPath("mount2", "file.txt"), "MOUNT2"); + File.WriteAllText(dirPath.AppendPath("mount2", "dir2", "nested-file.txt"), "NESTED MOUNT2"); + + appHost + .Init() + .Start(Config.ListeningOn); + } + + private string ClearFolders() + { + var dirPath = appHost.MapProjectPath("~/App_Data"); + if (Directory.Exists(dirPath.AppendPath("mount1"))) + Directory.Delete(dirPath.AppendPath("mount1"), recursive: true); + if (Directory.Exists(dirPath.AppendPath("mount2"))) + Directory.Delete(dirPath.AppendPath("mount2"), recursive: true); + return dirPath; + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + ClearFolders(); + } + + [Test] + public void Can_resolve_file_from_mapped_path() + { + var file1 = appHost.VirtualFileSources.GetFile("vfs1/file.txt"); + var file2 = appHost.VirtualFileSources.GetFile("vfs2/file.txt"); + + Assert.That(file1.Name, Is.EqualTo("file.txt")); + Assert.That(file1.ReadAllText(), Is.EqualTo("MOUNT1")); + + Assert.That(file2.Name, Is.EqualTo("file.txt")); + Assert.That(file2.ReadAllText(), Is.EqualTo("MOUNT2")); + } + + [Test] + public void Can_resolve_nested_file_from_mapped_path() + { + var file1 = appHost.VirtualFileSources.GetFile("vfs1/dir1/nested-file.txt"); + var file2 = appHost.VirtualFileSources.GetFile("vfs2/dir2/nested-file.txt"); + + Assert.That(file1.Name, Is.EqualTo("nested-file.txt")); + Assert.That(file1.ReadAllText(), Is.EqualTo("NESTED MOUNT1")); + + Assert.That(file2.Name, Is.EqualTo("nested-file.txt")); + Assert.That(file2.ReadAllText(), Is.EqualTo("NESTED MOUNT2")); + } + + [Test] + public void Can_resolve_mapped_files_from_service() + { + var client = new JsonServiceClient(Config.ListeningOn); + var response = client.Get(new GetMappedFile { VirtualPath = "vfs1/file.txt" }); + Assert.That(response.FileName, Is.EqualTo("file.txt")); + Assert.That(response.Contents, Is.EqualTo("MOUNT1")); + Assert.That(response.FileSize, Is.GreaterThan(0)); + + response = client.Get(new GetMappedFile { VirtualPath = "vfs2/dir2/nested-file.txt" }); + Assert.That(response.FileName, Is.EqualTo("nested-file.txt")); + Assert.That(response.Contents, Is.EqualTo("NESTED MOUNT2")); + Assert.That(response.FileSize, Is.GreaterThan(0)); + } + + [Test] + public void Can_resolve_mapped_files_directly() + { + var url = Config.ListeningOn.AppendPath("vfs1", "file.txt"); + var contents = url.GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("MOUNT1")); + + contents = Config.ListeningOn.AppendPath("vfs2", "dir2", "nested-file.txt").GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("NESTED MOUNT2")); + } + + [Test] + public void Can_resolve_mapped_files_directly_case_insenstive() + { + var url = Config.ListeningOn.AppendPath("VFS1", "file.txt"); + var contents = url.GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("MOUNT1")); + + contents = Config.ListeningOn.AppendPath("VFS2", "dir2", "nested-file.txt").GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("NESTED MOUNT2")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/VirtualPathProviderTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/VirtualPathProviderTests.cs new file mode 100644 index 00000000000..85fb0bb6da2 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/VirtualPathProviderTests.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using NUnit.Framework; +using ServiceStack.IO; +using ServiceStack.Testing; +using ServiceStack.Text; +using ServiceStack.VirtualPath; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class FileSystemVirtualPathProviderTests : AppendVirtualFilesTests + { + private static string RootDir = "~/App_Data/files".MapProjectPath(); + + public FileSystemVirtualPathProviderTests() + { + if (Directory.Exists(RootDir)) + Directory.Delete(RootDir, recursive:true); + + Directory.CreateDirectory(RootDir); + } + + public override IVirtualPathProvider GetPathProvider() + { + return new FileSystemVirtualFiles(RootDir); + } + } + + public class MemoryVirtualFilesTests : AppendVirtualFilesTests + { + public override IVirtualPathProvider GetPathProvider() + { + return new MemoryVirtualFiles(); + } + } + + [Ignore("Integration Tests")] + public class GistVirtualFilesTests : VirtualPathProviderTests + { + public static readonly string GistId = "a9cfcdced0002e82be20ea6314fb41d6"; + public static readonly string AccessToken = Environment.GetEnvironmentVariable("GITHUB_GIST_TOKEN"); + + public override IVirtualPathProvider GetPathProvider() + { + return new GistVirtualFiles(GistId, AccessToken); + } + } + + public abstract class AppendVirtualFilesTests : VirtualPathProviderTests + { + [Test] + public void Does_append_to_file() + { + var pathProvider = GetPathProvider(); + + pathProvider.DeleteFile("original.txt"); + pathProvider.WriteFile("original.txt", "original\n"); + + pathProvider.AppendFile("original.txt", "New Line1\n"); + pathProvider.AppendFile("original.txt", "New Line2\n"); + + var contents = pathProvider.GetFile("original.txt").ReadAllText(); + Assert.That(contents, Is.EqualTo("original\nNew Line1\nNew Line2\n")); + + pathProvider.DeleteFile("original.txt"); + } + + [Test] + public void Does_append_to_file_bytes() + { + var pathProvider = GetPathProvider(); + pathProvider.DeleteFile("original.bin"); + pathProvider.WriteFile("original.bin", "original\n".ToUtf8Bytes()); + + pathProvider.AppendFile("original.bin", "New Line1\n".ToUtf8Bytes()); + pathProvider.AppendFile("original.bin", "New Line2\n".ToUtf8Bytes()); + + var contents = pathProvider.GetFile("original.bin").ReadAllBytes(); + Assert.That(contents, Is.EquivalentTo("original\nNew Line1\nNew Line2\n".ToUtf8Bytes())); + + pathProvider.DeleteFile("original.bin"); + } + } + + [TestFixture] + public abstract class VirtualPathProviderTests + { + public abstract IVirtualPathProvider GetPathProvider(); + + protected ServiceStackHost appHost; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + appHost = new BasicAppHost() + .Init(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + appHost.Dispose(); + } + + [Test] + public void Can_create_file() + { + var pathProvider = GetPathProvider(); + + var filePath = "dir/file.txt"; + pathProvider.WriteFile(filePath, "file"); + + var file = pathProvider.GetFile(filePath); + + Assert.That(file.ReadAllText(), Is.EqualTo("file")); + Assert.That(file.ReadAllText(), Is.EqualTo("file")); //can read twice + + Assert.That(file.VirtualPath, Is.EqualTo(filePath)); + Assert.That(file.Name, Is.EqualTo("file.txt")); + Assert.That(file.Directory.Name, Is.EqualTo("dir")); + Assert.That(file.Directory.VirtualPath, Is.EqualTo("dir")); + Assert.That(file.Extension, Is.EqualTo("txt")); + + Assert.That(file.Directory.Name, Is.EqualTo("dir")); + + pathProvider.DeleteFolder("dir"); + } + + [Test] + public void Does_refresh_LastModified() + { + var pathProvider = GetPathProvider(); + + var filePath = "dir/file.txt"; + pathProvider.WriteFile(filePath, "file1"); + + var file = pathProvider.GetFile(filePath); + var prevLastModified = file.LastModified; + + file.Refresh(); + Assert.That(file.LastModified, Is.EqualTo(prevLastModified)); + + pathProvider.WriteFile(filePath, "file2"); + file.Refresh(); + + //Can be too quick and share same modified date sometimes, try again with a delay + if (file.LastModified == prevLastModified) + { + Thread.Sleep(1000); + pathProvider.WriteFile(filePath, "file3"); + file.Refresh(); + } + + Assert.That(file.LastModified, Is.Not.EqualTo(prevLastModified)); + + pathProvider.DeleteFolder("dir"); + } + + [Test] + public void Can_create_file_from_root() + { + var pathProvider = GetPathProvider(); + + var filePath = "file.txt"; + pathProvider.WriteFile(filePath, "file"); + + var file = pathProvider.GetFile(filePath); + + Assert.That(file.ReadAllText(), Is.EqualTo("file")); + Assert.That(file.Name, Is.EqualTo(filePath)); + Assert.That(file.Extension, Is.EqualTo("txt")); + + Assert.That(file.Directory.VirtualPath, Is.Null); + Assert.That(file.Directory.Name, Is.Null.Or.EqualTo("files")); + + pathProvider.DeleteFiles(new[] { "file.txt" }); + } + + [Test] + public void Does_override_existing_file() + { + var pathProvider = GetPathProvider(); + + pathProvider.WriteFile("file.txt", "original"); + pathProvider.WriteFile("file.txt", "updated"); + Assert.That(pathProvider.GetFile("file.txt").ReadAllText(), Is.EqualTo("updated")); + + pathProvider.WriteFile("/a/file.txt", "original"); + pathProvider.WriteFile("/a/file.txt", "updated"); + Assert.That(pathProvider.GetFile("/a/file.txt").ReadAllText(), Is.EqualTo("updated")); + + pathProvider.DeleteFiles(new[] { "file.txt", "/a/file.txt" }); + pathProvider.DeleteFolder("a"); + } + + [Test] + public void Can_view_files_in_Directory() + { + var pathProvider = GetPathProvider(); + + var testdirFileNames = new[] + { + "testdir/a.txt", + "testdir/b.txt", + "testdir/c.txt", + }; + + var to = new Dictionary<string, string>(); + testdirFileNames.Each(x => to[x] = "textfile"); + pathProvider.WriteFiles(to); + + var testdir = pathProvider.GetDirectory("testdir"); + var filePaths = testdir.Files.Map(x => x.VirtualPath); + + Assert.That(filePaths, Is.EquivalentTo(testdirFileNames)); + + var fileNames = testdir.Files.Map(x => x.Name); + Assert.That(fileNames, Is.EquivalentTo(testdirFileNames.Map(x => + x.SplitOnLast('/').Last()))); + + pathProvider.DeleteFolder("testdir"); + } + + [Test] + public void Does_resolve_nested_files_and_folders() + { + var pathProvider = GetPathProvider(); + + var allFilePaths = new[] { + "testfile.txt", + "a/testfile-a1.txt", + "a/testfile-a2.txt", + "a/b/testfile-ab1.txt", + "a/b/testfile-ab2.txt", + "a/b/c/testfile-abc1.txt", + "a/b/c/testfile-abc2.txt", + "a/d/testfile-ad1.txt", + "e/testfile-e1.txt", + }; + + var to = new Dictionary<string, string>(); + allFilePaths.Each(x => to[x] = x.SplitOnLast('.').First().SplitOnLast('/').Last()); + pathProvider.WriteFiles(to); + + Assert.That(allFilePaths.All(x => pathProvider.IsFile(x))); + Assert.That(new[] { "a", "a/b", "a/b/c", "a/d", "e" }.All(x => pathProvider.IsDirectory(x))); + + Assert.That(!pathProvider.IsFile("notfound.txt")); + Assert.That(!pathProvider.IsFile("a/notfound.txt")); + Assert.That(!pathProvider.IsDirectory("f")); + Assert.That(!pathProvider.IsDirectory("a/f")); + Assert.That(!pathProvider.IsDirectory("testfile.txt")); + Assert.That(!pathProvider.IsDirectory("a/testfile-a1.txt")); + + AssertContents(pathProvider.RootDirectory, new[] { + "testfile.txt", + }, new[] { + "a", + "e" + }); + + AssertContents(pathProvider.GetDirectory("a"), new[] { + "a/testfile-a1.txt", + "a/testfile-a2.txt", + }, new[] { + "a/b", + "a/d" + }); + + AssertContents(pathProvider.GetDirectory("a/b"), new[] { + "a/b/testfile-ab1.txt", + "a/b/testfile-ab2.txt", + }, new[] { + "a/b/c" + }); + + AssertContents(pathProvider.GetDirectory("a").GetDirectory("b"), new[] { + "a/b/testfile-ab1.txt", + "a/b/testfile-ab2.txt", + }, new[] { + "a/b/c" + }); + + AssertContents(pathProvider.GetDirectory("a/b/c"), new[] { + "a/b/c/testfile-abc1.txt", + "a/b/c/testfile-abc2.txt", + }, new string[0]); + + AssertContents(pathProvider.GetDirectory("a/d"), new[] { + "a/d/testfile-ad1.txt", + }, new string[0]); + + AssertContents(pathProvider.GetDirectory("e"), new[] { + "e/testfile-e1.txt", + }, new string[0]); + + Assert.That(pathProvider.GetFile("a/b/c/testfile-abc1.txt").ReadAllText(), Is.EqualTo("testfile-abc1")); + Assert.That(pathProvider.GetDirectory("a").GetFile("b/c/testfile-abc1.txt").ReadAllText(), Is.EqualTo("testfile-abc1")); + Assert.That(pathProvider.GetDirectory("a/b").GetFile("c/testfile-abc1.txt").ReadAllText(), Is.EqualTo("testfile-abc1")); + Assert.That(pathProvider.GetDirectory("a").GetDirectory("b").GetDirectory("c").GetFile("testfile-abc1.txt").ReadAllText(), Is.EqualTo("testfile-abc1")); + + var dirs = pathProvider.RootDirectory.Directories.Map(x => x.VirtualPath); + Assert.That(dirs, Is.EquivalentTo(new[] { "a", "e" })); + + var rootDirFiles = pathProvider.RootDirectory.GetAllMatchingFiles("*", 1).Map(x => x.VirtualPath); + Assert.That(rootDirFiles, Is.EquivalentTo(new[] { "testfile.txt" })); + + var allFiles = pathProvider.GetAllMatchingFiles("*").Map(x => x.VirtualPath); + Assert.That(allFiles, Is.EquivalentTo(allFilePaths)); + + allFiles = pathProvider.GetAllFiles().Map(x => x.VirtualPath); + Assert.That(allFiles, Is.EquivalentTo(allFilePaths)); + + Assert.That(pathProvider.DirectoryExists("a")); + Assert.That(!pathProvider.DirectoryExists("f")); + Assert.That(!pathProvider.GetDirectory("a/b/c").IsRoot); + Assert.That(!pathProvider.GetDirectory("a/b").IsRoot); + Assert.That(!pathProvider.GetDirectory("a").IsRoot); + Assert.That(pathProvider.GetDirectory("").IsRoot); + + pathProvider.DeleteFile("testfile.txt"); + pathProvider.DeleteFolder("a"); + pathProvider.DeleteFolder("e"); + + Assert.That(pathProvider.GetAllFiles().ToList().Count, Is.EqualTo(0)); + } + + [Test] + public void Can_GetAllMatchingFiles_in_nested_directories() + { + var pathProvider = GetPathProvider(); + + var allFilePaths = new[] { + "a/b/c/testfile-abc1.txt", + "a/b/c/d/e/f/g/testfile-abcdefg1.txt", + }; + + var to = new Dictionary<string, string>(); + allFilePaths.Each(x => to[x] = x.SplitOnLast('.').First().SplitOnLast('/').Last()); + pathProvider.WriteFiles(to); + + Assert.That(pathProvider.GetDirectory("a/b/c").GetAllMatchingFiles("testfile-abc1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a/b").GetAllMatchingFiles("testfile-abc1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a").GetAllMatchingFiles("testfile-abc1.txt").Count(), Is.EqualTo(1)); + + Assert.That(pathProvider.GetDirectory("a/b/c/d/e/f/g").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a/b/c/d/e/f").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a/b/c/d/e").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a/b/c/d").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a/b/c").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a/b").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + Assert.That(pathProvider.GetDirectory("a").GetAllMatchingFiles("testfile-abcdefg1.txt").Count(), Is.EqualTo(1)); + } + + [Test] + public void Does_create_file_in_nested_folders_with_correct_parent_directories() + { + var vfs = GetPathProvider(); + + vfs.WriteFile("a/b/c/file.txt", "file"); + var file = vfs.GetFile("a/b/c/file.txt"); + Assert.That(file != null); + + Assert.That(file.Directory.VirtualPath, Is.EqualTo("a/b/c")); + Assert.That(file.Directory.Name, Is.EqualTo("c")); + Assert.That(file.Directory.ParentDirectory.VirtualPath, Is.EqualTo("a/b")); + Assert.That(file.Directory.ParentDirectory.Name, Is.EqualTo("b")); + Assert.That(file.Directory.ParentDirectory.ParentDirectory.VirtualPath, Is.EqualTo("a")); + Assert.That(file.Directory.ParentDirectory.ParentDirectory.Name, Is.EqualTo("a")); + Assert.That(file.Directory.ParentDirectory.ParentDirectory.ParentDirectory.IsRoot); + Assert.That(vfs.RootDirectory.GetDirectories().Any(x => x.Name == "a")); + + vfs.DeleteFile("a/b/c/file.txt"); + } + + [Test] + public void Does_write_binary_file() + { + var pathProvider = GetPathProvider(); + + var bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + pathProvider.WriteFile("original.bin", bytes); + pathProvider.WriteFile("a/b/c/original.bin", bytes); + + var contents = pathProvider.GetFile("original.bin").ReadAllBytes(); + Assert.That(contents, Is.EquivalentTo(bytes)); + + contents = pathProvider.GetFile("a/b/c/original.bin").ReadAllBytes(); + Assert.That(contents, Is.EquivalentTo(bytes)); + + pathProvider.DeleteFiles(new[]{ "original.bin", "a/b/c/original.bin" }); + } + + [Test] + public void GetContents_of_Binary_File_returns_ReadOnlyMemory_byte() + { + var pathProvider = GetPathProvider(); + + var bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + pathProvider.WriteFile("original.bin", new ReadOnlyMemory<byte>(bytes)); + + var contents = (ReadOnlyMemory<byte>) pathProvider.GetFile("original.bin").GetContents(); + + Assert.That(contents.Span.SequenceEqual(bytes.AsSpan())); + } + + [Test] + public void GetContents_of_Text_File_returns_ReadOnlyMemory_char() + { + var pathProvider = GetPathProvider(); + + var text = "abcdef"; + + pathProvider.WriteFile("original.txt", text.AsMemory()); + + var contents = (ReadOnlyMemory<char>) pathProvider.GetFile("original.txt").GetContents(); + + Assert.That(contents.Span.SequenceEqual(text.AsSpan())); + } + + public void AssertContents(IVirtualDirectory dir, + string[] expectedFilePaths, string[] expectedDirPaths) + { + var filePaths = dir.Files.Map(x => x.VirtualPath); + Assert.That(filePaths, Is.EquivalentTo(expectedFilePaths)); + + var fileNames = dir.Files.Map(x => x.Name); + Assert.That(fileNames, Is.EquivalentTo(expectedFilePaths.Map(x => + x.SplitOnLast('/').Last()))); + + var dirPaths = dir.Directories.Map(x => x.VirtualPath); + Assert.That(dirPaths, Is.EquivalentTo(expectedDirPaths)); + + var dirNames = dir.Directories.Map(x => x.Name); + Assert.That(dirNames, Is.EquivalentTo(expectedDirPaths.Map(x => + x.SplitOnLast('/').Last()))); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/WebServiceExceptionTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/WebServiceExceptionTests.cs index 99af1eeae5f..55ca78bba98 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/WebServiceExceptionTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/WebServiceExceptionTests.cs @@ -1,7 +1,9 @@ +using System.Collections.Generic; using System.Runtime.Serialization; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface.ServiceModel; +#if !NETCORE +using ServiceStack.ServiceModel; +#endif namespace ServiceStack.WebHost.Endpoints.Tests { @@ -54,6 +56,21 @@ public void Can_retrieve_empty_Errors_from_Dto_NoStatusResponse() Assert.That(webEx.ServerStackTrace, Is.Null); } + [Test] + public void Can_Retrieve_Errors_From_ResponseBody_If_ResponseDto_Does_Not_Contain_ResponseStatus() + { + var webEx = new WebServiceException { + ResponseDto = new List<string> {"123"}, + ResponseBody = "{\"ResponseStatus\":" + + "{\"ErrorCode\":\"UnauthorizedAccessException\"," + + "\"Message\":\"Error Message\"," + + "\"StackTrace\":\"Some Stack Trace\",\"Errors\":[]}}", + }; + + Assert.That(webEx.ErrorCode, Is.EqualTo("UnauthorizedAccessException")); + Assert.That(webEx.ErrorMessage, Is.EqualTo("Error Message")); + Assert.That(webEx.ServerStackTrace, Is.EqualTo("Some Stack Trace")); + } } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/WsdlMetadataTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/WsdlMetadataTests.cs index 1b0a650e06e..90cec174ecb 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/WsdlMetadataTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/WsdlMetadataTests.cs @@ -1,54 +1,57 @@ +#if !NETCORE using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.WebHost.Endpoints.Metadata; -using ServiceStack.WebHost.Endpoints.Tests.Support; +using ServiceStack.Host; +using ServiceStack.Metadata; +using ServiceStack.Testing; using ServiceStack.WebHost.Endpoints.Tests.Support.Operations; namespace ServiceStack.WebHost.Endpoints.Tests { [TestFixture] - public class WsdlMetadataTests : MetadataTestBase + public class WsdlMetadataTests : IService { //private static ILog log = LogManager.GetLogger(typeof(WsdlMetadataTests)); [Test] public void Wsdl_state_is_correct() { - var wsdlGenerator = new Soap11WsdlMetadataHandler(); - var xsdMetadata = new XsdMetadata(Metadata); - var wsdlTemplate = wsdlGenerator.GetWsdlTemplate(xsdMetadata, "http://w3c.org/types", false, "http://w3c.org/types", "Service Name"); - - Assert.That(wsdlTemplate.ReplyOperationNames, Is.EquivalentTo(xsdMetadata.GetReplyOperationNames(Format.Soap12))); - Assert.That(wsdlTemplate.OneWayOperationNames, Is.EquivalentTo(xsdMetadata.GetOneWayOperationNames(Format.Soap12))); + using (var appHost = new BasicAppHost().Init()) + { + + var dummyServiceType = GetType(); + appHost.Metadata.Add(dummyServiceType, typeof(GetCustomer), typeof(GetCustomerResponse)); + appHost.Metadata.Add(dummyServiceType, typeof(GetCustomers), typeof(GetCustomersResponse)); + appHost.Metadata.Add(dummyServiceType, typeof(StoreCustomer), null); + + var wsdlGenerator = new Soap12WsdlMetadataHandler(); + var xsdMetadata = new XsdMetadata(appHost.Metadata); + var wsdlTemplate = wsdlGenerator.GetWsdlTemplate(xsdMetadata, "http://w3c.org/types", false, "http://w3c.org/types", "Service Name"); + + var soapTypes = appHost.Metadata.GetAllSoapOperationTypes().ToSet(); + Assert.That(wsdlTemplate.ReplyOperationNames, Is.EquivalentTo(xsdMetadata.GetReplyOperationNames(Format.Soap12, soapTypes))); + Assert.That(wsdlTemplate.OneWayOperationNames, Is.EquivalentTo(xsdMetadata.GetOneWayOperationNames(Format.Soap12, soapTypes))); + } } [Test] public void Xsd_output_does_not_contain_xml_declaration() { - var xsd = new XsdGenerator { - OperationTypes = new[] { typeof(GetCustomer), typeof(GetCustomerResponse), typeof(GetCustomers), typeof(GetCustomersResponse), typeof(StoreCustomer) }, - OptimizeForFlash = false, - }.ToString(); - - Assert.That(!xsd.StartsWith("<?")); - } - - [Test] - public void XsdUtils_strips_all_xml_declarations() - { -#if no - const string xsd = "<?xml version=\"1.0\" encoding=\"utf-16\"?>" - + "<xs:schema xmlns:tns=\"http://schemas.sericestack.net/examples/types\" elementFormDefault=\"qualified\" targetNamespace=\"http://schemas.sericestack.net/examples/types\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" - + "<xs:complexType name=\"ArrayOfLong\">" - + " <xs:sequence><xs:element minOccurs=\"0\" maxOccurs=\"unbounded\" name=\"long\" type=\"xs:long\" /></xs:sequence>" - + "</xs:complexType>"; - - const string xsds = xsd + xsd + xsd; -#endif - //var strippedXsd = XsdUtils.StripXmlDeclaration(xsds); - - //Assert.That(strippedXsd.IndexOf("<?"), Is.EqualTo(-1)); + using (var appHost = new BasicAppHost().Init()) + { + var xsd = new XsdGenerator + { + OperationTypes = new[] + { + typeof (GetCustomer), typeof (GetCustomerResponse), typeof (GetCustomers), + typeof (GetCustomersResponse), typeof (StoreCustomer) + }, + OptimizeForFlash = false, + }.ToString(); + + Assert.That(!xsd.StartsWith("<?")); + } } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/XmlMetaDataHandlerTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/XmlMetaDataHandlerTests.cs index 7a26cbfacd4..9baa3b59f0d 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/XmlMetaDataHandlerTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/XmlMetaDataHandlerTests.cs @@ -1,5 +1,5 @@ using NUnit.Framework; -using ServiceStack.WebHost.Endpoints.Metadata; +using ServiceStack.Metadata; using System.Runtime.Serialization; namespace ServiceStack.WebHost.Endpoints.Tests @@ -14,7 +14,6 @@ public void when_creating_a_response_for_a_dto_with_no_default_constructor_the_r var response = handler.CreateResponse(typeof(NoDefaultConstructor)); Assert.That(response, Is.Not.Empty); } - } [DataContract(Namespace = "http://schemas.servicestack.net/types")] diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ZipServiceClientTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ZipServiceClientTests.cs new file mode 100644 index 00000000000..4e3bd059126 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ZipServiceClientTests.cs @@ -0,0 +1,195 @@ +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Net; +using System.Reflection; +using System.Runtime.Serialization; +using System.Threading.Tasks; +using Funq; +using NUnit.Framework; +using ServiceStack; +using ServiceStack.Web; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + [DataContract] + [Route("/hellozip")] + public class HelloZip : IReturn<HelloZipResponse> + { + [DataMember] + public string Name { get; set; } + + [DataMember] + public List<string> Test { get; set; } + } + + [DataContract] + public class HelloZipResponse + { + [DataMember] + public string Result { get; set; } + } + + public class HelloZipService : IService + { + public object Any(HelloZip request) + { + return request.Test == null + ? new HelloZipResponse { Result = $"Hello, {request.Name}" } + : new HelloZipResponse { Result = $"Hello, {request.Name} ({request.Test?.Count})" }; + } + } + + [TestFixture] + public class ZipServiceClientTests + { + private readonly ServiceStackHost appHost; + + public ZipServiceClientTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ZipServiceClientTests), typeof(HelloZipService).Assembly) { } + + public override void Configure(Container container) {} + } + + [Test] + public void Can_send_GZip_client_request_list() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = client.Post(new HelloZip + { + Name = "GZIP", + Test = new List<string> { "Test" } + }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP (1)")); + } + + [Test] + public async Task Can_send_GZip_client_request_list_async() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = await client.PostAsync(new HelloZip + { + Name = "GZIP", + Test = new List<string> { "Test" } + }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP (1)")); + } + + [Test] + public void Can_send_GZip_client_request_list_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = client.Post(new HelloZip + { + Name = "GZIP", + Test = new List<string> { "Test" } + }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP (1)")); + } + + [Test] + public async Task Can_send_GZip_client_request_list_HttpClient_async() + { + var client = new JsonHttpClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = await client.PostAsync(new HelloZip + { + Name = "GZIP", + Test = new List<string> { "Test" } + }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP (1)")); + } + + [Test] + public void Can_send_GZip_client_request() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = client.Post(new HelloZip { Name = "GZIP" }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP")); + } + + [Test] + public void Can_send_Deflate_client_request() + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.Deflate, + }; + var response = client.Post(new HelloZip { Name = "Deflate" }); + Assert.That(response.Result, Is.EqualTo("Hello, Deflate")); + } + + [Test] + public void Can_send_GZip_client_request_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = client.Post(new HelloZip { Name = "GZIP" }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP")); + } + + [Test] + public void Can_send_Deflate_client_request_HttpClient() + { + var client = new JsonHttpClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.Deflate, + }; + var response = client.Post(new HelloZip { Name = "Deflate" }); + Assert.That(response.Result, Is.EqualTo("Hello, Deflate")); + } + + [Ignore("Integration Test"), Test] + public void Can_send_gzip_client_request_ASPNET() + { + var client = new JsonServiceClient(Config.AspNetServiceStackBaseUri) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = client.Post(new HelloZip { Name = "GZIP" }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP")); + } + + + + [TestCase(CompressionTypes.Deflate)] + [TestCase(CompressionTypes.GZip)] + public async Task Can_send_async_compressed_client_request(string compressionType) + { + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestCompressionType = compressionType, + }; + var response = await client.PostAsync(new HelloZip { Name = compressionType }); + Assert.That(response.Result, Is.EqualTo($"Hello, {compressionType}")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/ZipTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/ZipTests.cs new file mode 100644 index 00000000000..807f5d4d973 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/ZipTests.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Funq; +using NUnit.Framework; +using ServiceStack.Caching; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.Endpoints.Tests +{ + public class ZipTests + { + private readonly bool hold; + public ZipTests() + { + hold = MemoryStreamFactory.UseRecyclableMemoryStream; + MemoryStreamFactory.UseRecyclableMemoryStream = true; + } + + [OneTimeTearDown] + public void OneTimeTearDown() => MemoryStreamFactory.UseRecyclableMemoryStream = hold; + + private static void DoesCompress(IStreamCompressor compressor, string text) + { + var zipBytes = compressor.Compress(text); + var unzip = compressor.Decompress(zipBytes); + Assert.That(unzip, Is.EqualTo(text)); + } + +#if NET6_0_OR_GREATER + [Test] + public void Can_zip_and_unzip_bytes_using_BrotliStream() + { + DoesCompress(StreamCompressors.GetRequired(CompressionTypes.Brotli), "hello zip"); + } +#endif + + [Test] + public void Can_zip_and_unzip_bytes_using_DeflateStream() + { + DoesCompress(StreamCompressors.GetRequired(CompressionTypes.Deflate), "hello zip"); + } + + [Test] + public void Can_zip_and_unzip_bytes_using_Gzip() + { + DoesCompress(StreamCompressors.GetRequired(CompressionTypes.GZip), "hello zip"); + } + } + + public class ZipRequestLoggerTests + { + private readonly ServiceStackHost appHost; + + public ZipRequestLoggerTests() + { + appHost = new AppHost() + .Init() + .Start(Config.ListeningOn); + } + + [OneTimeTearDown] + public void OneTimeTearDown() => appHost.Dispose(); + + class AppHost : AppSelfHostBase + { + public AppHost() + : base(nameof(ZipRequestLoggerTests), typeof(HelloZipService).Assembly) { } + + public override void Configure(Container container) + { + SetConfig(new HostConfig { + StrictMode = true, + }); + + Plugins.Add(new RequestLogsFeature { + EnableRequestBodyTracking = true, + }); + } + } + + [Test] + public void Does_log_compressed_requests() + { + var hold = JsConfig.UTF8Encoding; + JsConfig.UTF8Encoding = new UTF8Encoding(false, true); + + var client = new JsonServiceClient(Config.ListeningOn) + { + RequestCompressionType = CompressionTypes.GZip, + }; + var response = client.Post(new HelloZip + { + Name = "GZIP", + Test = new List<string> { "Test" } + }); + Assert.That(response.Result, Is.EqualTo("Hello, GZIP (1)")); + + JsConfig.UTF8Encoding = hold; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/dir/index.html b/tests/ServiceStack.WebHost.Endpoints.Tests/dir/index.html new file mode 100644 index 00000000000..31063146576 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/dir/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Title</title> +</head> +<body> + + <h1>dir/index.html</h1> + +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/dir/sub/index.html b/tests/ServiceStack.WebHost.Endpoints.Tests/dir/sub/index.html new file mode 100644 index 00000000000..e9fa3e179b7 --- /dev/null +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/dir/sub/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Title</title> +</head> +<body> + + <h1>dir/sub/index.html</h1> + +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/packages.config b/tests/ServiceStack.WebHost.Endpoints.Tests/packages.config deleted file mode 100644 index e0a2084bd73..00000000000 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<packages> - <package id="protobuf-net" version="2.0.0.640" targetFramework="net40" /> -</packages> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/App.config b/tests/ServiceStack.WebHost.IntegrationTests/App.config new file mode 100644 index 00000000000..739906ff1a1 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/App.config @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8" ?> +<configuration> + <appSettings> + </appSettings> +</configuration> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/bootstrap.css b/tests/ServiceStack.WebHost.IntegrationTests/Content/bootstrap.css index 637998aad73..7fa1f93fd1f 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/bootstrap.css +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/bootstrap.css @@ -1,7 +1,7 @@ /*! * Bootstrap @VERSION * - * Copyright 2011 Twitter, Inc + * Copyright 2014 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/default.css b/tests/ServiceStack.WebHost.IntegrationTests/Content/default.css index 0b747a561f5..ca3d40c7f67 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/default.css +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/default.css @@ -19,7 +19,7 @@ #login #register { display: none; } -#login .error .error-summary +#login .has-errors .error-summary { display: inline; color: #B94A48; diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/default.html b/tests/ServiceStack.WebHost.IntegrationTests/Content/default.html new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/default.html @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/app.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/app.js deleted file mode 100644 index ad17abe3c3f..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/app.js +++ /dev/null @@ -1,159 +0,0 @@ -/// <reference path="base.js" /> -/// <reference path="login.js" /> -/// <reference path="register.js" /> -/// <reference path="userprofile.js" /> -/// <reference path="twitter.js" /> -(function (root) -{ - var app = root.App; - - app.BaseModel = Backbone.Model.extend({ - parse: function (resp, xhr) { - if (!resp) return resp; - return resp.result || resp.results || resp; - }, - _super: function (funcName) { - return this.constructor.__super__[funcName].apply(this, _.rest(arguments)); - } - }); - - app.BaseView = Backbone.View.extend({ - loading: function () { - $(this.el).css({ opacity: 0.5 }); - }, - finishedLoading: function () { - $(this.el).css({ opacity: 1 }); - } - }); - - _.extend(app, { - UnAuthorized: 401, - initialize: function () - { - _.bindAll(this, "error", "trigger"); - this.handleClicks(); - }, - handleClicks: function () - { - $(document.body).click(function (e) - { - var dataCmd = $(e.srcElement).data('cmd'); - if (!dataCmd) return; - - var cmd = dataCmd.split(':'), - evt = cmd[0], - args = cmd.length > 1 ? cmd[1].split(',') : []; - - app.sendCmd(evt, args); - }); - }, - route: function (evt) { - var args = _.rest(arguments); - console.log("route: " + evt, args); - this.sendCmd(evt, args); - }, - sendCmd: function (evt, args) - { - if (_.isFunction(this.routes[evt])) - this.routes[evt].apply(this.routes, args); - - _.each(this.models, function (el) { - if (_.isFunction(el[evt])) el[evt].apply(el, args); - }); - _.each(this.views, function (el) { - if (_.isFunction(el[evt])) el[evt].apply(el, args); - }); - }, - error: function (xhr, err, statusText) - { - console.log("App Error: ", arguments); - this.trigger("error", arguments); - if (xhr.status == this.UnAuthorized) - { - //verify user is no longer authenticated - $.getJSON("api/userinfo", function (r) { }, function (xhr) { - if (xhr.status == this.UnAuthorized) - location.href = location.href; - }); - } - } - }); - _.extend(app, Backbone.Events); - app.sendCmd = _.bind(app.sendCmd, app); - - var login = new app.Login(); - var userProfile = new app.UserProfile({ login: login }); - var twitter = new app.Twitter({ profile: userProfile }); - - app.Routes = Backbone.Router.extend({ - routes: { - "tweets": "tweets", - "friends": "friends", - "followers": "followers", - "userTweets": ":user/tweets", - "userFriends": ":user/friends", - "userFollowers": ":user/followers" - }, - initialize: function (opt) { - this.app = opt.app; - }, - tweets: function () { - this.app.route("twitterProfileChange", login.get('screenName'), "tweets"); - }, - friends: function () { - this.app.route("twitterProfileChange", login.get('screenName'), "friends"); - }, - followers: function () { - this.app.route("twitterProfileChange", login.get('screenName'), "followers"); - }, - userTweets: function (user) { - this.app.route("twitterProfileChange", user, "tweets"); - }, - userFriends: function (user) { - this.app.route("twitterProfileChange", user, "friends"); - }, - userFollowers: function (user) { - this.app.route("twitterProfileChange", user, "followers"); - } - }); - app.routes = new app.Routes({app:app}); - - console.log(login.attributes, userProfile.attributes, twitter.attributes); - - app.models = { - login: login, - userProfile: userProfile, - twitter: twitter - }; - _.each(app.models, function(model) { - model.sendCmd = app.sendCmd; - }) - - app.views = { - login: new app.LoginView({ - el: "#login", - model: login - }), - register: new app.RegisterView({ - el: "#register", - model: login - }), - userProfile: new app.UserProfileView({ - el: "#user-profile", - model: userProfile - }), - twitter: new app.TwitterView({ - el: "#twitter", - model: twitter - }) - }; - - app.initialize(); - $(".tabs").tabs(); - - - Backbone.history.start(); //{ pushState: true } - $(function () { - }); - -})(window); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/base.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/base.js deleted file mode 100644 index b673247e05c..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/base.js +++ /dev/null @@ -1,116 +0,0 @@ -/// <reference path="../jquery-1.7.js" /> -/// <reference path="../underscore.js" /> -/// <reference path="../backbone.js" /> -/// <reference path="ss-validation.js" /> -(function (root) -{ - $.ss.validation.overrideMessages = true; - - var app = root.App = root.App || {}; - var emptyFn = function() {}; - - _.mixin({ - cmdHandler: function (handlers) - { - $(document.body).click(function (e) { - var dataCmd = $(e.srcElement || e.target).data('cmd'); - if (!dataCmd) return; - - var cmd = dataCmd.split(':'), - evt = cmd[0], - args = cmd.length > 1 ? cmd[1].split(',') : []; - - if (_.isFunction(handlers[evt])) - handlers[evt].apply(handlers, args); - }); - }, - setFieldError: function(field, msg) { - var $field = $(field), form = $field.parents("form"); - $field.parent().add(form).addClass("error"); - if (msg) - $field.next().html(msg); - }, - formData: function (form) - { - var ret = {}; - $(form).find("input,textarea").each(function() { - if (this.type == "button" || this.type == "submit") return; - var value = this.type == "checkbox" - ? this.checked.toString() - : $(this).val(); - ret[this.name] = value; - }); - return ret; - }, - xhrMessage: function (xhr) - { - try - { - var respObj = JSON.parse(xhr.responseText); - if (!respObj.responseStatus) return null; - return respObj.responseStatus.message; - } - catch (e) - { - return null; - } - }, - get: function (url, data, success, error) { - if (_.isFunction(data)) { - success = data; - error = success; - data = undefined; - } - return _.ajax({ - type: 'GET', - url: url, - data: data, - success: success, - error: error - }); - }, - post: function (opt) { - return _.ajax(opt); - }, - ajax: function (opt) - { - var o = _.defaults(opt, { - type: 'POST', - loading: function() { - $(document.body).add(opt.form).addClass("loading"); - }, - finishedLoading: function() { - $(document.body).add(opt.form).removeClass("loading"); - }, - dataType: "json" - }); - o.loading(); - $.ajax({ - type: o.type, - url: o.url, - data: o.data, - success: function() - { - //console.log(arguments); - o.finishedLoading(); - $(o.form).clearErrors(); - if (o.success) o.success.apply(null, arguments); - }, - error: function(xhr,err,status) - { - //console.log(arguments); - o.finishedLoading(); - try { - if (o.form) { - var r = JSON.parse(xhr.responseText); - $(o.form).applyErrors(r && r.responseStatus); - } - } catch(e){} - (o.error || (app.error || emptyFn)).apply(null, arguments); - }, - dataType: o.dataType - }); - } - }); - -})(window); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/jsonreport.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/jsonreport.js index 401ea126368..e05058474ea 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/jsonreport.js +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/jsonreport.js @@ -32,20 +32,20 @@ var cssText = document.write('<style type="text/css">' + cssText + '</style>\r\n'); -if (!_) var _ = {}; +if (!_) let _ = {}; _.jsonreport = (function(){ - var root = this, doc = document, + let root = this, doc = document, $ = function(id) { return doc.getElementById(id); }, $$ = function(sel) { return doc.getElementsByTagName(sel); }, - $each = function(fn) { for (var i=0,len=this.length; i<len; i++) fn(i, this[i], this); }, + $each = function(fn) { for (let i=0,len=this.length; i<len; i++) fn(i, this[i], this); }, isIE = /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent); $.each = function(arr, fn) { $each.call(arr, fn); }; - var splitCase = function(t) { return typeof t != 'string' ? t : t.replace(/([A-Z]|[0-9]+)/g, ' $1').replace(/_/g,' '); }, - uniqueKeys = function(m){ var h={}; for (var i=0,len=m.length; i<len; i++) for (var k in m[i]) h[k] = k; return h; }, - keys = function(o){ var a=[]; for (var k in o) a.push(k); return a; } - var tbls = []; + let splitCase = function(t) { return typeof t != 'string' ? t : t.replace(/([A-Z]|[0-9]+)/g, ' $1').replace(/_/g,' '); }, + uniqueKeys = function(m){ let h={}; for (let i=0,len=m.length; i<len; i++) for (let k in m[i]) h[k] = k; return h; }, + keys = function(o){ let a=[]; for (let k in o) a.push(k); return a; } + let tbls = []; function val(m) { if (m == null) return ''; @@ -56,34 +56,34 @@ _.jsonreport = (function(){ } function num(m) { return m; } function str(m) { - return m.substr(0,6) == '/Date(' ? dfmt(date(m)) : m; + return m.substr(0,6) === '/Date(' ? dfmt(date(m)) : m; } function date(s) { return new Date(parseFloat(/Date\(([^)]+)\)/.exec(s)[1])); } function pad(d) { return d < 10 ? '0'+d : d; } function dfmt(d) { return d.getFullYear() + '/' + pad(d.getMonth() + 1) + '/' + pad(d.getDate()); } function obj(m) { - var sb = '<dl>'; - for (var k in m) sb += '<dt class="ib">' + splitCase(k) + '</dt><dd>' + val(m[k]) + '</dd>'; + let sb = '<dl>'; + for (let k in m) sb += '<dt class="ib">' + splitCase(k) + '</dt><dd>' + val(m[k]) + '</dd>'; sb += '</dl>'; return sb; } function arr(m) { if (typeof m[0] == 'string' || typeof m[0] == 'number') return m.join(', '); - var id=tbls.length, h=uniqueKeys(m); - var sb = '<table id="tbl-' + id + '"><caption></caption><thead><tr>'; + let id=tbls.length, h=uniqueKeys(m); + let sb = '<table id="tbl-' + id + '"><caption></caption><thead><tr>'; tbls.push(m); - var i=0; - for (var k in h) sb += '<th id="h-' + id + '-' + (i++) + '"><b></b>' + splitCase(k) + '</th>'; + let i=0; + for (let k in h) sb += '<th id="h-' + id + '-' + (i++) + '"><b></b>' + splitCase(k) + '</th>'; sb += '</tr></thead><tbody>' + makeRows(h,m) + '</tbody></table>'; return sb; } function makeRows(h,m) { - var sb = ''; - for (var r=0,len=m.length; r<len; r++) { + let sb = ''; + for (let r=0,len=m.length; r<len; r++) { sb += '<tr>'; - var row = m[r]; - for (var k in h) sb += '<td>' + val(row[k]) + '</td>'; + let row = m[r]; + for (let k in h) sb += '<td>' + val(row[k]) + '</td>'; sb += '</tr>'; } return sb; @@ -91,7 +91,7 @@ _.jsonreport = (function(){ function setTableBody(tbody, html) { if (!isIE) { tbody.innerHTML = html; return; } - var temp = tbody.ownerDocument.createElement('div'); + let temp = tbody.ownerDocument.createElement('div'); temp.innerHTML = '<table>' + html + '</table>'; tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); } @@ -99,17 +99,17 @@ _.jsonreport = (function(){ function clearSel() { if (doc.selection && doc.selection.empty) doc.selection.empty(); else if(root.getSelection) { - var sel=root.getSelection(); + let sel=root.getSelection(); if (sel && sel.removeAllRanges) sel.removeAllRanges(); } } function cmp(v1, v2){ - var f1, f2, f1=parseFloat(v1), f2=parseFloat(v2); - if (!isNaN(f1) && !isNaN(f2)) v1=f1, v2=f2; - if (typeof v1 == 'string' && v1.substr(0,6) == '/Date(') v1=date(v1), v2=date(v2); - if (v1 == v2) return 0; - return v1 > v2 ? 1 : -1; + let f1=parseFloat(v1), f2=parseFloat(v2) + if (!isNaN(f1) && !isNaN(f2)) { v1=f1; v2=f2 } + if (typeof v1 == 'string' && v1.substr(0,6) === '/Date(') { v1=date(v1); v2=date(v2) } + if (v1 === v2) return 0 + return v1 > v2 ? 1 : -1 } function enc(html) { @@ -127,22 +127,23 @@ _.jsonreport = (function(){ } addEvent(doc, 'click', function (e) { - var e = e || root.event, el = e.target || e.srcElement, cls = el.className; - if (el.tagName == 'B') el = el.parentNode; - if (el.tagName != 'TH') return; - el.className = cls == 'asc' ? 'desc' : (cls == 'desc' ? null : 'asc'); - $.each($$('TH'), function(i,th){ if (th == el) return; th.className = null; }); - clearSel(); - var ids=el.id.split('-'), tId=ids[1], cId=ids[2]; - var tbl=tbls[tId].slice(0), h=uniqueKeys(tbl), col=keys(h)[cId], tbody=el.parentNode.parentNode.nextSibling; - if (!el.className){ setTableBody(tbody, makeRows(h,tbls[tId])); return; } - var d=el.className=='asc'?1:-1; - tbl.sort(function(a,b){ return cmp(a[col],b[col]) * d; }); - setTableBody(tbody, makeRows(h,tbl)); - }); + e = e || root.event + let el = e.target || e.srcElement, cls = el.className + if (el.tagName === 'B') el = el.parentNode + if (el.tagName !== 'TH') return + el.className = cls === 'asc' ? 'desc' : (cls === 'desc' ? null : 'asc') + $.each($$('TH'), function(i,th){ if (th === el) return; th.className = null; }) + clearSel() + let ids=el.id.split('-'), tId=ids[1], cId=ids[2] + let tbl=tbls[tId].slice(0), h=uniqueKeys(tbl), col=keys(h)[cId], tbody=el.parentNode.parentNode.nextSibling + if (!el.className){ setTableBody(tbody, makeRows(h,tbls[tId])); return } + let d=el.className==='asc'?1:-1 + tbl.sort(function(a,b){ return cmp(a[col],b[col]) * d; }) + setTableBody(tbody, makeRows(h,tbl)) + }) return function(json) { - var model = typeof json == "string" ? JSON.parse(json) : json; + let model = typeof json == "string" ? JSON.parse(json) : json; return val(model); }; })(); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/login.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/login.js deleted file mode 100644 index e40fbc4dcaf..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/login.js +++ /dev/null @@ -1,84 +0,0 @@ -/// <reference path="base.js" /> -(function (root) -{ - var app = root.App; - - app.Login = app.BaseModel.extend({ - urlRoot: "api/auth/credentials", - defaults: { - isAuthenticated: null, - hasRegistered: false, - sessionId: null, - userId: null, - displayName: null, - form: null - }, - initialize: function () - { - _.bindAll(this, "loginSuccess", "loginError"); - }, - signOut: function () - { - console.log('Login.signOut'); - this.set({ isAuthenticated: false }); - }, - login: function ($form) - { - this.$form = $form; - _.post({ - form: $form, - url: $form.attr("action"), - data: _.formData($form), - success: this.loginSuccess, - error: this.loginError - }); - }, - loginSuccess: function (r) - { - this.$form.removeClass("error"); - this.set({ isAuthenticated: true }); - }, - loginError: function () - { - this.$form.addClass("error"); - } - }); - - app.LoginView = app.BaseView.extend( - { - className: "view-login", - - initialize: function () - { - _.bindAll(this, "login", "render"); - - this.model.bind("change:isAuthenticated", this.render); - this.model.bind("change:displayName", this.render); - - this.$("form").submit(this.login); - }, - login: function (e) - { - if (e) e.preventDefault(); - this.model.login(this.$("form")); - }, - render: function () - { - var isAuth = this.model.get('isAuthenticated'); - - $("#signed-out").toggle(!isAuth); - $("#signed-in").toggle(isAuth); - $("#signed-in a.dropdown-toggle").html(this.model.get('displayName') || ''); - }, - signOut: function () - { - console.log('LoginView.signOut'); - var self = this; - _.get("api/auth/logout", function() { - self.model.set({ isAuthenticated: false }); - }); - } - } - ); - -})(window); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/register.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/register.js deleted file mode 100644 index 382ef9f76b8..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/register.js +++ /dev/null @@ -1,71 +0,0 @@ -/// <reference path="base.js" /> -(function (root) -{ - var app = root.App; - - app.RegisterView = app.BaseView.extend( - { - className: "view-register", - initialize: function () - { - _.bindAll(this, "render", "register", "registerSuccess", "login"); - - this.model.bind("change", this.render); - - this.$("[name=displayName]").val("Demis"); - this.$("[name=email]").val("demis.bellot@gmail.com"); - this.$("[name=password]").val("test"); - - this.$el = $(this.el); - this.$errorMsg = this.$el.find("form b[data-error=summary]"); - this.$signup = $(this.el).find("#signup"); - this.$registerLogin = $(this.el).find("#register-login"); - - this.$signup.find("form").submit(this.register); - this.$registerLogin.find("form").submit(this.login); - }, - register: function (e) - { - if (e) e.preventDefault(); - - var form = this.$signup.find("form"); - _.post({ - form: form, - url: form.attr("action"), - data: _.formData(form), - success: this.registerSuccess - }); - - this.$registerLogin.find("INPUT[name=userName]").val(form.find("INPUT[name=email]").val()); - }, - registerSuccess: function (r) - { - this.model.set({ hasRegistered: true, userId: r.userId }); - }, - login: function (e) - { - if (e) e.preventDefault(); - this.model.login(this.$registerLogin.find("form")); - }, - signIn: function (e) - { - this.model.set({ hasRegistered: true }); - }, - unregistered: function (e) { - this.model.set({ hasRegistered: false }); - }, - render: function () - { - this.$errorMsg.html(""); - - var auth = this.model.get("isAuthenticated"); - var registered = this.model.get('hasRegistered'); - console.log("register.render(): auth=" + auth); - - this.$registerLogin.toggle(registered && !auth); - this.$signup.toggle(!registered && !auth); - } - } - ); - -})(window); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/ss-validation.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/ss-validation.js deleted file mode 100644 index 423e74b449b..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/ss-validation.js +++ /dev/null @@ -1,79 +0,0 @@ -(function ($) { - - if (!$.ss) $.ss = {}; - if (!$.ss.validation) - $.ss.validation = { - overrideMessages: false, - messages: { - NotEmpty: "Required", - NotNull: "Required", - Email: "Invalid email", - AlreadyExists: "Already exists" - }, - errorFilter: function (errorMsg, errorCode, type) { - return this.overrideMessages - ? this.messages[errorCode] || errorMsg || splitCase(errorCode) - : errorMsg || splitCase(errorCode); - } - }; - - function splitCase(t) { - return typeof t != 'string' ? t : t.replace( /([A-Z]|[0-9]+)/g , ' $1').replace( /_/g , ' '); - }; - - $.fn.applyErrors = function(responseStatus, opt) { - this.clearErrors(); - if (!responseStatus) return this; - - this.addClass("error"); - - var o = _.defaults({}, opt, $.ss.validation); - if (opt && opt.messages) { - o.overrideMessages = true; - _.extend(o.messages, $.ss.validation.messages); - } - - var filter = _.bind(o.errorFilter, o), - errors = responseStatus.errors; - - console.log(errors, responseStatus); - - if (errors && errors.length) { - var fieldMap = { }; - this.find("input").each(function() { - var $el = $(this); - var $prev = $el.prev(), $next = $el.next(); - - if ($prev.hasClass("help-inline") || $prev.hasClass("help-block")) { - fieldMap[(this.id || $el.attr("name")).toLowerCase()] = $prev; - } else if ($next.hasClass("help-inline") || $next.hasClass("help-block")) { - fieldMap[(this.id || $el.attr("name")).toLowerCase()] = $next; - } - }); - _.each(errors, function(error) { - var $field = fieldMap[(error.fieldName||"").toLowerCase()]; - if (!$field) return; - - $field.parent().addClass("error"); - $field.html(filter(error.message, error.errorCode, "field")); - $field.show(); - }); - } else { - this.find(".error-summary").html( - filter(responseStatus.message || splitCase(responseStatus.errorCode), responseStatus.errorCode, "summary") - ).show(); - } - return this; - }; - - $.fn.clearErrors = function() { - this.removeClass("error"); - this.find(".error>.help-inline, .error>.help-block").each(function () { - $(this).html(""); - }); - return this.find(".error").each(function() { - $(this).removeClass("error"); - }); - }; - -})(window.jQuery); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/userprofile.js b/tests/ServiceStack.WebHost.IntegrationTests/Content/js/userprofile.js deleted file mode 100644 index 9dfa463843c..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Content/js/userprofile.js +++ /dev/null @@ -1,72 +0,0 @@ -/// <reference path="base.js" /> -/// <reference path="login.js" /> -(function (root) -{ - var app = root.App; - - app.UserProfile = app.BaseModel.extend({ - url: "api/profile", - defaults: { - id: null, - userName: null, - displayName: null, - profileImageUrl64: null, - showProfile: null, - email: null - }, - initialize: function (opt) - { - _.bindAll(this, "authChange", "onChange"); - - this.login = opt.login; - this.login.bind("change:isAuthenticated", this.authChange); - this.bind("change", this.onChange); - }, - onChange: function () { - this.login.set({ displayName: this.get('displayName') }); - }, - authChange: function () - { - if (this.login.get("isAuthenticated")) - this.fetch(); - else - this.clear(); - } - }); - - app.UserProfileView = app.BaseView.extend( - { - initialize: function () - { - _.bindAll(this, "render"); - this.model.bind("change", this.render); - this.$el = $(this.el); - this.template = _.template($("#template-userprofile").html()); - }, - render: function () - { - this.$el.hide(); - var attrs = this.model.attributes; - attrs.twitterUserId = attrs.twitterUserId || null; - attrs.facebookUserId = attrs.facebookUserId || null; - console.log(attrs); - - var showProfile = attrs.email || attrs.twitterUserId || attrs.facebookUserId; - if (showProfile) - { - var html = this.template(attrs); - this.$el.html(html); - this.$el.fadeIn('fast'); - } - else - { - this.$el.html(""); - this.$el.hide(); - } - - $("#facebook-signin").toggle(!attrs.facebookUserId); - $("#twitter-signin").toggle(!attrs.twitterUserId); - } - }); - -})(window); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/static-sub-embedded.txt b/tests/ServiceStack.WebHost.IntegrationTests/Content/static-sub-embedded.txt new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/static-sub-embedded.txt @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Content/static-sub.txt b/tests/ServiceStack.WebHost.IntegrationTests/Content/static-sub.txt new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Content/static-sub.txt @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx index 8e0ddc447d1..83694904b79 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx +++ b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx @@ -15,13 +15,14 @@ <![endif]--> <!-- Le styles --> - <link href="Content/bootstrap.css" rel="stylesheet" /> <link href="Content/default.css" rel="stylesheet" /> <script src="Content/js/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="Content/js/underscore.min.js" type="text/javascript"></script> <script src="Content/js/backbone.min.js" type="text/javascript"></script> <script src="Content/js/jsonreport.js" type="text/javascript"></script> <script src="Content/js/ss-validation.js" type="text/javascript"></script> <script src="Content/js/base.js" type="text/javascript"></script> - <style type="text/css"> + <link href="Content/bootstrap.css" rel="stylesheet" /> + <link href="Content/default.css" rel="stylesheet" /> + <%=ServiceStack.MiniProfiler.Profiler.RenderIncludes().AsRaw() %> + <script src="Content/js/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="Content/js/underscore.min.js" type="text/javascript"></script> <script src="Content/js/backbone.min.js" type="text/javascript"></script> <script src="Content/js/jsonreport.js" type="text/javascript"></script> <script src="api/js/ss-utils.js" type="text/javascript"></script> <style type="text/css"> body { padding-top: 60px; } </style> - <%=ServiceStack.MiniProfiler.Profiler.RenderIncludes(null, null, null, null, false, null).AsRaw() %> </head> <body> @@ -45,7 +46,7 @@ <p> <button class="btn" type="submit">Sign In</button><b data-ajax="loading"></b> - or <a href="#" data-cmd="toggle:register,signin">register</a> + or <a href="#" data-click="toggle:register,signin">register</a> </p> <div id="facebook-signin"> @@ -63,7 +64,7 @@ nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. </p> - <button class="btn large primary" data-cmd="toggle:register,signin">Register Now</button> + <button class="btn large primary" data-click="toggle:register,signin">Register Now</button> </div> </div> @@ -88,7 +89,7 @@ <p> <button class="btn" type="submit">Sign Up</button><b data-ajax="loading"></b> - or <a href="#" data-cmd="toggle:signin,register">sign in</a> + or <a href="#" data-click="toggle:signin,register">sign in</a> </p> </fieldset> </div> @@ -117,7 +118,7 @@ <div id="oAuthProviders"></div> <script type="text/javascript"> - $.getJSON("api/userauths", function(r) { + $.getJSON("api/userauths", function (r) { $("#userauths").html(_.jsonreport(r.results)); $("#oAuthProviders").html(_.jsonreport(r.oAuthProviders)); }); @@ -126,61 +127,49 @@ <script type="text/javascript"> - _.each({ - UserName: 'as@if.com', - DisplayName: 'mythz', - Email: 'as@if.com', - Password: 'test', - ConfirmPassword: 'test' - }, function (val, name) { - $("[name=" + name + "]").val(val); - }); - - var clear = function () { - $(".success, .error-summary").hide(); - $(".error").removeClass("error"); - $(".help-inline").html(""); - }; - - $("FORM").submit(function (e) { - e.preventDefault(); - clear(); - - var $form = $(this), - $config = $form.find("#ConfirmPassword"); - - if ($config.length) { - if ($config.val() != $form.find("#Password").val()) { - _.setFieldError($config, "passwords do not match"); - return; - } + $(document).applyValues({ + UserName: 'as@if.com', + DisplayName: 'mythz', + Email: 'as@if.com', + Password: 'test', + ConfirmPassword: 'test' + }); + + function success(r) { + var msg = r.userName + ? "<strong>Welcome " + r.userName + "!</strong> your sessionId is <b>" + r.sessionId + "</b>." + : r.userId + ? "<strong>Welcome</strong> you are user #" + r.userId + + "! You should now <a href='#' data-click='toggle:signin,register'>sign in</a>." + : ""; + if (msg) { + $(".success P").html(msg); + $(".success").fadeIn(); } + } - _.post({ - form: $form, - url: $form.attr("action"), - data: _.formData($form), - success: function (r) { - var msg = r.userName - ? "<strong>Welcome " + r.userName + "!</strong> your sessionId is <b>" + r.sessionId + "</b>." - : r.userId - ? "<strong>Welcome</strong> you are user #" + r.userId - + "! You should now <a href='#' data-cmd='toggle:signin,register'>sign in</a>." - : ""; - if (msg) { - $(".success P").html(msg); - $(".success").fadeIn(); - - if (r.userId) - $("#signin #UserName").val($("#register #Email").val()); - } + $("#signin FORM").bindForm({ + success: success + }); + + $("#register FORM").bindForm({ + validate: function () { + console.log("validate", $(this).serializeMap()); + var formData = $(this).serializeMap(); + + if (formData["ConfirmPassword"] != formData["Password"]) { + $(this).setFieldError("Password", "passwords do not match"); + return false; } - }); + }, + success: function(r) { + $("#signin #UserName").val($("#register #Email").val()); + success(r); + } }); - _.cmdHandler({ + $(document).bindHandlers({ toggle: function (show, hide) { - clear(); $("#" + hide).hide(); $("#" + show).fadeIn(); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs index 714e76d6117..e0e1b15c37d 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.cs @@ -11,7 +11,9 @@ public partial class Default : PageBase { protected void Page_Load(object sender, EventArgs e) { - + var ssTest = base.SessionBag["ss-test"]; + + SessionBag["test"] = "foo"; } } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.designer.cs b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.designer.cs index a6c31be29d5..db1d453bb5e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.designer.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Default.aspx.designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs b/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs index d68ffbe3c72..8cd62811529 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Global.asax.cs @@ -1,26 +1,30 @@ using System; +using System.Linq; +using System.Net; +using System.Runtime.Serialization; using Funq; -using ServiceStack.Authentication.OpenId; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.Common; -using ServiceStack.Common.Utils; +using NUnit.Framework; +using ServiceStack.Admin; +using ServiceStack.Api.OpenApi; +using ServiceStack.Auth; +using ServiceStack.Caching; using ServiceStack.Configuration; +using ServiceStack.Data; +using ServiceStack.Host; using ServiceStack.Messaging; +using ServiceStack.Messaging.Redis; using ServiceStack.MiniProfiler; using ServiceStack.MiniProfiler.Data; using ServiceStack.OrmLite; -using ServiceStack.Plugins.ProtoBuf; +using ServiceStack.ProtoBuf; using ServiceStack.Redis; -using ServiceStack.Redis.Messaging; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Admin; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.Api.Swagger; -using ServiceStack.ServiceInterface.Validation; +using ServiceStack.Common.Tests; +using ServiceStack.DataAnnotations; +using ServiceStack.Formats; +using ServiceStack.Shared.Tests; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Validation; +using ServiceStack.Web; using ServiceStack.WebHost.IntegrationTests.Services; using ServiceStack.WebHost.IntegrationTests.Tests; @@ -28,27 +32,45 @@ namespace ServiceStack.WebHost.IntegrationTests { public class Global : System.Web.HttpApplication { - private const bool StartMqHost = false; + private const bool StartMqHost = false; public class AppHost : AppHostBase { public AppHost() - : base("ServiceStack WebHost IntegrationTests", typeof(Reverse).Assembly) {} + : base("ServiceStack WebHost IntegrationTests", typeof(Reverse).Assembly) + { + //typeof(Authenticate) + // .AddAttributes(new ExcludeAttribute(Feature.Metadata)); + + foreach (var pi in typeof(Authenticate).GetPublicProperties()) + { + if (pi.Name != "provider" && pi.Name != "UserName" && pi.Name != "Password") + { + pi.AddAttributes(new IgnoreDataMemberAttribute()); + } + } + } public override void Configure(Container container) { - JsConfig.EmitCamelCaseNames = true; + IocShared.Configure(this); - this.PreRequestFilters.Add((req, res) => { - req.Items["_DataSetAtPreRequestFilters"] = true; - }); + JsConfig.Init(new Text.Config { + TextCase = TextCase.CamelCase, + }); + ServiceStack.Auth.RegisterService.AllowUpdates = true; - this.RequestFilters.Add((req, res, dto) => { + this.PreRequestFilters.Add((req, res) => + { + req.Items["_DataSetAtPreRequestFilters"] = true; + }); + + this.GlobalRequestFilters.Add((req, res, dto) => + { req.Items["_DataSetAtRequestFilters"] = true; - var requestFilter = dto as RequestFilter; - if (requestFilter != null) + if (dto is RequestFilter requestFilter) { res.StatusCode = requestFilter.StatusCode; if (!requestFilter.HeaderName.IsNullOrEmpty()) @@ -58,19 +80,22 @@ public override void Configure(Container container) res.Close(); } - var secureRequests = dto as IRequiresSession; - if (secureRequests != null) + if (dto is IRequiresSession secureRequests) { res.ReturnAuthRequired(); } }); + + Plugins.Add(new SoapFormat()); + Plugins.Add(new MiniProfilerFeature()); this.Container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory( "~/App_Data/db.sqlite".MapHostAbsolutePath(), - SqliteDialect.Provider) { - ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current) - }); + SqliteDialect.Provider) + { + ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current) + }); this.Container.Register<ICacheClient>(new MemoryCacheClient()); //this.Container.Register<ICacheClient>(new BasicRedisClientManager()); @@ -81,7 +106,10 @@ public override void Configure(Container container) // c => new SessionFactory(c.Resolve<ICacheClient>())); var dbFactory = this.Container.Resolve<IDbConnectionFactory>(); - dbFactory.Run(db => db.CreateTable<Movie>(true)); + + using (var db = dbFactory.Open()) + db.DropAndCreateTable<Movie>(); + ModelConfig<Movie>.Id(x => x.Title); Routes .Add<Movies>("/custom-movies", "GET, OPTIONS") @@ -94,38 +122,53 @@ public override void Configure(Container container) var resetMovies = this.Container.Resolve<ResetMoviesService>(); resetMovies.Post(null); + container.Register<IRedisClientsManager>(c => new RedisManagerPool()); + + Plugins.Add(new SharpPagesFeature()); + Plugins.Add(new ValidationFeature()); Plugins.Add(new SessionFeature()); Plugins.Add(new ProtoBufFormat()); - Plugins.Add(new SwaggerFeature()); - Plugins.Add(new RequestLogsFeature()); + Plugins.Add(new RequestLogsFeature + { + //RequestLogger = new RedisRequestLogger(container.Resolve<IRedisClientsManager>()) + RequestLogger = new CsvRequestLogger(), + }); + Plugins.Add(new OpenApiFeature + { + }); + Plugins.Add(new PostmanFeature()); + Plugins.Add(new CorsFeature()); + Plugins.Add(new AutoQueryFeature { MaxLimit = 100 }); + //Plugins.Add(new AdminFeature()); container.RegisterValidators(typeof(CustomersValidator).Assembly); + typeof(ResponseStatus) + .AddAttributes(new ServiceStack.DataAnnotations.DescriptionAttribute("This is the Response Status!")); - container.Register(c => new FunqSingletonScope()).ReusedWithin(ReuseScope.Default); - container.Register(c => new FunqRequestScope()).ReusedWithin(ReuseScope.Request); - container.Register(c => new FunqNoneScope()).ReusedWithin(ReuseScope.None); - Routes.Add<IocScope>("/iocscope"); - + typeof(ResponseStatus) + .GetProperty("Message") + .AddAttributes(new ServiceStack.DataAnnotations.DescriptionAttribute("A human friendly error message")); //var onlyEnableFeatures = Feature.All.Remove(Feature.Jsv | Feature.Soap); - SetConfig(new EndpointHostConfig { - GlobalResponseHeaders = { - { "Access-Control-Allow-Origin", "*" }, - { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, - { "Access-Control-Allow-Headers", "Content-Type, X-Requested-With" }, - }, + SetConfig(new HostConfig + { AdminAuthSecret = AuthTestsBase.AuthSecret, + ApiVersion = "0.2.0", //EnableFeatures = onlyEnableFeatures, DebugMode = true, //Show StackTraces for easier debugging + RedirectPaths = + { + { "/swagger-ui", "/swagger-ui/" } + } }); if (StartMqHost) { var redisManager = new BasicRedisClientManager(); var mqHost = new RedisMqServer(redisManager); - mqHost.RegisterHandler<Reverse>(ServiceController.ExecuteMessage); + mqHost.RegisterHandler<Reverse>(ExecuteMessage); mqHost.Start(); this.Container.Register((IMessageService)mqHost); } @@ -135,31 +178,37 @@ public override void Configure(Container container) private void ConfigureAuth(Funq.Container container) { Routes - .Add<Registration>("/register"); + .Add<Register>("/register"); var appSettings = new AppSettings(); Plugins.Add(new AuthFeature(() => new CustomUserSession(), new IAuthProvider[] { - new CredentialsAuthProvider(appSettings), - new FacebookAuthProvider(appSettings), - new TwitterAuthProvider(appSettings), - new GoogleOpenIdOAuthProvider(appSettings), - new OpenIdOAuthProvider(appSettings), + new CredentialsAuthProvider(appSettings), + new FacebookAuthProvider(appSettings), + new TwitterAuthProvider(appSettings), + new GoogleAuthProvider(appSettings), new DigestAuthProvider(appSettings), - new BasicAuthProvider(appSettings), - })); + new BasicAuthProvider(appSettings), + })); Plugins.Add(new RegistrationFeature()); - container.Register<IUserAuthRepository>(c => + container.Register<IAuthRepository>(c => new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())); - var authRepo = (OrmLiteAuthRepository)container.Resolve<IUserAuthRepository>(); + var authRepo = (OrmLiteAuthRepository)container.Resolve<IAuthRepository>(); if (new AppSettings().Get("RecreateTables", true)) authRepo.DropAndReCreateTables(); else - authRepo.CreateMissingTables(); + authRepo.InitSchema(); + } + + public override object OnPreExecuteServiceFilter(IService service, object request, IRequest httpReq, IResponse httpRes) + { + if (service is IocScopeService) + service.InjectRequestIntoDependencies(httpReq); + return request; } } @@ -179,10 +228,9 @@ protected void Application_EndRequest(object src, EventArgs e) { Profiler.Stop(); - var mqHost = AppHostBase.Instance.Container.TryResolve<IMessageService>(); + var mqHost = HostContext.TryResolve<IMessageService>(); if (mqHost != null) mqHost.Start(); } - } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/PageBase.cs b/tests/ServiceStack.WebHost.IntegrationTests/PageBase.cs index c4f4a8bc790..ef73c1d2eaf 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/PageBase.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/PageBase.cs @@ -1,66 +1,49 @@ +using System.ServiceModel.Channels; using System.Web.UI; -using ServiceStack.CacheAccess; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Auth; +using ServiceStack.Caching; +using ServiceStack.Configuration; using ServiceStack.WebHost.IntegrationTests.Tests; namespace ServiceStack.WebHost.IntegrationTests { - public class CustomUserSession : AuthUserSession - { - public string CustomPropety { get; set; } + public class CustomUserSession : AuthUserSession + { + public string CustomProperty { get; set; } - public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, System.Collections.Generic.Dictionary<string, string> authInfo) - { - base.OnAuthenticated(authService, session, tokens, authInfo); + public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, System.Collections.Generic.Dictionary<string, string> authInfo) + { + base.OnAuthenticated(authService, session, tokens, authInfo); - if (session.Email == AuthTestsBase.AdminEmail) - session.Roles.Add(RoleNames.Admin); - } - } + if (session.Email == AuthTestsBase.AdminEmail) + { + var authRepo = authService.TryResolve<IAuthRepository>(); + var userAuth = authRepo.GetUserAuth(session, tokens); + authRepo.AssignRoles(userAuth, roles: new[] { RoleNames.Admin }); + } + } + } - public class PageBase : Page - { + public class PageBase : Page + { /// <summary> /// Typed UserSession /// </summary> private object userSession; - protected virtual TUserSession SessionAs<TUserSession>() - { - return (TUserSession)(userSession ?? (userSession = Cache.SessionAs<TUserSession>())); - } + protected virtual TUserSession SessionAs<TUserSession>() => (TUserSession)(userSession ??= Cache.SessionAs<TUserSession>()); - protected CustomUserSession UserSession - { - get - { - return SessionAs<CustomUserSession>(); - } - } + protected CustomUserSession UserSession => SessionAs<CustomUserSession>(); - public new ICacheClient Cache - { - get { return AppHostBase.Resolve<ICacheClient>(); } - } + public new ICacheClient Cache => HostContext.AppHost.GetCacheClient(null); private ISessionFactory sessionFactory; - public virtual ISessionFactory SessionFactory - { - get { return sessionFactory ?? (sessionFactory = AppHostBase.Resolve<ISessionFactory>()) ?? new SessionFactory(Cache); } - } + public virtual ISessionFactory SessionFactory => sessionFactory ?? (sessionFactory = HostContext.Resolve<ISessionFactory>()) ?? new SessionFactory(Cache); /// <summary> /// Dynamic Session Bag /// </summary> - private ISession session; - public new ISession Session - { - get - { - return session ?? (session = SessionFactory.GetOrCreateSession()); - } - } + private Caching.ISession session; + public Caching.ISession SessionBag => session ??= SessionFactory.GetOrCreateSession(); public void ClearSession() { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs b/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs index 7801735e4ae..b3b8f8a2f15 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Properties/AssemblyInfo.cs @@ -11,8 +11,8 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Microsoft")] [assembly: AssemblyProduct("ServiceStack.WebHost.IntegrationTests")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] +[assembly: AssemblyCopyright("Copyright (c) Microsoft 2010")] +[assembly: AssemblyTrademark("Service Stack")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible @@ -33,7 +33,7 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("6.0.0.0")] [assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStack.WebHost.IntegrationTests.Services")] diff --git a/tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj b/tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj index 617de12f6ae..a68517e612c 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj +++ b/tests/ServiceStack.WebHost.IntegrationTests/ServiceStack.WebHost.IntegrationTests.csproj @@ -1,7 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> + <Version>6.0.0</Version><!-- update manually to remove circular reference --> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>9.0.30729</ProductVersion> @@ -12,12 +13,12 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>ServiceStack.WebHost.IntegrationTests</RootNamespace> <AssemblyName>ServiceStack.WebHost.IntegrationTests</AssemblyName> - <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> <FileUpgradeFlags> </FileUpgradeFlags> <OldToolsVersion>4.0</OldToolsVersion> <UpgradeBackupLocation /> - <UseIISExpress>true</UseIISExpress> + <UseIISExpress>false</UseIISExpress> <IISExpressSSLPort /> <IISExpressAnonymousAuthentication /> <IISExpressWindowsAuthentication /> @@ -25,6 +26,10 @@ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\src\</SolutionDir> <RestorePackages>true</RestorePackages> <TargetFrameworkProfile /> + <UseGlobalApplicationHostFile /> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> + <Use64BitIISExpress /> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>True</DebugSymbols> @@ -35,8 +40,9 @@ <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <Prefer32Bit>false</Prefer32Bit> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> @@ -47,6 +53,7 @@ <WarningLevel>4</WarningLevel> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <PlatformTarget>x86</PlatformTarget> + <Prefer32Bit>false</Prefer32Bit> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'MONOTOUCH|AnyCPU'"> <OutputPath>bin\</OutputPath> @@ -64,60 +71,40 @@ <CodeAnalysisRuleDirectories>;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories> <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules> <WarningLevel>4</WarningLevel> + <Prefer32Bit>false</Prefer32Bit> </PropertyGroup> <ItemGroup> - <Reference Include="Mono.Data.Sqlite"> - <HintPath>..\..\lib\tests\Mono.Data.Sqlite.dll</HintPath> - </Reference> - <Reference Include="protobuf-net, Version=2.0.0.640, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\..\src\packages\protobuf-net.2.0.0.640\lib\net40\protobuf-net.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite"> - <HintPath>..\..\lib\ServiceStack.OrmLite.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.OrmLite.Sqlite"> - <HintPath>..\..\lib\ServiceStack.OrmLite.Sqlite.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Redis"> - <HintPath>..\..\lib\ServiceStack.Redis.dll</HintPath> - </Reference> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="mscorlib" /> <Reference Include="System" /> + <Reference Include="System.ComponentModel.DataAnnotations" /> + <Reference Include="System.Core" /> <Reference Include="System.Data" /> <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.IdentityModel" /> + <Reference Include="System.Net" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Numerics" /> + <Reference Include="System.Runtime" /> <Reference Include="System.Runtime.Serialization"> <RequiredTargetFramework>3.0</RequiredTargetFramework> </Reference> <Reference Include="System.ServiceModel"> <RequiredTargetFramework>3.0</RequiredTargetFramework> </Reference> - <Reference Include="System.Web.ApplicationServices" /> - <Reference Include="System.Web.DynamicData" /> - <Reference Include="System.Web.Entity" /> - <Reference Include="System.Web.Extensions" /> <Reference Include="System.Drawing" /> + <Reference Include="System.Threading" /> + <Reference Include="System.Threading.Tasks" /> <Reference Include="System.Web" /> + <Reference Include="System.Web.Extensions" /> + <Reference Include="System.Web.Services" /> <Reference Include="System.Xml" /> <Reference Include="System.Configuration" /> - <Reference Include="System.Web.Services" /> - <Reference Include="System.EnterpriseServices" /> - <Reference Include="Moq"> - <HintPath>..\..\lib\tests\Moq.dll</HintPath> - </Reference> - <Reference Include="nunit.framework"> - <HintPath>..\..\lib\tests\nunit.framework.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Text"> - <HintPath>..\..\lib\ServiceStack.Text.dll</HintPath> - </Reference> - <Reference Include="System.Xml.Linq" /> </ItemGroup> <ItemGroup> - <Content Include="..\..\lib\sqlite3.dll"> - <Link>sqlite3.dll</Link> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> <Content Include="Content\bootstrap.css" /> + <EmbeddedResource Include="Content\static-sub-embedded.txt" /> + <Content Include="Content\default.html" /> <Content Include="Content\default.css" /> <Content Include="Content\img\bootstrap-apple-114x114.png" /> <Content Include="Content\img\bootstrap-apple-57x57.png" /> @@ -138,37 +125,19 @@ <Content Include="Content\img\ui-icons_454545_256x240.png" /> <Content Include="Content\img\ui-icons_888888_256x240.png" /> <Content Include="Content\img\ui-icons_cd0a0a_256x240.png" /> - <Content Include="Content\js\app.js" /> <Content Include="Content\js\backbone.min.js" /> - <Content Include="Content\js\base.js" /> <Content Include="Content\js\jquery-1.7.1.min.js" /> <Content Include="Content\js\jsonreport.js" /> - <Content Include="Content\js\login.js" /> - <Content Include="Content\js\register.js" /> - <Content Include="Content\js\ss-validation.js" /> <Content Include="Content\js\underscore.min.js" /> - <Content Include="Content\js\userprofile.js" /> <Content Include="Content\js\_blank.js" /> + <Content Include="Content\static-sub.txt" /> + <EmbeddedResource Include="static-root-embedded.txt" /> <Content Include="Default.aspx" /> + <Content Include="default.html" /> + <Content Include="start.cmd" /> <Content Include="Subpages\Test.aspx" /> - <Content Include="swagger-ui\css\hightlight.default.css" /> - <Content Include="swagger-ui\css\screen.css" /> - <Content Include="swagger-ui\images\logo_small.png" /> - <Content Include="swagger-ui\images\pet_store_api.png" /> - <Content Include="swagger-ui\images\throbber.gif" /> - <Content Include="swagger-ui\images\wordnik_api.png" /> - <Content Include="swagger-ui\index.html" /> - <Content Include="swagger-ui\lib\backbone-min.js" /> - <Content Include="swagger-ui\lib\handlebars-1.0.rc.1.js" /> - <Content Include="swagger-ui\lib\highlight.7.3.pack.js" /> - <Content Include="swagger-ui\lib\jquery-1.8.0.min.js" /> - <Content Include="swagger-ui\lib\jquery.ba-bbq.min.js" /> - <Content Include="swagger-ui\lib\jquery.slideto.min.js" /> - <Content Include="swagger-ui\lib\jquery.wiggle.min.js" /> - <Content Include="swagger-ui\lib\swagger.js" /> - <Content Include="swagger-ui\lib\underscore-min.js" /> - <Content Include="swagger-ui\swagger-ui.js" /> - <Content Include="swagger-ui\swagger-ui.min.js" /> + <EmbeddedResource Include="Templates\OperationControl.html" /> + <EmbeddedResource Include="Templates\HtmlFormat.html" /> <Content Include="user-notfound.htm" /> <Content Include="user-default.htm" /> <Content Include="Global.asax" /> @@ -182,9 +151,22 @@ <Content Include="webpage.html" /> </ItemGroup> <ItemGroup> - <Compile Include="PageBase.cs"> - <SubType>ASPXCodeBehind</SubType> + <Compile Include="..\ServiceStack.Common.Tests\IocExtensions.cs"> + <Link>Common.Tests\IocExtensions.cs</Link> + </Compile> + <Compile Include="..\ServiceStack.Common.Tests\TestBase.cs"> + <Link>Common.Tests\TestBase.cs</Link> </Compile> + <Compile Include="Services\AsyncTaskServices.cs" /> + <Compile Include="Services\CookiesService.cs" /> + <Compile Include="Services\CustomPathServices.cs" /> + <Compile Include="Services\CustomRouteService.cs" /> + <Compile Include="Services\SessionTest.cs" /> + <Compile Include="Services\TemplateService.cs" /> + <Compile Include="Services\VerbOnlyService.cs" /> + <Compile Include="Shared\IocService.cs" /> + <Compile Include="Tests\AsyncProgressTests.cs" /> + <Compile Include="PageBase.cs" /> <Compile Include="Default.aspx.cs"> <DependentUpon>Default.aspx</DependentUpon> <SubType>ASPXCodeBehind</SubType> @@ -197,9 +179,9 @@ <Compile Include="Services\CustomHeadersService.cs" /> <Compile Include="Services\EndpointAccessService.cs" /> <Compile Include="Services\HelloImage.cs" /> - <Compile Include="Services\IocServiceTests.cs" /> <Compile Include="Services\RequestItemsService.cs" /> <Compile Include="Services\SwaggerTestService.cs" /> + <Compile Include="Services\TestProgressService.cs" /> <Compile Include="Subpages\Test.aspx.cs"> <DependentUpon>Test.aspx</DependentUpon> <SubType>ASPXCodeBehind</SubType> @@ -207,8 +189,13 @@ <Compile Include="Subpages\Test.aspx.designer.cs"> <DependentUpon>Test.aspx</DependentUpon> </Compile> + <Compile Include="Tests\AsyncRestClientTests.cs" /> <Compile Include="Tests\BinarySerializedTests.cs" /> + <Compile Include="Tests\AsyncTaskTests.cs" /> + <Compile Include="Tests\CookieTests.cs" /> <Compile Include="Tests\CustomHeadersTests.cs" /> + <Compile Include="Tests\LoadTests.cs" /> + <Compile Include="Tests\ReqtestsTests.cs" /> <Compile Include="Tests\ExceptionHandlingTests.cs" /> <Compile Include="Tests\ProtoBufServiceTests.cs" /> <Compile Include="Services\ContentManagerOnly.cs" /> @@ -218,7 +205,7 @@ <Compile Include="Services\BatchWidgetValidationService.cs" /> <Compile Include="Services\CachedMoviesService.cs" /> <Compile Include="Tests\RawRequestTests.cs" /> - <Compile Include="Tests\ManageRolesTests.cs" /> + <Compile Include="Tests\AssertValidAccessTests.cs" /> <Compile Include="Services\TestService.cs" /> <Compile Include="Services\CustomerService.cs" /> <Compile Include="Services\SessionService.cs" /> @@ -227,7 +214,7 @@ <Compile Include="Services\CustomFormDataService.cs" /> <Compile Include="Services\GeoInfoService.cs" /> <Compile Include="Services\ProfilerService.cs" /> - <Compile Include="Services\RouteInfoService.cs" /> + <Compile Include="Services\RouteTokenInfoService.cs" /> <Compile Include="Services\UserAuths.cs" /> <Compile Include="Tests\AppHostBaseTests.cs" /> <Compile Include="Tests\CachedServiceTests.cs" /> @@ -264,62 +251,79 @@ <Compile Include="Tests\MovieServiceTests.cs" /> <Compile Include="Tests\RequestAndPathResolutionTests.cs" /> <Compile Include="Tests\RequestFilterTests.cs" /> + <Compile Include="Tests\RequestInfoTests.cs" /> <Compile Include="Tests\RestPathResolutionUnitTests.cs" /> <Compile Include="Tests\RestsTestBase.cs" /> <Compile Include="Tests\RestWebServiceTests.cs" /> + <Compile Include="Tests\RouteTests.cs" /> <Compile Include="Tests\SessionTests.cs" /> + <Compile Include="Tests\SoapTests.cs" /> <Compile Include="Tests\UniqueRequestTests.cs" /> + <Compile Include="Tests\VirtualPathTests.cs" /> <Compile Include="Tests\WebServicesTests.cs" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\..\src\ServiceStack.Api.Swagger\ServiceStack.Api.Swagger.csproj"> - <Project>{01D3F057-7984-498F-8B0A-EB375701E204}</Project> - <Name>ServiceStack.Api.Swagger</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Authentication.OpenId\ServiceStack.Authentication.OpenId.csproj"> - <Project>{6E240294-9D93-4C09-9BB0-38D82A22DEEE}</Project> - <Name>ServiceStack.Authentication.OpenId</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Common\ServiceStack.Common.csproj"> - <Project>{982416DB-C143-4028-A0C3-CF41892D18D3}</Project> - <Name>ServiceStack.Common</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Interfaces\ServiceStack.Interfaces.csproj"> - <Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project> - <Name>ServiceStack.Interfaces</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Plugins.ProtoBuf\ServiceStack.Plugins.ProtoBuf.csproj"> - <Project>{EF36A253-C53F-4BF3-B0EC-4D29211FA67D}</Project> - <Name>ServiceStack.Plugins.ProtoBuf</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj"> - <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project> - <Name>ServiceStack.ServiceInterface</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj"> - <Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project> - <Name>ServiceStack</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <Content Include="packages.config" /> + <Content Include="static-root.txt" /> + <Content Include="App.config" /> <None Include="Properties\DataSources\ServiceStack.ServiceInterface.ServiceModel.ResponseStatus.datasource" /> <None Include="README.md" /> - <Content Include="swagger-ui\LICENSE" /> + <Content Include="sample.pdf" /> <None Include="webpage.forbidden" /> </ItemGroup> <ItemGroup> <Folder Include="App_Data\" /> </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" /> + <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> + <PackageReference Include="NUnit" Version="3.13.2" /> + <PackageReference Include="protobuf-net" Version="3.0.101" /> + <PackageReference Include="protobuf-net.Core" Version="3.0.101" /> + <PackageReference Include="ServiceStack" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Api.OpenApi" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Client" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Common" Version="$(Version)" /> + <PackageReference Include="ServiceStack.HttpClient" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Interfaces" Version="$(Version)" /> + <PackageReference Include="ServiceStack.NetFramework" Version="$(Version)" /> + <PackageReference Include="ServiceStack.OrmLite" Version="$(Version)" /> + <PackageReference Include="ServiceStack.OrmLite.Sqlite" Version="$(Version)" /> + <PackageReference Include="ServiceStack.ProtoBuf" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Redis" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Server" Version="$(Version)" /> + <PackageReference Include="ServiceStack.Text" Version="$(Version)" /> + <PackageReference Include="System.Buffers" Version="4.5.1" /> + <PackageReference Include="System.Collections.Immutable" Version="1.7.1" /> + <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> + <PackageReference Include="System.Memory" Version="4.5.4" /> + <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" /> + <PackageReference Include="System.Reflection.Emit" Version="4.7.0" /> + <PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" /> + <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.1" /> + <PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.3.0" /> + <PackageReference Include="System.ServiceModel.Primitives" Version="4.8.1" /> + <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" /> + <PackageReference Include="System.ValueTuple" Version="4.5.0" /> + </ItemGroup> <PropertyGroup> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Signed|AnyCPU'"> + <OutputPath>bin\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <Optimize>true</Optimize> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x86</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" /> - <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" /> - <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> @@ -340,7 +344,7 @@ <AutoAssignPort>False</AutoAssignPort> <DevelopmentServerPort>50000</DevelopmentServerPort> <DevelopmentServerVPath>/</DevelopmentServerVPath> - <IISUrl>http://localhost:50095/</IISUrl> + <IISUrl>http://localhost:50000/</IISUrl> <NTLMAuthentication>False</NTLMAuthentication> <UseCustomServer>False</UseCustomServer> <CustomServerUrl> @@ -351,4 +355,4 @@ </VisualStudio> </ProjectExtensions> <Import Project="$(SolutionDir)\.nuget\NuGet.targets" /> -</Project> +</Project> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/AlwaysThrowsService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/AlwaysThrowsService.cs index a239b0f5846..35303e6febd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/AlwaysThrowsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/AlwaysThrowsService.cs @@ -1,21 +1,48 @@ using System; +using System.Collections.Generic; using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.FluentValidation; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { - [DataContract] - public class AlwaysThrows - { - [DataMember] - public int? StatusCode { get; set; } - [DataMember] - public string Value { get; set; } - } + [DataContract] + public class AlwaysThrows + { + [DataMember] + public int? StatusCode { get; set; } + [DataMember] + public string Value { get; set; } + } + + [Route("/throwslist/{StatusCode}/{Value}")] + [DataContract] + public class AlwaysThrowsList + { + [DataMember] + public int? StatusCode { get; set; } + [DataMember] + public string Value { get; set; } + } + + [Route("/throwsvalidation")] + [DataContract] + public class AlwaysThrowsValidation + { + [DataMember] + public string Value { get; set; } + } + + public class AlwaysThrowsValidator : AbstractValidator<AlwaysThrowsValidation> + { + public AlwaysThrowsValidator() + { + RuleFor(x => x.Value).NotEmpty(); + } + } - [DataContract] + + [DataContract] public class AlwaysThrowsResponse : IHasResponseStatus { @@ -31,23 +58,34 @@ public AlwaysThrowsResponse() public ResponseStatus ResponseStatus { get; set; } } - public class AlwaysThrowsService - : ServiceInterface.Service + public class AlwaysThrowsService : Service { - public object Any(AlwaysThrows request) - { + public object Any(AlwaysThrows request) + { if (request.StatusCode.HasValue) { throw new HttpError( request.StatusCode.Value, typeof(NotImplementedException).Name, - request.Value); + GetErrorMessage(request.Value)); } - throw new NotImplementedException(GetErrorMessage(request.Value)); - } + throw new NotImplementedException(GetErrorMessage(request.Value)); + } + + public List<AlwaysThrows> Any(AlwaysThrowsList request) + { + Any(request.ConvertTo<AlwaysThrows>()); + + return new List<AlwaysThrows>(); + } + + public List<AlwaysThrows> Any(AlwaysThrowsValidation request) + { + return new List<AlwaysThrows>(); + } - public static string GetErrorMessage(string value) + public static string GetErrorMessage(string value) { return value + " is not implemented"; } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/AsyncTaskServices.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/AsyncTaskServices.cs new file mode 100644 index 00000000000..7255b58565a --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/AsyncTaskServices.cs @@ -0,0 +1,148 @@ +using System.Runtime.Serialization; +using System.Threading.Tasks; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/factorial/sync/{ForNumber}")] + [DataContract] + public class GetFactorialSync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/async/{ForNumber}")] + [DataContract] + public class GetFactorialGenericAsync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/object/{ForNumber}")] + [DataContract] + public class GetFactorialObjectAsync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/await/{ForNumber}")] + [DataContract] + public class GetFactorialAwaitAsync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/delay/{ForNumber}")] + [DataContract] + public class GetFactorialDelayAsync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/newtask/{ForNumber}")] + [DataContract] + public class GetFactorialNewTaskAsync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/newtcs/{ForNumber}")] + [DataContract] + public class GetFactorialNewTcsAsync : IReturn<GetFactorialResponse> + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/factorial/unmarked/{ForNumber}")] + [DataContract] + public class GetFactorialUnmarkedAsync + { + [DataMember] + public long ForNumber { get; set; } + } + + [Route("/voidasync")] + [DataContract] + public class VoidAsync : IReturnVoid + { + [DataMember] + public string Message { get; set; } + } + + public class GetFactorialAsyncService : IService + { + public object Any(GetFactorialSync request) + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + } + + public Task<GetFactorialResponse> Any(GetFactorialGenericAsync request) + { + return Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public object Any(GetFactorialObjectAsync request) + { + return Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public async Task<GetFactorialResponse> Any(GetFactorialAwaitAsync request) + { + return await Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public async Task<GetFactorialResponse> Any(GetFactorialDelayAsync request) + { + await Task.Delay(1000); + + return await Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public Task<GetFactorialResponse> Any(GetFactorialNewTaskAsync request) + { + return new Task<GetFactorialResponse>(() => + new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }); + } + + public Task<GetFactorialResponse> Any(GetFactorialNewTcsAsync request) + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }.AsTaskResult(); + } + + public async Task<GetFactorialResponse> Any(GetFactorialUnmarkedAsync request) + { + return await Task.Factory.StartNew(() => + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + }); + } + + public async Task Any(VoidAsync request) + { + await Task.Delay(1); + } + + public static long GetFactorial(long n) + { + return n > 1 ? n * GetFactorial(n - 1) : 1; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/BatchWidgetValidationService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/BatchWidgetValidationService.cs index 78323ea7965..68f5c88f8ef 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/BatchWidgetValidationService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/BatchWidgetValidationService.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -20,9 +19,9 @@ public class BatchWidgetValidationResponse } public class BatchWidgetValidationRequestService - : IService<BatchWidgetValidationRequest> + : IService { - public object Execute(BatchWidgetValidationRequest request) + public object Any(BatchWidgetValidationRequest request) { throw new NotImplementedException(); } @@ -62,9 +61,9 @@ public class WidgetValidationResponse } public class WidgetValidationRequestService - : IService<WidgetValidationRequest> + : IService { - public object Execute(WidgetValidationRequest request) + public object Any(WidgetValidationRequest request) { throw new NotImplementedException(); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs index 347fe7f5332..723a7e99f4e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedMoviesService.cs @@ -1,6 +1,4 @@ using System.Runtime.Serialization; -using ServiceStack.Common; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -13,15 +11,14 @@ public class CachedMovies public string Genre { get; set; } } - public class CachedMoviesService : ServiceInterface.Service + public class CachedMoviesService : Service { public object Get(CachedMovies request) { var service = base.ResolveService<MoviesService>(); - return base.RequestContext.ToOptimizedResultUsingCache( - this.Cache, UrnId.Create<Movies>(request.Genre ?? "all"), () => - { + return base.Request.ToOptimizedResultUsingCache( + this.Cache, UrnId.Create<Movies>(request.Genre ?? "all"), () => { return (MoviesResponse)service.Get(new Movies { Genre = request.Genre }); }); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs index 5f109365715..75686dad11f 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CachedProtoBufEmailService.cs @@ -1,6 +1,4 @@ using System.Runtime.Serialization; -using ServiceStack.Common; -using ServiceStack.ServiceHost; using ServiceStack.WebHost.IntegrationTests.Tests; namespace ServiceStack.WebHost.IntegrationTests.Services @@ -23,7 +21,7 @@ public class UncachedProtoBufEmail public string FromAddress { get; set; } } - class UncachedProtoBufEmailService : ServiceInterface.Service + class UncachedProtoBufEmailService : Service { public object Any(UncachedProtoBufEmail request) { @@ -31,11 +29,11 @@ public object Any(UncachedProtoBufEmail request) } } - class CachedProtoBufEmailService : ServiceInterface.Service + class CachedProtoBufEmailService : Service { public object Any(CachedProtoBufEmail request) { - return base.RequestContext.ToOptimizedResultUsingCache(this.Cache, + return base.Request.ToOptimizedResultUsingCache(this.Cache, UrnId.Create<ProtoBufEmail>(request.FromAddress ?? "none"), () => new ProtoBufEmail { FromAddress = request.FromAddress ?? "none" }); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs index b522aa02af0..3ad9484e8d3 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ContentManagerOnly.cs @@ -1,7 +1,4 @@ -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.WebHost.IntegrationTests.Tests; +using ServiceStack.WebHost.IntegrationTests.Tests; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -16,8 +13,8 @@ public class ContentManagerOnlyResponse : IHasResponseStatus public ResponseStatus ResponseStatus { get; set; } } - [RequiredRole(ManageRolesTests.ContentManager)] - public class ContentManagerOnlyService : ServiceInterface.Service + [RequiredRole(AssertValidAccessTests.ContentManager)] + public class ContentManagerOnlyService : Service { public object Any(ContentManagerOnly request) { @@ -36,8 +33,8 @@ public class ContentPermissionOnlyResponse : IHasResponseStatus public ResponseStatus ResponseStatus { get; set; } } - [RequiredPermission(ManageRolesTests.ContentPermission)] - public class ContentPermissionOnlyService : ServiceInterface.Service + [RequiredPermission(AssertValidAccessTests.ContentPermission)] + public class ContentPermissionOnlyService : Service { public object Any(ContentPermissionOnly request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CookiesService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CookiesService.cs new file mode 100644 index 00000000000..b6d07746568 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CookiesService.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/cookies")] + public class Cookies : IReturn<CookiesResponse> {} + + public class CookiesResponse + { + public List<string> RequestCookieNames { get; set; } + } + + public class CookiesService : Service + { + public CookiesResponse Any(Cookies c) + { + var response = new CookiesResponse + { + RequestCookieNames = Request.Cookies.Keys.ToList(), + }; + return response; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomFormDataService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomFormDataService.cs index ef7d43e3ac7..10e46375461 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomFormDataService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomFormDataService.cs @@ -1,7 +1,5 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -25,18 +23,16 @@ public class CustomFormDataResponse : IHasResponseStatus public ResponseStatus ResponseStatus { get; set; } } - public class CustomFormDataService : ServiceInterface.Service + public class CustomFormDataService : Service { //Parsing: &first-name=tom&item-0=blah&item-1-delete=1 public object Post(CustomFormData request) { - var httpReq = base.RequestContext.Get<IHttpRequest>(); - return new CustomFormDataResponse { - FirstName = httpReq.FormData["first-name"], - Item0 = httpReq.FormData["item-0"], - Item1Delete = httpReq.FormData["item-1-delete"] + FirstName = Request.FormData["first-name"], + Item0 = Request.FormData["item-0"], + Item1Delete = Request.FormData["item-1-delete"] }; } } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomHeadersService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomHeadersService.cs index c81a1c1c05d..65f1a8970f0 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomHeadersService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomHeadersService.cs @@ -1,5 +1,4 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -17,7 +16,7 @@ public class CustomHeadersResponse public string Bar { get; set; } } - public class CustomHeadersService : ServiceInterface.Service + public class CustomHeadersService : Service { public CustomHeadersResponse Any(CustomHeaders c) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomPathServices.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomPathServices.cs new file mode 100644 index 00000000000..03f58183b68 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomPathServices.cs @@ -0,0 +1,15 @@ +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/gettestapi")] + public class GetTestapi + { + } + + public class CustomPathServices : Service + { + public object Any(GetTestapi request) + { + return new HelloResponse { Result = "GetTestapi" }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomRouteService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomRouteService.cs new file mode 100644 index 00000000000..9a00decf3f5 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomRouteService.cs @@ -0,0 +1,29 @@ +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/custom")] + [Route("/custom/{Data}")] + public class CustomRoute : IReturn<CustomRoute> + { + public string Data { get; set; } + } + + [Route("/customdot/{Id}.{Data}")] + public class CustomRouteDot : IReturn<CustomRouteDot> + { + public string Id { get; set; } + public string Data { get; set; } + } + + public class CustomRouteService : IService + { + public object Any(CustomRoute request) + { + return request; + } + + public object Any(CustomRouteDot request) + { + return request; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomerService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomerService.cs index 6537d3ec452..c872a60d1da 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomerService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/CustomerService.cs @@ -1,10 +1,5 @@ -using System.Runtime.Serialization; using System.Text.RegularExpressions; -using ServiceStack.Common.Web; using ServiceStack.FluentValidation; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -40,7 +35,7 @@ public CustomersValidator() RuleFor(x => x.FirstName).NotEmpty().WithMessage("Please specify a first name"); RuleFor(x => x.Company).NotNull(); RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount); - RuleFor(x => x.Address).Length(20, 250); + RuleFor(x => x.Address).NotNull().Length(20, 250); RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode"); }); } @@ -53,7 +48,7 @@ private bool BeAValidPostcode(string postcode) } } - public class CustomerService : ServiceInterface.Service + public class CustomerService : Service { public object Get(Customers request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs index 56e4c17d4e6..418ba2052a0 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoMethodService.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using ServiceStack.Host; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -17,7 +17,7 @@ public class EchoMethodResponse } [DefaultRequest(typeof(EchoMethod))] - public class EchoMethodService : ServiceInterface.Service + public class EchoMethodService : Service { public object Get(EchoMethod request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs index 7c0624b69ce..567eb77df21 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/EchoRequestService.cs @@ -1,7 +1,5 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -38,7 +36,7 @@ public class EchoRequestResponse public string Result { get; set; } } - public class EchoRequestService : ServiceInterface.Service + public class EchoRequestService : Service { public object Any(EchoRequest request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs index 9ae356b865e..4a4670da5b6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/EndpointAccessService.cs @@ -1,5 +1,4 @@ -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -20,33 +19,33 @@ public class LocalhostOnly { } [Restrict(InternalOnly = true)] public class InternalOnly { } - [Restrict(EndpointAttributes.Xml)] + [Restrict(RequestAttributes.Xml)] public class XmlOnly { } - [Restrict(EndpointAttributes.Json)] + [Restrict(RequestAttributes.Json)] public class JsonOnly { } - [Restrict(EndpointAttributes.Jsv)] + [Restrict(RequestAttributes.Jsv)] public class JsvOnly { } - [Restrict(EndpointAttributes.Csv)] + [Restrict(RequestAttributes.Csv)] public class CsvOnly { } - [Restrict(EndpointAttributes.ProtoBuf)] + [Restrict(RequestAttributes.ProtoBuf)] public class ProtoBufOnly { } - [Restrict(EndpointAttributes.Soap11)] + [Restrict(RequestAttributes.Soap11)] public class Soap11Only { } - [Restrict(EndpointAttributes.Soap12)] + [Restrict(RequestAttributes.Soap12)] public class Soap12Only { } - [Restrict(EndpointAttributes.FormatOther)] + [Restrict(RequestAttributes.FormatOther)] public class OtherFormatOnly { } [Restrict( - EndpointAttributes.InternalNetworkAccess | EndpointAttributes.Json, - EndpointAttributes.External | EndpointAttributes.Xml)] + RequestAttributes.InternalNetworkAccess | RequestAttributes.Json, + RequestAttributes.External | RequestAttributes.Xml)] public class JsonInternalXmlExternal { } - [Restrict(EndpointAttributes.Secure)] + [Restrict(RequestAttributes.Secure)] public class SslOnly { } - [Restrict(EndpointAttributes.Secure | EndpointAttributes.External, - EndpointAttributes.InSecure | EndpointAttributes.InternalNetworkAccess)] + [Restrict(RequestAttributes.Secure | RequestAttributes.External, + RequestAttributes.InSecure | RequestAttributes.InternalNetworkAccess)] public class SslExternalAndInsecureInternal { } @@ -66,7 +65,7 @@ public class ReturnsHttpResultWithResponse public int Id { get; set; } } - public class EndpointAccessService : ServiceInterface.Service + public class EndpointAccessService : Service { public Response Get(GetsOnly request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs index 118c000e6d4..3438b6fbcb5 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/FileUploadService.cs @@ -2,67 +2,106 @@ using System.IO; using System.Runtime.Serialization; using System.ServiceModel.Dispatcher; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using ServiceStack.Text; using ServiceStack.Validation; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { - [DataContract] - [Route("/fileuploads/{RelativePath*}", HttpMethods.Get)] - [Route("/fileuploads", HttpMethods.Post)] - public class FileUpload - { - [DataMember] - public string RelativePath { get; set; } - } - - [DataContract] - public class FileUploadResponse - { - [DataMember] - public string FileName { get; set; } - - [DataMember] - public long ContentLength { get; set; } - - [DataMember] - public string ContentType { get; set; } - - [DataMember] - public string Contents { get; set; } - } - - public class FileUploadService : ServiceInterface.Service - { - public object Get(FileUpload request) - { - if (request.RelativePath.IsNullOrEmpty()) - throw new ArgumentNullException("RelativePath"); - - var filePath = ("~/" + request.RelativePath).MapHostAbsolutePath(); - if (!File.Exists(filePath)) - throw new FilterInvalidBodyAccessException(request.RelativePath); - - var result = new HttpResult(new FileInfo(filePath)); - return result; - } - - public object Post(FileUpload request) - { - if (this.RequestContext.Files.Length == 0) - throw new ValidationError("UploadError", "No such file exists"); - - var file = this.RequestContext.Files[0]; - return new FileUploadResponse - { - FileName = file.FileName, - ContentLength = file.ContentLength, - ContentType = file.ContentType, - Contents = new StreamReader(file.InputStream).ReadToEnd(), - }; - } - } + [DataContract] + [Route("/fileuploads/{RelativePath*}")] + [Route("/fileuploads", HttpMethods.Post)] + public class FileUpload : IReturn<FileUploadResponse> + { + [DataMember] + public string RelativePath { get; set; } + + [DataMember] + public string CustomerName { get; set; } + + [DataMember] + public int? CustomerId { get; set; } + + [DataMember] + public DateTime CreatedDate { get; set; } + } + + [DataContract] + public class FileUploadResponse : IHasResponseStatus + { + [DataMember] + public string Name { get; set; } + + [DataMember] + public string FileName { get; set; } + + [DataMember] + public long ContentLength { get; set; } + + [DataMember] + public string ContentType { get; set; } + + [DataMember] + public string Contents { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + + [DataMember] + public string CustomerName { get; set; } + + [DataMember] + public int? CustomerId { get; set; } + + [DataMember] + public DateTime CreatedDate { get; set; } + } + + public class FileUploadService : Service + { + public object Get(FileUpload request) + { + if (request.RelativePath.IsNullOrEmpty()) + throw new ArgumentNullException("RelativePath"); + + var filePath = ("~/" + request.RelativePath).MapHostAbsolutePath(); + if (!File.Exists(filePath)) + throw new FileNotFoundException(request.RelativePath); + + var result = new HttpResult(new FileInfo(filePath)); + return result; + } + + public object Post(FileUpload request) + { + if (this.Request.Files.Length == 0) + throw new FileNotFoundException("UploadError", "No such file exists"); + + if (request.RelativePath == "ThrowError") + throw new NotSupportedException("ThrowError"); + + var file = this.Request.Files[0]; + return new FileUploadResponse + { + Name = file.Name, + FileName = file.FileName, + ContentLength = file.ContentLength, + ContentType = file.ContentType, + Contents = file.InputStream.ReadToEnd(), + CustomerId = request.CustomerId, + CustomerName = request.CustomerName, + CreatedDate = request.CreatedDate + }; + } + + public object Put(FileUpload request) + { + return new FileUploadResponse + { + CustomerId = request.CustomerId, + CustomerName = request.CustomerName, + CreatedDate = request.CreatedDate + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/GeoInfoService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/GeoInfoService.cs index 07b966704da..f940bd7dfdf 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/GeoInfoService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/GeoInfoService.cs @@ -1,7 +1,5 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -35,7 +33,7 @@ public class GeoInfoResponse : IHasResponseStatus public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized } - public class GeoInfoService : ServiceInterface.Service + public class GeoInfoService : Service { public object Post(GeoInfo request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloImage.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloImage.cs index 31ccc6df641..a53c299a85b 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloImage.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloImage.cs @@ -3,18 +3,19 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; -using ServiceStack.Common.Web; -using ServiceStack.Service; -using ServiceStack.ServiceHost; +using System.Threading; +using System.Threading.Tasks; +using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { [Route("/HelloImage")] public class HelloImage {} - public class HelloImageService : IService<HelloImage> + public class HelloImageService : IService { - public object Execute(HelloImage request) + public object Any(HelloImage request) { using (Bitmap image = new Bitmap(10, 10)) { @@ -32,9 +33,9 @@ public object Execute(HelloImage request) [Route("/HelloImage2")] public class HelloImage2 {} - public class HelloImage2Service : IService<HelloImage2> + public class HelloImage2Service : IService { - public object Execute(HelloImage2 request) + public object Any(HelloImage2 request) { using (Bitmap image = new Bitmap(10, 10)) { @@ -56,7 +57,7 @@ public object Execute(HelloImage2 request) public class HelloImage3 {} //Your own Custom Result, writes directly to response stream - public class ImageResult : IDisposable, IStreamWriter, IHasOptions + public class ImageResult : IDisposable, IStreamWriterAsync, IHasOptions { private readonly Image image; private readonly ImageFormat imgFormat; @@ -70,22 +71,28 @@ public ImageResult(Image image, ImageFormat imgFormat=null) }; } - public void WriteTo(Stream responseStream) - { - image.Save(responseStream, imgFormat); - } - public void Dispose() { this.image.Dispose(); } public IDictionary<string, string> Options { get; set; } + + public async Task WriteToAsync(Stream responseStream, CancellationToken token = new CancellationToken()) + { + using (var ms = MemoryStreamFactory.GetStream()) + { + image.Save(ms, imgFormat); + + ms.Position = 0; + await ms.WriteToAsync(responseStream, token); + } + } } - public class HelloImage3Service : IService<HelloImage3> + public class HelloImage3Service : IService { - public object Execute(HelloImage3 request) + public object Any(HelloImage3 request) { var image = new Bitmap(10, 10); using (var g = Graphics.FromImage(image)) @@ -95,5 +102,4 @@ public object Execute(HelloImage3 request) } } - } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloService.cs index 69998f3a94a..3679f202e1d 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/HelloService.cs @@ -1,7 +1,6 @@ using System.ComponentModel; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -31,9 +30,9 @@ public class HelloResponse public string Result { get; set; } } - public class HelloService : IService<Hello> + public class HelloService : IService { - public object Execute(Hello request) + public object Any(Hello request) { return new HelloResponse { Result = "Hello, " + request.Name }; } @@ -41,9 +40,7 @@ public object Execute(Hello request) public class TestFilterAttribute : ResponseFilterAttribute { - public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto) - { - } + public override void Execute(IRequest req, IResponse res, object responseDto) {} } [Route("/hello2")] @@ -62,9 +59,9 @@ public class Hello2Response } [TestFilter] - public class Hello2Service : IService<Hello2> + public class Hello2Service : IService { - public object Execute(Hello2 request) + public object Any(Hello2 request) { return request.Name; } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs index 9b1fd391bcb..5b4d3130c88 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/HttpResultsService.cs @@ -1,10 +1,6 @@ -using System; using System.Net; using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -32,7 +28,7 @@ public HttpResultsResponse() public ResponseStatus ResponseStatus { get; set; } } - public class HttpResultsService : ServiceInterface.Service + public class HttpResultsService : Service { public object Any(HttpResults request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/IocServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/IocServiceTests.cs deleted file mode 100644 index cae0589a02b..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/IocServiceTests.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.Text; -using ServiceStack.WebHost.IntegrationTests.Tests; - -namespace ServiceStack.WebHost.IntegrationTests.Services -{ - public class FunqRequestScope - { - public static int Count = 0; - public FunqRequestScope() { Count++; } - } - - public class FunqSingletonScope - { - public static int Count = 0; - public FunqSingletonScope() { Count++; } - } - - public class FunqNoneScope - { - public static int Count = 0; - public FunqNoneScope() { Count++; } - } - - public class IocScope { } - - public class IocScopeResponse : IHasResponseStatus - { - public IocScopeResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Results = new Dictionary<string, int>(); - } - - public Dictionary<string, int> Results { get; set; } - - public ResponseStatus ResponseStatus { get; set; } - } - - [IocRequestFilter] - public class IocScopeService : IService<IocScope>, IDisposable - { - public FunqRequestScope FunqRequestScope { get; set; } - public FunqSingletonScope FunqSingletonScope { get; set; } - public FunqNoneScope FunqNoneScope { get; set; } - - public object Execute(IocScope request) - { - var response = new IocScopeResponse { - Results = { - { typeof(FunqSingletonScope).Name, FunqSingletonScope.Count }, - { typeof(FunqRequestScope).Name, FunqRequestScope.Count }, - { typeof(FunqNoneScope).Name, FunqNoneScope.Count }, - }, - }; - - return response; - } - - public static int DisposedCount = 0; - public static bool ThrowErrors = false; - - public void Dispose() - { - DisposedCount++; - } - } - - public class IocRequestFilterAttribute : Attribute, IHasRequestFilter - { - public FunqSingletonScope FunqSingletonScope { get; set; } - public FunqRequestScope FunqRequestScope { get; set; } - public FunqNoneScope FunqNoneScope { get; set; } - - public int Priority { get; set; } - - public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto) - { - } - - public IHasRequestFilter Copy() - { - return (IHasRequestFilter)this.MemberwiseClone(); - } - } - - [TestFixture] - public class IocServiceTests - { - [Test] - public void Does_create_correct_instances_per_scope() - { - - var restClient = new JsonServiceClient(Config.ServiceStackBaseUri); - var response1 = restClient.Get<IocScopeResponse>("iocscope"); - var response2 = restClient.Get<IocScopeResponse>("iocscope"); - - Assert.That(response2.Results[typeof(FunqSingletonScope).Name], Is.EqualTo(1)); - - var requestScopeCounter = response2.Results[typeof(FunqRequestScope).Name] - response1.Results[typeof(FunqRequestScope).Name]; - Assert.That(requestScopeCounter, Is.EqualTo(1)); - var noneScopeCounter = response2.Results[typeof(FunqNoneScope).Name] - response1.Results[typeof(FunqNoneScope).Name]; - Assert.That(noneScopeCounter, Is.EqualTo(2)); - } - } -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/MovieService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/MovieService.cs index daea873ad12..346d6e8d56e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/MovieService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/MovieService.cs @@ -2,16 +2,18 @@ using System.Collections.Generic; using System.Net; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; -using ServiceStack.Common.Web; using ServiceStack.DataAnnotations; using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { + [Route("/movies/query", "GET")] + public class QueryMovies : QueryDb<Movie> + { + public string TitleContains { get; set; } + } [Route("/movies", "POST,PUT,PATCH")] [Route("/movies/{Id}")] @@ -84,7 +86,7 @@ public class MovieResponse public Movie Movie { get; set; } } - public class MovieService : ServiceInterface.Service + public class MovieService : Service { /// <summary> /// GET /movies/{Id} @@ -92,7 +94,7 @@ public class MovieService : ServiceInterface.Service public object Get(Movie movie) { return new MovieResponse { - Movie = Db.GetById<Movie>(movie.Id) + Movie = Db.SingleById<Movie>(movie.Id) }; } @@ -101,16 +103,15 @@ public object Get(Movie movie) /// </summary> public object Post(Movie movie) { - Db.Insert(movie); - var newMovieId = Db.GetLastInsertId(); + Db.Save(movie); var newMovie = new MovieResponse { - Movie = Db.GetById<Movie>(newMovieId) + Movie = Db.SingleById<Movie>(movie.Id) }; return new HttpResult(newMovie) { StatusCode = HttpStatusCode.Created, Headers = { - { HttpHeaders.Location, this.RequestContext.AbsoluteUri.WithTrailingSlash() + newMovieId } + { HttpHeaders.Location, this.Request.AbsoluteUri.WithTrailingSlash() + movie.Id } } }; } @@ -138,7 +139,7 @@ public object Delete(Movie request) /// </summary> public object Patch(Movie movie) { - var existingMovie = Db.GetById<Movie>(movie.Id); + var existingMovie = Db.SingleById<Movie>(movie.Id); if (movie.Title != null) existingMovie.Title = movie.Title; Db.Save(existingMovie); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs index baf7fd24120..2fc70884833 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/MoviesService.cs @@ -1,44 +1,43 @@ using System.Collections.Generic; using System.Runtime.Serialization; -using ServiceStack.Common.Extensions; using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; +using ServiceStack.Text; namespace ServiceStack.WebHost.IntegrationTests.Services { - [DataContract] - [Route("/movies", "GET, OPTIONS")] - [Route("/movies/genres/{Genre}")] - public class Movies - { - [DataMember] - public string Genre { get; set; } + [DataContract] + [Route("/movies", "GET, OPTIONS")] + [Route("/movies/genres/{Genre}")] + public class Movies + { + [DataMember] + public string Genre { get; set; } - [DataMember] - public Movie Movie { get; set; } - } + [DataMember] + public Movie Movie { get; set; } + } - [DataContract] - public class MoviesResponse - { - [DataMember(Order = 1)] - public List<Movie> Movies { get; set; } - } + [DataContract] + public class MoviesResponse + { + [DataMember(Order = 1)] + public List<Movie> Movies { get; set; } + } - public class MoviesService : ServiceInterface.Service - { - /// <summary> - /// GET /movies - /// GET /movies/genres/{Genre} - /// </summary> - public object Get(Movies request) - { - return new MoviesResponse - { - Movies = request.Genre.IsNullOrEmpty() - ? Db.Select<Movie>() - : Db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%") - }; - } - } + public class MoviesService : Service + { + /// <summary> + /// GET /movies + /// GET /movies/genres/{Genre} + /// </summary> + public object Get(Movies request) + { + return new MoviesResponse + { + Movies = request.Genre.IsNullOrEmpty() + ? Db.Select<Movie>() + : Db.Select<Movie>("Genres LIKE {0}", "%" + request.Genre + "%") + }; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/MqHostStatsService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/MqHostStatsService.cs index f1d3369f5b9..e3be1f673f4 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/MqHostStatsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/MqHostStatsService.cs @@ -17,7 +17,7 @@ public class MqHostStatsResponse public string Result { get; set; } } - public class MqHostStatsService : ServiceInterface.Service + public class MqHostStatsService : Service { public IMessageService MessageService { get; set; } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs index 916d7856902..0d591337b7f 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ProfilerService.cs @@ -1,10 +1,13 @@ using System.Collections.Generic; +using System.Linq; +using ServiceStack.Data; +using ServiceStack.DataAnnotations; using ServiceStack.MiniProfiler; using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { + [ExcludeMetadata] [Route("/profiler", "GET")] [Route("/profiler/{Type}", "GET")] public class MiniProfiler @@ -12,7 +15,7 @@ public class MiniProfiler public string Type { get; set; } } - public class MiniProfilerService : ServiceInterface.Service + public class MiniProfilerService : Service { public IDbConnectionFactory DbFactory { get; set; } @@ -21,18 +24,13 @@ public object Any(MiniProfiler request) var profiler = Profiler.Current; using (var db = DbFactory.OpenDbConnection()) - using (profiler.Step("MiniProfiler Service")) + using (profiler.Step("MiniProfiler Service")) { if (request.Type == "n1") { using (profiler.Step("N + 1 query")) { - var results = new List<Movie>(); - foreach (var movie in db.Select<Movie>()) - { - results.Add(db.QueryById<Movie>(movie.Id)); - } - return results; + return db.Select<Movie>().Select(movie => db.SingleById<Movie>(movie.Id)).ToList(); } } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs index bedc329e448..1b08d75f158 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestFilter.cs @@ -1,7 +1,5 @@ -using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -25,10 +23,8 @@ public class RequestFilterResponse public string Value { get; set; } } - public class StatusCodeService : ServiceInterface.Service, IRequiresRequestContext + public class StatusCodeService : Service { - new public IRequestContext RequestContext { get; set; } - public object Any(RequestFilter request) { return new RequestFilterResponse(); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs index 650ecddbeea..2a807219d60 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/RequestItemsService.cs @@ -1,6 +1,4 @@ using System; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -15,7 +13,7 @@ public class RequestItemsResponse : IHasResponseStatus public ResponseStatus ResponseStatus { get; set; } } - public class RequestItemsService : ServiceInterface.Service + public class RequestItemsService : Service { public object Any(RequestItems request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs index ef5ec54dc8b..19ef458e8d6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ResetMovies.cs @@ -2,16 +2,15 @@ using System.Collections.Generic; using System.ComponentModel; using System.Runtime.Serialization; +using ServiceStack.Data; using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.IntegrationTests.Services { [DataContract] [Description("Resets the database back to the original Top 5 movies.")] [Route("/reset-movies")] - public class ResetMovies { } + public class ResetMovies : IReturn<ResetMoviesResponse> { } [DataContract] public class ResetMoviesResponse : IHasResponseStatus @@ -25,7 +24,7 @@ public ResetMoviesResponse() public ResponseStatus ResponseStatus { get; set; } } - public class ResetMoviesService : ServiceInterface.Service + public class ResetMoviesService : Service { public static List<Movie> Top5Movies = new List<Movie> { @@ -47,4 +46,32 @@ public object Post(ResetMovies request) return new ResetMoviesResponse(); } } + + [Route("/factorial/{ForNumber}")] + [DataContract] + public class GetFactorial + { + [DataMember] + public long ForNumber { get; set; } + } + + [DataContract] + public class GetFactorialResponse + { + [DataMember] + public long Result { get; set; } + } + + public class GetFactorialService : IService + { + public object Any(GetFactorial request) + { + return new GetFactorialResponse { Result = GetFactorial(request.ForNumber) }; + } + + public static long GetFactorial(long n) + { + return n > 1 ? n * GetFactorial(n - 1) : 1; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ReturnsVoidService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReturnsVoidService.cs index 1555eb31a4f..306083ff42f 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ReturnsVoidService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReturnsVoidService.cs @@ -1,5 +1,3 @@ -using ServiceStack.ServiceHost; - namespace ServiceStack.WebHost.IntegrationTests.Services { [Route("/returnsvoid")] diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs index c0dbbfce72a..f9644bdff17 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ReverseService.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -18,8 +17,26 @@ public class ReverseResponse public string Result { get; set; } } + [DataContract] + public class AddInts : IReturn<AddIntsResponse> + { + [DataMember] + public int A { get; set; } + [DataMember] + public int B { get; set; } + } + + [DataContract] + public class AddIntsResponse + { + [DataMember] + public int Result { get; set; } + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + public class ReverseService - : ServiceInterface.Service + : Service { public object Any(Reverse request) { @@ -32,6 +49,10 @@ public static string Execute(string value) Array.Reverse(valueBytes); return new string(valueBytes); } + + public object Any(AddInts request) => new AddIntsResponse { + Result = request.A + request.B + }; } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/Rot13Service.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/Rot13Service.cs index 64c849d6967..855506439d8 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/Rot13Service.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/Rot13Service.cs @@ -1,5 +1,4 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; using ServiceStack.Text; namespace ServiceStack.WebHost.IntegrationTests.Services @@ -19,7 +18,7 @@ public class Rot13Response } public class Rot13Service - : ServiceInterface.Service + : Service { public object Any(Rot13 request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteInfoService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteInfoService.cs deleted file mode 100644 index aae39c82192..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteInfoService.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.Serialization; -using DeliveryService.Model.Types; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; - -namespace DeliveryService.Model.Operations -{ - [Description("POST the route information based on the Application Token associated to a route and Associate ID")] - [Route("/RouteInfo", "POST")] - [Route("/RouteInfo/{AppToken}")] - [Route("/RouteInfo/{AppToken}/{HasProduct}")] - [DataContract] - public class RouteInfo - { - [DataMember] - public string AppToken { get; set; } - - [DataMember] - public bool? HasProduct { get; set; } - } - - [DataContract] - public class RouteInfoResponse : IHasResponseStatus - { - public RouteInfoResponse() - { - this.ResponseStatus = new ResponseStatus(); - this.Customers = new List<Customer>(); - this.Outcomes = new List<Outcome>(); - this.DD = new Dictionary<string, Dictionary<string, string>>(); - this.Tweak = new Dictionary<string, int>(); - } - - [DataMember] - public List<Customer> Customers { get; set; } - - [DataMember] - public List<Outcome> Outcomes { get; set; } - - [DataMember] - public Dictionary<string, Dictionary<string, string>> DD { get; set; } - - [DataMember] - public Dictionary<string, int> Tweak { get; set; } - - [DataMember] - public ResponseStatus ResponseStatus { get; set; } - } - - public class RouteInfoService : Service - { - public object Any(RouteInfo request) - { - throw new NotImplementedException(); - } - } -} - -namespace DeliveryService.Model.Types -{ - [DataContract] - public class Outcome - { - [DataMember] - public string UID { get; set; } - - [DataMember] - public string Name { get; set; } - - [DataMember] - public List<OutcomeReason> Reasons { get; set; } - } - - - [DataContract] - public class OutcomeReason - { - [DataMember] - public string UID { get; set; } - - [DataMember] - public string Message { get; set; } - - } -} - - -namespace DeliveryService.Model.Types -{ - [DataContract] - public class Customer - { - [DataMember] - public string UID { get; set; } - [DataMember] - public int RoutePos { get; set; } - [DataMember] - public string Invoice { get; set; } - [DataMember] - public string FirstName { get; set; } - [DataMember] - public string LastName { get; set; } - [DataMember] - public string Address { get; set; } - [DataMember] - public string City { get; set; } - [DataMember] - public string State { get; set; } - [DataMember] - public string ZipCode { get; set; } - [DataMember] - public string HmPhone { get; set; } - [DataMember] - public string WkPhone { get; set; } - [DataMember] - public string ClPhone { get; set; } - [DataMember] - public string ArrivalETA { get; set; } - [DataMember] - public string CompletionCode { get; set; } - [DataMember] - public string ConfirmationCode { get; set; } - [DataMember] - public bool IsPosted { get; set; } - [DataMember] - public string Lat { get; set; } - [DataMember] - public string Long { get; set; } - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteTokenInfoService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteTokenInfoService.cs new file mode 100644 index 00000000000..b7cf7b9729a --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/RouteTokenInfoService.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.Serialization; +using DeliveryService.Model.Types; +using ServiceStack; + +namespace DeliveryService.Model.Operations +{ + [Description("POST the route information based on the Application Token associated to a route and Associate ID")] + [Route("/RouteTokenInfo", "POST")] + [Route("/RouteTokenInfo/{AppToken}")] + [Route("/RouteTokenInfo/{AppToken}/{HasProduct}")] + [DataContract] + public class RouteTokenInfo + { + [DataMember] + public string AppToken { get; set; } + + [DataMember] + public bool? HasProduct { get; set; } + } + + [DataContract] + public class RouteInfoResponse : IHasResponseStatus + { + public RouteInfoResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Customers = new List<Customer>(); + this.Outcomes = new List<Outcome>(); + this.DD = new Dictionary<string, Dictionary<string, string>>(); + this.Tweak = new Dictionary<string, int>(); + } + + [DataMember] + public List<Customer> Customers { get; set; } + + [DataMember] + public List<Outcome> Outcomes { get; set; } + + [DataMember] + public Dictionary<string, Dictionary<string, string>> DD { get; set; } + + [DataMember] + public Dictionary<string, int> Tweak { get; set; } + + [DataMember] + public ResponseStatus ResponseStatus { get; set; } + } + + public class RouteTokenInfoService : Service + { + public object Any(RouteTokenInfo request) + { + throw new NotImplementedException(); + } + } +} + +namespace DeliveryService.Model.Types +{ + [DataContract] + public class Outcome + { + [DataMember] + public string UID { get; set; } + + [DataMember] + public string Name { get; set; } + + [DataMember] + public List<OutcomeReason> Reasons { get; set; } + } + + + [DataContract] + public class OutcomeReason + { + [DataMember] + public string UID { get; set; } + + [DataMember] + public string Message { get; set; } + + } +} + + +namespace DeliveryService.Model.Types +{ + [DataContract] + public class Customer + { + [DataMember] + public string UID { get; set; } + [DataMember] + public int RoutePos { get; set; } + [DataMember] + public string Invoice { get; set; } + [DataMember] + public string FirstName { get; set; } + [DataMember] + public string LastName { get; set; } + [DataMember] + public string Address { get; set; } + [DataMember] + public string City { get; set; } + [DataMember] + public string State { get; set; } + [DataMember] + public string ZipCode { get; set; } + [DataMember] + public string HmPhone { get; set; } + [DataMember] + public string WkPhone { get; set; } + [DataMember] + public string ClPhone { get; set; } + [DataMember] + public string ArrivalETA { get; set; } + [DataMember] + public string CompletionCode { get; set; } + [DataMember] + public string ConfirmationCode { get; set; } + [DataMember] + public bool IsPosted { get; set; } + [DataMember] + public string Lat { get; set; } + [DataMember] + public string Long { get; set; } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs index 70a2a40760e..c63a8bd92d8 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs @@ -1,36 +1,156 @@ using System; +using System.Collections.Generic; using System.Runtime.Serialization; -using ServiceStack.ServiceInterface; +using ServiceStack.Configuration; namespace ServiceStack.WebHost.IntegrationTests.Services { - public interface IRequiresSession - { - Guid SessionId { get; } - } - - [DataContract] - public class Secure : IRequiresSession - { - [DataMember] - public Guid SessionId { get; set;} - - [DataMember] - public int StatusCode { get; set; } - } - - [DataContract] - public class SecureResponse - { - [DataMember] - public string Value { get; set; } - } - - public class SecureService : ServiceInterface.Service - { + public interface IRequiresSession + { + Guid SessionId { get; } + } + + [DataContract] + public class Secure : IRequiresSession + { + [DataMember] + public Guid SessionId { get; set; } + + [DataMember] + public int StatusCode { get; set; } + } + + [DataContract] + public class SecureResponse + { + [DataMember] + public string Value { get; set; } + } + + [Authenticate] + [Route("/requiresadmin")] + public class RequiresRoleInService + { + public string Role { get; set; } + } + + + [Authenticate] + [Route("/testauth")] + public class TestAuth + { + public int Id { get; set; } + public string Name { get; set; } + } + + + [Authenticate] + public class RequiresAuthRequest : IReturn<RequiresAuthRequest> + { + public string Name { get; set; } + } + + public class RequiresAuthAction : IReturn<RequiresAuthAction> + { + public string Name { get; set; } + } + + [RequiredRole("TheRole")] + public class RequiresRoleRequest : IReturn<RequiresRoleRequest> + { + public string Name { get; set; } + } + + public class RequiresRoleAction : IReturn<RequiresRoleAction> + { + public string Name { get; set; } + } + + [RequiresAnyRole("TheRole", "TheRole2")] + public class RequiresAnyRoleRequest : IReturn<RequiresAnyRoleRequest> + { + public List<string> Roles { get; set; } + + public RequiresAnyRoleRequest() + { + Roles = new List<string>(); + } + } + + [RequiredPermission("ThePermission")] + public class RequiresPermissionRequest : IReturn<RequiresPermissionRequest> + { + public string Name { get; set; } + } + + [RequiresAnyPermission("ThePermission", "ThePermission2")] + public class RequiresAnyPermissionRequest : IReturn<RequiresAnyPermissionRequest> + { + public List<string> Permissions { get; set; } + + public RequiresAnyPermissionRequest() + { + Permissions = new List<string>(); + } + } + + public class RequiresRolesAndPermissionsOnRequestService : Service + { + public object Any(RequiresAuthRequest request) + { + return request; + } + + public object Any(RequiresRoleRequest request) + { + return request; + } + + public object Any(RequiresAnyRoleRequest request) + { + return request; + } + + public object Any(RequiresPermissionRequest request) + { + return request; + } + + public object Any(RequiresAnyPermissionRequest request) + { + return request; + } + + [RequiredRole("TheRole")] + public object Any(RequiresRoleAction request) + { + return request; + } + + [Authenticate] + public object Any(RequiresAuthAction request) + { + return request; + } + } + + public class SecureService : Service + { public object Any(Secure request) - { - throw new UnauthorizedAccessException("You shouldn't be able to see this"); - } - } + { + throw new UnauthorizedAccessException("You shouldn't be able to see this"); + } + + public object Any(RequiresRoleInService request) + { + RequiredRoleAttribute.AssertRequiredRoles(Request, request.Role ?? RoleNames.Admin); + + return request; + } + + public object Any(TestAuth request) + { + return request; + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionService.cs index 2dc1bd49413..9f9780eb9cd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionService.cs @@ -1,11 +1,3 @@ -using System.Runtime.Serialization; -using System.Web; -using ServiceStack.CacheAccess; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Extensions; - namespace ServiceStack.WebHost.IntegrationTests.Services { public class CustomSession @@ -25,18 +17,18 @@ public class SessionResponse public CustomSession UnTyped { get; set; } } - public class SessionService : ServiceInterface.Service + public class SessionService : Service { public object Any(Session request) { - var untyped = Session["untyped"] as CustomSession ?? new CustomSession(); - var typed = Session.Get<CustomSession>("typed") ?? new CustomSession(); + var untyped = SessionBag["untyped"] as CustomSession ?? new CustomSession(); + var typed = SessionBag.Get<CustomSession>("typed") ?? new CustomSession(); untyped.Counter++; typed.Counter++; - Session["untyped"] = untyped; - Session.Set("typed", typed); + SessionBag["untyped"] = untyped; + SessionBag.Set("typed", typed); var response = new SessionResponse { Typed = typed, diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionTest.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionTest.cs new file mode 100644 index 00000000000..4da7efd5fa0 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/SessionTest.cs @@ -0,0 +1,25 @@ +using System.Web; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/session/test")] + public class SessionTest + { + public string Result { get; set; } + } + + public class SessionTestServices : ServiceStack.Service + { + public object Any(SessionTest request) + { + SessionBag["ss-test"] = "bar"; + + var sessions = HttpContext.Current.Session; + var aspNetReq = base.Request.OriginalRequest as HttpRequestBase; + var test = aspNetReq.RequestContext.HttpContext.Items["test"]; + return new SessionTest { + Result = test as string + }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/SwaggerTestService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/SwaggerTestService.cs index cd4f22305e0..933ce51267b 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/SwaggerTestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/SwaggerTestService.cs @@ -1,11 +1,30 @@ -using System.Drawing; +using System; +using System.Collections.Generic; +using System.Drawing; using System.Net; using System.Runtime.Serialization; -using ServiceStack.Api.Swagger; -using ServiceStack.ServiceHost; +using System.Security.Policy; +using ServiceStack.DataAnnotations; namespace ServiceStack.WebHost.IntegrationTests.Services { + public enum MyColor + { + Red, + Green, + Blue + } + + public enum MyColorDesc + { + [Description("The color Red")] + Red = 10, + [Description("The color Green")] + Green = 20, + [Description("The color Blue")] + Blue = 30, + } + [Api("SwaggerTest Service Description")] [ApiResponse(HttpStatusCode.BadRequest, "Your request was not understood")] [ApiResponse(HttpStatusCode.InternalServerError, "Oops, something broke")] @@ -17,24 +36,293 @@ public class SwaggerTest { [ApiMember(Description = "Color Description", ParameterType = "path", DataType = "string", IsRequired = true)] - [ApiAllowableValues("Color", typeof(Color))] //Enum - public string Color { get; set; } + [ApiAllowableValues("Name", typeof(MyColor))] //Enum + [DataMember] + public string Name { get; set; } + + [ApiMember] + [ApiAllowableValues("Color", typeof(MyColor))] //Enum + [DataMember] + public MyColor Color { get; set; } + + [ApiMember] + [ApiAllowableValues("ColorDesc", typeof(MyColorDesc))] //Enum + [DataMember] + public MyColorDesc ColorDesc { get; set; } [ApiMember(Description = "Aliased Description", - ParameterType = "path", DataType = "string", IsRequired = true)] + DataType = "string", IsRequired = true)] [DataMember(Name = "Aliased")] - public string Name { get; set; } + public string Original { get; set; } [ApiMember(Description = "Not Aliased Description", - ParameterType = "path", DataType = "string", IsRequired = true)] + DataType = "string", IsRequired = true)] + [DataMember] public string NotAliased { get; set; } + + [ApiMember(Description = "Format as password", DataType = "password")] + [DataMember] + public string Password { get; set; } + + [DataMember] + [ApiMember(IsRequired = false, AllowMultiple = true)] + public DateTime[] MyDateBetween { get; set; } + + [ApiMember(Description = "Nested model 1", DataType = "SwaggerNestedModel")] + [DataMember] + public SwaggerNestedModel NestedModel1 { get; set; } + + [ApiMember(Description = "Nested model 2", DataType = "SwaggerNestedModel2")] + [DataMember] + public SwaggerNestedModel2 NestedModel2 { get; set; } } - public class SwaggerTestService : ServiceInterface.Service + public class SwaggerNestedModel { - public object Get(SwaggerTest request) - { - return request; - } + [ApiMember(Description = "NestedProperty description")] + public bool NestedProperty { get; set; } + } + + public class SwaggerNestedModel2 + { + [ApiMember(Description = "NestedProperty2 description")] + public bool NestedProperty2 { get; set; } + + [ApiMember(Description = "MultipleValues description")] + [ApiAllowableValues("MultipleValues", new[] { "val1", "val2" })] + public string MultipleValues { get; set; } + + [ApiMember(Description = "TestRange description")] + [ApiAllowableValues("TestRange", 1, 10)] + public int TestRange { get; set; } + } + + public enum MyEnum { A, B, C } + + [Route("/swaggertest2", "POST")] + public class SwaggerTest2 + { + [ApiMember] + [ApiAllowableValues("MyEnumProperty", typeof(MyEnum))] + public MyEnum MyEnumProperty { get; set; } + + [IgnoreDataMember] + public string Ignored { get; set; } + + [ApiMember( + Name = "Token", + ParameterType = "header", + DataType = "string", + IsRequired = true)] + public string Token { get; set; } + } + + [Route("/swagger-complex", "POST")] + public class SwaggerComplex : IReturn<SwaggerComplexResponse> + { + [ApiMember] + [DataMember] + [Description("IsRequired Description")] + public bool IsRequired { get; set; } + + [ApiMember(IsRequired = true)] + [DataMember] + public string[] ArrayString { get; set; } + + [ApiMember] + [DataMember] + public int[] ArrayInt { get; set; } + + [ApiMember] + [DataMember] + public List<string> ListString { get; set; } + + [ApiMember] + [DataMember] + public List<int> ListInt { get; set; } + + [ApiMember] + [DataMember] + public Dictionary<string, string> DictionaryString { get; set; } + } + + public class SwaggerComplexResponse + { + [ApiMember] + [DataMember] + public bool IsRequired { get; set; } + + [ApiMember(IsRequired = true)] + [DataMember] + public string[] ArrayString { get; set; } + + [ApiMember] + [DataMember] + public int[] ArrayInt { get; set; } + + [ApiMember] + [DataMember] + public List<string> ListString { get; set; } + + [ApiMember] + [DataMember] + public List<int> ListInt { get; set; } + + [ApiMember] + [DataMember] + public Dictionary<string, string> DictionaryString { get; set; } + } + + [Route("/swaggerpost/{Required1}", Verbs = "GET")] + [Route("/swaggerpost/{Required1}/{Optional1}", Verbs = "GET")] + [Route("/swaggerpost", Verbs = "POST")] + public class SwaggerPostTest : IReturn<HelloResponse> + { + [ApiMember(Verb = "POST")] + [ApiMember(Route = "/swaggerpost/{Required1}", Verb = "GET", ParameterType = "path")] + [ApiMember(Route = "/swaggerpost/{Required1}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Required1 { get; set; } + + [ApiMember(Verb = "POST")] + [ApiMember(Route = "/swaggerpost/{Required1}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Optional1 { get; set; } + } + + [Route("/swaggerpost2/{Required1}/{Required2}", Verbs = "GET")] + [Route("/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verbs = "GET")] + [Route("/swaggerpost2", Verbs = "POST")] + public class SwaggerPostTest2 : IReturn<HelloResponse> + { + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}", Verb = "GET", ParameterType = "path")] + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Required1 { get; set; } + + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}", Verb = "GET", ParameterType = "path")] + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Required2 { get; set; } + + [ApiMember(Route = "/swaggerpost2/{Required1}/{Required2}/{Optional1}", Verb = "GET", ParameterType = "path")] + public string Optional1 { get; set; } + } + + [Api("Api GET All")] + [Route("/swaggerexamples", "GET")] + public class GetSwaggerExamples : IReturn<GetSwaggerExamples> + { + public string Get { get; set; } + } + + [Api("Api POST")] + [Route("/swaggerexamples", "POST")] + public class PostSwaggerExamples : IReturn<PostSwaggerExamples> + { + public string Post { get; set; } + } + + [Api("Api GET Id")] + [Route("/swaggerexamples/{Id}", "GET")] + public class GetSwaggerExample : IReturn<GetSwaggerExample> + { + public int Id { get; set; } + public string Get { get; set; } + } + + [Api("Api PUT Id")] + [Route("/swaggerexamples/{Id}", "PUT")] + public class PutSwaggerExample : IReturn<PutSwaggerExample> + { + public int Id { get; set; } + public string Get { get; set; } + } + + [Route("/lists", "GET")] + public class GetLists : IReturn<GetLists> + { + public string Id { get; set; } + } + + [Route("/lists", "POST")] + [Exclude(Feature.Metadata)] + public class CreateList : IReturn<CreateList> + { + public string Id { get; set; } + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public sealed class CustomApiResponseAttribute : ApiResponseAttribute + { + private static int errCode = 402; + + public CustomApiResponseAttribute() + : base(++errCode, Guid.NewGuid().ToString()) {} + } + + [ApiResponse(400, "Code 1")] + [CustomApiResponse()] + [ApiResponse(402, "Code 2")] + [CustomApiResponse()] + [CustomApiResponse()] + [ApiResponse(401, "Code 3")] + [Route("/swagger/multiattrtest", Verbs = "POST", Summary = "Sample request")] + public sealed class SwaggerMultiApiResponseTest : IReturnVoid {} + + public class SwaggerTestService : Service + { + public object Any(SwaggerTest request) + { + return request; + } + + public object Post(SwaggerTest2 request) + { + return request; + } + + public object Post(SwaggerComplex request) + { + return request.ConvertTo<SwaggerComplexResponse>(); + } + + public object Any(SwaggerPostTest request) + { + return new HelloResponse { Result = request.Required1 }; + } + + public object Any(SwaggerPostTest2 request) + { + return new HelloResponse { Result = request.Required1 }; + } + + public object Any(GetSwaggerExamples request) + { + return request; + } + + public object Any(GetSwaggerExample request) + { + return request; + } + + public object Any(PostSwaggerExamples request) + { + return request; + } + + public object Any(PutSwaggerExample request) + { + return request; + } + + public object Any(GetLists request) + { + return request; + } + + public object Any(CreateList request) + { + return request; + } + + public object Any(SwaggerMultiApiResponseTest request) => request; } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/TemplateService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/TemplateService.cs new file mode 100644 index 00000000000..c584d4f7f00 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/TemplateService.cs @@ -0,0 +1,53 @@ +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/templates", "POST")] + public class PostTemplateRequest : IReturn<PostTemplateResponse> + { + public string Template { get; set; } + } + + public class PostTemplateResponse + { + public string PostResult { get; set; } + } + + [Route("/templates", "GET")] + public class GetTemplatesRequest : IReturn<GetTemplatesResponse> + { + public string Name { get; set; } + } + + public class GetTemplatesResponse + { + public string GetResult { get; set; } + } + + [Route("/templates/{Name}", "GET")] + public class GetTemplateRequest : IReturn<GetTemplateResponse> + { + public string Name { get; set; } + } + + public class GetTemplateResponse + { + public string GetSingleResult { get; set; } + } + + public class TemplateService : Service + { + public object Post(PostTemplateRequest request) + { + return new PostTemplateResponse { PostResult = request.Template }; + } + + public object Get(GetTemplatesRequest request) + { + return new GetTemplatesResponse { GetResult = request.Name }; + } + + public object Get(GetTemplateRequest request) + { + return new GetTemplateResponse { GetSingleResult = request.Name }; + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/TestProgressService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/TestProgressService.cs new file mode 100644 index 00000000000..bc504f5d7e4 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/TestProgressService.cs @@ -0,0 +1,54 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System.Collections.Generic; +using System.IO; + +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + public class TestProgress : IReturn<List<Movie>> { } + public class TestProgressString : IReturn<string> { } + public class TestProgressBytes : IReturn<byte[]> { } + + public class TestProgressBytesHttpResult : IReturn<byte[]> { } + public class TestProgressBinaryFile : IReturn<byte[]> { } + public class TestProgressTextFile : IReturn<string> { } + + public class DownloadProgressService : Service + { + public object Any(TestProgress request) + { + return ResetMoviesService.Top5Movies; + } + + public string Any(TestProgressString request) + { + return ResetMoviesService.Top5Movies.ToJson(); + } + + public object Any(TestProgressBytes request) + { + return ResetMoviesService.Top5Movies.ToJson().ToUtf8Bytes(); + } + + public object Any(TestProgressBytesHttpResult request) + { + return new HttpResult(ResetMoviesService.Top5Movies.ToJson().ToUtf8Bytes(), "application/octet-stream"); + } + + public object Any(TestProgressBinaryFile request) + { + var path = Path.GetTempFileName(); + File.WriteAllBytes(path, ResetMoviesService.Top5Movies.ToJson().ToUtf8Bytes()); + return new HttpResult(new FileInfo(path), "application/octet-stream"); + } + + public object Any(TestProgressTextFile request) + { + var path = Path.GetTempFileName(); + File.WriteAllText(path, ResetMoviesService.Top5Movies.ToJson()); + return new HttpResult(new FileInfo(path), "application/json"); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/TestService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/TestService.cs index 2c442f505ee..63bb5b60d6c 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/TestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/TestService.cs @@ -1,7 +1,5 @@ using System.ComponentModel; using System.Runtime.Serialization; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -22,9 +20,9 @@ public class TestResponse public string Result { get; set; } } - public class TestService : IService<Test> + public class TestService : IService { - public object Execute(Test request) + public object Any(Test request) { var client = new Soap12ServiceClient("http://localhost/ServiceStack.WebHost.IntegrationTests/api/"); var response = client.Send<HelloResponse>(new Hello { Name = request.Name }); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs index 479e4e45875..bc46cf128db 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/ThrowsArgumentNullService.cs @@ -1,8 +1,5 @@ using System; using System.Runtime.Serialization; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -30,7 +27,7 @@ public ThrowsArgumentNullResponse() public ResponseStatus ResponseStatus { get; set; } } - public class ThrowsArgumentNullService : ServiceInterface.Service + public class ThrowsArgumentNullService : Service { public object Any(ThrowsArgumentNull request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs index b4965d015b7..a59267d1089 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/UserAuths.cs @@ -1,9 +1,6 @@ using System.Collections.Generic; +using ServiceStack.Auth; using ServiceStack.OrmLite; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.ServiceInterface.ServiceModel; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -18,26 +15,24 @@ public class UserAuthsResponse : IHasResponseStatus public UserAuthsResponse() { this.Results = new List<UserAuth>(); - this.OAuthProviders = new List<UserOAuthProvider>(); + this.OAuthProviders = new List<UserAuthDetails>(); } public List<UserAuth> Results { get; set; } - public List<UserOAuthProvider> OAuthProviders { get; set; } + public List<UserAuthDetails> OAuthProviders { get; set; } public ResponseStatus ResponseStatus { get; set; } } //Implementation. Can be called via any endpoint or format, see: http://servicestack.net/ServiceStack.Hello/ - public class UserAuthsService : ServiceInterface.Service + public class UserAuthsService : Service { - public IDbConnectionFactory DbFactory { get; set; } - public object Any(UserAuths request) { return new UserAuthsResponse { Results = Db.Select<UserAuth>(), - OAuthProviders = Db.Select<UserOAuthProvider>(), + OAuthProviders = Db.Select<UserAuthDetails>(), }; } } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs index 88f5e98c741..6ed8c9716c6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch1Service.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -21,9 +20,9 @@ public class VerbMatch1Response public string Result { get; set; } } - public class VerbMatch1Service : IService<VerbMatch1>, IRestService<VerbMatch1> + public class VerbMatch1Service : IService { - public object Execute(VerbMatch1 request) + public object Any(VerbMatch1 request) { throw new NotImplementedException(); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs index 6ac29b50eae..8b88342e814 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbMatch2Service.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.Serialization; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -21,9 +20,9 @@ public class VerbMatch2Response public string Result { get; set; } } - public class VerbMatch2Service : IService<VerbMatch2>, IRestService<VerbMatch2> + public class VerbMatch2Service : IService { - public object Execute(VerbMatch2 request) + public object Any(VerbMatch2 request) { throw new NotImplementedException(); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbOnlyService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbOnlyService.cs new file mode 100644 index 00000000000..93753c135b0 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/VerbOnlyService.cs @@ -0,0 +1,41 @@ +namespace ServiceStack.WebHost.IntegrationTests.Services +{ + [Route("/verbonly/post", "POST")] + public class PostOnly : IReturn<PostOnly> + { + public string Id { get; set; } + } + + [Route("/verbonly/put", "PUT")] + public class PutOnly : IReturn<PutOnly> + { + public string Id { get; set; } + } + + [Route("/verbonly/patch", "PATCH")] + public class PatchOnly : IReturn<PatchOnly> + { + public string Id { get; set; } + } + + [Route("/verbonly/get", "GET")] + public class GetOnly : IReturn<GetOnly> + { + public string Id { get; set; } + } + + [Route("/verbonly/delete", "DELETE")] + public class DeleteOnly : IReturn<DeleteOnly> + { + public string Id { get; set; } + } + + public class VerbOnlyService : Service + { + public object Any(PostOnly request) => request; + public object Any(PutOnly request) => request; + public object Any(PatchOnly request) => request; + public object Any(GetOnly request) => request; + public object Any(DeleteOnly request) => request; + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Services/WildCardRequestService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Services/WildCardRequestService.cs index 50ade004d50..889d28b89f2 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Services/WildCardRequestService.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Services/WildCardRequestService.cs @@ -1,5 +1,4 @@ using System.Runtime.Serialization; -using ServiceStack.ServiceHost; namespace ServiceStack.WebHost.IntegrationTests.Services { @@ -34,7 +33,7 @@ public class BasicWildcard public string Tail { get; set; } } - public class WildCardRequestService : ServiceStack.ServiceInterface.Service + public class WildCardRequestService : Service { public object Get(WildCardRequest request) { diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Shared/IocService.cs b/tests/ServiceStack.WebHost.IntegrationTests/Shared/IocService.cs new file mode 100644 index 00000000000..520fd5c0a5d --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Shared/IocService.cs @@ -0,0 +1,501 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Funq; +using ServiceStack.Configuration; +using ServiceStack.DataAnnotations; +using ServiceStack.Web; + +namespace ServiceStack.Shared.Tests +{ + public static class IocShared + { + public static void Configure(ServiceStackHost appHost) + { + var container = appHost.Container; + + container.Adapter = new IocAdapter(); + container.Register(c => new FunqDepCtor()); + container.Register(c => new FunqDepProperty()); + container.Register(c => new FunqDepDisposableProperty()); + + container.Register(c => new FunqSingletonScope()).ReusedWithin(ReuseScope.Default); + container.Register(c => new FunqRequestScope()).ReusedWithin(ReuseScope.Request); + container.Register(c => new FunqNoneScope()).ReusedWithin(ReuseScope.None); + container.Register(c => new FunqInjectRequest()).ReusedWithin(ReuseScope.None); + container.Register(c => new FunqRequestScopeDepDisposableProperty()).ReusedWithin(ReuseScope.Request); + + container.Register(c => new FunqSingletonScopeDisposable()).ReusedWithin(ReuseScope.Default); + container.Register(c => new FunqRequestScopeDisposable()).ReusedWithin(ReuseScope.Request); + container.Register(c => new FunqNoneScopeDisposable()).ReusedWithin(ReuseScope.None); + } + } + + public class IocAdapter : IContainerAdapter, IRelease + { + public T TryResolve<T>() + { + if (typeof(T) == typeof(IRequest)) + throw new ArgumentException("should not ask for IRequestContext"); + + if (typeof(T) == typeof(AltDepProperty)) + return (T)(object)new AltDepProperty(); + if (typeof(T) == typeof(AltDepDisposableProperty)) + return (T)(object)new AltDepDisposableProperty(); + if (typeof(T) == typeof(AltRequestScopeDepDisposableProperty)) + return (T)(object)RequestContext.Instance.GetOrCreate(() => new AltRequestScopeDepDisposableProperty()); + + return default(T); + } + + public T Resolve<T>() + { + if (typeof(T) == typeof(AltDepCtor)) + return (T)(object)new AltDepCtor(); + + return default(T); + } + + public void Release(object instance) + { + var disposable = instance as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + } + + + public class FunqRequestScope + { + public static int Count = 0; + public FunqRequestScope() { Count++; } + } + + public class FunqSingletonScope + { + public static int Count = 0; + public FunqSingletonScope() { Count++; } + } + + public class FunqNoneScope + { + public static int Count = 0; + public FunqNoneScope() { Count++; } + } + + public class FunqInjectRequest : IRequiresRequest + { + public FunqInjectRequest() + { + this.SecondLevel = new FunqInjectRequest2(); + } + + public IRequest Request { get; set; } + + public FunqInjectRequest2 SecondLevel { get; set; } + } + + public class FunqInjectRequest2 : IRequiresRequest + { + public IRequest Request { get; set; } + } + + public class FunqRequestScopeDisposable : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqRequestScopeDisposable() { Count++; } + + public void Dispose() + { + DisposeCount++; + } + } + + public class FunqSingletonScopeDisposable : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqSingletonScopeDisposable() { Count++; } + + public void Dispose() + { + DisposeCount++; + } + } + + public class FunqNoneScopeDisposable : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqNoneScopeDisposable() { Count++; } + + public void Dispose() + { + DisposeCount++; + } + } + + public class FunqRequestScopeDepDisposableProperty : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public FunqRequestScopeDepDisposableProperty() { Count++; } + public void Dispose() { DisposeCount++; } + } + + public class AltRequestScopeDepDisposableProperty : IDisposable + { + public static int Count = 0; + public static int DisposeCount = 0; + public AltRequestScopeDepDisposableProperty() { Count++; } + public void Dispose() { DisposeCount++; } + } + + public class FunqDepCtor { } + public class AltDepCtor { } + + public class FunqDepProperty { } + public class AltDepProperty { } + + public class FunqDepDisposableProperty : IDisposable + { + public static int DisposeCount = 0; + public void Dispose() { DisposeCount++; } + } + public class AltDepDisposableProperty : IDisposable + { + public static int DisposeCount = 0; + public void Dispose() { DisposeCount++; } + } + + [Route("/ioc")] + public class Ioc { } + [Route("/iocasync")] + public class IocAsync { } + + public class IocResponse : IHasResponseStatus + { + public IocResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new List<string>(); + } + + public List<string> Results { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + + [Exclude(Feature.Metadata)] + [Route("/action-attr")] + public class ActionAttr : IReturn<IocResponse> { } + + [Route("/action-attr-async")] + public class ActionAttrAsync : IReturn<IocResponse> { } + + public class ActionLevelAttribute : RequestFilterAttribute + { + public IRequest RequestContext { get; set; } + public FunqDepProperty FunqDepProperty { get; set; } + public FunqDepDisposableProperty FunqDepDisposableProperty { get; set; } + public AltDepProperty AltDepProperty { get; set; } + public AltDepDisposableProperty AltDepDisposableProperty { get; set; } + + public override void Execute(IRequest req, IResponse res, object requestDto) + { + var response = new IocResponse(); + + var deps = new object[] { + FunqDepProperty, FunqDepDisposableProperty, + AltDepProperty, AltDepDisposableProperty + }; + + foreach (var dep in deps) + { + if (dep != null) + response.Results.Add(dep.GetType().Name); + } + + req.Items["action-attr"] = response; + } + } + + public class ResetIoc + { + public bool ThrowErrors { get; set; } + } + + public class IocStats : IReturn<IocStatsResponse> { } + public class IocStatsResponse + { + public int FunqNoneScope_Count { get; set; } + public int FunqRequestScope_Count { get; set; } + public int IocService_DisposeCount { get; set; } + public int IocDisposableService_DisposeCount { get; set; } + public int FunqSingletonScopeDisposable_DisposeCount { get; set; } + public int FunqRequestScopeDisposable_DisposeCount { get; set; } + public int FunqNoneScopeDisposable_DisposeCount { get; set; } + public int FunqRequestScopeDepDisposableProperty_DisposeCount { get; set; } + public int AltRequestScopeDepDisposableProperty_DisposeCount { get; set; } + public int Container_disposablesCount { get; set; } + } + + + public class IocResetService : IService + { + public void Any(ResetIoc request) + { + FunqNoneScope.Count = + FunqRequestScope.Count = + IocService.DisposeCount = + IocDisposableService.DisposeCount = + FunqSingletonScopeDisposable.DisposeCount = + FunqRequestScopeDisposable.DisposeCount = + FunqNoneScopeDisposable.DisposeCount = + FunqRequestScopeDepDisposableProperty.DisposeCount = + AltRequestScopeDepDisposableProperty.DisposeCount = + 0; + + IocService.ThrowErrors = request.ThrowErrors; + } + + public object Any(IocStats request) + { + return new IocStatsResponse + { + FunqNoneScope_Count = FunqNoneScope.Count, + FunqRequestScope_Count = FunqRequestScope.Count, + IocService_DisposeCount = IocService.DisposeCount, + IocDisposableService_DisposeCount = IocDisposableService.DisposeCount, + FunqSingletonScopeDisposable_DisposeCount = FunqSingletonScopeDisposable.DisposeCount, + FunqRequestScopeDisposable_DisposeCount = FunqRequestScopeDisposable.DisposeCount, + FunqNoneScopeDisposable_DisposeCount = FunqNoneScopeDisposable.DisposeCount, + FunqRequestScopeDepDisposableProperty_DisposeCount = FunqRequestScopeDepDisposableProperty.DisposeCount, + AltRequestScopeDepDisposableProperty_DisposeCount = AltRequestScopeDepDisposableProperty.DisposeCount, + Container_disposablesCount = HostContext.Container.disposablesCount, + }; + } + } + + public class IocService : IService, IDisposable, IRequiresRequest + { + private readonly FunqDepCtor funqDepCtor; + private readonly AltDepCtor altDepCtor; + + public IocService(FunqDepCtor funqDepCtor, AltDepCtor altDepCtor) + { + this.funqDepCtor = funqDepCtor; + this.altDepCtor = altDepCtor; + } + + public IRequest Request { get; set; } + public FunqDepProperty FunqDepProperty { get; set; } + public FunqDepDisposableProperty FunqDepDisposableProperty { get; set; } + public AltDepProperty AltDepProperty { get; set; } + public AltDepDisposableProperty AltDepDisposableProperty { get; set; } + + public object Any(Ioc request) + { + var response = new IocResponse(); + + var deps = new object[] { + funqDepCtor, altDepCtor, + FunqDepProperty, FunqDepDisposableProperty, + AltDepProperty, AltDepDisposableProperty + }; + + foreach (var dep in deps) + { + if (dep != null) + response.Results.Add(dep.GetType().Name); + } + + if (ThrowErrors) throw new ArgumentException("This service has intentionally failed"); + + return response; + } + + public async Task<object> Any(IocAsync request) + { + await Task.Delay(10); + return Any(request.ConvertTo<Ioc>()); + } + + [ActionLevel] + public IocResponse Any(ActionAttr request) + { + return Request.Items["action-attr"] as IocResponse; + } + + [ActionLevel] + public async Task<IocResponse> Any(ActionAttrAsync request) + { + await Task.Delay(10); + return Request.Items["action-attr"] as IocResponse; + } + + public static int DisposeCount = 0; + public static bool ThrowErrors = false; + + public void Dispose() + { + DisposeCount++; + } + } + + [Route("/iocscope")] + public class IocScope + { + public bool Throw { get; set; } + } + + [Route("/iocscopeasync")] + public class IocScopeAsync + { + public bool Throw { get; set; } + } + + public class IocScopeResponse : IHasResponseStatus + { + public IocScopeResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new Dictionary<string, int>(); + } + + public Dictionary<string, int> Results { get; set; } + + public int InjectsRequest { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class IocRequestFilterAttribute : AttributeBase, IHasRequestFilter + { + public FunqSingletonScope FunqSingletonScope { get; set; } + public FunqRequestScope FunqRequestScope { get; set; } + public FunqNoneScope FunqNoneScope { get; set; } + public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } + public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } + + public int Priority { get; set; } + + public void RequestFilter(IRequest req, IResponse res, object requestDto) + { + } + + public IRequestFilterBase Copy() => (IRequestFilterBase)this.MemberwiseClone(); + } + + [IocRequestFilter] + public class IocScopeService : IService, IDisposable + { + public FunqRequestScope FunqRequestScope { get; set; } + public FunqSingletonScope FunqSingletonScope { get; set; } + public FunqNoneScope FunqNoneScope { get; set; } + public FunqInjectRequest FunqInjectRequest { get; set; } + public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } + public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } + + public object Any(IocScope request) + { + if (request.Throw) + throw new Exception("Exception requested by user"); + + var response = new IocScopeResponse + { + Results = { + { typeof(FunqSingletonScope).Name, FunqSingletonScope.Count }, + { typeof(FunqRequestScope).Name, FunqRequestScope.Count }, + { typeof(FunqNoneScope).Name, FunqNoneScope.Count }, + }, + InjectsRequest = FunqInjectRequest.Request != null + ? 1 + (FunqInjectRequest.SecondLevel.Request != null ? 1 : 0) + : 0, + }; + + return response; + } + + public async Task<object> Any(IocScopeAsync request) + { + await Task.Delay(10); + return Any(request.ConvertTo<IocScope>()); + } + + public static int DisposedCount = 0; + public static bool ThrowErrors = false; + + public void Dispose() + { + DisposedCount++; + } + } + + public class IocDispose : IReturn<IocDisposeResponse> + { + public bool Throw { get; set; } + } + + public class IocDisposeAsync : IReturn<IocDisposeResponse> + { + public bool Throw { get; set; } + } + + public class IocDisposeResponse : IHasResponseStatus + { + public IocDisposeResponse() + { + this.ResponseStatus = new ResponseStatus(); + this.Results = new Dictionary<string, int>(); + } + + public Dictionary<string, int> Results { get; set; } + + public ResponseStatus ResponseStatus { get; set; } + } + + public class IocDisposableService : IService, IDisposable + { + public FunqRequestScopeDisposable FunqRequestScopeDisposable { get; set; } + public FunqSingletonScopeDisposable FunqSingletonScopeDisposable { get; set; } + public FunqNoneScopeDisposable FunqNoneScopeDisposable { get; set; } + public FunqRequestScopeDepDisposableProperty FunqRequestScopeDepDisposableProperty { get; set; } + public AltRequestScopeDepDisposableProperty AltRequestScopeDepDisposableProperty { get; set; } + + public object Any(IocDispose request) + { + if (request.Throw) + throw new Exception("Exception requested by user"); + + var response = new IocDisposeResponse + { + Results = { + { typeof(FunqSingletonScopeDisposable).Name, FunqSingletonScopeDisposable.DisposeCount }, + { typeof(FunqRequestScopeDisposable).Name, FunqRequestScopeDisposable.DisposeCount }, + { typeof(FunqNoneScopeDisposable).Name, FunqNoneScopeDisposable.DisposeCount }, + { typeof(FunqRequestScopeDepDisposableProperty).Name, FunqRequestScopeDepDisposableProperty.DisposeCount }, + { typeof(AltRequestScopeDepDisposableProperty).Name, AltRequestScopeDepDisposableProperty.DisposeCount }, + }, + }; + + return response; + } + + public async Task<object> Any(IocDisposeAsync request) + { + await Task.Delay(10); + return Any(request.ConvertTo<IocDispose>()); + } + + public static int DisposeCount = 0; + + public void Dispose() + { + DisposeCount++; + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Templates/HtmlFormat.html b/tests/ServiceStack.WebHost.IntegrationTests/Templates/HtmlFormat.html new file mode 100644 index 00000000000..42b47b19c63 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Templates/HtmlFormat.html @@ -0,0 +1,381 @@ +<!doctype html> +<html lang="en-us"> +<head> +<title>${Title}</title> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<style type="text/css"> +BODY, H1, H2, H3, H4, H5, H6, DL, DT, DD { + margin: 0; + padding: 0; + color: #444; + font: 13px/15px Arial, Verdana, Helvetica; +} +H1 { + text-align: center; + font: 24px Helvetica, Verdana, Arial; + padding: 20px 0 10px 0; + background: #FBFBFB; + border-bottom: solid 1px #fff; +} +#lnks { + border-top: solid 1px #dfdfdf; + border-bottom: solid 1px #dfdfdf; + margin: 0 0 10px 0; + padding: 5px; + background: #f1f1f1; + line-height: 20px; + text-align: center; +} +#lnks B { + padding: 0 3px; +} +#body { + padding: 20px; +} +H1 B { + font-weight: normal; + color: #069; +} +H1 A { + color: #0E8F13; + text-decoration: underline; +} +H1 I { + font-style: normal; + color: #0E8F13; +} +A { + color: #00C; + text-decoration: none; +} +A:hover { + text-decoration: underline; +} +.ib { + position: relative; + display: -moz-inline-box; + display: inline-block; +} +* html .ib { + display: inline; +} +*:first-child + html .ib { + display: inline; +} +TABLE { + border-collapse:collapse; + border: solid 1px #ccc; + clear: left; +} +TH { + text-align: left; + padding: 4px 8px; + text-shadow: #fff 1px 1px -1px; + background: #f1f1f1; + white-space:nowrap; + cursor:pointer; + font-weight: bold; +} +TH, TD, TD DT, TD DD { + font-size: 13px; + font-family: Arial; +} +TD { + padding: 8px 8px 0 8px; + vertical-align: top; +} +DL { + clear: left; +} +DT { + margin: 10px 0 5px 0; + font: bold 18px Helvetica, Verdana, Arial; + min-width: 200px; + overflow: hidden; + clear: left; + float: left; + display:block; + white-space:nowrap; +} +DD { + margin: 5px 10px; + font: 18px Arial; + padding: 2px; + display: block; + float: left; +} +DL DL DT { + font: bold 16px Arial; +} +DL DL DD { + font: 16px Arial; +} +HR { + display:none; +} +TD DL HR +{ + display:block; + padding: 0; + clear: left; + border: none; +} +TD DL +{ + padding: 4px; + margin: 0; + height:100%; + max-width: 700px; +} +DL TD DL DT { + padding: 2px; + margin: 0 10px 0 0; + font-weight: bold; + font-size: 13px; + width: 120px; + overflow: hidden; + clear: left; + float: left; + display:block; +} +DL TD DL DD { + margin: 0; + padding: 2px; + font-size: 13px; + display: block; + float: left; +} +TBODY>TR:last-child>TD { + padding: 8px; +} +THEAD +{ + -webkit-user-select:none; + -moz-user-select:none; +} +.desc, .asc { + background-color: #FAFAD2; +} +.desc { + background-color: #D4EDC9; +} +TH B { + display:block; + float:right; + margin: 0 0 0 5px; + width: 0; + height: 0; + + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #ccc; + border-bottom: none; +} +.asc B { + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #333; + border-bottom: none; +} +.desc B { + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #333; + border-top: none; +} +#show-json { + display:none; +} +#mask { + display: none; + position:absolute; + top:0; + left:0; + height:100%; + width:100%; + background: rgba(0,0,0,0.7); + z-index: 1; +} +.show-json #show-json, .show-json #mask { + display:block; +} +#show-json { + position: absolute; + left: 50%; + margin: 0 0 0 -350px; + border: solid 4px #ccc; + padding: 10px 20px; + background: #fff; + text-align: center; + float: left; + z-index: 2; +} +H3 { + font-size: 18px; + margin: 0 0 10px 0; +} +#show-json TEXTAREA { + width: 750px; + height: 400px; + overflow:visible; + display: block; +} +#show-json BUTTON { + margin: 10px 0 0 0; + padding: 5px 10px; + clear: left; +} +</style> +${MvcIncludes} +</head> +<body> + +<div id="mask"></div> + +<h1>${Header} (Embedded Resource)</h1> + +<div id="lnks"> + <a href="javascript:showJson()">view json datasource</a> + <b>from original url:</b> + <a href="${ServiceUrl}">${ServiceUrl}</a> + <b>in other formats:</b> + <a href="${ServiceUrl}format=json">json</a> + <a href="${ServiceUrl}format=xml">xml</a> + <a href="${ServiceUrl}format=csv">csv</a> + <a href="${ServiceUrl}format=jsv">jsv</a> +</div> + +<div id="body"> + + <div id="show-json"> + <h3>This reports json data source</h3> + <textarea></textarea> + <button onclick="doc.body.className=null;">Close Window</button> + </div> + + <div id="content"></div> + +</div> + +<script> !window.JSON && document.write(unescape('%3Cscript src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"%3E%3C/script%3E'))</script> + +<script type="text/javascript"> +// <![CDATA[ + +var doc = document, win = window, + $ = function(id) { return doc.getElementById(id); }, + $$ = function(sel) { return doc.getElementsByTagName(sel); }, + $each = function(fn) { for (var i=0,len=this.length; i<len; i++) fn(i, this[i], this); }; + +$.each = function(arr, fn) { $each.call(arr, fn); }; + +var splitCase = function(t) { return typeof t != 'string' ? t : t.replace(/([A-Z]|[0-9]+)/g, ' $1'); }, + uniqueKeys = function(m){ var h={}; for (var i=0,len=m.length; i<len; i++) for (var k in m[i]) if (show(k)) h[k] = k; return h; }, + keys = function(o){ var a=[]; for (var k in o) if (show(k)) a.push(k); return a; } +var tbls = []; + +function val(m) { + if (m == null) return ''; + if (typeof m == 'number') return num(m); + if (typeof m == 'string') return str(m); + if (typeof m == 'boolean') return m ? 'true' : 'false'; + return m.length ? arr(m) : obj(m); +} +function num(m) { return m; } +function strFact(showFullDate){ + + function shortDate(m){ + return m.substr(0,6) == '/Date(' ? dmft(date(m)) : m; + } + + function fullDate(m){ + return m.substr(0,6) == '/Date(' ? dmfthm(date(m)) : m; + } + return showFullDate ? fullDate : shortDate; +} +str = strFact(location.hash.indexOf('show=') != -1 && location.hash.indexOf('fulldates') != -1); +function date(s) { return new Date(parseFloat(/Date\(([^)]+)\)/.exec(s)[1])); } +function pad(d) { return d < 10 ? '0'+d : d; } +function dmft(d) { return d.getFullYear() + '/' + pad(d.getMonth() + 1) + '/' + pad(d.getDate()); } +function dmfthm(d) { return d.getFullYear() + '/' + pad(d.getMonth() + 1) + '/' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ":" + pad(d.getMinutes()); } +function show(k) { return typeof k != 'string' || k.substr(0,2) != '__'; } +function obj(m) { + var sb = '<dl>'; + for (var k in m) if (show(k)) sb += '<dt class="ib">' + splitCase(k) + '</dt><dd>' + val(m[k]) + '</dd>'; + sb += '</dl>'; + return sb; +} +function arr(m) { + if (typeof m[0] == 'string' || typeof m[0] == 'number') return m.join(', '); + var id=tbls.length, h=uniqueKeys(m); + var sb = '<table id="tbl-' + id + '"><caption></caption><thead><tr>'; + tbls.push(m); + var i=0; + for (var k in h) sb += '<th id="h-' + id + '-' + (i++) + '"><b></b>' + splitCase(k) + '</th>'; + sb += '</tr></thead><tbody>' + makeRows(h,m) + '</tbody></table>'; + return sb; +} + +function makeRows(h,m) { + var sb = ''; + for (var r=0,len=m.length; r<len; r++) { + sb += '<tr>'; + var row = m[r]; + for (var k in h) if (show(k)) sb += '<td>' + val(row[k]) + '</td>'; + sb += '</tr>'; + } + return sb; +} + +var model = ${Dto}, + txt = $$('TEXTAREA')[0], + isIE = /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent); + +$("content").innerHTML = val(model); +txt.innerHTML=JSON.stringify(model); + +function showJson(){ doc.body.className='show-json'; txt.select(); txt.focus(); } + +doc.onclick = function(e) { + e = e || window.event, el = e.target || e.srcElement, cls = el.className; + if (el.tagName == 'B') el = el.parentNode; + if (el.tagName != 'TH') return; + el.className = cls == 'asc' ? 'desc' : (cls == 'desc' ? null : 'asc'); + $.each($$('TH'), function(i,th){ if (th == el) return; th.className = null; }); + clearSel(); + var ids=el.id.split('-'), tId=ids[1], cId=ids[2]; + if (!tbls[tId]) return; + var tbl=tbls[tId].slice(0), h=uniqueKeys(tbl), col=keys(h)[cId], tbody=el.parentNode.parentNode.nextSibling; + if (!el.className){ setTableBody(tbody, makeRows(h,tbls[tId])); return; } + var d=el.className=='asc'?1:-1; + tbl.sort(function(a,b){ return cmp(a[col],b[col]) * d; }); + setTableBody(tbody, makeRows(h,tbl)); +} + +function setTableBody(tbody, html) { + if (!isIE) { tbody.innerHTML = html; return; } + var temp = tbody.ownerDocument.createElement('div'); + temp.innerHTML = '<table>' + html + '</table>'; + tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); +} + +function clearSel() { + if (doc.selection && doc.selection.empty) doc.selection.empty(); + else if(win.getSelection) { + var sel=win.getSelection(); + if (sel && sel.removeAllRanges) sel.removeAllRanges(); + } +} + +function cmp(v1, v2){ + let f1=parseFloat(v1), f2=parseFloat(v2) + if (!isNaN(f1) && !isNaN(f2)) { v1=f1; v2=f2 } + if (typeof v1 == 'string' && v1.substr(0,6) === '/Date(') { v1=date(v1); v2=date(v2) } + if (v1 === v2) return 0 + return v1 > v2 ? 1 : -1 +} + +// ]]> +</script> +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Templates/OperationControl.html b/tests/ServiceStack.WebHost.IntegrationTests/Templates/OperationControl.html new file mode 100644 index 00000000000..8fac12e2d0c --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Templates/OperationControl.html @@ -0,0 +1,201 @@ +<!DOCTYPE html> +<html> +<head> + <title>{0}</title> + <style type="text/css"> + body { + background-color:white; + color:#000000; + font-family: "Helvetica Neue", Helvetica, Verdana, Arial,serif; + margin: 0; + font-size: 13px; + } + a#logo { + position: absolute; + top: 8px; + right: 5px; + width: 40px; + height: 30px; + background-repeat: no-repeat; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAeCAYAAABe3VzdAAAKQWlDQ1BJQ0MgUHJvZmlsZQAASA2dlndUU9kWh8+9N73QEiIgJfQaegkg0jtIFQRRiUmAUAKGhCZ2RAVGFBEpVmRUwAFHhyJjRRQLg4Ji1wnyEFDGwVFEReXdjGsJ7601896a/cdZ39nnt9fZZ+9917oAUPyCBMJ0WAGANKFYFO7rwVwSE8vE9wIYEAEOWAHA4WZmBEf4RALU/L09mZmoSMaz9u4ugGS72yy/UCZz1v9/kSI3QyQGAApF1TY8fiYX5QKUU7PFGTL/BMr0lSkyhjEyFqEJoqwi48SvbPan5iu7yZiXJuShGlnOGbw0noy7UN6aJeGjjAShXJgl4GejfAdlvVRJmgDl9yjT0/icTAAwFJlfzOcmoWyJMkUUGe6J8gIACJTEObxyDov5OWieAHimZ+SKBIlJYqYR15hp5ejIZvrxs1P5YjErlMNN4Yh4TM/0tAyOMBeAr2+WRQElWW2ZaJHtrRzt7VnW5mj5v9nfHn5T/T3IevtV8Sbsz55BjJ5Z32zsrC+9FgD2JFqbHbO+lVUAtG0GQOXhrE/vIADyBQC03pzzHoZsXpLE4gwnC4vs7GxzAZ9rLivoN/ufgm/Kv4Y595nL7vtWO6YXP4EjSRUzZUXlpqemS0TMzAwOl89k/fcQ/+PAOWnNycMsnJ/AF/GF6FVR6JQJhIlou4U8gViQLmQKhH/V4X8YNicHGX6daxRodV8AfYU5ULhJB8hvPQBDIwMkbj96An3rWxAxCsi+vGitka9zjzJ6/uf6Hwtcim7hTEEiU+b2DI9kciWiLBmj34RswQISkAd0oAo0gS4wAixgDRyAM3AD3iAAhIBIEAOWAy5IAmlABLJBPtgACkEx2AF2g2pwANSBetAEToI2cAZcBFfADXALDIBHQAqGwUswAd6BaQiC8BAVokGqkBakD5lC1hAbWgh5Q0FQOBQDxUOJkBCSQPnQJqgYKoOqoUNQPfQjdBq6CF2D+qAH0CA0Bv0BfYQRmALTYQ3YALaA2bA7HAhHwsvgRHgVnAcXwNvhSrgWPg63whfhG/AALIVfwpMIQMgIA9FGWAgb8URCkFgkAREha5EipAKpRZqQDqQbuY1IkXHkAwaHoWGYGBbGGeOHWYzhYlZh1mJKMNWYY5hWTBfmNmYQM4H5gqVi1bGmWCesP3YJNhGbjS3EVmCPYFuwl7ED2GHsOxwOx8AZ4hxwfrgYXDJuNa4Etw/XjLuA68MN4SbxeLwq3hTvgg/Bc/BifCG+Cn8cfx7fjx/GvyeQCVoEa4IPIZYgJGwkVBAaCOcI/YQRwjRRgahPdCKGEHnEXGIpsY7YQbxJHCZOkxRJhiQXUiQpmbSBVElqIl0mPSa9IZPJOmRHchhZQF5PriSfIF8lD5I/UJQoJhRPShxFQtlOOUq5QHlAeUOlUg2obtRYqpi6nVpPvUR9Sn0vR5Mzl/OX48mtk6uRa5Xrl3slT5TXl3eXXy6fJ18hf0r+pvy4AlHBQMFTgaOwVqFG4bTCPYVJRZqilWKIYppiiWKD4jXFUSW8koGStxJPqUDpsNIlpSEaQtOledK4tE20Otpl2jAdRzek+9OT6cX0H+i99AllJWVb5SjlHOUa5bPKUgbCMGD4M1IZpYyTjLuMj/M05rnP48/bNq9pXv+8KZX5Km4qfJUilWaVAZWPqkxVb9UU1Z2qbapP1DBqJmphatlq+9Uuq43Pp893ns+dXzT/5PyH6rC6iXq4+mr1w+o96pMamhq+GhkaVRqXNMY1GZpumsma5ZrnNMe0aFoLtQRa5VrntV4wlZnuzFRmJbOLOaGtru2nLdE+pN2rPa1jqLNYZ6NOs84TXZIuWzdBt1y3U3dCT0svWC9fr1HvoT5Rn62fpL9Hv1t/ysDQINpgi0GbwaihiqG/YZ5ho+FjI6qRq9Eqo1qjO8Y4Y7ZxivE+41smsImdSZJJjclNU9jU3lRgus+0zwxr5mgmNKs1u8eisNxZWaxG1qA5wzzIfKN5m/krCz2LWIudFt0WXyztLFMt6ywfWSlZBVhttOqw+sPaxJprXWN9x4Zq42Ozzqbd5rWtqS3fdr/tfTuaXbDdFrtOu8/2DvYi+yb7MQc9h3iHvQ732HR2KLuEfdUR6+jhuM7xjOMHJ3snsdNJp9+dWc4pzg3OowsMF/AX1C0YctFx4bgccpEuZC6MX3hwodRV25XjWuv6zE3Xjed2xG3E3dg92f24+ysPSw+RR4vHlKeT5xrPC16Il69XkVevt5L3Yu9q76c+Oj6JPo0+E752vqt9L/hh/QL9dvrd89fw5/rX+08EOASsCegKpARGBFYHPgsyCRIFdQTDwQHBu4IfL9JfJFzUFgJC/EN2hTwJNQxdFfpzGC4sNKwm7Hm4VXh+eHcELWJFREPEu0iPyNLIR4uNFksWd0bJR8VF1UdNRXtFl0VLl1gsWbPkRoxajCCmPRYfGxV7JHZyqffS3UuH4+ziCuPuLjNclrPs2nK15anLz66QX8FZcSoeGx8d3xD/iRPCqeVMrvRfuXflBNeTu4f7kufGK+eN8V34ZfyRBJeEsoTRRJfEXYljSa5JFUnjAk9BteB1sl/ygeSplJCUoykzqdGpzWmEtPi000IlYYqwK10zPSe9L8M0ozBDuspp1e5VE6JA0ZFMKHNZZruYjv5M9UiMJJslg1kLs2qy3mdHZZ/KUcwR5vTkmuRuyx3J88n7fjVmNXd1Z752/ob8wTXuaw6thdauXNu5Tnddwbrh9b7rj20gbUjZ8MtGy41lG99uit7UUaBRsL5gaLPv5sZCuUJR4b0tzlsObMVsFWzt3WazrWrblyJe0fViy+KK4k8l3JLr31l9V/ndzPaE7b2l9qX7d+B2CHfc3em681iZYlle2dCu4F2t5czyovK3u1fsvlZhW3FgD2mPZI+0MqiyvUqvakfVp+qk6oEaj5rmvep7t+2d2sfb17/fbX/TAY0DxQc+HhQcvH/I91BrrUFtxWHc4azDz+ui6rq/Z39ff0TtSPGRz0eFR6XHwo911TvU1zeoN5Q2wo2SxrHjccdv/eD1Q3sTq+lQM6O5+AQ4ITnx4sf4H++eDDzZeYp9qukn/Z/2ttBailqh1tzWibakNml7THvf6YDTnR3OHS0/m/989Iz2mZqzymdLz5HOFZybOZ93fvJCxoXxi4kXhzpXdD66tOTSna6wrt7LgZevXvG5cqnbvfv8VZerZ645XTt9nX297Yb9jdYeu56WX+x+aem172296XCz/ZbjrY6+BX3n+l37L972un3ljv+dGwOLBvruLr57/17cPel93v3RB6kPXj/Mejj9aP1j7OOiJwpPKp6qP6391fjXZqm99Oyg12DPs4hnj4a4Qy//lfmvT8MFz6nPK0a0RupHrUfPjPmM3Xqx9MXwy4yX0+OFvyn+tveV0auffnf7vWdiycTwa9HrmT9K3qi+OfrW9m3nZOjk03dp76anit6rvj/2gf2h+2P0x5Hp7E/4T5WfjT93fAn88ngmbWbm3/eE8/syOll+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAE3mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS4xLjIiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjE8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjU8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjcyPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjQwPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT4xPC9leGlmOkNvbG9yU3BhY2U+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4zMDwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iPgogICAgICAgICA8ZGM6c3ViamVjdD4KICAgICAgICAgICAgPHJkZjpCYWcvPgogICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxMy0xMC0xMFQxOToxMDo0MzwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+UGl4ZWxtYXRvciAyLjIuMTwveG1wOkNyZWF0b3JUb29sPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KIdC6QgAABLJJREFUWAm9WGtMW2UYfnoZYAsMaMe1UKBQKLeOy0BwEG4DI2FmC2aiWYg/zCQmXpLNzWxRExH8o1vMosbExMw//jH+8Ycxmjnc5uamU5lcOkDAXSy3ljIK0tL6vSdp08I5p6cN8iak3+W9POf9vvfyISupafYAkLE/UUrYHQ/H8kN4PMS+cyRnpkKCIzi7dinxydl+HOvphtGQu1MIvYpkXc5bUqw5nauIjo5C18En0NZUj4baarhcbkzfvce86pWiIhIemWSApN0yMYnWpv1QxcQgPi4W1ZVmbi5jhzA1cxfujY1IQIjKhAWQPBWnVqO40OhXSmDLy4rR3FAH25ID03/f8+9txyAsgGTQOjePzvYWyGTBV1f1SAzq9lXAXGzCxPQM7AzsdlDYAFecTlTtLYUmKZHX/h6tBm2N++F2uTB6Z5KXJ5xFiuKwaWRsXFRGoVCgp7sLb596FUmJu0V5Q21GBHB0XJpnykpM+KD/TRTmR56WIgI4OTUT6sP9+/Hxceg7fRx11ZX+tXAGYd9BUu5yu1BUkIdkrVaSLTryx2oq4Vxdw5hE7/sUiwKMiY4GpWCvNzgRb7B89/3gVQwNW5CTrUNiQuh7RlFfwdJRuCBFASqUCrxz+gRa6uuQnp7KlK9i0Wb3fRxm5xfw7cUfsbBoR2FeLqs00f49oQGBtC0tYfyvaSGWoHVRgOSpoeFRHD1yGKUmI9qbGri7pFTI8cA6i/V1F/MuMDE1je8GryAtJQWZGWlBBvgmVXvLcP8fq6SkLgqQlD9ccSIuNtYfidTVVJpLcfDxVugzM0B50To7j3/X13H52g3MLdpgZtGrVCr5sHFrdNxV5WX45dYfXPURZGQbIQGS8P0HVg5QoCIF86Jel4Hm+loUmwq4I1tyLIMi/PrNW9xHxKpVgSJBYwqcCnMJLl7+iTuJoM2AiSSA5CVKE+Q9PkrZo0V7SwO3b2FROrewiEtXf2aRng+thr/ikB61SoXc7ExcunKdTy23JgkgcRoNOcjVZwoqkrNjI54DrBVbXVvD8Ngd/MC8k5ejR3pqiqBcWkoyq9ssaCb5g0ZyorbZlwSNBG7Ex6rR+9yzOPVyL+TsGgyc+wi/3x4JZNky7nm6S7C2Swa4ORdusbJpoXZfOd594yToHva9fx4jFuH6TZ0QfRQfSQaYlJjAJy+6ZsjOwnt9Z6BLS0X/2Q9ZvrQJ8ldXmEG1ezNJBpit122WlTTXsA8jT1JKGjj3Mdxu4a776FNPbtEpCSD1fgZ91hZhqQv0lnntpRdgdzjw2RdfCooV5Bm4/BjIIAlgx4HGQJmIxhQ8r7/Sy0rjICZEytyRQx1B+kMCpLvX2d4aJBTphO7ksZ5ncP7Tz7Eh8L4uYE/anIB0JgpQyZqFk+xo6Ii2i1rY44ryqVhypmetjwQBRkVF4fiLz8NkNPh4t+23+3Anvvr6my1tnM9AY10NyD4RL8BM1loNnDkRcRfsMyT0q9UksWPMwrWbv/GyqFnuNJcUcnv+lkMul6PImI+m+ke5N66Czf9POtTRhgssoimh81FFWQlu/DrkkbF/HnmpCUhPTYaKFe+dpD9HLOzRX8Rr0rG84rk9Mib/D4GIYiVUxZizAAAAAElFTkSuQmCC); + } + .icons { + display: block; + float: right; + } + .auth { + display: block; + width: 17px; + height: 17px; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAIAAAC0D9CtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAADsSURBVDhPY/hPOsCr58Pi/w9s/t/k+X9P5//zjP+/X0OEcet5lvL/BgMKui3z/+d9oAwOPR9Xo6h+VfP/cQCI8dABKIlDD0QFBN0zAIn8eg7l/riNQ88dBYSeGyz/37T/f5YA5X5cjUMP0OkIPajo22lsel4UoKuDo1si//9+x9AD1IBHDzBs0MMAogEt0CDopsD/j8shqpD0IDSwIJS+bgbF7LfTQCdBlSH0oGl4VQ9CMIPRAFgPsgZgSgEGK17AgK4BmMAIAbCj33RDnUTIBggA2wPxLtCSr4ehwngB2D/A1ApEsKROAPz/DwCLE/At7aBI3gAAAABJRU5ErkJggg==); + } + h1 { + color: #FFF; + font-size: 26px; + font-weight: normal; + margin: 0; + padding: 0 0 0 15px; + + line-height: 48px; + min-height: 48px; + border-radius: 0px; + border-bottom: 1px solid #191e23; + background: #2c3742; /* Old browsers */ + background: -moz-linear-gradient(top, #2c3742 0%, #28303a 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#2c3742), color-stop(100%,#28303a)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #2c3742 0%,#28303a 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #2c3742 0%,#28303a 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #2c3742 0%,#28303a 100%); /* IE10+ */ + background: linear-gradient(to bottom, #2c3742 0%,#28303a 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2c3742', endColorstr='#28303a',GradientType=0 ); /* IE6-9 */ + } + h2 { + margin: 25px 0 20px 0; + color: #29323D; + font-family: 'Open Sans', sans-serif; + font-size: 24px; + } + h3 { + color: #29323D; + font-size: 18px; + font-family: 'Open Sans', sans-serif; + } + a { + color: #428bca; + font-weight: bold; + text-decoration: none; + } + a:hover, a:focus { + color: #2a6496; + text-decoration: underline; + } + ul { + margin: 10px 0 0 10px; + padding: 0 0 0 10px; + } + li { + clear: left; + margin-top: 10px; + } + table { + border-collapse: collapse; + border-spacing: 0; + margin: 0 0 20px 0; + } + table, tr, th, td { + border: none; + } + .operations, .operation { + padding: 0 0 0 15px; + } + /* All Operations */ + .operations table { + margin-left: 1.5em; + } + .operations th { + text-align: left; + font-weight: normal; + line-height: 18px; + min-width: 27em; + white-space: nowrap; + } + /* Single Operation */ + .operations td { + font-size: 12px; + line-height: 18px; + font-weight: bold; + color: #CCC; + padding-left: 1.5em; + vertical-align: top; + } + .operation caption { + text-align: left; + font-size: 14px; + padding: 10px 0; + white-space: nowrap; + } + .operation tbody th { + text-align: left; + } + .operation thead th { + text-align: left; + text-transform: uppercase; + } + .operation th, .operation td { + padding: 5px 15px; + vertical-align: top; + } + .operation h4 { + margin: 10px 0; + padding: 0; + } + .operation li { + margin: 0; + } + .example { + padding-left: 15px; + } + .example h3 { + color:#000000; + margin: 10px 0 0 -15px; + } + .example pre { + background-color: #E5E5CC; + border: 1px solid #F0F0E0; + font-family: Courier New,monospace; + font-size: 15px; + padding: 5px; + margin-right: 15px; + white-space: pre-wrap; + overflow:auto; + } + .example .value { + color: blue; + } + .call-info { + margin: 0 0 20px 0; + } + #desc{ + margin: 0; + padding: 0 0 15px 15px; + font-size: 16px; + } + #desc P { + margin: 5px 0; + padding: 0; + line-height: 20px; + color: #444; + } + </style> +</head> +<body> + <a id="logo" href="http://www.servicestack.net" title="ServiceStack"></a> + <h1>{0} (File Resource)</h1> + + <div class="operation"> + <div> + <p><a href="{1}">&lt;back to all web services</a></p> + <h2>{3}</h2> + + {6} + + <div class="example"> + <!-- REST Examples --> + + <h3>HTTP + {2}</h3> + <p> The following are sample HTTP requests and responses. + The placeholders shown need to be replaced with actual values.</p> + +<div class="request"> +<pre> +{4} +</pre> +</div> + +{5} + + </div> + </div> + </div> +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/upload.html b/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/upload.html index ff2e0f75a03..3a6e1d1d0ed 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/upload.html +++ b/tests/ServiceStack.WebHost.IntegrationTests/TestExistingDir/upload.html @@ -10,4 +10,4 @@ <input type="file" value="upload" /> </form> </body> -</html> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AppHostBaseTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AppHostBaseTests.cs index 6ed1cebfd73..922f67ede89 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AppHostBaseTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AppHostBaseTests.cs @@ -1,45 +1,40 @@ using System.Net; using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.Text; namespace ServiceStack.WebHost.IntegrationTests.Tests { - /// <summary> - /// Note: These tests don't test ServiceStack when its mounted at /api - /// </summary> - [TestFixture] - public class AppHostBaseTests - { + [TestFixture] + public class AppHostBaseTests + { private const string BasePath = Config.AbsoluteBaseUri; - [Test] - public void Root_path_redirects_to_metadata_page() - { - var html = Config.ServiceStackBaseUri.GetStringFromUrl(); - Assert.That(html.Contains("The following operations are supported.")); - } + [Test] + public void Can_download_metadata_page() + { + var html = Config.ServiceStackBaseUri.CombineWith("metadata").GetStringFromUrl(); + Assert.That(html.Contains("The following operations are supported.")); + } - [Test] - public void Can_download_webpage_html_page() - { + [Test] + public void Can_download_webpage_html_page() + { var html = (BasePath + "webpage.html").GetStringFromUrl(); - Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); - } + Assert.That(html.Contains("Default index ServiceStack.WebHost.Endpoints.Tests page")); + } - [Test] - public void Gets_404_on_non_existant_page() - { - var webRes = (BasePath + "nonexistant.html").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); - } + [Test] + public void Gets_404_on_non_existent_page() + { + var webRes = (BasePath + "nonexistant.html").GetErrorResponse(); + Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); + } - [Test] - public void Gets_404_3_on_page_with_non_whitelisted_extension() - { - var webRes = (BasePath + "api/webpage.forbidden").GetErrorResponse(); - Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); - } - - } + [Test] + public void Gets_403_on_page_with_non_whitelisted_extension() + { + var webRes = (BasePath + "api/webpage.forbidden").GetErrorResponse(); + Assert.That(webRes.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden)); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AssertValidAccessTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AssertValidAccessTests.cs new file mode 100644 index 00000000000..bb409855dfe --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AssertValidAccessTests.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using System.Net; +using NUnit.Framework; +using ServiceStack.Auth; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class AssertValidAccessTests : AuthTestsBase + { + protected Register register; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + Tracer.Instance = new Tracer.ConsoleTracer(); + register = CreateAdminUser(); + } + + [OneTimeTearDown] + public void TestFixtureTearDown() + { + Tracer.Instance = new Tracer.NullTracer(); + } + + public string RoleName1 = "Role1"; + public string RoleName2 = "Role2"; + public const string ContentManager = "ContentManager"; + public const string ContentPermission = "ContentPermission"; + + public string Permission1 = "Permission1"; + public string Permission2 = "Permission2"; + + public Register RegisterNewUser(bool? autoLogin = null) + { + var userId = Environment.TickCount % 10000; + + var newUserRegistration = new Register + { + UserName = "UserName" + userId, + DisplayName = "DisplayName" + userId, + Email = "user{0}@sf.com".Fmt(userId), + FirstName = "FirstName" + userId, + LastName = "LastName" + userId, + Password = "Password" + userId, + AutoLogin = autoLogin, + }; + + ServiceClient.Send(newUserRegistration); + + return newUserRegistration; + } + + [Test] + public void Authenticating_does_return_session_cookies() + { + var client = AuthenticateWithAdminUser(); + Assert.That(client.CookieContainer.Count, Is.GreaterThan(0)); + } + + [Test] + public void Cannot_assign_roles_with_normal_user() + { + var newUser = RegisterNewUser(autoLogin: true); + + try + { + var response = ServiceClient.Send( + new AssignRoles + { + UserName = newUser.UserName, + Roles = { RoleName1, RoleName2 }, + Permissions = { Permission1, Permission2 } + }); + + Assert.Fail("Should not be allowed"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + //StatusDescription is ignored in WebDevServer + //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); + } + } + + [Test] + public void Can_Assign_Roles_and_Permissions_to_new_User() + { + var newUser = RegisterNewUser(); + + var client = AuthenticateWithAdminUser(); + + var response = client.Send( + new AssignRoles + { + UserName = newUser.UserName, + Roles = { RoleName1, RoleName2 }, + Permissions = { Permission1, Permission2 } + }); + + Console.WriteLine("Assigned Roles: " + response.Dump()); + + Assert.That(response.AllRoles, Is.EquivalentTo(new[] { RoleName1, RoleName2 })); + Assert.That(response.AllPermissions, Is.EquivalentTo(new[] { Permission1, Permission2 })); + } + + [Test] + public void Can_UnAssign_Roles_and_Permissions_to_new_User() + { + var newUser = RegisterNewUser(); + + var client = AuthenticateWithAdminUser(); + + client.Send( + new AssignRoles + { + UserName = newUser.UserName, + Roles = new List<string> { RoleName1, RoleName2 }, + Permissions = new List<string> { Permission1, Permission2 } + }); + + var response = client.Send( + new UnAssignRoles + { + UserName = newUser.UserName, + Roles = { RoleName1 }, + Permissions = { Permission2 }, + }); + + Console.WriteLine("Remaining Roles: " + response.Dump()); + + Assert.That(response.AllRoles, Is.EquivalentTo(new[] { RoleName2 })); + Assert.That(response.AllPermissions, Is.EquivalentTo(new[] { Permission1 })); + } + + [Test] + public void Can_only_access_ContentManagerOnlyService_service_after_Assigned_Role() + { + var newUser = RegisterNewUser(autoLogin: true); + + try + { + ServiceClient.Send(new ContentManagerOnly()); + Assert.Fail("Should not be allowed - no roles"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + //StatusDescription is ignored in WebDevServer + //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); + } + + var client = AuthenticateWithAdminUser(); + + client.Send( + new AssignRoles + { + UserName = newUser.UserName, + Roles = new List<string> { RoleName1 }, + }); + + var newUserClient = Login(newUser.UserName, newUser.Password); + + try + { + newUserClient.Send(new ContentManagerOnly()); + Assert.Fail("Should not be allowed - wrong roles"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + //StatusDescription is ignored in WebDevServer + //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); + } + + var assignResponse = client.Send( + new AssignRoles + { + UserName = newUser.UserName, + Roles = new List<string> { ContentManager }, + }); + + Assert.That(assignResponse.AllRoles, Is.EquivalentTo(new[] { RoleName1, ContentManager })); + + var response = newUserClient.Send(new ContentManagerOnly()); + + Assert.That(response.Result, Is.EqualTo("Haz Access")); + } + + [Test] + public void Can_only_access_ContentPermissionOnlyService_service_after_Assigned_Permission() + { + var newUser = RegisterNewUser(autoLogin: true); + + try + { + ServiceClient.Send(new ContentPermissionOnly()); + Assert.Fail("Should not be allowed - no permissions"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + //StatusDescription is ignored in WebDevServer + //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Permissions")); + } + + var client = AuthenticateWithAdminUser(); + + client.Send( + new AssignRoles + { + UserName = newUser.UserName, + Permissions = new List<string> { RoleName1 }, + }); + + var newUserClient = Login(newUser.UserName, newUser.Password); + + try + { + newUserClient.Send(new ContentPermissionOnly()); + Assert.Fail("Should not be allowed - wrong permissions"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); + //StatusDescription is ignored in WebDevServer + //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Permissions")); + } + + var assignResponse = client.Send( + new AssignRoles + { + UserName = newUser.UserName, + Permissions = new List<string> { ContentPermission }, + }); + + Assert.That(assignResponse.AllPermissions, Is.EquivalentTo(new[] { RoleName1, ContentPermission })); + + var response = newUserClient.Send(new ContentPermissionOnly()); + + Assert.That(response.Result, Is.EqualTo("Haz Access")); + } + + [Test] + public void Cannot_access_Admin_service_by_default() + { + try + { + var response = BaseUri.AppendPath("requiresadmin").GetJsonFromUrl(); + + Assert.Fail("Should not allow access to protected resource"); + } + catch (Exception ex) + { + if (ex.IsUnauthorized() || ex.IsAny400()) //redirect to login + return; + + throw; + } + } + + [Test] + public void Can_access_Admin_service_with_AuthSecret() + { + BaseUri.AppendPath("requiresadmin") + .AddQueryParam("authsecret", AuthSecret).GetJsonFromUrl(); + } + + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncProgressTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncProgressTests.cs new file mode 100644 index 00000000000..990d120e82e --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncProgressTests.cs @@ -0,0 +1,107 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + public class AsyncProgressTests + { + [Test] + public async Task Can_report_progress_when_downloading_async() + { + var hold = AsyncServiceClient.BufferSize; + AsyncServiceClient.BufferSize = 100; //Default BufferSize = 8192 + + try + { + var asyncClient = new JsonServiceClient(Config.ServiceStackBaseUri); + + var progress = new List<string>(); + + //Note: total = -1 when 'Transfer-Encoding: chunked' + //Available in ASP.NET or in HttpListener when downloading responses with known lengths: + //E.g: Strings, Files, etc. + asyncClient.OnDownloadProgress = (done, total) => + progress.Add("{0}/{1} bytes downloaded".Fmt(done, total)); + + List<Movie> response = await asyncClient.GetAsync(new TestProgress()); + + progress.Each(x => x.Print()); + + Assert.That(response.Count, Is.GreaterThan(0)); + Assert.That(progress.Count, Is.GreaterThan(0)); + Assert.That(progress.First(), Is.EqualTo("100/1160 bytes downloaded")); + Assert.That(progress.Last(), Is.EqualTo("1160/1160 bytes downloaded")); + } + finally + { + AsyncServiceClient.BufferSize = hold; + } + } + + [Test] + public async Task Can_report_progress_when_downloading_async_with_Post() + { + await AsyncDownloadWithProgress(new TestProgressString()); + } + + [Test] + [Ignore("Setting Content-Length requires IIS integrated pipeline mode")] + public async Task Can_report_progress_when_downloading_async_with_Post_bytes() + { + await AsyncDownloadWithProgress(new TestProgressBytes()); + } + + [Test] + [Ignore("Setting Content-Length requires IIS integrated pipeline mode")] + public async Task Can_report_progress_when_downloading_async_with_Post_File_bytes() + { + await AsyncDownloadWithProgress(new TestProgressBinaryFile()); + } + + [Test] + [Ignore("Setting Content-Length requires IIS integrated pipeline mode")] + public async Task Can_report_progress_when_downloading_async_with_Post_File_text() + { + await AsyncDownloadWithProgress(new TestProgressTextFile()); + } + + private static async Task AsyncDownloadWithProgress<TResponse>(IReturn<TResponse> requestDto) + { + var hold = AsyncServiceClient.BufferSize; + AsyncServiceClient.BufferSize = 100; + + try + { + var asyncClient = new JsonServiceClient(Config.ServiceStackBaseUri); + + var progress = new List<string>(); + + //Note: total = -1 when 'Transfer-Encoding: chunked' + //Available in ASP.NET or in HttpListener when downloading responses with known lengths: + //E.g: Strings, Files, etc. + asyncClient.OnDownloadProgress = (done, total) => + progress.Add("{0}/{1} bytes downloaded".Fmt(done, total)); + + var response = await asyncClient.PostAsync(requestDto); + + progress.Each(x => x.Print()); + + Assert.That(progress.Count, Is.GreaterThan(0)); + Assert.That(progress.First(), Is.EqualTo("100/1160 bytes downloaded")); + Assert.That(progress.Last(), Is.EqualTo("1160/1160 bytes downloaded")); + } + finally + { + AsyncServiceClient.BufferSize = hold; + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncRestClientTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncRestClientTests.cs new file mode 100644 index 00000000000..fff1d77a0aa --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncRestClientTests.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + public abstract class AsyncRestClientTests + { + private const string ListeningOn = Config.ServiceStackBaseUri; + + protected abstract IHttpRestClientAsync CreateServiceClient(); + + [Test] + public async Task Can_call_GetAsync_on_GetFactorial_using_RestClientAsync() + { + var asyncClient = CreateServiceClient(); + + var response = await asyncClient.GetAsync<GetFactorialResponse>("factorial/3"); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(3))); + } + + [Test] + public async Task Can_call_GetAsync_on_Movies_using_RestClientAsync() + { + var asyncClient = CreateServiceClient(); + await asyncClient.PostAsync(new ResetMovies()); + + var response = await asyncClient.GetAsync<MoviesResponse>("movies"); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Movies.EquivalentTo(ResetMoviesService.Top5Movies)); + } + + [Test] + public async Task Can_call_GetAsync_on_single_Movie_using_RestClientAsync() + { + var asyncClient = CreateServiceClient(); + await asyncClient.PostAsync(new ResetMovies()); + + var response = await asyncClient.GetAsync<MovieResponse>("movies/1"); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(response.Movie.Id, Is.EqualTo(1)); + } + + [Test] + public async Task Can_call_PostAsync_to_add_new_Movie_using_RestClientAsync() + { + var asyncClient = CreateServiceClient(); + await asyncClient.PostAsync(new ResetMovies()); + + var newMovie = new Movie + { + ImdbId = "tt0450259", + Title = "Blood Diamond", + Rating = 8.0m, + Director = "Edward Zwick", + ReleaseDate = new DateTime(2007, 1, 26), + TagLine = "A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.", + Genres = new List<string> { "Adventure", "Drama", "Thriller" }, + }; + + var response = await asyncClient.PostAsync<MovieResponse>("movies", newMovie); + + Assert.That(response, Is.Not.Null, "No response received"); + + var createdMovie = response.Movie; + Assert.That(createdMovie.Id, Is.GreaterThan(0)); + Assert.That(createdMovie.ImdbId, Is.EqualTo(newMovie.ImdbId)); + } + + [Test] + public async Task Can_call_DeleteAsync_to_delete_Movie_using_RestClientAsync() + { + var asyncClient = CreateServiceClient(); + await asyncClient.PostAsync(new ResetMovies()); + + var newMovie = new Movie + { + ImdbId = "tt0450259", + Title = "Blood Diamond", + Rating = 8.0m, + Director = "Edward Zwick", + ReleaseDate = new DateTime(2007, 1, 26), + TagLine = "A fisherman, a smuggler, and a syndicate of businessmen match wits over the possession of a priceless diamond.", + Genres = new List<string> { "Adventure", "Drama", "Thriller" }, + }; + + var response = await asyncClient.PostAsync<MovieResponse>("movies", newMovie); + + var createdMovie = response.Movie; + + response = await asyncClient.DeleteAsync<MovieResponse>("movies/" + createdMovie.Id); + + Assert.That(response, Is.Not.Null, "No response received"); + Assert.That(createdMovie, Is.Not.Null); + Assert.That(response.Movie, Is.Null); + } + + [TestFixture] + public class JsonAsyncRestServiceClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateServiceClient() + { + return new JsonServiceClient(ListeningOn); + } + } + + [TestFixture] + public class JsvAsyncRestServiceClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateServiceClient() + { + return new JsvServiceClient(ListeningOn); + } + } + + [TestFixture] + public class XmlAsyncRestServiceClientTests : AsyncRestClientTests + { + protected override IHttpRestClientAsync CreateServiceClient() + { + return new XmlServiceClient(ListeningOn); + } + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncTaskTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncTaskTests.cs new file mode 100644 index 00000000000..3c3b2f96cf0 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AsyncTaskTests.cs @@ -0,0 +1,305 @@ +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + public abstract class AsyncTaskTests + { + private const string ListeningOn = Config.ServiceStackBaseUri; + + protected abstract IServiceClient CreateServiceClient(); + + private const int Param = 3; + + [Test] + public void GetSync_GetFactorialGenericSync() + { + var response = CreateServiceClient().Get(new GetFactorialSync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialGenericAsync() + { + var response = CreateServiceClient().Get(new GetFactorialGenericAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialObjectAsync() + { + var response = CreateServiceClient().Get(new GetFactorialObjectAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialAwaitAsync() + { + var response = CreateServiceClient().Get(new GetFactorialAwaitAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialDelayAsync() + { + var response = CreateServiceClient().Get(new GetFactorialDelayAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void GetSync_GetFactorialUnmarkedAsync() + { + var response = CreateServiceClient().Get<GetFactorialResponse>( + new GetFactorialUnmarkedAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + + [Test] + public async Task GetAsync_GetFactorialGenericSync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialSync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialGenericAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialGenericAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialObjectAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialObjectAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialAwaitAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialAwaitAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialDelayAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialDelayAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialNewTaskAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialNewTaskAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialNewTcsAsync() + { + var response = await CreateServiceClient().GetAsync(new GetFactorialNewTcsAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task GetAsync_GetFactorialUnmarkedAsync() + { + var response = await CreateServiceClient().GetAsync<GetFactorialResponse>( + new GetFactorialUnmarkedAsync { ForNumber = Param }); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + + [Test] + public async Task VoidAsync() + { + await CreateServiceClient() + .GetAsync(new VoidAsync { Message = "VoidAsync" }); + } + + + [TestFixture] + public class JsonAsyncTaskTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsonServiceClient(ListeningOn); + } + } + + [TestFixture] + public class JsvAsyncRestServiceClientTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsvServiceClient(ListeningOn); + } + } + + [TestFixture] + public class XmlAsyncRestServiceClientTests : AsyncTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new XmlServiceClient(ListeningOn); + } + } + } + + [TestFixture] + public class Soap12AsyncPostTaskTests : AsyncPostTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new Soap12ServiceClient(Config.ServiceStackBaseUri); + } + } + + [TestFixture] + public class JsonServiceClientAsyncPostTaskTests : AsyncPostTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsonServiceClient(Config.ServiceStackBaseUri); + } + } + + [TestFixture] + public class JsonHttpClientAsyncPostTaskTests : AsyncPostTaskTests + { + protected override IServiceClient CreateServiceClient() + { + return new JsonHttpClient(Config.ServiceStackBaseUri); + } + } + + public abstract class AsyncPostTaskTests + { + private const int Param = 3; + + protected abstract IServiceClient CreateServiceClient(); + + [Test] + public void PostSync_GetFactorialGenericSync() + { + var response = CreateServiceClient().Post(new GetFactorialSync {ForNumber = Param}); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void PostSync_GetFactorialGenericAsync() + { + var response = CreateServiceClient().Post(new GetFactorialGenericAsync {ForNumber = Param}); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void PostSync_GetFactorialObjectAsync() + { + var response = CreateServiceClient().Post(new GetFactorialObjectAsync {ForNumber = Param}); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void PostSync_GetFactorialAwaitAsync() + { + var response = CreateServiceClient().Post(new GetFactorialAwaitAsync {ForNumber = Param}); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void PostSync_GetFactorialDelayAsync() + { + var response = CreateServiceClient().Post(new GetFactorialDelayAsync {ForNumber = Param}); + Assert.That(response.Result, Is.EqualTo(GetFactorialService.GetFactorial(Param))); + } + + [Test] + public void PostSync_GetFactorialUnmarkedAsync() + { + var response = CreateServiceClient().Post<GetFactorialResponse>( + new GetFactorialUnmarkedAsync {ForNumber = Param}); + Assert.That(response.Result, Is.EqualTo(GetFactorialAsyncService.GetFactorial(Param))); + } + } + + [Ignore("Load Test"), TestFixture] + public class AsyncLoadTests + { + const int NoOfTimes = 1000; + + [Test] + public void Load_test_GetFactorialSync_sync() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + for (var i = 0; i < NoOfTimes; i++) + { + var response = client.Get(new GetFactorialSync { ForNumber = 3 }); + if (i % 100 == 0) + { + "{0}: {1}".Print(i, response.Result); + } + } + } + + [Test] + public async Task Load_test_GetFactorialSync_async() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + int i = 0; + + var fetchTasks = NoOfTimes.Times(() => + client.GetAsync(new GetFactorialSync { ForNumber = 3 }) + .ContinueWith(t => + { + if (++i % 100 == 0) + { + "{0}: {1}".Print(i, t.Result.Result); + } + })); + + await Task.WhenAll(fetchTasks); + } + + [Test] + public void Load_test_GetFactorialGenericAsync_sync() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + for (var i = 0; i < NoOfTimes; i++) + { + var response = client.Get(new GetFactorialGenericAsync { ForNumber = 3 }); + if (i % 100 == 0) + { + "{0}: {1}".Print(i, response.Result); + } + } + } + + [Test] + public async Task Load_test_GetFactorialGenericAsync_async() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + + int i = 0; + + var fetchTasks = NoOfTimes.Times(() => + client.GetAsync(new GetFactorialGenericAsync { ForNumber = 3 }) + .ContinueWith(t => + { + if (++i % 100 == 0) + { + "{0}: {1}".Print(i, t.Result.Result); + } + })); + + await Task.WhenAll(fetchTasks); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AuthTestsBase.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AuthTestsBase.cs index dc2aaf3de43..dea20f7e860 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/AuthTestsBase.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/AuthTestsBase.cs @@ -1,82 +1,81 @@ using System; using System.Net; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface.Auth; using ServiceStack.Text; namespace ServiceStack.WebHost.IntegrationTests.Tests { - public class AuthTestsBase - { - public const string BaseUri = Config.ServiceStackBaseUri; - public const string AdminEmail = "admin@servicestack.com"; - public const string AuthSecret = "secretz"; - private const string AdminPassword = "E8828A3E26884CE0B345D0D2DFED358A"; + public class AuthTestsBase + { + public const string BaseUri = Config.ServiceStackBaseUri; + public const string AdminEmail = "admin@servicestack.com"; + public const string AuthSecret = "secretz"; + private const string AdminPassword = "E8828A3E26884CE0B345D0D2DFED358A"; - private IServiceClient serviceClient; - public IServiceClient ServiceClient - { - get - { - return serviceClient ?? (serviceClient = new JsonServiceClient(BaseUri)); - } - } + private IServiceClient serviceClient; + public IServiceClient ServiceClient + { + get + { + return serviceClient ?? (serviceClient = new JsonServiceClient(BaseUri)); + } + } - public Registration CreateAdminUser() - { - var registration = new Registration { - UserName = "Admin", - DisplayName = "The Admin User", - Email = AdminEmail, //this email is automatically assigned as Admin in Web.Config - FirstName = "Admin", - LastName = "User", - Password = AdminPassword, - }; - try - { - ServiceClient.Send(registration); - } - catch (WebServiceException ex) - { - ("Error while creating Admin User: " + ex.Message).Print(); - ex.ResponseDto.PrintDump(); - } - return registration; - } + public Register CreateAdminUser() + { + var registration = new Register + { + UserName = "Admin", + DisplayName = "The Admin User", + Email = AdminEmail, //this email is automatically assigned as Admin in Web.Config + FirstName = "Admin", + LastName = "User", + Password = AdminPassword, + }; + try + { + ServiceClient.Send(registration); + } + catch (WebServiceException ex) + { + ("Error while creating Admin User: " + ex.Message).Print(); + } + return registration; + } - public JsonServiceClient Login(string userName, string password) - { - var client = new JsonServiceClient(BaseUri); - client.Send(new Auth { - UserName = userName, - Password = password, - RememberMe = true, - }); + public JsonServiceClient Login(string userName, string password) + { + var client = new JsonServiceClient(BaseUri); + client.Send(new Authenticate + { + UserName = userName, + Password = password, + RememberMe = true, + }); - return client; - } + return client; + } - public JsonServiceClient AuthenticateWithAdminUser() - { - var registration = CreateAdminUser(); - var adminServiceClient = new JsonServiceClient(BaseUri); - adminServiceClient.Send(new Auth { - UserName = registration.UserName, - Password = registration.Password, - RememberMe = true, - }); + public JsonServiceClient AuthenticateWithAdminUser() + { + var registration = CreateAdminUser(); + var adminServiceClient = new JsonServiceClient(BaseUri); + adminServiceClient.Send(new Authenticate + { + UserName = registration.UserName, + Password = registration.Password, + RememberMe = true, + }); - return adminServiceClient; - } + return adminServiceClient; + } - protected void AssertUnAuthorized(WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); - Assert.That(webEx.StatusDescription, Is.EqualTo(HttpStatusCode.Unauthorized.ToString())); - } + protected void AssertUnAuthorized(WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Unauthorized)); + Assert.That(webEx.StatusDescription, Is.EqualTo(HttpStatusCode.Unauthorized.ToString())); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/BinarySerializedTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/BinarySerializedTests.cs index d41dbd0dc18..61ba99b6bd3 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/BinarySerializedTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/BinarySerializedTests.cs @@ -2,8 +2,7 @@ using System.IO; using System.Text; using NUnit.Framework; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; +using ServiceStack.ProtoBuf; using ServiceStack.Text; using ServiceStack.WebHost.IntegrationTests.Services; @@ -29,9 +28,9 @@ public void Can_serialize_RandomString() var rand = RandomString(32); using (var ms = new MemoryStream()) { - ProtoBuf.Serializer.Serialize(ms, rand); + global::ProtoBuf.Serializer.Serialize(ms, rand); ms.Position = 0; - var fromBytes = ProtoBuf.Serializer.Deserialize<string>(ms); + var fromBytes = global::ProtoBuf.Serializer.Deserialize<string>(ms); Assert.That(rand, Is.EqualTo(fromBytes)); } @@ -45,19 +44,15 @@ public void Can_call_cached_WebService_with_Protobuf() try { var fromEmail = RandomString(32); - var response = client.Post<ProtoBufEmail>( - "/cached/protobuf", - new CachedProtoBufEmail { - FromAddress = fromEmail - }); - - response.PrintDump(); + var response = client.Post<ProtoBufEmail>("/cached/protobuf", new CachedProtoBufEmail + { + FromAddress = fromEmail + }); Assert.That(response.FromAddress, Is.EqualTo(fromEmail)); } catch (WebServiceException webEx) { - webEx.ResponseDto.PrintDump(); Assert.Fail(webEx.Message); } } @@ -72,19 +67,15 @@ public void Can_call_WebService_with_Protobuf() try { var fromEmail = RandomString(32); - var response = client.Post<ProtoBufEmail>( - "/cached/protobuf", - new UncachedProtoBufEmail { - FromAddress = fromEmail - }); - - response.PrintDump(); + var response = client.Post<ProtoBufEmail>("/cached/protobuf", new UncachedProtoBufEmail + { + FromAddress = fromEmail + }); Assert.That(response.FromAddress, Is.EqualTo(fromEmail)); } catch (WebServiceException webEx) { - webEx.ResponseDto.PrintDump(); Assert.Fail(webEx.Message); } } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs index 59d9ac1f178..0b86f46665d 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CachedServiceTests.cs @@ -1,16 +1,15 @@ using NUnit.Framework; using ServiceStack.Common; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; +using ServiceStack.ProtoBuf; using ServiceStack.Text; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class CachedServiceTests - { - [TestFixtureSetUp] + [TestFixture] + public class CachedServiceTests + { + [OneTimeSetUp] public void OnBeforeEachTest() { var jsonClient = new JsonServiceClient(Config.ServiceStackBaseUri); @@ -49,11 +48,11 @@ public void Can_call_Cached_WebService_with_ProtoBuf_without_compression() } [Test] - public void Can_call_Cached_WebService_with_JSONP() - { - var url = Config.ServiceStackBaseUri.CombineWith("/cached/movies?callback=cb"); - var jsonp = url.GetJsonFromUrl(); - Assert.That(jsonp.StartsWith("cb(")); - } - } + public void Can_call_Cached_WebService_with_JSONP() + { + var url = Config.ServiceStackBaseUri.CombineWith("/cached/movies?callback=cb"); + var jsonp = url.GetJsonFromUrl(); + Assert.That(jsonp.StartsWith("cb(")); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/Config.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/Config.cs index 9135ad1afc0..4c39cc97edb 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/Config.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/Config.cs @@ -1,8 +1,8 @@ namespace ServiceStack.WebHost.IntegrationTests.Tests { - public class Config - { + public class Config + { public const string AbsoluteBaseUri = "http://localhost:50000/"; public const string ServiceStackBaseUri = AbsoluteBaseUri + "api"; - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CookieTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CookieTests.cs new file mode 100644 index 00000000000..f2cb3ac2757 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CookieTests.cs @@ -0,0 +1,23 @@ +using NUnit.Framework; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class CookieTests + { + [Test] + public void Handles_malicious_php_cookies() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri) + { + StoreCookies = false, + RequestFilter = r => r.Headers["Cookie"] = "$Version=1; $Path=/; $Path=/; RealCookie=choc-chip" + }; + //client.Headers.Add("Cookie", "$Version=1; $Path=/; $Path=/"); + + var response = client.Get(new Cookies()); + Assert.That(response.RequestCookieNames, Contains.Item("RealCookie")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CsvContentTypeFilterTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CsvContentTypeFilterTests.cs index bfac850706e..9e1ff066d18 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CsvContentTypeFilterTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CsvContentTypeFilterTests.cs @@ -3,130 +3,122 @@ using System.Linq; using System.Net; using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class CsvContentTypeFilterTests - { - const int HeaderRowCount = 1; - private const string ServiceClientBaseUri = Config.ServiceStackBaseUri + "/"; + [TestFixture] + public class CsvContentTypeFilterTests + { + const int HeaderRowCount = 1; + private const string ServiceClientBaseUri = Config.ServiceStackBaseUri + "/"; - private static void FailOnAsyncError<T>(T response, Exception ex) - { - Assert.Fail(ex.Message); - } + private static void FailOnAsyncError<T>(T response, Exception ex) + { + Assert.Fail(ex.Message); + } [SetUp] public void SetUp() { // make sure that movies db is not modified - RestsTestBase.GetWebResponse(HttpMethods.Post, ServiceClientBaseUri + "reset-movies", ContentType.Xml, 0); + RestsTestBase.GetWebResponse(HttpMethods.Post, ServiceClientBaseUri + "reset-movies", MimeTypes.Xml, 0); } - [Test] - [Ignore("Fails because CSV Deserializer is not implemented")] - public void Can_download_movies_in_Csv() - { - var asyncClient = new AsyncServiceClient - { - ContentType = ContentType.Csv, - StreamSerializer = (r, o, s) => CsvSerializer.SerializeToStream(o, s), - StreamDeserializer = CsvSerializer.DeserializeFromStream, - }; - - MoviesResponse response = null; - asyncClient.SendAsync<MoviesResponse>(HttpMethods.Get, ServiceClientBaseUri + "/movies", null, - r => response = r, FailOnAsyncError); + [Test] + public async Task Can_download_movies_in_Csv() + { + var client = new CsvServiceClient(ServiceClientBaseUri); - Thread.Sleep(1000); + var response = await client.GetAsync<MoviesResponse>(new Movies()); - Assert.That(response, Is.Not.Null, "No response received"); - } + Assert.That(response, Is.Not.Null, "No response received"); + } - [Test] - public void Can_download_CSV_movies_using_csv_syncreply_endpoint() - { - var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/syncreply/Movies"); + [Test] + public void Can_download_CSV_movies_using_csv_reply_endpoint() + { + var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/reply/Movies"); - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); - var csvRows = new StreamReader(res.GetResponseStream()).ReadLines().ToList(); + var csvRows = res.ReadLines().ToList(); - const int headerRowCount = 1; - Assert.That(csvRows, Has.Count.EqualTo(headerRowCount + ResetMoviesService.Top5Movies.Count)); - //Console.WriteLine(csvRows.Join("\n")); - } + const int headerRowCount = 1; + Assert.That(csvRows, Has.Count.EqualTo(headerRowCount + ResetMoviesService.Top5Movies.Count)); + //Console.WriteLine(csvRows.Join("\n")); + } - [Test] - public void Can_download_CSV_movies_using_csv_SyncReply_Path_and_alternate_XML_Accept_Header() - { - var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/syncreply/Movies"); - req.Accept = "application/xml"; + [Test] + public void Can_download_CSV_movies_using_csv_reply_Path_and_alternate_XML_Accept_Header() + { + var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/reply/Movies"); + req.Accept = "application/xml"; - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); - var csvRows = new StreamReader(res.GetResponseStream()).ReadLines().ToList(); + var csvRows = res.ReadLines().ToList(); - Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); - Console.WriteLine(csvRows.Join("\n")); - } + Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); + Console.WriteLine(csvRows.Join("\n")); + } - [Test] - public void Can_download_CSV_movies_using_csv_Accept_and_RestPath() - { - var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "movies"); - req.Accept = ContentType.Csv; + [Test] + public void Can_download_CSV_movies_using_csv_Accept_and_RestPath() + { + var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "movies"); + req.Accept = MimeTypes.Csv; - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Movies.csv")); - var csvRows = new StreamReader(res.GetResponseStream()).ReadLines().ToList(); + var csvRows = res.ReadLines().ToList(); - Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); - //Console.WriteLine(csvRows.Join("\n")); - } + Assert.That(csvRows, Has.Count.EqualTo(HeaderRowCount + ResetMoviesService.Top5Movies.Count)); + //Console.WriteLine(csvRows.Join("\n")); + } - [Test] - public void Can_download_CSV_Hello_using_csv_syncreply_endpoint() - { - var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/syncreply/Hello?Name=World!"); + [Test] + public void Can_download_CSV_Hello_using_csv_reply_endpoint() + { + var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "csv/reply/Hello?Name=World!"); - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Hello.csv")); + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Hello.csv")); - var csv = new StreamReader(res.GetResponseStream()).ReadToEnd(); - Assert.That(csv, Is.EqualTo("Result\r\n\"Hello, World!\"\r\n")); + var csv = res.ReadToEnd(); + var lf = Environment.NewLine; + Assert.That(csv, Is.EqualTo("Result{0}\"Hello, World!\"{0}".Fmt(lf))); - Console.WriteLine(csv); - } + Console.WriteLine(csv); + } - [Test] - public void Can_download_CSV_Hello_using_csv_Accept_and_RestPath() - { - var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "hello/World!"); - req.Accept = ContentType.Csv; + [Test] + public void Can_download_CSV_Hello_using_csv_Accept_and_RestPath() + { + var req = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "hello/World!"); + req.Accept = MimeTypes.Csv; - var res = req.GetResponse(); - Assert.That(res.ContentType, Is.EqualTo(ContentType.Csv)); - Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Hello.csv")); + var res = req.GetResponse(); + Assert.That(res.ContentType, Is.EqualTo(MimeTypes.Csv)); + Assert.That(res.Headers[HttpHeaders.ContentDisposition], Is.EqualTo("attachment;filename=Hello.csv")); - var csv = new StreamReader(res.GetResponseStream()).ReadToEnd(); - Assert.That(csv, Is.EqualTo("Result\r\n\"Hello, World!\"\r\n")); + var csv = res.ReadToEnd(); + var lf = Environment.NewLine; + Assert.That(csv, Is.EqualTo("Result{0}\"Hello, World!\"{0}".Fmt(lf))); - Console.WriteLine(csv); - } + Console.WriteLine(csv); + } - } -} \ No newline at end of file + } +} diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs index 6465764b433..12a8710718e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomHeadersTests.cs @@ -1,6 +1,5 @@ using NUnit.Framework; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; +using ServiceStack.ProtoBuf; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests @@ -12,7 +11,7 @@ public class CustomHeadersTests public void GetRequest() { var client = new JsonServiceClient(Config.ServiceStackBaseUri); - client.Headers.Add("Foo","abc123"); + client.Headers.Add("Foo", "abc123"); var response = client.Get(new CustomHeaders()); Assert.That(response.Foo, Is.EqualTo("abc123")); Assert.That(response.Bar, Is.Null); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomRequestDataTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomRequestDataTests.cs index 51a78fc0a3c..25b8469b3bd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomRequestDataTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomRequestDataTests.cs @@ -1,43 +1,42 @@ -using System; -using System.IO; +using System.IO; using System.Net; -using System.Web; using NUnit.Framework; -using ServiceStack.Common.Web; +using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class CustomRequestDataTests - { - /// <summary> - /// first-name=tom&item-0=blah&item-1-delete=1 - /// </summary> - [Test] - public void Can_parse_custom_form_data() - { - var webReq = (HttpWebRequest)WebRequest.Create(Config.ServiceStackBaseUri + "/customformdata?format=json"); - webReq.Method = HttpMethods.Post; - webReq.ContentType = ContentType.FormUrlEncoded; + [TestFixture] + public class CustomRequestDataTests + { + /// <summary> + /// first-name=tom&item-0=blah&item-1-delete=1 + /// </summary> + [Test] + public void Can_parse_custom_form_data() + { + var webReq = (HttpWebRequest)WebRequest.Create(Config.ServiceStackBaseUri + "/customformdata?format=json"); + webReq.Method = HttpMethods.Post; + webReq.ContentType = MimeTypes.FormUrlEncoded; - try - { - using (var sw = new StreamWriter(webReq.GetRequestStream())) - { - sw.Write("&first-name=tom&item-0=blah&item-1-delete=1"); - } - var response = new StreamReader(webReq.GetResponse().GetResponseStream()).ReadToEnd(); + try + { + using (var sw = new StreamWriter(webReq.GetRequestStream())) + { + sw.Write("&first-name=tom&item-0=blah&item-1-delete=1"); + } + var response = webReq.GetResponse().ReadToEnd(); - Assert.That(response, Is.EqualTo("{\"firstName\":\"tom\",\"item0\":\"blah\",\"item1Delete\":\"1\"}")); - } - catch (WebException webEx) - { - var errorWebResponse = ((HttpWebResponse)webEx.Response); - var errorResponse = new StreamReader(errorWebResponse.GetResponseStream()).ReadToEnd(); + Assert.That(response, Is.EqualTo("{\"firstName\":\"tom\",\"item0\":\"blah\",\"item1Delete\":\"1\"}")); + } + catch (WebException webEx) + { + var errorWebResponse = ((HttpWebResponse)webEx.Response); + var errorResponse = errorWebResponse.ReadToEnd(); - Assert.Fail(errorResponse); - } - } + Assert.Fail(errorResponse); + } + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomerServiceValidationTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomerServiceValidationTests.cs index 4bb299a43ec..2966f00c770 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomerServiceValidationTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/CustomerServiceValidationTests.cs @@ -2,118 +2,118 @@ using System.Linq; using System.Net; using NUnit.Framework; -using ServiceStack.Service; using ServiceStack.Text; -using ServiceStack.ServiceClient.Web; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class CustomerServiceValidationTests - { - private const string ListeningOn = Config.ServiceStackBaseUri; + [TestFixture] + public class CustomerServiceValidationTests + { + private const string ListeningOn = Config.ServiceStackBaseUri; - private string[] ExpectedPostErrorFields = new[] { - "Id", - "LastName", - "FirstName", - "Company", - "Address", - "Postcode", - }; + private string[] ExpectedPostErrorFields = new[] { + "Id", + "LastName", + "FirstName", + "Company", + "Address", + "Postcode", + }; - private string[] ExpectedPostErrorCodes = new[] { - "NotEqual", - "ShouldNotBeEmpty", - "NotEmpty", - "NotNull", - "Length", - "Predicate", - }; + private string[] ExpectedPostErrorCodes = new[] { + "NotEqual", + "ShouldNotBeEmpty", + "NotEmpty", + "NotNull", + "NotNull", //Length returns true if null + "Predicate", + }; - Customers validRequest; + Customers validRequest; - [SetUp] - public void SetUp() - { - validRequest = new Customers { - Id = 1, - FirstName = "FirstName", - LastName = "LastName", - Address = "12345 Address St, New York", - Company = "Company", - Discount = 10, - HasDiscount = true, - Postcode = "11215", - }; - } + [SetUp] + public void SetUp() + { + validRequest = new Customers + { + Id = 1, + FirstName = "FirstName", + LastName = "LastName", + Address = "12345 Address St, New York", + Company = "Company", + Discount = 10, + HasDiscount = true, + Postcode = "11215", + }; + } - public static IEnumerable ServiceClients - { - get - { - return new IServiceClient[] { - new JsonServiceClient(ListeningOn), - new JsvServiceClient(ListeningOn), - new XmlServiceClient(ListeningOn), - }; - } - } + public static IEnumerable ServiceClients + { + get + { + return new IServiceClient[] { + new JsonServiceClient(ListeningOn), + new JsvServiceClient(ListeningOn), + new XmlServiceClient(ListeningOn), + }; + } + } - [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] - public void Post_empty_request_throws_validation_exception(IServiceClient client) - { - try - { - var response = client.Send(new Customers()); - response.PrintDump(); - Assert.Fail("Should throw Validation Exception"); - } - catch (WebServiceException ex) - { - var response = (CustomersResponse)ex.ResponseDto; + [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] + public void Post_empty_request_throws_validation_exception(IServiceClient client) + { + try + { + var response = client.Send(new Customers()); + Assert.Fail("Should throw Validation Exception"); + } + catch (WebServiceException ex) + { + var response = (CustomersResponse)ex.ResponseDto; - var errorFields = response.ResponseStatus.Errors; - var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); - var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); + var errorFields = response.ResponseStatus.Errors; + var fieldNames = errorFields.Select(x => x.FieldName).ToArray(); + var fieldErrorCodes = errorFields.Select(x => x.ErrorCode).ToArray(); - Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); - Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); - Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); - Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); - } - } + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); + Assert.That(errorFields.Count, Is.EqualTo(ExpectedPostErrorFields.Length)); + Assert.That(fieldNames, Is.EquivalentTo(ExpectedPostErrorFields)); + Assert.That(fieldErrorCodes, Is.EquivalentTo(ExpectedPostErrorCodes)); + } + } - [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] - public void Get_empty_request_throws_validation_exception(IRestClient client) - { - try - { - var response = client.Get(new Customers()); - response.PrintDump(); - Assert.Fail("Should throw Validation Exception"); - } - catch (WebServiceException ex) - { - var response = (CustomersResponse)ex.ResponseDto; + [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] + public void Get_empty_request_throws_validation_exception(IRestClient client) + { + try + { + var response = client.Get(new Customers()); + Assert.Fail("Should throw Validation Exception"); + } + catch (WebServiceException ex) + { + var response = (CustomersResponse)ex.ResponseDto; - var errorFields = response.ResponseStatus.Errors; - Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); - Assert.That(errorFields.Count, Is.EqualTo(1)); - Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); - Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); - } - } + var errorFields = response.ResponseStatus.Errors; + Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); + //Assert.That(ex.StatusDescription, Is.EqualTo("NotEqual")); //BadRequest + Assert.That(response.ResponseStatus.Message, Is.EqualTo("'Id' must not be equal to '0'.")); + Assert.That(errorFields.Count, Is.EqualTo(1)); + Assert.That(errorFields[0].ErrorCode, Is.EqualTo("NotEqual")); + Assert.That(errorFields[0].FieldName, Is.EqualTo("Id")); + Assert.That(errorFields[0].Message, Is.EqualTo("'Id' must not be equal to '0'.")); + } + } - [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] - public void Post_ValidRequest_succeeds(IServiceClient client) - { - var response = client.Send(validRequest); - Assert.That(response.ResponseStatus, Is.Null); - } + [Test, TestCaseSource(typeof(CustomerServiceValidationTests), "ServiceClients")] + public void Post_ValidRequest_succeeds(IServiceClient client) + { + var response = client.Send(validRequest); + Assert.That(response.ResponseStatus, Is.Null); + } - } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ExceptionHandlingTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ExceptionHandlingTests.cs index 53b9d2b3729..4c6458ed256 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ExceptionHandlingTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ExceptionHandlingTests.cs @@ -1,12 +1,8 @@ using System; using System.Net; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Tests { @@ -17,7 +13,7 @@ public class UserResponse : IHasResponseStatus public ResponseStatus ResponseStatus { get; set; } } - public class UserService : ServiceInterface.Service + public class UserService : Service { public object Get(User request) { @@ -50,7 +46,7 @@ public class ExceptionWithResponseStatusResponse { public ResponseStatus ResponseStatus { get; set; } } - public class ExceptionWithResponseStatusService : ServiceInterface.Service + public class ExceptionWithResponseStatusService : Service { public object Any(ExceptionWithResponseStatus request) { @@ -60,7 +56,7 @@ public object Any(ExceptionWithResponseStatus request) public class ExceptionNoResponseStatus { } public class ExceptionNoResponseStatusResponse { } - public class ExceptionNoResponseStatusService : ServiceInterface.Service + public class ExceptionNoResponseStatusService : Service { public object Any(ExceptionNoResponseStatus request) { @@ -69,7 +65,7 @@ public object Any(ExceptionNoResponseStatus request) } public class ExceptionNoResponseDto { } - public class ExceptionNoResponseDtoService : ServiceInterface.Service + public class ExceptionNoResponseDtoService : Service { public object Any(ExceptionNoResponseDto request) { @@ -77,16 +73,54 @@ public object Any(ExceptionNoResponseDto request) } } + public class CustomHttpError + { + public int StatusCode { get; set; } + public string StatusDescription { get; set; } + } + public class CustomHttpErrorResponse + { + public string Custom { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + public class CustomHttpErrorService : Service + { + public object Any(CustomHttpError request) + { + throw new HttpError(request.StatusCode, request.StatusDescription); + } + } + + public class CustomFieldHttpError { } + public class CustomFieldHttpErrorResponse + { + public string Custom { get; set; } + public ResponseStatus ResponseStatus { get; set; } + } + public class CustomFieldHttpErrorService : Service + { + public object Any(CustomFieldHttpError request) + { + throw new HttpError(new CustomFieldHttpErrorResponse + { + Custom = "Ignored", + ResponseStatus = new ResponseStatus("StatusErrorCode", "StatusErrorMessage") + }, + 500, + "HeaderErrorCode"); + } + } + [TestFixture] public class ExceptionHandlingTests { private const string ListeningOn = Config.ServiceStackBaseUri + "/"; - protected static IRestClient[] ServiceClients = - { - new JsonServiceClient(ListeningOn), - new XmlServiceClient(ListeningOn), - new JsvServiceClient(ListeningOn) + protected static IRestClient[] ServiceClients = + { + new JsonServiceClient(ListeningOn), + new XmlServiceClient(ListeningOn), + new JsvServiceClient(ListeningOn) //SOAP not supported in HttpListener //new Soap11ServiceClient(ServiceClientBaseUri), //new Soap12ServiceClient(ServiceClientBaseUri) @@ -161,7 +195,7 @@ public void Handles_Normal_Exception(IRestClient client) public string PredefinedJsonUrl<T>() { - return ListeningOn + "json/syncreply/" + typeof(T).Name; + return ListeningOn + "json/reply/" + typeof(T).Name; } [Test] @@ -170,14 +204,13 @@ public void Returns_populated_dto_when_has_ResponseStatus() try { var json = PredefinedJsonUrl<ExceptionWithResponseStatus>().GetJsonFromUrl(); - json.PrintDump(); Assert.Fail("Should throw"); } catch (WebException webEx) { var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.StringStarting( + var body = errorResponse.GetResponseStream().ReadToEnd(); + Assert.That(body, Does.StartWith( "{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); //inc stacktrace } } @@ -188,13 +221,13 @@ public void Returns_empty_dto_when_NoResponseStatus() try { var json = PredefinedJsonUrl<ExceptionNoResponseStatus>().GetJsonFromUrl(); - json.PrintDump(); + json.PrintDump(); Assert.Fail("Should throw"); } catch (WebException webEx) { var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); + var body = errorResponse.GetResponseStream().ReadToEnd(); Assert.That(body, Is.EqualTo("{}")); } } @@ -205,14 +238,57 @@ public void Returns_no_body_when_NoResponseDto() try { var json = PredefinedJsonUrl<ExceptionNoResponseDto>().GetJsonFromUrl(); - json.PrintDump(); Assert.Fail("Should throw"); } catch (WebException webEx) { var errorResponse = ((HttpWebResponse)webEx.Response); - var body = errorResponse.GetResponseStream().ReadFully().FromUtf8Bytes(); - Assert.That(body, Is.StringStarting("{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); + var body = errorResponse.GetResponseStream().ReadToEnd(); + Assert.That(body, Does.StartWith("{\"responseStatus\":{\"errorCode\":\"CustomException\",\"message\":\"User Defined Error\"")); + } + } + + [Test] + public void Returns_custom_ResponseStatus_with_CustomFieldHttpError() + { + try + { + var json = PredefinedJsonUrl<CustomFieldHttpError>().GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (WebException webEx) + { + var errorResponse = ((HttpWebResponse)webEx.Response); + Assert.That((int)errorResponse.StatusCode, Is.EqualTo(500)); + //IIS doesn't allow overriding of StatusDescription + //Assert.That(errorResponse.StatusDescription, Is.EqualTo("HeaderErrorCode")); + + var body = errorResponse.GetResponseStream().ReadToEnd(); + var customResponse = body.FromJson<CustomFieldHttpErrorResponse>(); + var errorStatus = customResponse.ResponseStatus; + Assert.That(errorStatus.ErrorCode, Is.EqualTo("StatusErrorCode")); + Assert.That(errorStatus.Message, Is.EqualTo("StatusErrorMessage")); + Assert.That(customResponse.Custom, Is.Null); + } + } + + [Test] + public void Returns_custom_Status_and_Description_with_CustomHttpError() + { + try + { + var json = PredefinedJsonUrl<CustomHttpError>() + .AddQueryParam("StatusCode", 406) + .AddQueryParam("StatusDescription", "CustomDescription") + .GetJsonFromUrl(); + Assert.Fail("Should throw"); + } + catch (WebException webEx) + { + var errorResponse = ((HttpWebResponse)webEx.Response); + Assert.That((int)errorResponse.StatusCode, Is.EqualTo(406)); + //IIS doesn't allow overriding of StatusDescription + //Assert.That(errorResponse.StatusDescription, Is.EqualTo("CustomDescription")); } } } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/FileUploadTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/FileUploadTests.cs index be8ee96f4ad..2a53cbeb917 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/FileUploadTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/FileUploadTests.cs @@ -1,114 +1,160 @@ using System; -using System.Drawing; using System.IO; using System.Net; using NUnit.Framework; -using ServiceStack.Common.Utils; -using ServiceStack.Common.Web; using ServiceStack.Text; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class FileUploadTests - : RestsTestBase - { - public WebResponse UploadFile(string pathInfo, FileInfo fileInfo) - { - //long length = 0; - string boundary = "----------------------------" + - DateTime.Now.Ticks.ToString("x"); + [TestFixture] + public class FileUploadTests + : RestsTestBase + { + public WebResponse UploadFile(string pathInfo, FileInfo fileInfo) + { + //long length = 0; + string boundary = "----------------------------" + + DateTime.Now.Ticks.ToString("x"); - var httpWebRequest = (HttpWebRequest)WebRequest.Create(base.ServiceClientBaseUri + pathInfo); - httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary; - httpWebRequest.Accept = ContentType.Json; - httpWebRequest.Method = "POST"; - httpWebRequest.AllowAutoRedirect = false; - httpWebRequest.KeepAlive = false; + var httpWebRequest = (HttpWebRequest)WebRequest.Create(base.ServiceClientBaseUri + pathInfo); + httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary; + httpWebRequest.Accept = MimeTypes.Json; + httpWebRequest.Method = "POST"; + httpWebRequest.AllowAutoRedirect = false; + httpWebRequest.KeepAlive = false; - Stream memStream = new System.IO.MemoryStream(); + Stream memStream = new System.IO.MemoryStream(); - byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary); + byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary); - string headerTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n"; + string headerTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n"; - string header = string.Format(headerTemplate, "upload", fileInfo.Name, MimeTypes.GetMimeType(fileInfo.Name)); + string header = string.Format(headerTemplate, "upload", fileInfo.Name, MimeTypes.GetMimeType(fileInfo.Name)); - byte[] headerbytes = System.Text.Encoding.ASCII.GetBytes(header); + byte[] headerbytes = System.Text.Encoding.ASCII.GetBytes(header); - memStream.Write(headerbytes, 0, headerbytes.Length); + memStream.Write(headerbytes, 0, headerbytes.Length); - //Image img = null; - //img = Image.FromFile("C:/Documents and Settings/Dorin Cucicov/My Documents/My Pictures/Sunset.jpg", true); - //img.Save(memStream, System.Drawing.Imaging.ImageFormat.Jpeg); + //Image img = null; + //img = Image.FromFile("C:/Documents and Settings/Dorin Cucicov/My Documents/My Pictures/Sunset.jpg", true); + //img.Save(memStream, System.Drawing.Imaging.ImageFormat.Jpeg); - using (var fs = fileInfo.OpenRead()) - { - fs.WriteTo(memStream); - } + using (var fs = fileInfo.OpenRead()) + { + fs.WriteTo(memStream); + } - memStream.Write(boundarybytes, 0, boundarybytes.Length); + memStream.Write(boundarybytes, 0, boundarybytes.Length); - //string formdataTemplate = "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; + //string formdataTemplate = "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; - //string formitem = string.Format(formdataTemplate, "headline", "Sunset"); - //byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem); - //memStream.Write(formitembytes, 0, formitembytes.Length); + //string formitem = string.Format(formdataTemplate, "headline", "Sunset"); + //byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem); + //memStream.Write(formitembytes, 0, formitembytes.Length); - //memStream.Write(boundarybytes, 0, boundarybytes.Length); + //memStream.Write(boundarybytes, 0, boundarybytes.Length); - httpWebRequest.ContentLength = memStream.Length; + httpWebRequest.ContentLength = memStream.Length; - var requestStream = httpWebRequest.GetRequestStream(); + var requestStream = httpWebRequest.GetRequestStream(); - memStream.Position = 0; - var tempBuffer = new byte[memStream.Length]; - memStream.Read(tempBuffer, 0, tempBuffer.Length); - memStream.Close(); - requestStream.Write(tempBuffer, 0, tempBuffer.Length); - requestStream.Close(); + memStream.Position = 0; + var tempBuffer = new byte[memStream.Length]; + memStream.Read(tempBuffer, 0, tempBuffer.Length); + memStream.Close(); + requestStream.Write(tempBuffer, 0, tempBuffer.Length); + requestStream.Close(); - return httpWebRequest.GetResponse(); - } + return httpWebRequest.GetResponse(); + } - [Test] - public void Can_POST_upload_file() - { - var uploadForm = new FileInfo("~/TestExistingDir/upload.html".MapHostAbsolutePath()); - var webResponse = UploadFile("/fileuploads", uploadForm); + [Test] + public void Can_POST_upload_file() + { + var uploadForm = new FileInfo("~/TestExistingDir/upload.html".MapHostAbsolutePath()); + var webResponse = UploadFile("/fileuploads", uploadForm); - AssertResponse<FileUploadResponse>((HttpWebResponse)webResponse, r => - { - var expectedContents = new StreamReader(uploadForm.OpenRead()).ReadToEnd(); - Assert.That(r.FileName, Is.EqualTo(uploadForm.Name)); - Assert.That(r.ContentLength, Is.EqualTo(uploadForm.Length)); - Assert.That(r.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadForm.Name))); - Assert.That(r.Contents, Is.EqualTo(expectedContents)); - }); - } + AssertResponse<FileUploadResponse>((HttpWebResponse)webResponse, r => + { + var expectedContents = uploadForm.OpenRead().ReadToEnd(); + Assert.That(r.Name, Is.EqualTo("upload")); + Assert.That(r.FileName, Is.EqualTo(uploadForm.Name)); + Assert.That(r.ContentLength, Is.EqualTo(uploadForm.Length)); + Assert.That(r.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadForm.Name))); + Assert.That(r.Contents, Is.EqualTo(expectedContents)); + }); + } - [Test] - public void Can_GET_upload_file() - { - var uploadForm = new FileInfo("~/TestExistingDir/upload.html".MapHostAbsolutePath()); - var webRequest = (HttpWebRequest)WebRequest.Create(base.ServiceClientBaseUri + "/fileuploads/TestExistingDir/upload.html"); - var expectedContents = new StreamReader(uploadForm.OpenRead()).ReadToEnd(); + [Test] + public void Can_GET_upload_file() + { + var uploadForm = new FileInfo("~/TestExistingDir/upload.html".MapHostAbsolutePath()); + var webRequest = (HttpWebRequest)WebRequest.Create(base.ServiceClientBaseUri + "/fileuploads/TestExistingDir/upload.html"); + var expectedContents = uploadForm.OpenRead().ReadToEnd(); - var webResponse = webRequest.GetResponse(); - var actualContents = new StreamReader(webResponse.GetResponseStream()).ReadToEnd(); + var webResponse = webRequest.GetResponse(); + var actualContents = webResponse.ReadToEnd(); - Assert.That(webResponse.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadForm.Name))); - Assert.That(actualContents, Is.EqualTo(expectedContents)); - } + Assert.That(webResponse.ContentType, Is.EqualTo(MimeTypes.GetMimeType(uploadForm.Name))); + Assert.That(actualContents.NormalizeNewLines(), Is.EqualTo(expectedContents.NormalizeNewLines())); + } - } + [Test] + public void Can_POST_upload_file_using_ServiceClient_with_request() + { + IServiceClient client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapHostAbsolutePath()); + + var request = new FileUpload { CustomerId = 123, CustomerName = "Foo,Bar" }; + var response = client.PostFileWithRequest<FileUploadResponse>(Config.ServiceStackBaseUri + "/fileuploads", uploadFile, request); + + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(response.Name, Is.EqualTo("upload")); + Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); + Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + Assert.That(response.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(response.CustomerId, Is.EqualTo(123)); + } + + [Test] + public void Can_POST_upload_file_using_ServiceClient_with_request_and_QueryString() + { + IServiceClient client = new JsonServiceClient(Config.ServiceStackBaseUri); + + var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapHostAbsolutePath()); + + var request = new FileUpload(); + var response = client.PostFileWithRequest<FileUploadResponse>( + Config.ServiceStackBaseUri + "/fileuploads?CustomerId=123&CustomerName=Foo,Bar", + uploadFile, request); + + var expectedContents = uploadFile.OpenRead().ReadToEnd(); + Assert.That(response.Name, Is.EqualTo("upload")); + Assert.That(response.FileName, Is.EqualTo(uploadFile.Name)); + Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length)); + Assert.That(response.Contents, Is.EqualTo(expectedContents)); + Assert.That(response.CustomerName, Is.EqualTo("Foo,Bar")); + Assert.That(response.CustomerId, Is.EqualTo(123)); + } + } + + + public static class TestExtensions + { + public static string NormalizeNewLines(this string text) + { + return text.Replace("\r\n", "\n"); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/FilterTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/FilterTests.cs index 7026cdf2081..2c689867cf2 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/FilterTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/FilterTests.cs @@ -4,16 +4,16 @@ namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class FilterTests - { - [Test] - public void Can_call_service_returning_string() - { - var response = Config.ServiceStackBaseUri.CombineWith("hello2/world") - .GetJsonFromUrl(); + [TestFixture] + public class FilterTests + { + [Test] + public void Can_call_service_returning_string() + { + var response = Config.ServiceStackBaseUri.CombineWith("hello2/world") + .GetJsonFromUrl(); - Assert.That(response, Is.EqualTo("world")); - } - } + Assert.That(response, Is.EqualTo("world")); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldRawHttpPostTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldRawHttpPostTests.cs index 25552d28df4..6eb040299c1 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldRawHttpPostTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldRawHttpPostTests.cs @@ -5,49 +5,47 @@ namespace ServiceStack.WebHost.IntegrationTests.Tests { - public class HelloWorldRawHttpPostTests - { - [Test] - public void Post_JSON_to_HelloWorld() - { - var httpReq = (HttpWebRequest)WebRequest.Create(Config.ServiceStackBaseUri + "/hello"); - httpReq.Method = "POST"; - httpReq.ContentType = httpReq.Accept = "application/json"; + public class HelloWorldRawHttpPostTests + { + [Test] + public void Post_JSON_to_HelloWorld() + { + var httpReq = (HttpWebRequest)WebRequest.Create(Config.ServiceStackBaseUri + "/hello"); + httpReq.Method = "POST"; + httpReq.ContentType = httpReq.Accept = "application/json"; - using (var stream = httpReq.GetRequestStream()) - using (var sw = new StreamWriter(stream)) - { - sw.Write("{\"Name\":\"World!\"}"); - } + using (var stream = httpReq.GetRequestStream()) + using (var sw = new StreamWriter(stream)) + { + sw.Write("{\"Name\":\"World!\"}"); + } - using (var response = httpReq.GetResponse()) - using (var stream = response.GetResponseStream()) - using (var reader = new StreamReader(stream)) - { - Assert.That(reader.ReadToEnd(), Is.EqualTo("{\"result\":\"Hello, World!\"}")); - } - } + using (var response = httpReq.GetResponse()) + using (var stream = response.GetResponseStream()) + { + Assert.That(stream.ReadToEnd(), Is.EqualTo("{\"result\":\"Hello, World!\"}")); + } + } - [Test] - public void Post_XML_to_HelloWorld() - { - var httpReq = (HttpWebRequest)WebRequest.Create(Config.ServiceStackBaseUri + "/hello"); - httpReq.Method = "POST"; - httpReq.ContentType = httpReq.Accept = "application/xml"; + [Test] + public void Post_XML_to_HelloWorld() + { + var httpReq = (HttpWebRequest)WebRequest.Create(Config.ServiceStackBaseUri + "/hello"); + httpReq.Method = "POST"; + httpReq.ContentType = httpReq.Accept = "application/xml"; - using (var stream = httpReq.GetRequestStream()) - using (var sw = new StreamWriter(stream)) - { - sw.Write("<Hello xmlns=\"http://schemas.servicestack.net/types\"><Name>World!</Name></Hello>"); - } + using (var stream = httpReq.GetRequestStream()) + using (var sw = new StreamWriter(stream)) + { + sw.Write("<Hello xmlns=\"http://schemas.servicestack.net/types\"><Name>World!</Name></Hello>"); + } - using (var response = httpReq.GetResponse()) - using (var stream = response.GetResponseStream()) - using (var reader = new StreamReader(stream)) - { - Assert.That(reader.ReadToEnd(), Is.EqualTo("<HelloResponse xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.servicestack.net/types\"><Result>Hello, World!</Result></HelloResponse>")); - } - } - } + using (var response = httpReq.GetResponse()) + using (var stream = response.GetResponseStream()) + { + Assert.That(stream.ReadToEnd(), Is.EqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?><HelloResponse xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.servicestack.net/types\"><Result>Hello, World!</Result></HelloResponse>")); + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldServiceClientTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldServiceClientTests.cs index b29075acb66..b2f5eb0bfcd 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldServiceClientTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/HelloWorldServiceClientTests.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections; -using System.Threading; +using System.Collections; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests @@ -16,12 +13,12 @@ public static IEnumerable ServiceClients get { return new IServiceClient[] { - new JsonServiceClient(Config.ServiceStackBaseUri), - new JsvServiceClient(Config.ServiceStackBaseUri), - new XmlServiceClient(Config.ServiceStackBaseUri), - new Soap11ServiceClient(Config.ServiceStackBaseUri), - new Soap12ServiceClient(Config.ServiceStackBaseUri) - }; + new JsonServiceClient(Config.ServiceStackBaseUri), + new JsvServiceClient(Config.ServiceStackBaseUri), + new XmlServiceClient(Config.ServiceStackBaseUri), + new Soap11ServiceClient(Config.ServiceStackBaseUri), + new Soap12ServiceClient(Config.ServiceStackBaseUri) + }; } } @@ -30,10 +27,10 @@ public static IEnumerable RestClients get { return new IRestClient[] { - new JsonServiceClient(Config.ServiceStackBaseUri), - new JsvServiceClient(Config.ServiceStackBaseUri), - new XmlServiceClient(Config.ServiceStackBaseUri), - }; + new JsonServiceClient(Config.ServiceStackBaseUri), + new JsvServiceClient(Config.ServiceStackBaseUri), + new XmlServiceClient(Config.ServiceStackBaseUri), + }; } } @@ -46,13 +43,9 @@ public void Sync_Call_HelloWorld_with_Sync_ServiceClients_on_PreDefined_Routes(I } [Test, TestCaseSource("RestClients")] - public void Async_Call_HelloWorld_with_ServiceClients_on_PreDefined_Routes(IServiceClient client) + public async Task Async_Call_HelloWorld_with_ServiceClients_on_PreDefined_Routes(IServiceClient client) { - HelloResponse response = null; - client.SendAsync<HelloResponse>(new Hello { Name = "World!" }, - r => response = r, (r, e) => Assert.Fail("NetworkError")); - - Thread.Sleep(TimeSpan.FromSeconds(1)); + var response = await client.SendAsync<HelloResponse>(new Hello { Name = "World!" }); Assert.That(response.Result, Is.EqualTo("Hello, World!")); } @@ -66,15 +59,9 @@ public void Sync_Call_HelloWorld_with_RestClients_on_UserDefined_Routes(IRestCli } [Test, TestCaseSource("RestClients")] - public void Async_Call_HelloWorld_with_Async_ServiceClients_on_UserDefined_Routes(IServiceClient client) + public async Task Async_Call_HelloWorld_with_Async_ServiceClients_on_UserDefined_Routes(IServiceClient client) { - HelloResponse response = null; - client.GetAsync<HelloResponse>("/hello/World!", - r => response = r, (r, e) => Assert.Fail("NetworkError")); - - var i = 0; - while (response == null && i++ < 5) - Thread.Sleep(TimeSpan.FromSeconds(1)); + var response = await client.GetAsync<HelloResponse>("/hello/World!"); Assert.That(response.Result, Is.EqualTo("Hello, World!")); } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/LoadTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/LoadTests.cs new file mode 100644 index 00000000000..e6e1a5b28a9 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/LoadTests.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NUnit.Framework; +using ServiceStack.Text; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [Ignore("Load Test"), TestFixture] + public class LoadTests + { + string BaseUrl = "http://localhost:50000/api/"; + private int BytesSize = 333930; + + [Test] + public void Can_download_sync_pdf() + { + var client = new ImagingService(BaseUrl); + + var pdfBytes = client.GetBytes("/sample.pdf"); + + "PDF Size: {0} bytes".Print(pdfBytes.Length); + + Assert.That(pdfBytes.Length, Is.EqualTo(BytesSize)); + } + + [Test] + public async Task Can_download_async_pdf() + { + var client = new ImagingService(BaseUrl); + + var pdfBytes = await client.GetBytesAsync("/sample.pdf"); + + "PDF Size: {0} bytes".Print(pdfBytes.Length); + + Assert.That(pdfBytes.Length, Is.EqualTo(BytesSize)); + } + + [Test] + public async Task Load_test_download_async_pdf() + { + const int NoOfTimes = 1000; + + var client = new ImagingService(BaseUrl); + + var fetchTasks = new List<Task>(); + + for (var i = 0; i < NoOfTimes; i++) + { + var asyncResponse = client.GetBytesAsync("/sample.pdf") + .ContinueWith(task => + { + var pdfBytes = task.Result; + "PDF Size: {0} bytes".Print(pdfBytes.Length); + Assert.That(pdfBytes.Length, Is.EqualTo(BytesSize)); + }); + + fetchTasks.Add(asyncResponse); + } + + await Task.WhenAll(fetchTasks); + } + } + + public class ImagingService : JsonServiceClient + { + public ImagingService(string url) + : base(url) + { + //Headers.Add("X-ApiKey", "blah "); //This does not work on Async methods, but is should. + RequestFilter += (request) => + { + request.Headers.Add("X-ApiKey", "BLAH"); + }; + } + + public byte[] GetBytes(string relativePath) + { + return Get<byte[]>(relativePath); + } + + public async Task<byte[]> GetBytesAsync(string relativePath) + { + return await GetAsync<byte[]>(relativePath); + } + } + + public class ImagingServiceWithHighTimeout : ImagingService + { + public ImagingServiceWithHighTimeout(string url) + : base(url) + { + Timeout = new TimeSpan(0, 3, 0); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ManageRolesTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ManageRolesTests.cs deleted file mode 100644 index f55c8941e67..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ManageRolesTests.cs +++ /dev/null @@ -1,253 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using NUnit.Framework; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.Text; -using ServiceStack.WebHost.IntegrationTests.Services; - -namespace ServiceStack.WebHost.IntegrationTests.Tests -{ - [TestFixture] - public class ManageRolesTests : AuthTestsBase - { - protected Registration registration; - - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - registration = CreateAdminUser(); - } - - public string RoleName1 = "Role1"; - public string RoleName2 = "Role2"; - public const string ContentManager = "ContentManager"; - public const string ContentPermission = "ContentPermission"; - - public string Permission1 = "Permission1"; - public string Permission2 = "Permission2"; - - public Registration RegisterNewUser(bool? autoLogin = null) - { - var userId = Environment.TickCount % 10000; - - var newUserRegistration = new Registration { - UserName = "UserName" + userId, - DisplayName = "DisplayName" + userId, - Email = "user{0}@sf.com".Fmt(userId), - FirstName = "FirstName" + userId, - LastName = "LastName" + userId, - Password = "Password" + userId, - AutoLogin = autoLogin, - }; - - ServiceClient.Send(newUserRegistration); - - return newUserRegistration; - } - - - [Test] - public void Cannot_assign_roles_with_normal_user() - { - var newUser = RegisterNewUser(autoLogin: true); - - try - { - var response = ServiceClient.Send( - new AssignRoles { - UserName = newUser.UserName, - Roles = { RoleName1, RoleName2 }, - Permissions = { Permission1, Permission2 } - }); - - response.PrintDump(); - Assert.Fail("Should not be allowed"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); - } - } - - [Test] - public void Can_Assign_Roles_and_Permissions_to_new_User() - { - var newUser = RegisterNewUser(); - - var client = AuthenticateWithAdminUser(); - - var response = client.Send( - new AssignRoles { - UserName = newUser.UserName, - Roles = { RoleName1, RoleName2 }, - Permissions = { Permission1, Permission2 } - }); - - Console.WriteLine("Assigned Roles: " + response.Dump()); - - Assert.That(response.AllRoles, Is.EquivalentTo(new[] { RoleName1, RoleName2 })); - Assert.That(response.AllPermissions, Is.EquivalentTo(new[] { Permission1, Permission2 })); - } - - [Test] - public void Can_UnAssign_Roles_and_Permissions_to_new_User() - { - var newUser = RegisterNewUser(); - - var client = AuthenticateWithAdminUser(); - - client.Send( - new AssignRoles { - UserName = newUser.UserName, - Roles = new List<string> { RoleName1, RoleName2 }, - Permissions = new List<string> { Permission1, Permission2 } - }); - - var response = client.Send( - new UnAssignRoles { - UserName = newUser.UserName, - Roles = { RoleName1 }, - Permissions = { Permission2 }, - }); - - Console.WriteLine("Remaining Roles: " + response.Dump()); - - Assert.That(response.AllRoles, Is.EquivalentTo(new[] { RoleName2 })); - Assert.That(response.AllPermissions, Is.EquivalentTo(new[] { Permission1 })); - } - - [Test] - public void Can_only_access_ContentManagerOnlyService_service_after_Assigned_Role() - { - var newUser = RegisterNewUser(autoLogin: true); - - try - { - ServiceClient.Send(new ContentManagerOnly()); - Assert.Fail("Should not be allowed - no roles"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); - } - - var client = AuthenticateWithAdminUser(); - - client.Send( - new AssignRoles { - UserName = newUser.UserName, - Roles = new List<string> { RoleName1 }, - }); - - var newUserClient = Login(newUser.UserName, newUser.Password); - - try - { - newUserClient.Send(new ContentManagerOnly()); - Assert.Fail("Should not be allowed - wrong roles"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Role")); - } - - var assignResponse = client.Send( - new AssignRoles { - UserName = newUser.UserName, - Roles = new List<string> { ContentManager }, - }); - - Assert.That(assignResponse.AllRoles, Is.EquivalentTo(new[] { RoleName1, ContentManager })); - - var response = newUserClient.Send(new ContentManagerOnly()); - - Assert.That(response.Result, Is.EqualTo("Haz Access")); - } - - [Test] - public void Can_only_access_ContentPermissionOnlyService_service_after_Assigned_Permission() - { - var newUser = RegisterNewUser(autoLogin: true); - - try - { - ServiceClient.Send(new ContentPermissionOnly()); - Assert.Fail("Should not be allowed - no permissions"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Permissions")); - } - - var client = AuthenticateWithAdminUser(); - - client.Send( - new AssignRoles { - UserName = newUser.UserName, - Permissions = new List<string> { RoleName1 }, - }); - - var newUserClient = Login(newUser.UserName, newUser.Password); - - try - { - newUserClient.Send(new ContentPermissionOnly()); - Assert.Fail("Should not be allowed - wrong permissions"); - } - catch (WebServiceException webEx) - { - Assert.That(webEx.StatusCode, Is.EqualTo((int)HttpStatusCode.Forbidden)); - //StatusDescription is ignored in WebDevServer - //Assert.That(webEx.StatusDescription, Is.EqualTo("Invalid Permissions")); - } - - var assignResponse = client.Send( - new AssignRoles { - UserName = newUser.UserName, - Permissions = new List<string> { ContentPermission }, - }); - - Assert.That(assignResponse.AllPermissions, Is.EquivalentTo(new[] { RoleName1, ContentPermission })); - - var response = newUserClient.Send(new ContentPermissionOnly()); - - Assert.That(response.Result, Is.EqualTo("Haz Access")); - } - - [Test] - public void Cannot_access_Admin_service_by_default() - { - try - { - BaseUri.AppendPath("requestlogs").GetStringFromUrl(); - - Assert.Fail("Should not allow access to protected resource"); - } - catch (Exception ex) - { - if (ex.IsUnauthorized()) - return; - - throw; - } - } - - [Test] - public void Can_access_Admin_service_with_AuthSecret() - { - BaseUri.AppendPath("requestlogs").AddQueryParam("authsecret", AuthSecret).GetStringFromUrl(); - } - - } -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/MovieServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/MovieServiceTests.cs index 5f4806d8565..6e3288d8fe6 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/MovieServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/MovieServiceTests.cs @@ -1,117 +1,116 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common.Web; +using ServiceStack.Data; using ServiceStack.OrmLite; -using ServiceStack.OrmLite.Sqlite; -using ServiceStack.ServiceClient.Web; using ServiceStack.Text; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class MovieServiceTests - : RestsTestBase - { - public Movie NewMovie = new Movie { - ImdbId = "tt0111161", - Title = "The Shawshank Redemption", - Rating = 9.2m, - Director = "Frank Darabont", - ReleaseDate = new DateTime(1995, 2, 17), - TagLine = "Fear can hold you prisoner. Hope can set you free.", - Genres = new List<string> { "Crime", "Drama" }, - }; - - IDbConnectionFactory DbFactory { get; set; } - - [SetUp] - public override void OnBeforeEachTest() - { - base.OnBeforeEachTest(); - - this.Container.Register<IDbConnectionFactory>(c => - new OrmLiteConnectionFactory( - ":memory:", false, - SqliteOrmLiteDialectProvider.Instance)); - - this.DbFactory = this.Container.Resolve<IDbConnectionFactory>(); - this.DbFactory.Run(db => db.CreateTable<Movie>(true)); - } - - [Test] - public void Can_PATCH_Movie_from_dto() - { - ExecutePath(HttpMethods.Post, "/movies", null, null, NewMovie); - - var lastInsertId = (int)this.DbFactory.Run(db => db.GetLastInsertId()); - - var patchMovie = new Movie { Id = lastInsertId, Title = "PATCHED " + NewMovie.Title }; - ExecutePath(HttpMethods.Patch, "/movies", null, null, patchMovie); - - this.DbFactory.Run(db => { - var movie = db.GetById<Movie>(lastInsertId); - Assert.That(movie, Is.Not.Null); - Assert.That(movie.Title, Is.EqualTo(patchMovie.Title)); - }); - } - - [Test] - public void Can_create_new_Movie_from_FormData() - { - var formData = NewMovie.ToStringDictionary(); - - var response = ExecutePath(HttpMethods.Post, "/movies", null, formData, null); - response.PrintDump(); - this.DbFactory.Run(db => { - var lastInsertId = db.GetLastInsertId(); - var createdMovie = db.GetById<Movie>(lastInsertId); - Assert.That(createdMovie, Is.Not.Null); - Assert.That(createdMovie, Is.EqualTo(NewMovie)); - }); - } - - [Test] - public void Can_create_new_Movie_from_dto() - { - var response = ExecutePath(HttpMethods.Post, "/movies", null, null, NewMovie); - response.PrintDump(); - this.DbFactory.Run(db => { - var lastInsertId = db.GetLastInsertId(); - var createdMovie = db.GetById<Movie>(lastInsertId); - Assert.That(createdMovie, Is.Not.Null); - Assert.That(createdMovie, Is.EqualTo(NewMovie)); - }); - } - - [Test] - public void Can_POST_to_resetmovies() - { - var response = ExecutePath(HttpMethods.Post, "/reset-movies"); - response.PrintDump(); - this.DbFactory.Run(db => { - var movies = db.Select<Movie>(); - Assert.That(movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); - }); - } - - [Test] - public void Error_calling_GET_on_resetmovies() - { - try - { - var response = (ResetMoviesResponse)ExecutePath(HttpMethods.Get, "/reset-movies"); - response.PrintDump(); - Assert.Fail("Should throw HTTP errors"); - } - catch (WebServiceException webEx) - { - var response = (ResetMoviesResponse)webEx.ResponseDto; - Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(typeof(NotImplementedException).Name)); - } - } - - } + [TestFixture] + public class MovieServiceTests + : RestsTestBase + { + public Movie NewMovie = new Movie + { + ImdbId = "tt0111161", + Title = "The Shawshank Redemption", + Rating = 9.2m, + Director = "Frank Darabont", + ReleaseDate = new DateTime(1995, 2, 17), + TagLine = "Fear can hold you prisoner. Hope can set you free.", + Genres = new List<string> { "Crime", "Drama" }, + }; + + IDbConnectionFactory DbFactory { get; set; } + + [SetUp] + public override void OnBeforeEachTest() + { + base.OnBeforeEachTest(); + + this.Container.Register<IDbConnectionFactory>(c => + new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); + + this.DbFactory = this.Container.Resolve<IDbConnectionFactory>(); + + using (var db = DbFactory.Open()) + db.DropAndCreateTable<Movie>(); + } + + [Test] + public void Can_PATCH_Movie_from_dto() + { + ExecutePath(HttpMethods.Post, "/movies", null, null, NewMovie); + + using (var db = DbFactory.Open()) + { + var lastInsertId = (int)db.LastInsertId(); + + var patchMovie = new Movie { Id = lastInsertId, Title = "PATCHED " + NewMovie.Title }; + ExecutePath(HttpMethods.Patch, "/movies", null, null, patchMovie); + + var movie = db.SingleById<Movie>(lastInsertId); + Assert.That(movie, Is.Not.Null); + Assert.That(movie.Title, Is.EqualTo(patchMovie.Title)); + } + } + + [Test] + public void Can_create_new_Movie_from_FormData() + { + var formData = NewMovie.ToStringDictionary(); + + var response = ExecutePath(HttpMethods.Post, "/movies", null, formData, null); + using (var db = DbFactory.Open()) + { + var lastInsertId = db.LastInsertId(); + var createdMovie = db.SingleById<Movie>(lastInsertId); + Assert.That(createdMovie, Is.Not.Null); + Assert.That(createdMovie, Is.EqualTo(NewMovie)); + }; + } + + [Test] + public void Can_create_new_Movie_from_dto() + { + var response = ExecutePath(HttpMethods.Post, "/movies", null, null, NewMovie); + using (var db = DbFactory.Open()) + { + var lastInsertId = db.LastInsertId(); + var createdMovie = db.SingleById<Movie>(lastInsertId); + Assert.That(createdMovie, Is.Not.Null); + Assert.That(createdMovie, Is.EqualTo(NewMovie)); + }; + } + + [Test] + public void Can_POST_to_resetmovies() + { + var response = ExecutePath(HttpMethods.Post, "/reset-movies"); + using (var db = DbFactory.Open()) + { + var movies = db.Select<Movie>(); + Assert.That(movies.Count, Is.EqualTo(ResetMoviesService.Top5Movies.Count)); + }; + } + + [Test] + public void Error_calling_GET_on_resetmovies() + { + try + { + var response = (ResetMoviesResponse)ExecutePath(HttpMethods.Get, "/reset-movies"); + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + var response = (ResetMoviesResponse)webEx.ResponseDto; + Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(typeof(NotImplementedException).Name)); + } + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ProtoBufServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ProtoBufServiceTests.cs index 34d04420b23..853a6f91636 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ProtoBufServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ProtoBufServiceTests.cs @@ -1,109 +1,139 @@ using System; using System.Runtime.Serialization; using System.Text; +using System.Threading.Tasks; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Plugins.ProtoBuf; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.ServiceModel; +using ServiceStack.ProtoBuf; using ServiceStack.Text; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [DataContract] - public class ProtoBufEmail - { - [DataMember(Order = 1)] - public string ToAddress { get; set; } - [DataMember(Order = 2)] - public string FromAddress { get; set; } - [DataMember(Order = 3)] - public string Subject { get; set; } - [DataMember(Order = 4)] - public string Body { get; set; } - [DataMember(Order = 5)] - public byte[] AttachmentData { get; set; } - - public bool Equals(ProtoBufEmail other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Equals(other.ToAddress, ToAddress) - && Equals(other.FromAddress, FromAddress) - && Equals(other.Subject, Subject) - && Equals(other.Body, Body) - && other.AttachmentData.EquivalentTo(AttachmentData); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (ProtoBufEmail)) return false; - return Equals((ProtoBufEmail) obj); - } - - public override int GetHashCode() - { - unchecked - { - int result = (ToAddress != null ? ToAddress.GetHashCode() : 0); - result = (result*397) ^ (FromAddress != null ? FromAddress.GetHashCode() : 0); - result = (result*397) ^ (Subject != null ? Subject.GetHashCode() : 0); - result = (result*397) ^ (Body != null ? Body.GetHashCode() : 0); - result = (result*397) ^ (AttachmentData != null ? AttachmentData.GetHashCode() : 0); - return result; - } - } - } - - [DataContract] - public class ProtoBufEmailResponse - { - [DataMember(Order = 1)] - public ResponseStatus ResponseStatus { get; set; } - } - - public class ProtoBufEmailService : ServiceInterface.Service - { + [DataContract] + public class ProtoBufEmail + { + [DataMember(Order = 1)] + public string ToAddress { get; set; } + [DataMember(Order = 2)] + public string FromAddress { get; set; } + [DataMember(Order = 3)] + public string Subject { get; set; } + [DataMember(Order = 4)] + public string Body { get; set; } + [DataMember(Order = 5)] + public byte[] AttachmentData { get; set; } + + public bool Equals(ProtoBufEmail other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(other.ToAddress, ToAddress) + && Equals(other.FromAddress, FromAddress) + && Equals(other.Subject, Subject) + && Equals(other.Body, Body) + && other.AttachmentData.EquivalentTo(AttachmentData); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof(ProtoBufEmail)) return false; + return Equals((ProtoBufEmail)obj); + } + + public override int GetHashCode() + { + unchecked + { + int result = (ToAddress != null ? ToAddress.GetHashCode() : 0); + result = (result * 397) ^ (FromAddress != null ? FromAddress.GetHashCode() : 0); + result = (result * 397) ^ (Subject != null ? Subject.GetHashCode() : 0); + result = (result * 397) ^ (Body != null ? Body.GetHashCode() : 0); + result = (result * 397) ^ (AttachmentData != null ? AttachmentData.GetHashCode() : 0); + return result; + } + } + } + + [DataContract] + public class ProtoBufEmailResponse + { + [DataMember(Order = 1)] + public ResponseStatus ResponseStatus { get; set; } + } + + public class ProtoBufEmailService : Service + { public object Any(ProtoBufEmail request) - { - return request; - } - } - - - [TestFixture] - public class ProtoBufServiceTests - { - [Test] - public void Can_Send_ProtoBuf_request() - { - var client = new ProtoBufServiceClient(Config.ServiceStackBaseUri); - - var request = new ProtoBufEmail { - ToAddress = "to@email.com", - FromAddress = "from@email.com", - Subject = "Subject", - Body = "Body", - AttachmentData = Encoding.UTF8.GetBytes("AttachmentData"), - }; - - try - { - var response = client.Send<ProtoBufEmail>(request); - - Console.WriteLine(response.Dump()); - - Assert.That(response.Equals(request)); - } - catch (WebServiceException webEx) - { - Console.WriteLine(webEx.ResponseDto.Dump()); - Assert.Fail(webEx.Message); - } - } - - } + { + return request; + } + } + + + [TestFixture] + public class ProtoBufServiceTests + { + private const string ListeningOn = Config.ServiceStackBaseUri; + + private static ProtoBufEmail CreateProtoBufEmail() + { + var request = new ProtoBufEmail + { + ToAddress = "to@email.com", + FromAddress = "from@email.com", + Subject = "Subject", + Body = "Body", + AttachmentData = Encoding.UTF8.GetBytes("AttachmentData"), + }; + return request; + } + + [Test] + public void Can_Send_ProtoBuf_request() + { + var client = new ProtoBufServiceClient(ListeningOn) + { + RequestFilter = req => + Assert.That(req.Accept, Is.EqualTo(MimeTypes.ProtoBuf)) + }; + + var request = CreateProtoBufEmail(); + var response = client.Send<ProtoBufEmail>(request); + + response.PrintDump(); + Assert.That(response.Equals(request)); + } + + [Test] + public async Task Can_Send_ProtoBuf_request_Async() + { + var client = new ProtoBufServiceClient(ListeningOn) + { + RequestFilter = req => + Assert.That(req.Accept, Is.EqualTo(MimeTypes.ProtoBuf)) + }; + + var request = CreateProtoBufEmail(); + var response = await client.SendAsync<ProtoBufEmail>(request); + + response.PrintDump(); + Assert.That(response.Equals(request)); + } + + [Test] + public void Does_return_ProtoBuf_when_using_ProtoBuf_Content_Type_and_Wildcard() + { + var bytes = ListeningOn.CombineWith("x-protobuf/reply/ProtoBufEmail") + .PostBytesToUrl(accept: "{0}, */*".Fmt(MimeTypes.ProtoBuf), + requestBody: CreateProtoBufEmail().ToProtoBuf(), + responseFilter: res => Assert.That(res.ContentType, Is.EqualTo(MimeTypes.ProtoBuf))); + + Assert.That(bytes.Length, Is.GreaterThan(0)); + + bytes = ListeningOn.CombineWith("x-protobuf/reply/ProtoBufEmail") + .GetBytesFromUrl(accept: "{0}, */*".Fmt(MimeTypes.ProtoBuf), + responseFilter: res => Assert.That(res.ContentType, Is.EqualTo(MimeTypes.ProtoBuf))); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RawRequestTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RawRequestTests.cs index d735d228348..d1d20d610ab 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RawRequestTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RawRequestTests.cs @@ -1,59 +1,123 @@ -using System; -using System.IO; -using System.Net; +using System.IO; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; using ServiceStack.Text; -using ServiceStack.WebHost.IntegrationTests.Services; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [Route("/rawrequest")] - public class RawRequest : IRequiresRequestStream - { - public Stream RequestStream { get; set; } - } - - public class RawRequestResponse - { - public string Result { get; set; } - } - - public class RawRequestService : IService<RawRequest> - { - public object Execute(RawRequest request) - { - var rawRequest = request.RequestStream.ToUtf8String(); - return new RawRequestResponse { Result = rawRequest }; - } - } - - [TestFixture] - public class RawRequestTests - { - [Test] - public void Can_POST_raw_request() - { - var rawData = "<<(( 'RAW_DATA' ))>>"; - var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; - var json = requestUrl.PutStringToUrl(rawData, contentType: ContentType.PlainText, acceptContentType: ContentType.Json); - var response = json.FromJson<RawRequestResponse>(); - Assert.That(response.Result, Is.EqualTo(rawData)); - } - - [Test] - public void Can_PUT_raw_request() - { - var rawData = "<<(( 'RAW_DATA' ))>>"; - var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; - var json = requestUrl.PutStringToUrl(rawData, contentType: ContentType.PlainText, acceptContentType: ContentType.Json); - var response = json.FromJson<RawRequestResponse>(); - Assert.That(response.Result, Is.EqualTo(rawData)); - } - - } + [Route("/rawrequest")] + public class RawRequest : IRequiresRequestStream + { + public Stream RequestStream { get; set; } + } + + [Route("/rawrequest/{Path}")] + public class RawRequestWithParam : IRequiresRequestStream + { + public string Path { get; set; } + public string Param { get; set; } + public Stream RequestStream { get; set; } + } + + public class RawRequestResponse + { + public string Result { get; set; } + } + + [Restrict(RequestAttributes.Xml)] + [Route("/Leads/LeadData/", "POST", Notes = "LMS - DirectApi")] + public class CustomXml : IRequiresRequestStream + { + public Stream RequestStream { get; set; } + } + + public class RawRequestService : IService + { + public object Any(RawRequest request) + { + var rawRequest = request.RequestStream.ToUtf8String(); + return new RawRequestResponse { Result = rawRequest }; + } + + public object Any(RawRequestWithParam request) + { + var rawRequest = request.RequestStream.ToUtf8String(); + return new RawRequestResponse { Result = request.Path + ":" + request.Param + ":" + rawRequest }; + } + + public object Any(CustomXml request) + { + var xml = request.RequestStream.ReadToEnd(); + return xml; + } + } + + [TestFixture] + public class RawRequestTests + { + [Test] + public void Can_POST_raw_request() + { + var rawData = "<<(( 'RAW_DATA' ))>>"; + var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; + var json = requestUrl.PostStringToUrl(rawData, contentType: MimeTypes.PlainText, accept: MimeTypes.Json); + var response = json.FromJson<RawRequestResponse>(); + Assert.That(response.Result, Is.EqualTo(rawData)); + } + + [Test] + public void Can_POST_raw_request_to_predefined_route() + { + var rawData = "{\"raw\":\"json\"}"; + var requestUrl = Config.ServiceStackBaseUri + "/json/reply/RawRequest"; + var json = requestUrl.PostJsonToUrl(rawData); + var response = json.FromJson<RawRequestResponse>(); + Assert.That(response.Result, Is.EqualTo(rawData)); + } + + [Test] + public void Can_POST_raw_request_with_params() + { + var rawData = "<<(( 'RAW_DATA' ))>>"; + var requestUrl = Config.ServiceStackBaseUri + "/rawrequest/Foo?Param=Bar"; + var json = requestUrl.PostStringToUrl(rawData, contentType: MimeTypes.PlainText, accept: MimeTypes.Json); + var response = json.FromJson<RawRequestResponse>(); + var expected = "{0}:{1}:{2}".Fmt("Foo", "Bar", rawData); + Assert.That(response.Result, Is.EqualTo(expected)); + } + + [Test] + public void Can_PUT_raw_request() + { + var rawData = "<<(( 'RAW_DATA' ))>>"; + var requestUrl = Config.ServiceStackBaseUri + "/rawrequest"; + var json = requestUrl.PutStringToUrl(rawData, contentType: MimeTypes.PlainText, accept: MimeTypes.Json); + var response = json.FromJson<RawRequestResponse>(); + Assert.That(response.Result, Is.EqualTo(rawData)); + } + + [Test] + public void Can_POST_Custom_XML() + { + var xml = @"<LeadApplications> + <LeadApplication> + <Email>daffy.duck@example.com</Email> + <FirstName>Joey</FirstName> + <MiddleName>Disney</MiddleName> + <LastName>Duck</LastName> + <Street1>1 Disneyland Street</Street1> + <Street2>2 Disneyland Street</Street2> + <City>PAUMA VALLEY</City> + <State>CA</State> + <Zip>92503</Zip> + </LeadApplication> + </LeadApplications>"; + + var requestUrl = Config.ServiceStackBaseUri + "/Leads/LeadData/"; + var responseXml = requestUrl.PostXmlToUrl(xml); + + Assert.That(responseXml, Is.EqualTo(xml)); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/ReqtestsTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ReqtestsTests.cs new file mode 100644 index 00000000000..ba49bb9a124 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/ReqtestsTests.cs @@ -0,0 +1,45 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using NUnit.Framework; +using ServiceStack.Host.Handlers; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [Route("/reqtests")] + [Route("/reqtests/{PathInfoParam}")] + public class Reqtests : IReturn<Reqtests> + { + public string PathInfo { get; set; } + public string QueryString { get; set; } + } + + public class ReqtestsService : Service + { + public Reqtests Any(Reqtests request) + { + return request; + } + + public RequestInfoResponse Any(RequestInfo request) + { + var requestInfo = RequestInfoHandler.GetRequestInfo(base.Request); + return requestInfo; + } + } + + [TestFixture] + public class ReqtestsTests + { + [Test] + public void AspNet_doesnt_transparently_decode_QueryStrings() + { + var client = new JsonServiceClient(Config.ServiceStackBaseUri); + var request = new Reqtests { QueryString = "pathseperator%2Ftest" }; + var response = client.Get(request); + Assert.That(response.QueryString, Is.EqualTo(request.QueryString)); + } + } + +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestAndPathResolutionTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestAndPathResolutionTests.cs index 7e0b62349dd..a41207220f1 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestAndPathResolutionTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestAndPathResolutionTests.cs @@ -1,60 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Web; using NUnit.Framework; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Common.Tests; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class RequestAndPathResolutionTests - : TestBase - { - public RequestAndPathResolutionTests() - : base(Config.ServiceStackBaseUri, typeof(ReverseService).Assembly) - { - } - - protected override void Configure(Funq.Container container) { } + [TestFixture] + public class RequestAndPathResolutionTests + : TestBase + { + public RequestAndPathResolutionTests() + : base(Config.ServiceStackBaseUri, typeof(ReverseService).Assembly) + { + } - [SetUp] - public void OnBeforeTest() - { - base.OnBeforeEachTest(); - RegisterConfig(); - } + protected override void Configure(Funq.Container container) { } - private void RegisterConfig() + [SetUp] + public void OnBeforeTest() { - EndpointHost.CatchAllHandlers.Add(new PredefinedRoutesFeature().ProcessRequest); - EndpointHost.CatchAllHandlers.Add(new MetadataFeature().ProcessRequest); + base.OnBeforeEachTest(); } - [Test] - public void Can_process_default_request() - { - var request = (EchoRequest)ExecutePath("/Xml/SyncReply/EchoRequest"); - Assert.That(request, Is.Not.Null); - } + [Test] + public void Can_process_default_request() + { + var request = (EchoRequest)ExecutePath("/Xml/reply/EchoRequest"); + Assert.That(request, Is.Not.Null); + } - [Test] - public void Can_process_default_case_insensitive_request() - { - var request = (EchoRequest)ExecutePath("/xml/syncreply/echorequest"); - Assert.That(request, Is.Not.Null); - } + [Test] + public void Can_process_default_case_insensitive_request() + { + var request = (EchoRequest)ExecutePath("/xml/reply/echorequest"); + Assert.That(request, Is.Not.Null); + } - [Test] - public void Can_process_default_request_with_queryString() - { - var request = (EchoRequest)ExecutePath("/Xml/SyncReply/EchoRequest?Id=1&String=Value"); - Assert.That(request, Is.Not.Null); - Assert.That(request.Id, Is.EqualTo(1)); - Assert.That(request.String, Is.EqualTo("Value")); - } - } + [Test] + public void Can_process_default_request_with_queryString() + { + var request = (EchoRequest)ExecutePath("/Xml/reply/EchoRequest?Id=1&String=Value"); + Assert.That(request, Is.Not.Null); + Assert.That(request.Id, Is.EqualTo(1)); + Assert.That(request.String, Is.EqualTo("Value")); + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestFilterTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestFilterTests.cs index b7d0fa61402..f186e570d63 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestFilterTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestFilterTests.cs @@ -1,76 +1,76 @@ using System.Net; using NUnit.Framework; -using ServiceStack.Common.Web; using ServiceStack.Text; +using ServiceStack.Web; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class RequestFilterTests - { - private const string ServiceClientBaseUri = Config.ServiceStackBaseUri; + [TestFixture] + public class RequestFilterTests + { + private const string ServiceClientBaseUri = Config.ServiceStackBaseUri; - [Test] - public void Does_return_bare_401_StatusCode() - { - try - { - var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri - + "/json/syncreply/RequestFilter?StatusCode=401"); + [Test] + public void Does_return_bare_401_StatusCode() + { + try + { + var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + + "/json/reply/RequestFilter?StatusCode=401"); - var webResponse = (HttpWebResponse)webRequest.GetResponse(); - webResponse.Method.Print(); - Assert.Fail("Should throw 401 WebException"); - } - catch (WebException ex) - { + var webResponse = (HttpWebResponse)webRequest.GetResponse(); + webResponse.Method.Print(); + Assert.Fail("Should throw 401 WebException"); + } + catch (WebException ex) + { var httpResponse = (HttpWebResponse)ex.Response; Assert.That(httpResponse.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); - } - } + } + } - [Test] - public void Does_return_bare_401_with_AuthRequired_header() - { - try - { - var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri - + "/json/syncreply/RequestFilter?StatusCode=401" - + "&HeaderName=" + HttpHeaders.WwwAuthenticate - + "&HeaderValue=" + "Basic realm=\"Auth Required\"".UrlEncode()); + [Test] + public void Does_return_bare_401_with_AuthRequired_header() + { + try + { + var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + + "/json/reply/RequestFilter?StatusCode=401" + + "&HeaderName=" + HttpHeaders.WwwAuthenticate + + "&HeaderValue=" + "Basic realm=\"Auth Required\"".UrlEncode()); - var webResponse = (HttpWebResponse)webRequest.GetResponse(); - webResponse.Method.Print(); - Assert.Fail("Should throw 401 WebException"); - } - catch (WebException ex) - { + var webResponse = (HttpWebResponse)webRequest.GetResponse(); + webResponse.Method.Print(); + Assert.Fail("Should throw 401 WebException"); + } + catch (WebException ex) + { var httpResponse = (HttpWebResponse)ex.Response; Assert.That(httpResponse.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); - Assert.That(ex.Response.Headers[HttpHeaders.WwwAuthenticate], - Is.EqualTo("Basic realm=\"Auth Required\"")); - } - } + Assert.That(ex.Response.Headers[HttpHeaders.WwwAuthenticate], + Is.EqualTo("Basic realm=\"Auth Required\"")); + } + } - [Test] - public void Does_return_send_401_for_access_to_ISecure_requests() - { - try - { - var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri - + "/json/syncreply/Secure?SessionId=175BEA29-DC79-4555-BD42-C4DD5D57A004"); + [Test] + public void Does_return_send_401_for_access_to_ISecure_requests() + { + try + { + var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + + "/json/reply/Secure?SessionId=175BEA29-DC79-4555-BD42-C4DD5D57A004"); - var webResponse = (HttpWebResponse)webRequest.GetResponse(); - webResponse.Method.Print(); - Assert.Fail("Should throw 401 WebException"); - } - catch (WebException ex) - { + var webResponse = (HttpWebResponse)webRequest.GetResponse(); + webResponse.Method.Print(); + Assert.Fail("Should throw 401 WebException"); + } + catch (WebException ex) + { var httpResponse = (HttpWebResponse)ex.Response; Assert.That(httpResponse.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); - } - } - } + } + } + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestInfoTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestInfoTests.cs new file mode 100644 index 00000000000..cfcf106e757 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RequestInfoTests.cs @@ -0,0 +1,93 @@ +using System.Net; +using NUnit.Framework; +using ServiceStack.Host.Handlers; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + public class RequestInfoServices : Service {} + + public partial class RequestInfoTests + { + public string BaseUrl = Config.ServiceStackBaseUri; + + private RequestInfoResponse GetRequestInfoForPath(string path) + { + var url = BaseUrl.CombineWith(path).AddQueryParam("debug", "requestinfo"); + var json = url.GetJsonFromUrl(); + var info = json.FromJson<RequestInfoResponse>(); + return info; + } + + private void AssertHasContent(string pathInfo, string accept, string containsContent) + { + var url = BaseUrl.CombineWith(pathInfo); + var content = url.GetStringFromUrl(accept: accept); + Assert.That(content, Does.Contain(containsContent)); + } + + [Test] + public void Does_return_expected_content() + { + AssertHasContent("metadata", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("metadata/", MimeTypes.Html, "The following operations are supported"); + AssertHasContent("dir", MimeTypes.Html, "<h1>dir/index.html</h1>"); + AssertHasContent("dir/", MimeTypes.Html, "<h1>dir/index.html</h1>"); + AssertHasContent("dir/sub", MimeTypes.Html, "<h1>dir/sub/index.html</h1>"); + AssertHasContent("dir/sub/", MimeTypes.Html, "<h1>dir/sub/index.html</h1>"); + AssertHasContent("swagger-ui", MimeTypes.Html, "<title>Swagger UI</title>"); + AssertHasContent("swagger-ui/", MimeTypes.Html, "<title>Swagger UI</title>"); + } + + [Test] + public void Does_have_correct_path_info() + { + Assert.That(GetRequestInfoForPath("dir/").PathInfo, Is.EqualTo("/dir/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("dir/sub/").PathInfo, Is.EqualTo("/dir/sub/")); + Assert.That(GetRequestInfoForPath("swagger-ui/").PathInfo, Is.EqualTo("/swagger-ui/")); + } + } + + public partial class RequestInfoTests + { + private void DoesRedirectToRemoveTrailingSlash(string dirWIthoutSlash) + { + BaseUrl.CombineWith(dirWIthoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWIthoutSlash + "/"))); + }); + } + + private void DoesRedirectToAddTrailingSlash(string dirWithoutSlash) + { + BaseUrl.CombineWith(dirWithoutSlash) + .GetStringFromUrl(accept: MimeTypes.Html, + requestFilter: req => req.AllowAutoRedirect = false, + responseFilter: res => + { + Assert.That(res.StatusCode, Is.EqualTo(HttpStatusCode.Redirect)); + Assert.That(res.Headers[HttpHeaders.Location], + Is.EqualTo(BaseUrl.CombineWith(dirWithoutSlash.TrimEnd('/')))); + }); + } + + [Test] + public void Does_redirect_dirs_without_trailing_slash() + { + DoesRedirectToRemoveTrailingSlash("dir"); + DoesRedirectToRemoveTrailingSlash("dir/sub"); + DoesRedirectToRemoveTrailingSlash("swagger-ui"); + } + + [Test] + public void Does_redirect_metadata_page_to_without_slash() + { + DoesRedirectToAddTrailingSlash("metadata/"); + } + } + } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestPathResolutionUnitTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestPathResolutionUnitTests.cs index 71ee96fd3f9..2273837ec0a 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestPathResolutionUnitTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestPathResolutionUnitTests.cs @@ -1,50 +1,49 @@ -using Funq; using NUnit.Framework; -using ServiceStack.Common.Web; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Common.Tests; +using ServiceStack.Web; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class RestPathResolutionUnitTests - : TestBase - { - public RestPathResolutionUnitTests() - : base(Config.ServiceStackBaseUri, typeof(ReverseService).Assembly) - { - } - - protected override void Configure(Funq.Container container) - { - - } - - [SetUp] - public void OnBeforeTest() - { - base.OnBeforeEachTest(); - } - - [Test] - public void Can_execute_EchoRequest_rest_path() - { - var request = (EchoRequest)GetRequest("/echo/1/One"); - Assert.That(request, Is.Not.Null); - Assert.That(request.Id, Is.EqualTo(1)); - Assert.That(request.String, Is.EqualTo("One")); - } - - [Test] - public void Can_call_EchoRequest_with_QueryString() - { - var request = (EchoRequest)GetRequest("/echo/1/One?Long=2&Bool=True"); - - Assert.That(request.Id, Is.EqualTo(1)); - Assert.That(request.String, Is.EqualTo("One")); - Assert.That(request.Long, Is.EqualTo(2)); - Assert.That(request.Bool, Is.EqualTo(true)); - } + [TestFixture] + public class RestPathResolutionUnitTests + : TestBase + { + public RestPathResolutionUnitTests() + : base(Config.ServiceStackBaseUri, typeof(ReverseService).Assembly) + { + } + + protected override void Configure(Funq.Container container) + { + + } + + [SetUp] + public void OnBeforeTest() + { + base.OnBeforeEachTest(); + } + + [Test] + public void Can_execute_EchoRequest_rest_path() + { + var request = (EchoRequest)GetRequest("/echo/1/One"); + Assert.That(request, Is.Not.Null); + Assert.That(request.Id, Is.EqualTo(1)); + Assert.That(request.String, Is.EqualTo("One")); + } + + [Test] + public void Can_call_EchoRequest_with_QueryString() + { + var request = (EchoRequest)GetRequest("/echo/1/One?Long=2&Bool=True"); + + Assert.That(request.Id, Is.EqualTo(1)); + Assert.That(request.String, Is.EqualTo("One")); + Assert.That(request.Long, Is.EqualTo(2)); + Assert.That(request.Bool, Is.EqualTo(true)); + } [Test] public void Can_get_empty_BasicWildcard() @@ -69,75 +68,75 @@ public void Can_call_WildCardRequest_with_alternate_matching_WildCard_defined() Assert.That(request.RemainingPath, Is.Null); } - [Test] - public void Can_call_WildCardRequest_WildCard_mapping() - { - var request = (WildCardRequest)GetRequest("/wildcard/1/remaining/path/to/here"); - Assert.That(request.Id, Is.EqualTo(1)); - Assert.That(request.Path, Is.Null); - Assert.That(request.Action, Is.Null); - Assert.That(request.RemainingPath, Is.EqualTo("remaining/path/to/here")); - } - - [Test] - public void Can_call_WildCardRequest_WildCard_mapping_with_QueryString() - { - var request = (WildCardRequest)GetRequest("/wildcard/1/remaining/path/to/here?Action=edit"); - Assert.That(request.Id, Is.EqualTo(1)); - Assert.That(request.Path, Is.Null); - Assert.That(request.Action, Is.EqualTo("edit")); - Assert.That(request.RemainingPath, Is.EqualTo("remaining/path/to/here")); - } - - [Test] - public void Can_call_GET_on_VerbMatch_Services() - { - var request = (VerbMatch1)GetRequest(HttpMethods.Get, "/verbmatch"); - Assert.That(request.Name, Is.Null); - - var request2 = (VerbMatch1)GetRequest(HttpMethods.Get, "/verbmatch/arg"); - Assert.That(request2.Name, Is.EqualTo("arg")); - } - - [Test] - public void Can_call_POST_on_VerbMatch_Services() - { - var request = (VerbMatch2)GetRequest(HttpMethods.Post, "/verbmatch"); - Assert.That(request.Name, Is.Null); - - var request2 = (VerbMatch2)GetRequest(HttpMethods.Post, "/verbmatch/arg"); - Assert.That(request2.Name, Is.EqualTo("arg")); - } - - [Test] - public void Can_call_DELETE_on_VerbMatch_Services() - { - var request = (VerbMatch1)GetRequest(HttpMethods.Delete, "/verbmatch"); - Assert.That(request.Name, Is.Null); - - var request2 = (VerbMatch1)GetRequest(HttpMethods.Delete, "/verbmatch/arg"); - Assert.That(request2.Name, Is.EqualTo("arg")); - } - - [Test] - public void Can_call_PUT_on_VerbMatch_Services() - { - var request = (VerbMatch2)GetRequest(HttpMethods.Put, "/verbmatch"); - Assert.That(request.Name, Is.Null); - - var request2 = (VerbMatch2)GetRequest(HttpMethods.Put, "/verbmatch/arg"); - Assert.That(request2.Name, Is.EqualTo("arg")); - } - - [Test] - public void Can_call_PATCH_on_VerbMatch_Services() - { - var request = (VerbMatch2)GetRequest(HttpMethods.Patch, "/verbmatch"); - Assert.That(request.Name, Is.Null); - - var request2 = (VerbMatch2)GetRequest(HttpMethods.Patch, "/verbmatch/arg"); - Assert.That(request2.Name, Is.EqualTo("arg")); - } - - } + [Test] + public void Can_call_WildCardRequest_WildCard_mapping() + { + var request = (WildCardRequest)GetRequest("/wildcard/1/remaining/path/to/here"); + Assert.That(request.Id, Is.EqualTo(1)); + Assert.That(request.Path, Is.Null); + Assert.That(request.Action, Is.Null); + Assert.That(request.RemainingPath, Is.EqualTo("remaining/path/to/here")); + } + + [Test] + public void Can_call_WildCardRequest_WildCard_mapping_with_QueryString() + { + var request = (WildCardRequest)GetRequest("/wildcard/1/remaining/path/to/here?Action=edit"); + Assert.That(request.Id, Is.EqualTo(1)); + Assert.That(request.Path, Is.Null); + Assert.That(request.Action, Is.EqualTo("edit")); + Assert.That(request.RemainingPath, Is.EqualTo("remaining/path/to/here")); + } + + [Test] + public void Can_call_GET_on_VerbMatch_Services() + { + var request = (VerbMatch1)GetRequest(HttpMethods.Get, "/verbmatch"); + Assert.That(request.Name, Is.Null); + + var request2 = (VerbMatch1)GetRequest(HttpMethods.Get, "/verbmatch/arg"); + Assert.That(request2.Name, Is.EqualTo("arg")); + } + + [Test] + public void Can_call_POST_on_VerbMatch_Services() + { + var request = (VerbMatch2)GetRequest(HttpMethods.Post, "/verbmatch"); + Assert.That(request.Name, Is.Null); + + var request2 = (VerbMatch2)GetRequest(HttpMethods.Post, "/verbmatch/arg"); + Assert.That(request2.Name, Is.EqualTo("arg")); + } + + [Test] + public void Can_call_DELETE_on_VerbMatch_Services() + { + var request = (VerbMatch1)GetRequest(HttpMethods.Delete, "/verbmatch"); + Assert.That(request.Name, Is.Null); + + var request2 = (VerbMatch1)GetRequest(HttpMethods.Delete, "/verbmatch/arg"); + Assert.That(request2.Name, Is.EqualTo("arg")); + } + + [Test] + public void Can_call_PUT_on_VerbMatch_Services() + { + var request = (VerbMatch2)GetRequest(HttpMethods.Put, "/verbmatch"); + Assert.That(request.Name, Is.Null); + + var request2 = (VerbMatch2)GetRequest(HttpMethods.Put, "/verbmatch/arg"); + Assert.That(request2.Name, Is.EqualTo("arg")); + } + + [Test] + public void Can_call_PATCH_on_VerbMatch_Services() + { + var request = (VerbMatch2)GetRequest(HttpMethods.Patch, "/verbmatch"); + Assert.That(request.Name, Is.Null); + + var request2 = (VerbMatch2)GetRequest(HttpMethods.Patch, "/verbmatch/arg"); + Assert.That(request2.Name, Is.EqualTo("arg")); + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestWebServiceTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestWebServiceTests.cs index fb49eabe055..b3e56ff3346 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestWebServiceTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestWebServiceTests.cs @@ -3,198 +3,199 @@ using System.Net; using System.Text; using NUnit.Framework; -using ServiceStack.Common.Web; +using ServiceStack.Text; +using ServiceStack.Web; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class RestWebServiceTests - : RestsTestBase - { - - [Test] - public void Can_call_EchoRequest_with_AcceptAll() - { - var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", "*/*"); - var contents = GetContents(response); - - Assert.That(contents, Is.Not.Null); - Assert.That(contents.Contains("\"id\":1")); - Assert.That(contents.Contains("\"string\":\"One\"")); - } - - [Test] - public void Can_call_EchoRequest_with_AcceptJson() - { - var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", ContentType.Json); - AssertResponse<EchoRequest>(response, ContentType.Json, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.String, Is.EqualTo("One")); - }); - } - - [Test] - public void Can_call_EchoRequest_with_AcceptXml() - { - var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", ContentType.Xml); - AssertResponse<EchoRequest>(response, ContentType.Xml, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.String, Is.EqualTo("One")); - }); - } - - [Test] - public void Can_call_EchoRequest_with_AcceptJsv() - { - var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", ContentType.Jsv); - AssertResponse<EchoRequest>(response, ContentType.Jsv, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.String, Is.EqualTo("One")); - }); - } - - [Test] - public void Can_call_EchoRequest_with_QueryString() - { - var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One?Long=2&Bool=True", ContentType.Json); - AssertResponse<EchoRequest>(response, ContentType.Json, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.String, Is.EqualTo("One")); - Assert.That(x.Long, Is.EqualTo(2)); - Assert.That(x.Bool, Is.EqualTo(true)); - }); - } - - private HttpWebResponse EmulateHttpMethod(string emulateMethod, string useMethod) - { - var webRequest = (HttpWebRequest) WebRequest.Create(ServiceClientBaseUri + "/echomethod"); - webRequest.Accept = ContentType.Json; - webRequest.Method = useMethod; - webRequest.Headers[HttpHeaders.XHttpMethodOverride] = emulateMethod; - if (useMethod == HttpMethods.Post) - webRequest.ContentLength = 0; - var response = (HttpWebResponse) webRequest.GetResponse(); - return response; - } - - [Test] - public void Can_emulate_Put_HttpMethod_with_POST() - { - var response = EmulateHttpMethod(HttpMethods.Put, HttpMethods.Post); - - AssertResponse<EchoMethodResponse>(response, ContentType.Json, x => - Assert.That(x.Result, Is.EqualTo(HttpMethods.Put))); - } - - [Test] - public void Can_emulate_Put_HttpMethod_with_GET() - { - var response = EmulateHttpMethod(HttpMethods.Put, HttpMethods.Get); - - AssertResponse<EchoMethodResponse>(response, ContentType.Json, x => - Assert.That(x.Result, Is.EqualTo(HttpMethods.Put))); - } - - [Test] - public void Can_emulate_Delete_HttpMethod_with_GET() - { - var response = EmulateHttpMethod(HttpMethods.Delete, HttpMethods.Get); - - AssertResponse<EchoMethodResponse>(response, ContentType.Json, x => - Assert.That(x.Result, Is.EqualTo(HttpMethods.Delete))); - } - - [Test] - public void Can_call_WildCardRequest_with_alternate_WildCard_defined() - { - var response = GetWebResponse(ServiceClientBaseUri + "/wildcard/1/aPath/edit", ContentType.Json); - AssertResponse<WildCardRequest>(response, ContentType.Json, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.Path, Is.EqualTo("aPath")); - Assert.That(x.Action, Is.EqualTo("edit")); - Assert.That(x.RemainingPath, Is.Null); - }); - } - - [Test] - public void Can_call_WildCardRequest_WildCard_mapping() - { - var response = GetWebResponse(ServiceClientBaseUri + "/wildcard/1/remaining/path/to/here", ContentType.Json); - AssertResponse<WildCardRequest>(response, ContentType.Json, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.Path, Is.Null); - Assert.That(x.Action, Is.Null); - Assert.That(x.RemainingPath, Is.EqualTo("remaining/path/to/here")); - }); - } - - [Test] - public void Can_call_WildCardRequest_WildCard_mapping_with_QueryString() - { - var response = GetWebResponse(ServiceClientBaseUri + "/wildcard/1/remaining/path/to/here?Action=edit", ContentType.Json); - AssertResponse<WildCardRequest>(response, ContentType.Json, x => - { - Assert.That(x.Id, Is.EqualTo(1)); - Assert.That(x.Path, Is.Null); - Assert.That(x.Action, Is.EqualTo("edit")); - Assert.That(x.RemainingPath, Is.EqualTo("remaining/path/to/here")); - }); - } - - [Test(Description = "Test for error processing empty XML request")] - public void Can_call_ResetMovies_mapping_with_empty_Xml_post() - { - var response = GetWebResponse(HttpMethods.Post, ServiceClientBaseUri + "/reset-movies", ContentType.Xml, 0); - AssertResponse<ResetMoviesResponse>(response, ContentType.Xml, x => - { - }); - } - - [Test] - public void Can_POST_new_movie_with_FormData() - { - const string formData = "Id=0&ImdbId=tt0110912&Title=Pulp+Fiction&Rating=8.9&Director=Quentin+Tarantino&ReleaseDate=1994-11-24&TagLine=Girls+like+me+don't+make+invitations+like+this+to+just+anyone!&Genres=Crime%2CDrama%2CThriller"; - var formDataBytes = Encoding.UTF8.GetBytes(formData); - var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "/movies"); - webRequest.Accept = ContentType.Json; - webRequest.ContentType = ContentType.FormUrlEncoded; - webRequest.Method = HttpMethods.Post; - webRequest.ContentLength = formDataBytes.Length; - webRequest.GetRequestStream().Write(formDataBytes, 0, formDataBytes.Length); - - try - { - var response = (HttpWebResponse)webRequest.GetResponse(); - - AssertResponse<MovieResponse>(response, ContentType.Json, x => - { - Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Created)); - Assert.That(response.Headers["Location"], Is.EqualTo(ServiceClientBaseUri + "/movies/" + x.Movie.Id)); - }); - } - catch (WebException webEx) - { - if (webEx.Status == WebExceptionStatus.ProtocolError) - { - var errorResponse = ((HttpWebResponse)webEx.Response); - Console.WriteLine("Error: " + webEx); - Console.WriteLine("Status Code : {0}", errorResponse.StatusCode); - Console.WriteLine("Status Description : {0}", errorResponse.StatusDescription); - - Console.WriteLine("Body:" + new StreamReader(errorResponse.GetResponseStream()).ReadToEnd()); - } - - throw; - } - } - - } + [TestFixture] + public class RestWebServiceTests + : RestsTestBase + { + + [Test] + public void Can_call_EchoRequest_with_AcceptAll() + { + var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", "*/*"); + var contents = GetContents(response); + + Assert.That(contents, Is.Not.Null); + Assert.That(contents.Contains("\"id\":1")); + Assert.That(contents.Contains("\"string\":\"One\"")); + } + + [Test] + public void Can_call_EchoRequest_with_AcceptJson() + { + var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", MimeTypes.Json); + AssertResponse<EchoRequest>(response, MimeTypes.Json, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.String, Is.EqualTo("One")); + }); + } + + [Test] + public void Can_call_EchoRequest_with_AcceptXml() + { + var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", MimeTypes.Xml); + AssertResponse<EchoRequest>(response, MimeTypes.Xml, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.String, Is.EqualTo("One")); + }); + } + + [Test] + public void Can_call_EchoRequest_with_AcceptJsv() + { + var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One", MimeTypes.Jsv); + AssertResponse<EchoRequest>(response, MimeTypes.Jsv, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.String, Is.EqualTo("One")); + }); + } + + [Test] + public void Can_call_EchoRequest_with_QueryString() + { + var response = GetWebResponse(ServiceClientBaseUri + "/echo/1/One?Long=2&Bool=True", MimeTypes.Json); + AssertResponse<EchoRequest>(response, MimeTypes.Json, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.String, Is.EqualTo("One")); + Assert.That(x.Long, Is.EqualTo(2)); + Assert.That(x.Bool, Is.EqualTo(true)); + }); + } + + private HttpWebResponse EmulateHttpMethod(string emulateMethod, string useMethod) + { + var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "/echomethod"); + webRequest.Accept = MimeTypes.Json; + webRequest.Method = useMethod; + webRequest.Headers[HttpHeaders.XHttpMethodOverride] = emulateMethod; + if (useMethod == HttpMethods.Post) + webRequest.ContentLength = 0; + var response = (HttpWebResponse)webRequest.GetResponse(); + return response; + } + + [Test] + public void Can_emulate_Put_HttpMethod_with_POST() + { + var response = EmulateHttpMethod(HttpMethods.Put, HttpMethods.Post); + + AssertResponse<EchoMethodResponse>(response, MimeTypes.Json, x => + Assert.That(x.Result, Is.EqualTo(HttpMethods.Put))); + } + + [Test] + public void Can_emulate_Put_HttpMethod_with_GET() + { + var response = EmulateHttpMethod(HttpMethods.Put, HttpMethods.Get); + + AssertResponse<EchoMethodResponse>(response, MimeTypes.Json, x => + Assert.That(x.Result, Is.EqualTo(HttpMethods.Put))); + } + + [Test] + public void Can_emulate_Delete_HttpMethod_with_GET() + { + var response = EmulateHttpMethod(HttpMethods.Delete, HttpMethods.Get); + + AssertResponse<EchoMethodResponse>(response, MimeTypes.Json, x => + Assert.That(x.Result, Is.EqualTo(HttpMethods.Delete))); + } + + [Test] + public void Can_call_WildCardRequest_with_alternate_WildCard_defined() + { + var response = GetWebResponse(ServiceClientBaseUri + "/wildcard/1/aPath/edit", MimeTypes.Json); + AssertResponse<WildCardRequest>(response, MimeTypes.Json, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.Path, Is.EqualTo("aPath")); + Assert.That(x.Action, Is.EqualTo("edit")); + Assert.That(x.RemainingPath, Is.Null); + }); + } + + [Test] + public void Can_call_WildCardRequest_WildCard_mapping() + { + var response = GetWebResponse(ServiceClientBaseUri + "/wildcard/1/remaining/path/to/here", MimeTypes.Json); + AssertResponse<WildCardRequest>(response, MimeTypes.Json, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.Path, Is.Null); + Assert.That(x.Action, Is.Null); + Assert.That(x.RemainingPath, Is.EqualTo("remaining/path/to/here")); + }); + } + + [Test] + public void Can_call_WildCardRequest_WildCard_mapping_with_QueryString() + { + var response = GetWebResponse(ServiceClientBaseUri + "/wildcard/1/remaining/path/to/here?Action=edit", MimeTypes.Json); + AssertResponse<WildCardRequest>(response, MimeTypes.Json, x => + { + Assert.That(x.Id, Is.EqualTo(1)); + Assert.That(x.Path, Is.Null); + Assert.That(x.Action, Is.EqualTo("edit")); + Assert.That(x.RemainingPath, Is.EqualTo("remaining/path/to/here")); + }); + } + + [Test(Description = "Test for error processing empty XML request")] + public void Can_call_ResetMovies_mapping_with_empty_Xml_post() + { + var response = GetWebResponse(HttpMethods.Post, ServiceClientBaseUri + "/reset-movies", MimeTypes.Xml, 0); + AssertResponse<ResetMoviesResponse>(response, MimeTypes.Xml, x => + { + }); + } + + [Test] + public void Can_POST_new_movie_with_FormData() + { + const string formData = "Id=0&ImdbId=tt0110912&Title=Pulp+Fiction&Rating=8.9&Director=Quentin+Tarantino&ReleaseDate=1994-11-24&TagLine=Girls+like+me+don't+make+invitations+like+this+to+just+anyone!&Genres=Crime%2CDrama%2CThriller"; + var formDataBytes = Encoding.UTF8.GetBytes(formData); + var webRequest = (HttpWebRequest)WebRequest.Create(ServiceClientBaseUri + "/movies"); + webRequest.Accept = MimeTypes.Json; + webRequest.ContentType = MimeTypes.FormUrlEncoded; + webRequest.Method = HttpMethods.Post; + webRequest.ContentLength = formDataBytes.Length; + webRequest.GetRequestStream().Write(formDataBytes, 0, formDataBytes.Length); + + try + { + var response = (HttpWebResponse)webRequest.GetResponse(); + + AssertResponse<MovieResponse>(response, MimeTypes.Json, x => + { + Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Created)); + Assert.That(response.Headers["Location"], Is.EqualTo(ServiceClientBaseUri + "/movies/" + x.Movie.Id)); + }); + } + catch (WebException webEx) + { + if (webEx.Status == WebExceptionStatus.ProtocolError) + { + var errorResponse = ((HttpWebResponse)webEx.Response); + Console.WriteLine("Error: " + webEx); + Console.WriteLine("Status Code : {0}", errorResponse.StatusCode); + Console.WriteLine("Status Description : {0}", errorResponse.StatusDescription); + + Console.WriteLine("Body:" + errorResponse.GetResponseStream().ReadToEnd()); + } + + throw; + } + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestsTestBase.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestsTestBase.cs index 2a94c62b3da..16dca0dc814 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestsTestBase.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RestsTestBase.cs @@ -2,181 +2,180 @@ using System.IO; using System.Net; using NUnit.Framework; -using ServiceStack.Common.Web; +using ServiceStack.Common.Tests; +using ServiceStack.Host; using ServiceStack.Logging; -using ServiceStack.ServiceInterface.ServiceModel; -using ServiceStack.ServiceInterface.Testing; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; +using ServiceStack.Web; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - public class RestsTestBase - : TestBase - { - private static readonly ILog Log = LogManager.GetLogger(typeof (RestsTestBase)); - - readonly EndpointHostConfig defaultConfig = new EndpointHostConfig(); - - public RestsTestBase() - : base(Config.ServiceStackBaseUri, typeof(HelloService).Assembly) - //: base("http://localhost:4000", typeof(HelloService).Assembly) //Uncomment to test on dev web server - { - } - - protected override void Configure(Funq.Container container) { } - - public HttpWebResponse GetWebResponse(string uri, string acceptContentTypes) - { - var webRequest = (HttpWebRequest)WebRequest.Create(uri); - webRequest.Accept = acceptContentTypes; - return (HttpWebResponse)webRequest.GetResponse(); - } - - public static HttpWebResponse GetWebResponse(string httpMethod, string uri, string contentType, int contentLength) - { - var webRequest = (HttpWebRequest)WebRequest.Create(uri); - webRequest.Accept = contentType; - webRequest.ContentType = contentType; - webRequest.Method = HttpMethods.Post; - webRequest.ContentLength = contentLength; - return (HttpWebResponse)webRequest.GetResponse(); - } - - public static string GetContents(WebResponse webResponse) - { - using (var stream = webResponse.GetResponseStream()) - { - var contents = new StreamReader(stream).ReadToEnd(); - return contents; - } - } - - public T DeserializeContents<T>(WebResponse webResponse) - { - var contentType = webResponse.ContentType ?? defaultConfig.DefaultContentType; - return DeserializeContents<T>(webResponse, contentType); - } - - private static T DeserializeContents<T>(WebResponse webResponse, string contentType) - { - try - { - var contents = GetContents(webResponse); - var result = DeserializeResult<T>(webResponse, contents, contentType); - return result; - } - catch (WebException webEx) - { - if (webEx.Status == WebExceptionStatus.ProtocolError) - { - var errorResponse = ((HttpWebResponse)webEx.Response); - Log.Error(webEx); - Log.DebugFormat("Status Code : {0}", errorResponse.StatusCode); - Log.DebugFormat("Status Description : {0}", errorResponse.StatusDescription); - - try - { - using (var stream = errorResponse.GetResponseStream()) - { - var response = HttpResponseFilter.Instance.DeserializeFromStream(contentType, typeof(T), stream); - return (T)response; - } - } - catch (WebException) - { - // Oh, well, we tried - throw; - } - } - - throw; - } - } - - public void AssertResponse(HttpWebResponse response, string contentType) - { - var statusCode = (int)response.StatusCode; - Assert.That(statusCode, Is.LessThan(400)); - Assert.That(response.ContentType.StartsWith(contentType)); - } - - public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode, Func<T, ResponseStatus> responseStatusFn) - { - Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); - var response = DeserializeContents<T>(webResponse); - Assert.That(responseStatusFn(response).ErrorCode, Is.Not.Null); - } - - public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode, Func<T, ResponseStatus> responseStatusFn, string errorCode) - { - Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); - var response = DeserializeContents<T>(webResponse); - Assert.That(responseStatusFn(response).ErrorCode, Is.EqualTo(errorCode)); - } - - public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode) - where T : IHasResponseStatus - { - Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); - var response = DeserializeContents<T>(webResponse); - Assert.That(response.ResponseStatus.ErrorCode, Is.Not.Null); - } - - public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode, string errorCode) - where T : IHasResponseStatus - { - Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); - var response = DeserializeContents<T>(webResponse); - Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(errorCode)); - } - - public void AssertResponse<T>(HttpWebResponse response, Action<T> customAssert) - { - var contentType = response.ContentType ?? defaultConfig.DefaultContentType; - - AssertResponse(response, contentType); - - var result = DeserializeContents<T>(response, contentType); - - customAssert(result); - } - - public void AssertResponse<T>(HttpWebResponse response, string contentType, Action<T> customAssert) - { - contentType = contentType ?? defaultConfig.DefaultContentType; - - AssertResponse(response, contentType); - - var result = DeserializeContents<T>(response, contentType); - - customAssert(result); - } - - private static T DeserializeResult<T>(WebResponse response, string contents, string contentType) - { - T result; - switch (contentType) - { - case ContentType.Xml: - result = XmlSerializer.DeserializeFromString<T>(contents); - break; - - case ContentType.Json: - case ContentType.Json + ContentType.Utf8Suffix: - result = JsonSerializer.DeserializeFromString<T>(contents); - break; - - case ContentType.Jsv: - result = TypeSerializer.DeserializeFromString<T>(contents); - break; - - default: - throw new NotSupportedException(response.ContentType); - } - return result; - } - - } + public class RestsTestBase + : TestBase + { + private static readonly ILog Log = LogManager.GetLogger(typeof(RestsTestBase)); + + readonly HostConfig defaultConfig = new HostConfig(); + + public RestsTestBase() + : base(Config.ServiceStackBaseUri, typeof(HelloService).Assembly) + //: base("http://localhost:4000", typeof(HelloService).Assembly) //Uncomment to test on dev web server + { + } + + protected override void Configure(Funq.Container container) { } + + public HttpWebResponse GetWebResponse(string uri, string acceptContentTypes) + { + var webRequest = (HttpWebRequest)WebRequest.Create(uri); + webRequest.Accept = acceptContentTypes; + return (HttpWebResponse)webRequest.GetResponse(); + } + + public static HttpWebResponse GetWebResponse(string httpMethod, string uri, string contentType, int contentLength) + { + var webRequest = (HttpWebRequest)WebRequest.Create(uri); + webRequest.Accept = contentType; + webRequest.ContentType = contentType; + webRequest.Method = HttpMethods.Post; + webRequest.ContentLength = contentLength; + return (HttpWebResponse)webRequest.GetResponse(); + } + + public static string GetContents(WebResponse webResponse) + { + using (var stream = webResponse.GetResponseStream()) + { + var contents = stream.ReadToEnd(); + return contents; + } + } + + public T DeserializeContents<T>(WebResponse webResponse) + { + var contentType = webResponse.ContentType ?? defaultConfig.DefaultContentType; + return DeserializeContents<T>(webResponse, contentType); + } + + private static T DeserializeContents<T>(WebResponse webResponse, string contentType) + { + try + { + var contents = GetContents(webResponse); + var result = DeserializeResult<T>(webResponse, contents, contentType); + return result; + } + catch (WebException webEx) + { + if (webEx.Status == WebExceptionStatus.ProtocolError) + { + var errorResponse = ((HttpWebResponse)webEx.Response); + Log.Error(webEx); + Log.DebugFormat("Status Code : {0}", errorResponse.StatusCode); + Log.DebugFormat("Status Description : {0}", errorResponse.StatusDescription); + + try + { + using (var stream = errorResponse.GetResponseStream()) + { + var response = ContentTypes.Instance.DeserializeFromStream(contentType, typeof(T), stream); + return (T)response; + } + } + catch (WebException) + { + // Oh, well, we tried + throw; + } + } + + throw; + } + } + + public void AssertResponse(HttpWebResponse response, string contentType) + { + var statusCode = (int)response.StatusCode; + Assert.That(statusCode, Is.LessThan(400)); + Assert.That(response.ContentType.StartsWith(contentType)); + } + + public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode, Func<T, ResponseStatus> responseStatusFn) + { + Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); + var response = DeserializeContents<T>(webResponse); + Assert.That(responseStatusFn(response).ErrorCode, Is.Not.Null); + } + + public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode, Func<T, ResponseStatus> responseStatusFn, string errorCode) + { + Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); + var response = DeserializeContents<T>(webResponse); + Assert.That(responseStatusFn(response).ErrorCode, Is.EqualTo(errorCode)); + } + + public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode) + where T : IHasResponseStatus + { + Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); + var response = DeserializeContents<T>(webResponse); + Assert.That(response.ResponseStatus.ErrorCode, Is.Not.Null); + } + + public void AssertErrorResponse<T>(HttpWebResponse webResponse, HttpStatusCode statusCode, string errorCode) + where T : IHasResponseStatus + { + Assert.That(webResponse.StatusCode, Is.EqualTo(statusCode)); + var response = DeserializeContents<T>(webResponse); + Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(errorCode)); + } + + public void AssertResponse<T>(HttpWebResponse response, Action<T> customAssert) + { + var contentType = response.ContentType ?? defaultConfig.DefaultContentType; + + AssertResponse(response, contentType); + + var result = DeserializeContents<T>(response, contentType); + + customAssert(result); + } + + public void AssertResponse<T>(HttpWebResponse response, string contentType, Action<T> customAssert) + { + contentType = contentType ?? defaultConfig.DefaultContentType; + + AssertResponse(response, contentType); + + var result = DeserializeContents<T>(response, contentType); + + customAssert(result); + } + + private static T DeserializeResult<T>(WebResponse response, string contents, string contentType) + { + T result; + switch (contentType) + { + case MimeTypes.Xml: + result = XmlSerializer.DeserializeFromString<T>(contents); + break; + + case MimeTypes.Json: + case MimeTypes.Json + ContentFormat.Utf8Suffix: + result = JsonSerializer.DeserializeFromString<T>(contents); + break; + + case MimeTypes.Jsv: + result = TypeSerializer.DeserializeFromString<T>(contents); + break; + + default: + throw new NotSupportedException(response.ContentType); + } + return result; + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/RouteTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RouteTests.cs new file mode 100644 index 00000000000..9e6a679b891 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/RouteTests.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using ServiceStack.Host.Handlers; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [Route("/routeinfo/{Path*}")] + public class GetRouteInfo + { + public string Path { get; set; } + } + + public class GetRouteInfoResponse + { + public string BaseUrl { get; set; } + public string ResolvedUrl { get; set; } + } + + public class RouteInfoService : Service + { + public object Any(GetRouteInfo request) + { + return new GetRouteInfoResponse + { + BaseUrl = base.Request.GetBaseUrl(), + ResolvedUrl = base.Request.ResolveAbsoluteUrl("~/resolved") + }; + } + } + + public class RouteInfoPathTests + { + [Test] + public void ApiPath_returns_BaseUrl() + { + var url = Config.AbsoluteBaseUri.AppendPath("api"); + + var reqInfoResponse = url.AddQueryParam("debug", "requestinfo") + .GetJsonFromUrl().FromJson<RequestInfoResponse>(); + Assert.That(reqInfoResponse.ApplicationBaseUrl, Is.EqualTo(url)); + Assert.That(reqInfoResponse.ResolveAbsoluteUrl, Is.EqualTo(url + "/resolve")); + + var response = url.CombineWith("/routeinfo").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + + response = url.CombineWith("/routeinfo/dir/sub").GetJsonFromUrl().FromJson<GetRouteInfoResponse>(); + Assert.That(response.BaseUrl, Is.EqualTo(url)); + Assert.That(response.ResolvedUrl, Is.EqualTo(url.AppendPath("resolved"))); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/SessionTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/SessionTests.cs index 5e8f8fd3033..1805f541a4e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/SessionTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/SessionTests.cs @@ -1,21 +1,45 @@ using System; +using System.IO; +using System.Web; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.Messaging; -using ServiceStack.ServiceInterface; +using ServiceStack.Testing; namespace ServiceStack.WebHost.IntegrationTests.Tests { - [TestFixture] - public class SessionTests - { - [Test] + [TestFixture] + public class SessionTests + { + [Test] public void Adhoc() { - var appliesTo = ApplyTo.Post | ApplyTo.Put; - Console.WriteLine(appliesTo.ToString()); - Console.WriteLine(appliesTo.ToDescription()); - Console.WriteLine(string.Join(", ", appliesTo.ToList().ToArray())); + var appliesTo = ApplyTo.Post | ApplyTo.Put; + Console.WriteLine(appliesTo.ToString()); + Console.WriteLine(appliesTo.ToDescription()); + Console.WriteLine(string.Join(", ", appliesTo.ToList().ToArray())); } - } + + [Test] + public void Can_mock_Session_when_accessed_via_HttpRequest_Context() + { + using (new BasicAppHost().Init()) + { + HttpContext.Current = new HttpContext( + new HttpRequest(null, "http://example.com", null), + new HttpResponse(new StringWriter())); + + HttpContext.Current.Items[Keywords.Session] = + new AuthUserSession + { + Id = "mock-session-id", + }; + + var httpReq = HttpContext.Current.ToRequest(); + var session = httpReq.GetSession(); + + Assert.That(session, Is.Not.Null); + Assert.That(session.Id, Is.EqualTo("mock-session-id")); + } + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/SoapTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/SoapTests.cs new file mode 100644 index 00000000000..2e2d6c6c007 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/SoapTests.cs @@ -0,0 +1,136 @@ +using System; +using System.Runtime.Remoting; +using System.Runtime.Serialization; +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class SoapTests + { + [Test] + public void Does_call_Hello_Service() + { + var client = new Soap12ServiceClient(Config.ServiceStackBaseUri); + + var response = client.Send<HelloResponse>(new Hello { Name = "World" }); + + Assert.That(response.Result, Is.EqualTo("Hello, World")); + } + + [Test] + public void Soap12_Service_does_not_return_BOM() + { + var soapBody = @" +<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"" +xmlns:a=""http://www.w3.org/2005/08/addressing""> +<s:Header> + <a:Action s:mustUnderstand=""1"">Hello</a:Action> + <a:MessageID>urn:uuid:be5fddae-9fa3-4d5f-bc31-6ee4980d74f1</a:MessageID> + <a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo> + <a:To s:mustUnderstand=""1"">http://macbook/api/Soap12</a:To> +</s:Header> +<s:Body> + <Hello xmlns=""http://schemas.servicestack.net/types"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""> + <Name>World</Name> + </Hello> +</s:Body> +</s:Envelope>"; + + var url = Config.ServiceStackBaseUri.AppendPath("Soap12"); + var soapBytes = url.PostBytesToUrl(requestBody: soapBody.ToUtf8Bytes(), + contentType: "application/soap+xml; charset=utf-8"); + + //http://en.wikipedia.org/wiki/Byte_order_mark + //BitConverter.ToString(soapBytes).Print(); //print hex + + byte firstByte = soapBytes[0]; + Assert.That(firstByte, Is.Not.EqualTo(239)); //UTF-8 BOM + Assert.That(firstByte, Is.EqualTo((int)'<')); + + var soapXml = soapBytes.FromUtf8Bytes(); + + Assert.That(soapXml, Does.StartWith(@"<?xml version=""1.0"" encoding=""utf-8""?><s:Envelope")); + } + + [Test] + public void Can_send_SoapRequest() + { + var client = new Soap12ServiceClient(Config.ServiceStackBaseUri); +// var client = new Soap12ServiceClient("http://test.servicestack.net"); + + var request = new GetStuff { + SummaryDate = DateTime.Parse("2018-04-26"), + SummaryEndDate = DateTime.Parse("2018-04-26"), + Symbol = "TOU", + Email = "Guy.Smiley@myCompany.net", + IsEnabled = true, + }; + + var response = client.Send(request); + + Assert.That(response.SummaryDate, Is.EqualTo(request.SummaryDate)); + Assert.That(response.SummaryEndDate, Is.EqualTo(request.SummaryEndDate)); + Assert.That(response.Symbol, Is.EqualTo(request.Symbol)); + Assert.That(response.Email, Is.EqualTo(request.Email)); + Assert.That(response.IsEnabled, Is.EqualTo(request.IsEnabled)); + } + } + + [DataContract(Namespace = "http://schemas.servicestack.net/types")] + [Route("/Stuff")] + public class GetStuff : IReturn<GetStuffResponse> + { + [DataMember] + [ApiMember(Name = "Summary Date", + DataType = "DateTime", + IsRequired = false)] + public DateTime? SummaryDate { get; set; } + + [DataMember] + [ApiMember(Name = "Summary End Date", + DataType = "DateTime", + IsRequired = false)] + public DateTime? SummaryEndDate { get; set; } + + [DataMember] + [ApiMember(Name = "Symbol", + DataType = "string", + IsRequired = false)] + public string Symbol { get; set; } + + [DataMember] + [ApiMember(Name = "Email", + DataType = "string", + IsRequired = false)] + public string Email { get; set; } + + [DataMember] + [ApiMember(Name = "Is Enabled", + DataType = "bool", + IsRequired = false)] + public bool? IsEnabled { get; set; } + } + + [DataContract(Namespace = "http://schemas.servicestack.net/types")] + public class GetStuffResponse + { + [DataMember] + public DateTime? SummaryDate { get; set; } + [DataMember] + public DateTime? SummaryEndDate { get; set; } + [DataMember] + public string Symbol { get; set; } + [DataMember] + public string Email { get; set; } + [DataMember] + public bool? IsEnabled { get; set; } + } + + public class SoapTestServices : Service + { + public object Any(GetStuff request) => request.ConvertTo<GetStuffResponse>(); + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/UniqueRequestTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/UniqueRequestTests.cs index e458c4e0140..d1853119d1e 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/UniqueRequestTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/UniqueRequestTests.cs @@ -1,8 +1,5 @@ -using Funq; +using System.Collections.Generic; using NUnit.Framework; -using ServiceStack.Common; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; using ServiceStack.Text; namespace ServiceStack.WebHost.IntegrationTests.Tests @@ -13,21 +10,33 @@ public class UniqueRequest public string Id { get; set; } } + [Route("/collections")] + public class Collections : IReturn<Collections> + { + public int[] Ids { get; set; } + public List<string> Names { get; set; } + } + public class UniqueRequestService : IService { public string Get(UniqueRequest uniqueRequest) { return uniqueRequest.Id; } + + public object Any(Collections request) + { + return request; + } } [TestFixture] public class UniqueRequestTests { - private const string BaseUri = Config.AbsoluteBaseUri; + private const string BaseUri = Config.ServiceStackBaseUri; [Test] - [Explicit("ASP.NET does not allow invalid chars see http://stackoverflow.com/questions/13691829/path-parameters-w-url-unfriendly-characters")] + [Ignore("ASP.NET does not allow invalid chars see http://stackoverflow.com/questions/13691829/path-parameters-w-url-unfriendly-characters")] public void Can_handle_encoded_chars() { var response = BaseUri.CombineWith("request/123%20456").GetStringFromUrl(); @@ -36,5 +45,75 @@ public void Can_handle_encoded_chars() Assert.That(response, Is.EqualTo("123%7C456")); } + [Test] + public void Can_handle_collections_with_ServiceClient() + { + var client = new JsonServiceClient(BaseUri); + var request = new Collections + { + Ids = new[] { 1, 2, 3 }, + Names = new List<string> { "A", "B", "C" }, + }; + var response = client.Get(request); + + Assert.That(response.Ids, Is.EquivalentTo(request.Ids)); + Assert.That(response.Names, Is.EquivalentTo(request.Names)); + } + + [Test] + public void Can_handle_collections_with_HttpClient() + { + var url = BaseUri.CombineWith("collections") + .AddQueryParam("Ids", "1,2,3") + .AddQueryParam("Names", "A,B,C"); + + var response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + + url = BaseUri.CombineWith("collections") + .AddQueryParam("Ids", "1") + .AddQueryParam("Ids", "2") + .AddQueryParam("Ids", "3") + .AddQueryParam("Names", "A") + .AddQueryParam("Names", "B") + .AddQueryParam("Names", "C"); + + response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + } + + [Test] + public void Can_handle_collections_with_HttpClient_on_predefined_route() + { + var url = BaseUri.CombineWith("json/reply/Collections") + .AddQueryParam("Ids", "1,2,3") + .AddQueryParam("Names", "A,B,C"); + + var response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + + url = BaseUri.CombineWith("json/reply/Collections") + .AddQueryParam("Ids", "1") + .AddQueryParam("Ids", "2") + .AddQueryParam("Ids", "3") + .AddQueryParam("Names", "A") + .AddQueryParam("Names", "B") + .AddQueryParam("Names", "C"); + + response = url.GetJsonFromUrl() + .FromJson<Collections>(); + + Assert.That(response.Ids, Is.EquivalentTo(new[] { 1, 2, 3 })); + Assert.That(response.Names, Is.EquivalentTo(new List<string> { "A", "B", "C" })); + } } } diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/VirtualPathTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/VirtualPathTests.cs new file mode 100644 index 00000000000..5d50be4a198 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/VirtualPathTests.cs @@ -0,0 +1,111 @@ +// Copyright (c) ServiceStack, Inc. All Rights Reserved. +// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt + + +using NUnit.Framework; +using ServiceStack.Text; +using ServiceStack.WebHost.IntegrationTests.Services; + +namespace ServiceStack.WebHost.IntegrationTests.Tests +{ + [TestFixture] + public class VirtualPathTests + { + public static string ServiceStackBaseUri = Config.ServiceStackBaseUri; + + [Test] + public void Can_download_static_file_at_root_directory() + { + var contents = "{0}/static-root.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_static_file_at_sub_directory() + { + var contents = "{0}/Content/static-sub.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_embedded_static_file_at_root_directory() + { + var contents = "{0}/static-root-embedded.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_embedded_static_file_at_sub_directory() + { + var contents = "{0}/Content/static-sub-embedded.txt".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_default_static_file_at_sub_directory() + { + var contents = "{0}/Content".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.EqualTo("static")); + } + + [Test] + public void Can_download_default_document_at_root_directory() + { + var contents = "{0}/".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Is.Not.Null); + } + + [Test] + public void Can_download_ServiceStack_Template_IndexOperations() + { + var contents = "{0}/metadata".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain("The following operations are supported.")); + } + + [Test] + public void Can_download_File_Template_OperationControl() + { + var contents = "{0}/json/metadata?op=Hello".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain("(File Resource)")); + } + + [Test] + public void Can_download_EmbeddedResource_Template_HtmlFormat() + { + var contents = "{0}/hello".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain("(Embedded Resource)")); + } + + [Test] + public void Can_get_service_matching_api_prefix() + { + var contents = "{0}/gettestapi".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain("GetTestapi")); + } + + [Test] + public void Can_get_swagger_urls() + { + var contents = "{0}/swagger-ui/".Fmt(ServiceStackBaseUri).GetStringFromUrl(); + Assert.That(contents, Does.Contain(ServiceStackBaseUri)); + + contents = "{0}/api/openapi".Fmt(ServiceStackBaseUri).GetJsonFromUrl(); + Assert.That(contents, Does.Contain("ServiceStack WebHost IntegrationTests")); + } + + [Test] + public void Can_call_template_Service() + { + var client = new JsonServiceClient(ServiceStackBaseUri); + + var postResponse = client.Post(new PostTemplateRequest { Template = "foo" }); + Assert.That(postResponse.PostResult, Is.EqualTo("foo")); + + var getResponse = client.Get(new GetTemplatesRequest { Name = "bar" }); + Assert.That(getResponse.GetResult, Is.EqualTo("bar")); + + var getSingleResponse = client.Get(new GetTemplateRequest { Name = "baz" }); + Assert.That(getSingleResponse.GetSingleResult, Is.EqualTo("baz")); + } + } +} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs b/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs index bc9290932a7..51fa69b2939 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs +++ b/tests/ServiceStack.WebHost.IntegrationTests/Tests/WebServicesTests.cs @@ -1,82 +1,132 @@ using System; +using System.Collections.Generic; using System.Net; +using System.Runtime.Serialization; +using System.ServiceModel.Channels; +using System.Xml; using NUnit.Framework; -using ServiceStack.Service; -using ServiceStack.ServiceClient.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Testing; +using ServiceStack.Common.Tests; using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints.Support; +using ServiceStack.Validation; using ServiceStack.WebHost.IntegrationTests.Services; namespace ServiceStack.WebHost.IntegrationTests.Tests { - /// <summary> - /// This base class executes all Web Services ignorant of the endpoints its hosted on. - /// The same tests below are re-used by the Unit and Integration TestFixture's declared below - /// </summary> - [TestFixture] - public abstract class WebServicesTests - : TestBase - { - private const string TestString = "ServiceStack"; - - protected WebServicesTests() - : base(Config.ServiceStackBaseUri, typeof(ReverseService).Assembly) - { - } - - protected override void Configure(Funq.Container container) { } - - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - EndpointHandlerBase.ServiceManager = null; - } - - [Test] - public void Does_Execute_ReverseService() - { - var client = CreateNewServiceClient(); - var response = client.Send<ReverseResponse>( - new Reverse { Value = TestString }); - - var expectedValue = ReverseService.Execute(TestString); - Assert.That(response.Result, Is.EqualTo(expectedValue)); - } - - [Test] - public void Does_Execute_Rot13Service() - { - var client = CreateNewServiceClient(); - var response = client.Send<Rot13Response>(new Rot13 { Value = TestString }); - - var expectedValue = TestString.ToRot13(); - Assert.That(response.Result, Is.EqualTo(expectedValue)); - } - - [Test] - public void Can_Handle_Exception_from_AlwaysThrowService() - { - var client = CreateNewServiceClient(); - try - { - var response = client.Send<AlwaysThrowsResponse>( - new AlwaysThrows { Value = TestString }); - - response.PrintDump(); - Assert.Fail("Should throw HTTP errors"); - } - catch (WebServiceException webEx) - { - var response = (AlwaysThrowsResponse) webEx.ResponseDto; - var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); - Assert.That(response.ResponseStatus.ErrorCode, - Is.EqualTo(typeof(NotImplementedException).Name)); - Assert.That(response.ResponseStatus.Message, - Is.EqualTo(expectedError)); - } - } + /// <summary> + /// This base class executes all Web Services ignorant of the endpoints its hosted on. + /// The same tests below are re-used by the Unit and Integration TestFixture's declared below + /// </summary> + [TestFixture] + public abstract class WebServicesTests + : TestBase + { + private const string TestString = "ServiceStack"; + + protected WebServicesTests() + : base(Config.ServiceStackBaseUri, typeof(ReverseService).Assembly) + { + } + + protected override void Configure(Funq.Container container) { } + + [Test] + public void Does_Execute_ReverseService() + { + var client = CreateNewServiceClient(); + var response = client.Send<ReverseResponse>( + new Reverse { Value = TestString }); + + var expectedValue = ReverseService.Execute(TestString); + Assert.That(response.Result, Is.EqualTo(expectedValue)); + } + + [Test] + public void Does_Execute_Rot13Service() + { + var client = CreateNewServiceClient(); + var response = client.Send<Rot13Response>(new Rot13 { Value = TestString }); + + var expectedValue = TestString.ToRot13(); + Assert.That(response.Result, Is.EqualTo(expectedValue)); + } + + [Test] + public void Does_Execute_AddInts() + { + var client = CreateNewServiceClient(); + var response = client.Send<AddIntsResponse>(new AddInts { A = 1, B = 2 }); + + Assert.That(response.Result, Is.EqualTo(3)); + } + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowService() + { + var client = CreateNewServiceClient(); + try + { + var response = client.Send<AlwaysThrowsResponse>( + new AlwaysThrows { Value = TestString }); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + var response = (AlwaysThrowsResponse)webEx.ResponseDto; + var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); + Assert.That(response.ResponseStatus.ErrorCode, + Is.EqualTo(typeof(NotImplementedException).Name)); + Assert.That(response.ResponseStatus.Message, + Is.EqualTo(expectedError)); + } + } + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowsList_with_GET_route() + { + var client = CreateNewServiceClient(); + if (client is WcfServiceClient) return; + try + { + var response = client.Get<List<AlwaysThrows>>("/throwslist/404/{0}".Fmt(TestString)); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + Assert.That(webEx.StatusCode, Is.EqualTo(404)); + + var response = (ErrorResponse)webEx.ResponseDto; + var expectedError = AlwaysThrowsService.GetErrorMessage(TestString); + Assert.That(response.ResponseStatus.ErrorCode, + Is.EqualTo(typeof(NotImplementedException).Name)); + Assert.That(response.ResponseStatus.Message, + Is.EqualTo(expectedError)); + } + } + + [Test] + public void Can_Handle_Exception_from_AlwaysThrowsValidation() + { + var client = CreateNewServiceClient(); + try + { + var response = client.Send<List<AlwaysThrows>>( + new AlwaysThrowsValidation()); + + Assert.Fail("Should throw HTTP errors"); + } + catch (WebServiceException webEx) + { + var response = (ErrorResponse)webEx.ResponseDto; + var status = response.ResponseStatus; + Assert.That(status.ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Message, Is.EqualTo("'Value' must not be empty.")); + Assert.That(status.Errors[0].ErrorCode, Is.EqualTo("NotEmpty")); + Assert.That(status.Errors[0].FieldName, Is.EqualTo("Value")); + Assert.That(status.Errors[0].Message, Is.EqualTo("'Value' must not be empty.")); + } + } [Test] public void Request_items_are_preserved_between_filters() @@ -89,57 +139,132 @@ public void Request_items_are_preserved_between_filters() } - /// <summary> - /// Unit tests simulates an in-process ServiceStack host where all services - /// are executed all in-memory so DTO's are not even serialized. - /// </summary> - public class UnitTests : WebServicesTests - { - protected override IServiceClient CreateNewServiceClient() - { - EndpointHandlerBase.ServiceManager = new ServiceManager(typeof(ReverseService).Assembly).Init(); - return new DirectServiceClient(this, EndpointHandlerBase.ServiceManager); - } - } - - public class XmlIntegrationTests : WebServicesTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new XmlServiceClient(ServiceClientBaseUri); - } - } - - public class JsonIntegrationTests : WebServicesTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new JsonServiceClient(ServiceClientBaseUri); - } - } - - public class JsvIntegrationTests : WebServicesTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new JsvServiceClient(ServiceClientBaseUri); - } - } - - public class Soap11IntegrationTests : WebServicesTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new Soap11ServiceClient(ServiceClientBaseUri); - } - } - - public class Soap12IntegrationTests : WebServicesTests - { - protected override IServiceClient CreateNewServiceClient() - { - return new Soap12ServiceClient(ServiceClientBaseUri); - } - } + /// <summary> + /// Unit tests simulates an in-process ServiceStack host where all services + /// are executed all in-memory so DTO's are not even serialized. + /// </summary> + public class UnitTests : WebServicesTests + { + public UnitTests() + { + AppHost.Container.RegisterValidators(typeof(AlwaysThrowsValidator).Assembly); + AppHost.LoadPlugin(new ValidationFeature()); + } + + protected override IServiceClient CreateNewServiceClient() + { + return new DirectServiceClient(this, AppHost.ServiceController); + } + } + + public class XmlIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new XmlServiceClient(ServiceClientBaseUri); + } + } + + public class JsonIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new JsonServiceClient(ServiceClientBaseUri); + } + } + + public class JsvIntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new JsvServiceClient(ServiceClientBaseUri); + } + } + public class Soap11IntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new Soap11ServiceClient(ServiceClientBaseUri); + } + } + + public class Soap12IntegrationTests : WebServicesTests + { + protected override IServiceClient CreateNewServiceClient() + { + return new Soap12ServiceClient(ServiceClientBaseUri); +// return new Soap12ServiceClient("http://test.servicestack.net"); + } + + [Test] + public void Call_AddInts() + { + var soap = @"<?xml version=""1.0"" encoding=""UTF-8""?> +<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"" xmlns:a=""http://www.w3.org/2005/08/addressing""> + <s:Header> + <a:Action s:mustUnderstand=""1"">AddInts</a:Action> + <a:MessageID>urn:uuid:e6be43e0-c120-4ba8-920e-7ecaa1823fd2</a:MessageID> + <a:ReplyTo> + <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> + </a:ReplyTo> + <a:To s:mustUnderstand=""1"">http://localhost:50000/api/Soap12</a:To> + </s:Header> + <s:Body> + <AddInts xmlns=""http://schemas.servicestack.net/types"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""> + <A>1</A> + <B>2</B> + </AddInts> + </s:Body> +</s:Envelope>"; + + var responseXml = ServiceClientBaseUri.CombineWith("/soap12") + .PostToUrl(soap, requestFilter:req => req.ContentType = "application/soap+xml; charset=utf-8"); + + responseXml.Print(); + Assert.That(responseXml, Does.Contain("<Result>3</Result>")); + } + + [Test] + public void Sending_invalid_request_returns_invalid_response() + { + var soap = @"<?xml version=""1.0"" encoding=""UTF-8""?> +<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"" xmlns:a=""http://www.w3.org/2005/08/addressing""> + <s:Header> + <a:Action s:mustUnderstand=""1"">AddInts</a:Action> + <a:MessageID>urn:uuid:e6be43e0-c120-4ba8-920e-7ecaa1823fd2</a:MessageID> + <a:ReplyTo> + <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> + </a:ReplyTo> + <a:To s:mustUnderstand=""1"">http://localhost:50000/api/Soap12</a:To> + </s:Header> + <s:Body> + <AddInts xmlns=""http://schemas.servicestack.net/types"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""> + <A>not a</A> + <B>number</B> + </AddInts> + </s:Body> +</s:Envelope>"; + + var responseXml = ServiceClientBaseUri.CombineWith("/soap12") + .PostToUrl(soap, requestFilter: req => req.ContentType = "application/soap+xml; charset=utf-8"); + + var doc = new XmlDocument(); + doc.LoadXml(responseXml); + + var responseMsg = Message.CreateMessage(new XmlNodeReader(doc), int.MaxValue, + MessageVersion.Soap12WSAddressingAugust2004); + + using (var reader = responseMsg.GetReaderAtBodyContents()) + { + var bodyXml = reader.ReadOuterXml(); + var responseType = typeof(AddIntsResponse); + var response = (AddIntsResponse)Serialization.DataContractSerializer.Instance.DeserializeFromString(bodyXml, responseType); + + Assert.That(response.ResponseStatus.ErrorCode, Is.EqualTo(nameof(SerializationException))); + Assert.That(response.ResponseStatus.Message, Does.Contain("Error trying to deserialize requestType:")); + } + } + + } } \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/Web.config b/tests/ServiceStack.WebHost.IntegrationTests/Web.config index 62013c0eea8..f53c77b66e5 100644 --- a/tests/ServiceStack.WebHost.IntegrationTests/Web.config +++ b/tests/ServiceStack.WebHost.IntegrationTests/Web.config @@ -1,40 +1,50 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="utf-8"?> + <configuration> - <appSettings> - <add key="test" value="val"/> - <add key="oauth.facebook.AppId" value="231464590266507"/> - <add key="oauth.facebook.AppSecret" value="9dd6ce54b4405dd1325d271d2419bc34"/> - <add key="oauth.facebook.Permissions" value="email,read_stream,offline_access"/> - <add key="RecreateTables" value="True"/> - </appSettings> - <connectionStrings/> - <location path="api"> + <appSettings> + <add key="test" value="val" /> + <add key="oauth.facebook.AppId" value="231464590266507" /> + <add key="oauth.facebook.AppSecret" value="9dd6ce54b4405dd1325d271d2419bc34" /> + <add key="oauth.facebook.Permissions" value="email,read_stream,offline_access" /> + <add key="RecreateTables" value="True" /> + </appSettings> + <connectionStrings /> + <location path="api"> + <system.webServer> + <handlers> + <add path="*" name="ServiceStack.Factory" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*" + preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" /> + </handlers> + </system.webServer> + </location> + <!-- + For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367. + + The following attributes can be set on the <httpRuntime> tag. + <system.Web> + <httpRuntime targetFramework="4.5.1" /> + </system.Web> + --> <system.web> - <httpHandlers> - <add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*"/> - </httpHandlers> - </system.web> - <system.webServer> - <handlers> - <add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/> - </handlers> - </system.webServer> - </location> - <system.web> - <!-- - Set compilation debug="true" to insert debugging - symbols into the compiled page. Because this - affects performance, set this value to true only + <!-- + Set compilation debug="true" to insert debugging + symbols into the compiled page. Because this + affects performance, set this value to true only during development. --> - <compilation debug="true" targetFramework="4.0"/> - <!-- + <compilation debug="true" targetFramework="4.7.2"> + <assemblies> + <add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <add assembly="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" /> + </assemblies> + </compilation> + <!-- The <authentication> section enables configuration of the security authentication mode used by ASP.NET to identify an incoming user. --> - <authentication mode="Windows"/> - <!-- + <authentication mode="Windows" /> + <!-- The <customErrors> section enables configuration of what to do if/when an unhandled error occurs during the execution of a request. Specifically, @@ -46,19 +56,49 @@ <error statusCode="404" redirect="FileNotFound.htm" /> </customErrors> --> - <customErrors mode="Off"/> - <httpHandlers> - <!--<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*"/>--> - </httpHandlers> - <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/> - </system.web> - <!-- + <customErrors mode="Off" /> + <httpHandlers> + <!--<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*"/>--> + </httpHandlers> + <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" /> + </system.web> + <!-- The system.webServer section is required for running ASP.NET AJAX under Internet Information Services 7.0. It is not necessary for previous version of IIS. --> - <system.webServer> - <handlers> - <!--<add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>--> - </handlers> - </system.webServer> + <system.webServer> + <handlers> + <!--<add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>--> + </handlers> + <httpErrors existingResponse="PassThrough" /> + </system.webServer> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="protobuf-net" publicKeyToken="257b51d87d2e4d67" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.4.0.0" newVersion="2.4.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Threading.Tasks.Extensions" culture="neutral" + publicKeyToken="cc7b13ffcd2ddd51" /> + <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /> + <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /> + </dependentAssembly> + </assemblyBinding> + </runtime> </configuration> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/default.html b/tests/ServiceStack.WebHost.IntegrationTests/default.html new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/default.html @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/dir/index.html b/tests/ServiceStack.WebHost.IntegrationTests/dir/index.html new file mode 100644 index 00000000000..31063146576 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/dir/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Title</title> +</head> +<body> + + <h1>dir/index.html</h1> + +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/dir/sub/index.html b/tests/ServiceStack.WebHost.IntegrationTests/dir/sub/index.html new file mode 100644 index 00000000000..e9fa3e179b7 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/dir/sub/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Title</title> +</head> +<body> + + <h1>dir/sub/index.html</h1> + +</body> +</html> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/dir/sub/webpage.forbidden b/tests/ServiceStack.WebHost.IntegrationTests/dir/sub/webpage.forbidden new file mode 100644 index 00000000000..ecf61b47162 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/dir/sub/webpage.forbidden @@ -0,0 +1 @@ +This page should not be displayed. \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/packages.config b/tests/ServiceStack.WebHost.IntegrationTests/packages.config deleted file mode 100644 index e0a2084bd73..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<packages> - <package id="protobuf-net" version="2.0.0.640" targetFramework="net40" /> -</packages> \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/sample.pdf b/tests/ServiceStack.WebHost.IntegrationTests/sample.pdf new file mode 100644 index 00000000000..9a291058dcf Binary files /dev/null and b/tests/ServiceStack.WebHost.IntegrationTests/sample.pdf differ diff --git a/tests/ServiceStack.WebHost.IntegrationTests/start.cmd b/tests/ServiceStack.WebHost.IntegrationTests/start.cmd new file mode 100644 index 00000000000..6bf5f973a30 --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/start.cmd @@ -0,0 +1 @@ +"C:/Program Files (x86)/IIS Express/iisexpress.exe" /config:C:/src/ServiceStack/src/.idea/config/applicationhost.config /site:ServiceStack.WebHost.IntegrationTests /apppool:Clr4IntegratedAppPool diff --git a/tests/ServiceStack.WebHost.IntegrationTests/static-root-embedded.txt b/tests/ServiceStack.WebHost.IntegrationTests/static-root-embedded.txt new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/static-root-embedded.txt @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/static-root.txt b/tests/ServiceStack.WebHost.IntegrationTests/static-root.txt new file mode 100644 index 00000000000..86594e659da --- /dev/null +++ b/tests/ServiceStack.WebHost.IntegrationTests/static-root.txt @@ -0,0 +1 @@ +static \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/LICENSE b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/LICENSE deleted file mode 100644 index 9129770f4c5..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/LICENSE +++ /dev/null @@ -1,5 +0,0 @@ -Copyright 2011-2012 Wordnik, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/css/hightlight.default.css b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/css/hightlight.default.css deleted file mode 100644 index e417fc17995..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/css/hightlight.default.css +++ /dev/null @@ -1,135 +0,0 @@ -/* - -Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org> - -*/ - -pre code { - display: block; padding: 0.5em; - background: #F0F0F0; -} - -pre code, -pre .subst, -pre .tag .title, -pre .lisp .title, -pre .clojure .built_in, -pre .nginx .title { - color: black; -} - -pre .string, -pre .title, -pre .constant, -pre .parent, -pre .tag .value, -pre .rules .value, -pre .rules .value .number, -pre .preprocessor, -pre .ruby .symbol, -pre .ruby .symbol .string, -pre .aggregate, -pre .template_tag, -pre .django .variable, -pre .smalltalk .class, -pre .addition, -pre .flow, -pre .stream, -pre .bash .variable, -pre .apache .tag, -pre .apache .cbracket, -pre .tex .command, -pre .tex .special, -pre .erlang_repl .function_or_atom, -pre .markdown .header { - color: #800; -} - -pre .comment, -pre .annotation, -pre .template_comment, -pre .diff .header, -pre .chunk, -pre .markdown .blockquote { - color: #888; -} - -pre .number, -pre .date, -pre .regexp, -pre .literal, -pre .smalltalk .symbol, -pre .smalltalk .char, -pre .go .constant, -pre .change, -pre .markdown .bullet, -pre .markdown .link_url { - color: #080; -} - -pre .label, -pre .javadoc, -pre .ruby .string, -pre .decorator, -pre .filter .argument, -pre .localvars, -pre .array, -pre .attr_selector, -pre .important, -pre .pseudo, -pre .pi, -pre .doctype, -pre .deletion, -pre .envvar, -pre .shebang, -pre .apache .sqbracket, -pre .nginx .built_in, -pre .tex .formula, -pre .erlang_repl .reserved, -pre .prompt, -pre .markdown .link_label, -pre .vhdl .attribute, -pre .clojure .attribute, -pre .coffeescript .property { - color: #88F -} - -pre .keyword, -pre .id, -pre .phpdoc, -pre .title, -pre .built_in, -pre .aggregate, -pre .css .tag, -pre .javadoctag, -pre .phpdoc, -pre .yardoctag, -pre .smalltalk .class, -pre .winutils, -pre .bash .variable, -pre .apache .tag, -pre .go .typename, -pre .tex .command, -pre .markdown .strong, -pre .request, -pre .status { - font-weight: bold; -} - -pre .markdown .emphasis { - font-style: italic; -} - -pre .nginx .built_in { - font-weight: normal; -} - -pre .coffeescript .javascript, -pre .javascript .xml, -pre .tex .formula, -pre .xml .javascript, -pre .xml .vbscript, -pre .xml .css, -pre .xml .cdata { - opacity: 0.5; -} diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/css/screen.css b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/css/screen.css deleted file mode 100644 index 06050e760d9..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/css/screen.css +++ /dev/null @@ -1,1759 +0,0 @@ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -body { - line-height: 1; -} - -ol, ul { - list-style: none; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -caption, th, td { - text-align: left; - font-weight: normal; - vertical-align: middle; -} - -q, blockquote { - quotes: none; -} - -q:before, q:after, blockquote:before, blockquote:after { - content: ""; - content: none; -} - -a img { - border: none; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary { - display: block; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - text-decoration: none; -} - -h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover { - text-decoration: underline; -} - -h1 span.divider, h2 span.divider, h3 span.divider, h4 span.divider, h5 span.divider, h6 span.divider { - color: #aaaaaa; -} - -h1 { - color: black; - font-size: 1.5em; - line-height: 1.3em; - padding: 10px 0 10px 0; - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -h2 { - color: black; - font-size: 1.3em; - padding: 10px 0 10px 0; -} - -h2 a { - color: black; -} - -h2 span.sub { - font-size: 0.7em; - color: #999999; - font-style: italic; -} - -h2 span.sub a { - color: #777777; -} - -h3 { - color: black; - font-size: 1.1em; - padding: 10px 0 10px 0; -} - -.heading_with_menu { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -.heading_with_menu h1, .heading_with_menu h2, .heading_with_menu h3, .heading_with_menu h4, .heading_with_menu h5, .heading_with_menu h6 { - display: block; - clear: none; - float: left; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - width: 60%; -} - -.heading_with_menu ul { - display: block; - clear: none; - float: right; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - margin-top: 10px; -} - -input.parameter { - width: 300px; - border: 1px solid #aaa; -} - -.body-textarea { - width: 300px; - height: 100px; - border: 1px solid #aaa; -} - -p { - line-height: 1.4em; - padding: 0 0 10px; - color: #333333; -} - -ol { - margin: 0px 0 10px; - padding: 0 0 0 18px; - list-style-type: decimal; -} - -ol li { - padding: 5px 0px; - font-size: 0.9em; - color: #333333; -} - -.markdown h3 { - color: #547f00; -} - -.markdown h4 { - color: #666666; -} - -.markdown pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #fcf6db; - border: 1px solid #e5e0c6; - padding: 10px; - margin: 0 0 10px 0; -} - -.markdown pre code { - line-height: 1.6em; -} - -.markdown p code, .markdown li code { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #f0f0f0; - color: black; - padding: 1px 3px; -} - -.markdown ol, .markdown ul { - font-family: "Droid Sans", sans-serif; - margin: 5px 0 10px; - padding: 0 0 0 18px; - list-style-type: disc; -} - -.markdown ol li, .markdown ul li { - padding: 3px 0px; - line-height: 1.4em; - color: #333333; -} - -div.gist { - margin: 20px 0 25px 0 !important; -} - -p.big, div.big p { - font-size: 1em; - margin-bottom: 10px; -} - -span.weak { - color: #666666; -} - -span.blank, span.empty { - color: #888888; - font-style: italic; -} - -a { - color: #547f00; -} - -b, strong { - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -.code { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; -} - -pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - background-color: #fcf6db; - border: 1px solid #e5e0c6; - padding: 10px; -} - -pre code { - line-height: 1.6em; -} - -.required { - font-weight: bold; -} - -table.fullwidth { - width: 100%; -} - -table thead tr th { - padding: 5px; - font-size: 0.9em; - color: #666666; - border-bottom: 1px solid #999999; -} - -table tbody tr.offset { - background-color: #f5f5f5; -} - -table tbody tr td { - padding: 6px; - font-size: 0.9em; - border-bottom: 1px solid #cccccc; - vertical-align: top; - line-height: 1.3em; -} - -table tbody tr:last-child td { - border-bottom: none; -} - -table tbody tr.offset { - background-color: #f0f0f0; -} - -form.form_box { - background-color: #ebf3f9; - border: 1px solid #c3d9ec; - padding: 10px; -} - -form.form_box label { - color: #0f6ab4 !important; -} - -form.form_box input[type=submit] { - display: block; - padding: 10px; -} - -form.form_box p { - font-size: 0.9em; - padding: 0 0 15px; - color: #7e7b6d; -} - -form.form_box p a { - color: #646257; -} - -form.form_box p strong { - color: black; -} - -form.form_box p.weak { - font-size: 0.8em; -} - -form.formtastic fieldset.inputs ol li p.inline-hints { - margin-left: 0; - font-style: italic; - font-size: 0.9em; - margin: 0; -} - -form.formtastic fieldset.inputs ol li label { - display: block; - clear: both; - width: auto; - padding: 0 0 3px; - color: #666666; -} - -form.formtastic fieldset.inputs ol li label abbr { - padding-left: 3px; - color: #888888; -} - -form.formtastic fieldset.inputs ol li.required label { - color: black; -} - -form.formtastic fieldset.inputs ol li.string input, form.formtastic fieldset.inputs ol li.url input, form.formtastic fieldset.inputs ol li.numeric input { - display: block; - padding: 4px; - width: auto; - clear: both; -} - -form.formtastic fieldset.inputs ol li.string input.title, form.formtastic fieldset.inputs ol li.url input.title, form.formtastic fieldset.inputs ol li.numeric input.title { - font-size: 1.3em; -} - -form.formtastic fieldset.inputs ol li.text textarea { - font-family: "Droid Sans", sans-serif; - height: 250px; - padding: 4px; - display: block; - clear: both; -} - -form.formtastic fieldset.inputs ol li.select select { - display: block; - clear: both; -} - -form.formtastic fieldset.inputs ol li.boolean { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -form.formtastic fieldset.inputs ol li.boolean input { - display: block; - float: left; - clear: none; - margin: 0 5px 0 0; -} - -form.formtastic fieldset.inputs ol li.boolean label { - display: block; - float: left; - clear: none; - margin: 0; - padding: 0; -} - -form.formtastic fieldset.buttons { - margin: 0; - padding: 0; -} - -form.fullwidth ol li.string input, form.fullwidth ol li.url input, form.fullwidth ol li.text textarea, form.fullwidth ol li.numeric input { - width: 500px !important; -} - -body { - font-family: "Droid Sans", sans-serif; -} - -body #content_message { - margin: 10px 15px; - font-style: italic; - color: #999999; -} - -body #header { - background-color: #89bf04; - padding: 14px; -} - -body #header a#logo { - font-size: 1.5em; - font-weight: bold; - text-decoration: none; - background: transparent url(../images/logo_small.png) no-repeat left center; - padding: 20px 0 20px 40px; - color: white; -} - -body #header form#api_selector { - display: block; - clear: none; - float: right; -} - -body #header form#api_selector .input { - display: block; - clear: none; - float: left; - margin: 0 10px 0 0; -} - -body #header form#api_selector .input input { - font-size: 0.9em; - padding: 3px; - margin: 0; -} - -body #header form#api_selector .input input#input_baseUrl { - width: 400px; -} - -body #header form#api_selector .input input#input_apiKey { - width: 200px; -} - -body #header form#api_selector .input a#explore { - display: block; - text-decoration: none; - font-weight: bold; - padding: 6px 8px; - font-size: 0.9em; - color: white; - background-color: #547f00; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -o-border-radius: 4px; - -ms-border-radius: 4px; - -khtml-border-radius: 4px; - border-radius: 4px; -} - -body #header form#api_selector .input a#explore:hover { - background-color: #547f00; -} - -body p#colophon { - margin: 0 15px 40px 15px; - padding: 10px 0; - font-size: 0.8em; - border-top: 1px solid #dddddd; - font-family: "Droid Sans", sans-serif; - color: #999999; - font-style: italic; -} - -body p#colophon a { - text-decoration: none; - color: #547f00; -} - -body ul#resources { - font-family: "Droid Sans", sans-serif; - font-size: 0.9em; -} - -body ul#resources li.resource { - border-bottom: 1px solid #dddddd; -} - -body ul#resources li.resource:last-child { - border-bottom: none; -} - -body ul#resources li.resource div.heading { - border: 1px solid transparent; - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource div.heading h2 { - color: #999999; - padding-left: 0; - display: block; - clear: none; - float: left; - font-family: "Droid Sans", sans-serif; - font-weight: bold; -} - -body ul#resources li.resource div.heading h2 a { - color: #999999; -} - -body ul#resources li.resource div.heading h2 a:hover { - color: black; -} - -body ul#resources li.resource div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 14px 10px 0 0; -} - -body ul#resources li.resource div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource div.heading ul.options li:first-child, body ul#resources li.resource div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource div.heading ul.options li:last-child, body ul#resources li.resource div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource div.heading ul.options li { - color: #666666; - font-size: 0.9em; -} - -body ul#resources li.resource div.heading ul.options li a { - color: #aaaaaa; - text-decoration: none; -} - -body ul#resources li.resource div.heading ul.options li a:hover { - text-decoration: underline; - color: black; -} - -body ul#resources li.resource:hover div.heading h2 a, body ul#resources li.resource.active div.heading h2 a { - color: black; -} - -body ul#resources li.resource:hover div.heading ul.options li a, body ul#resources li.resource.active div.heading ul.options li a { - color: #555555; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #e7f0f7; - border: 1px solid #c3d9ec; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #0f6ab4; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { - border-right-color: #c3d9ec; - color: #0f6ab4; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { - color: #0f6ab4; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { - background-color: #ebf3f9; - border: 1px solid #c3d9ec; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { - color: #0f6ab4; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fa5d2; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #e7f6ec; - border: 1px solid #c3e8d1; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #10a54a; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { - border-right-color: #c3e8d1; - color: #10a54a; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { - color: #10a54a; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { - background-color: #ebf7f0; - border: 1px solid #c3e8d1; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { - color: #10a54a; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fc992; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #f9f2e9; - border: 1px solid #f0e0ca; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #c5862b; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { - border-right-color: #f0e0ca; - color: #c5862b; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { - color: #c5862b; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { - background-color: #faf5ee; - border: 1px solid #f0e0ca; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { - color: #c5862b; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #dcb67f; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #FCE9E3; - border: 1px solid #F5D5C3; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #D38042; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { - border-right-color: #f0cecb; - color: #D38042; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { - color: #D38042; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { - background-color: #faf0ef; - border: 1px solid #f0cecb; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { - color: #D38042; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #F5D5C3; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #dcb67f; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px 0; - padding: 0 0 0 0px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 0 0; - padding: 0; - background-color: #fcffcd; - border: 1px solid black; - border-color: #ffd20f; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #ffd20f; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options { - float: none; - clear: both; - overflow: hidden; - margin: 0; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { - border-right-color: #ffd20f; - color: #ffd20f; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { - color: #ffd20f; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { - background-color: #fcffcd; - border: 1px solid black; - border-color: #ffd20f; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { - color: #ffd20f; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px 0px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header img { - display: block; - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #6fc992; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.response div.block { - background-color: #fcf6db; - border: 1px solid black; - border-color: #e5e0c6; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0 0 10px; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { - float: none; - clear: both; - overflow: hidden; - display: block; - margin: 0; - padding: 0; - background-color: #f5e8e8; - border: 1px solid #e8c6c7; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 { - display: block; - clear: none; - float: left; - width: auto; - margin: 0; - padding: 0; - line-height: 1.1em; - color: black; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span { - margin: 0; - padding: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { - text-transform: uppercase; - background-color: #a41e22; - text-decoration: none; - color: white; - display: inline-block; - width: 50px; - font-size: 0.7em; - text-align: center; - padding: 7px 0 4px 0; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - -o-border-radius: 2px; - -ms-border-radius: 2px; - -khtml-border-radius: 2px; - border-radius: 2px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path { - padding-left: 10px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a { - color: black; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a:hover { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options { - overflow: hidden; - padding: 0; - display: block; - clear: none; - float: right; - margin: 6px 10px 0 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { - float: left; - clear: none; - margin: 0; - padding: 2px 10px; - border-right: 1px solid #dddddd; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.first { - padding-left: 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { - padding-right: 0; - border-right: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { - border-right-color: #e8c6c7; - color: #a41e22; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { - color: #a41e22; - text-decoration: none; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a.active { - text-decoration: underline; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { - background-color: #f7eded; - border: 1px solid #e8c6c7; - border-top: none; - padding: 10px; - -moz-border-radius-bottomleft: 6px; - -webkit-border-bottom-left-radius: 6px; - -o-border-bottom-left-radius: 6px; - -ms-border-bottom-left-radius: 6px; - -khtml-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -moz-border-radius-bottomright: 6px; - -webkit-border-bottom-right-radius: 6px; - -o-border-bottom-right-radius: 6px; - -ms-border-bottom-right-radius: 6px; - -khtml-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - margin: 0 0 20px 0; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { - color: #a41e22; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content form input[type='text'].error { - outline: 2px solid black; - outline-color: #cc0000; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header { - float: none; - clear: both; - overflow: hidden; - display: block; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header input.submit { - display: block; - clear: none; - float: left; - padding: 6px 8px; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header img { - display: block; - clear: none; - float: right; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { - padding: 4px 0 0 10px; - color: #c8787a; - display: inline-block; - font-size: 0.9em; -} - -body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.response div.block pre { - font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; - padding: 10px; - font-size: 0.9em; - max-height: 400px; - overflow-y: auto; -} - - -.model-signature { - font-family: "Droid Sans", sans-serif; - font-size: 1em; - line-height: 1.5em; -} - -.model-signature .description div { - font-size: 0.9em; - line-height: 1.5em; - margin-left: 1em; -} - -.model-signature .description .strong { - font-weight: bold; - color: #000; - font-size: .9em; -} - -.model-signature .description .stronger { - font-weight: bold; - color: #000; -} - -.model-signature .signature-nav a { - text-decoration: none; - color: #AAA; -} - -.model-signature pre { - font-size: .85em; - line-height: 1.2em; - overflow: auto; - max-height: 200px; - cursor: pointer; -} - -.model-signature pre:hover { - background-color: #ffffdd; -} - -.model-signature .snippet small { - font-size: 0.75em; -} - -.model-signature .signature-container { - clear: both; -} - -.model-signature .signature-nav a:hover { - text-decoration: underline; - color: black; -} - -.model-signature .signature-nav .selected { - color: black; - text-decoration: none; -} - -.model-signature ul.signature-nav { - display: block; - margin: 0; - padding: 0; -} - -.model-signature ul.signature-nav li { - float: left; - margin: 0 5px 5px 0; - padding: 2px 5px 2px 0; - border-right: 1px solid #ddd; -} - -.model-signature ul.signature-nav li:last-child { - padding-right: 0; - border-right: none; -} - -.model-signature .propName { - font-weight: bold; -} -.model-signature .propType { - color: #5555aa; -} -.model-signature .propOptKey { - font-style: italic; -} -.model-signature .propOpt { - color: #555; -} - -pre code { - background: none; -} - -.content pre { - font-size: 12px; - margin-top: 5px; - padding: 5px; -} - -.content > .content-type > div > label { - clear: both; - display: block; - color: #0F6AB4; - font-size: 1.1em; - margin: 0; - padding: 15px 0 5px; -} - -.swagger-ui-wrap { - max-width: 960px; - margin-left: auto; - margin-right: auto; -} - -.icon-btn { - cursor: pointer; -} - -#message-bar { - min-height: 30px; - text-align: center; - padding-top: 10px; -} - -.message-success { - color: #89BF04; -} - -.message-fail { - color: #cc0000; -} \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/logo_small.png b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/logo_small.png deleted file mode 100644 index 5496a65579a..00000000000 Binary files a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/logo_small.png and /dev/null differ diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/pet_store_api.png b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/pet_store_api.png deleted file mode 100644 index f9f9cd4aeb3..00000000000 Binary files a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/pet_store_api.png and /dev/null differ diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/throbber.gif b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/throbber.gif deleted file mode 100644 index 06393889242..00000000000 Binary files a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/throbber.gif and /dev/null differ diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/wordnik_api.png b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/wordnik_api.png deleted file mode 100644 index dca4f1455ac..00000000000 Binary files a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/images/wordnik_api.png and /dev/null differ diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/index.html b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/index.html deleted file mode 100644 index 66c6fa23c65..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/index.html +++ /dev/null @@ -1,80 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>Swagger UI</title> - <link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/> - <link href='css/hightlight.default.css' media='screen' rel='stylesheet' type='text/css'/> - <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/> - <script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script> - <script src='lib/jquery.slideto.min.js' type='text/javascript'></script> - <script src='lib/jquery.wiggle.min.js' type='text/javascript'></script> - <script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script> - <script src='lib/handlebars-1.0.rc.1.js' type='text/javascript'></script> - <script src='lib/underscore-min.js' type='text/javascript'></script> - <script src='lib/backbone-min.js' type='text/javascript'></script> - <script src='lib/swagger.js' type='text/javascript'></script> - <script src='swagger-ui.js' type='text/javascript'></script> - <script src='lib/highlight.7.3.pack.js' type='text/javascript'></script> - - <script type="text/javascript"> - $(function () { - window.swaggerUi = new SwaggerUi({ - discoveryUrl:"http://petstore.swagger.wordnik.com/api/api-docs.json", - apiKey:"special-key", - dom_id:"swagger-ui-container", - supportHeaderParams: false, - supportedSubmitMethods: ['get', 'post', 'put'], - onComplete: function(swaggerApi, swaggerUi){ - if(console) { - console.log("Loaded SwaggerUI") - console.log(swaggerApi); - console.log(swaggerUi); - } - $('pre code').each(function(i, e) {hljs.highlightBlock(e)}); - }, - onFailure: function(data) { - if(console) { - console.log("Unable to Load SwaggerUI"); - console.log(data); - } - }, - docExpansion: "none" - }); - - window.swaggerUi.load(); - }); - - </script> -</head> - -<body> -<div id='header'> - <div class="swagger-ui-wrap"> - <a id="logo" href="http://swagger.wordnik.com">swagger</a> - - <form id='api_selector'> - <div class='input icon-btn'> - <img id="show-pet-store-icon" src="images/pet_store_api.png" title="Show Swagger Petstore Example Apis"> - </div> - <div class='input icon-btn'> - <img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis"> - </div> - <div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" - type="text"/></div> - <div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div> - <div class='input'><a id="explore" href="#">Explore</a></div> - </form> - </div> -</div> - -<div id="message-bar" class="swagger-ui-wrap"> - &nbsp; -</div> - -<div id="swagger-ui-container" class="swagger-ui-wrap"> - -</div> - -</body> - -</html> diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/backbone-min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/backbone-min.js deleted file mode 100644 index c1c0d4fff28..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/backbone-min.js +++ /dev/null @@ -1,38 +0,0 @@ -// Backbone.js 0.9.2 - -// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Backbone may be freely distributed under the MIT license. -// For all details and documentation: -// http://backbonejs.org -(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks= -{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g= -z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent= -{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null== -b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent: -b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)}; -a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error, -h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t(); -return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending= -{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length|| -!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator); -this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");g=e.cid;i=e.id;j[g]||this._byCid[g]||null!=i&&(k[i]||this._byId[i])? -l.push(c):j[g]=k[i]=e}for(c=l.length;c--;)a.splice(l[c],1);c=0;for(d=a.length;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=e.id&&(this._byId[e.id]=e);this.length+=d;A.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;c=0;for(d=this.models.length;c<d;c++)if(j[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)? -a.slice():[a];c=0;for(d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,b);return a},pop:function(a){var b=this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,f.extend({at:0},b));return a}, -shift:function(a){var b=this.at(0);this.remove(b,a);return b},get:function(a){return null==a?void 0:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return f.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return!1;return!0})},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length? -this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,f.extend({silent:!0},b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d, -e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId= -{};this._byCid={}},_prepareModel:function(a,b){b||(b={});a instanceof o?a.collection||(a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this, -arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),function(a){r.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});var u=g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)},B=/:\w+/g, -C=/\*\w+/g,D=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(u.prototype,k,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new m);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b, -this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(D,"\\$&").replace(B,"([^/]+)").replace(C,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var m=g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")},s=/^[#\/]/,E=/msie [\w.]+/;m.started=!1;f.extend(m.prototype,k,{interval:50,getHash:function(a){return(a=(a?a.location:window.location).href.match(/#(.*)$/))?a[1]: -""},getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=this.getHash();a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(s,"")},start:function(a){if(m.started)throw Error("Backbone.history has already been started");m.started=!0;this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState= -!(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=E.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=i('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?i(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?i(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl, -this.interval));this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&(this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()}, -stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a==this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers, -function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!m.started)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(s,"");this.fragment!=c&&(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace|| -this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},F=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(","); -f.extend(v.prototype,k,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c&&i(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents(); -for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(F),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b<c;b++){var d=w[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el, -!1);else{var a=n(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});o.extend=r.extend=u.extend=v.extend=function(a,b){var c=G(this,a,b);c.extend=this.extend;return c};var H={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=H[a];c||(c={});var e={type:d,dataType:"json"};c.url||(e.url=n(b,"url")||t());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json", -e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return i.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var x=function(){},G=function(a, -b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);x.prototype=a.prototype;d.prototype=new x;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},n=function(a,b){return!a||!a[b]?null:f.isFunction(a[b])?a[b]():a[b]},t=function(){throw Error('A "url" property or function must be specified');}}).call(this); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/handlebars-1.0.rc.1.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/handlebars-1.0.rc.1.js deleted file mode 100644 index 05346370a20..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/handlebars-1.0.rc.1.js +++ /dev/null @@ -1,1920 +0,0 @@ -// lib/handlebars/base.js - -/*jshint eqnull:true*/ -this.Handlebars = {}; - -(function(Handlebars) { - -Handlebars.VERSION = "1.0.rc.1"; - -Handlebars.helpers = {}; -Handlebars.partials = {}; - -Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; -}; - -Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; -}; - -Handlebars.registerHelper('helperMissing', function(arg) { - if(arguments.length === 2) { - return undefined; - } else { - throw new Error("Could not find property '" + arg + "'"); - } -}); - -var toString = Object.prototype.toString, functionType = "[object Function]"; - -Handlebars.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse || function() {}, fn = options.fn; - - - var ret = ""; - var type = toString.call(context); - - if(type === functionType) { context = context.call(this); } - - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if(type === "[object Array]") { - if(context.length > 0) { - return Handlebars.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - return fn(context); - } -}); - -Handlebars.K = function() {}; - -Handlebars.createFrame = Object.create || function(object) { - Handlebars.K.prototype = object; - var obj = new Handlebars.K(); - Handlebars.K.prototype = null; - return obj; -}; - -Handlebars.registerHelper('each', function(context, options) { - var fn = options.fn, inverse = options.inverse; - var ret = "", data; - - if (options.data) { - data = Handlebars.createFrame(options.data); - } - - if(context && context.length > 0) { - for(var i=0, j=context.length; i<j; i++) { - if (data) { data.index = i; } - ret = ret + fn(context[i], { data: data }); - } - } else { - ret = inverse(this); - } - return ret; -}); - -Handlebars.registerHelper('if', function(context, options) { - var type = toString.call(context); - if(type === functionType) { context = context.call(this); } - - if(!context || Handlebars.Utils.isEmpty(context)) { - return options.inverse(this); - } else { - return options.fn(this); - } -}); - -Handlebars.registerHelper('unless', function(context, options) { - var fn = options.fn, inverse = options.inverse; - options.fn = inverse; - options.inverse = fn; - - return Handlebars.helpers['if'].call(this, context, options); -}); - -Handlebars.registerHelper('with', function(context, options) { - return options.fn(context); -}); - -Handlebars.registerHelper('log', function(context) { - Handlebars.log(context); -}); - -}(this.Handlebars)); -; -// lib/handlebars/compiler/parser.js -/* Jison generated parser */ -var handlebars = (function(){ -var parser = {trace: function trace() { }, -yy: {}, -symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"DATA":27,"param":28,"STRING":29,"INTEGER":30,"BOOLEAN":31,"hashSegments":32,"hashSegment":33,"ID":34,"EQUALS":35,"pathSegments":36,"SEP":37,"$accept":0,"$end":1}, -terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",27:"DATA",29:"STRING",30:"INTEGER",31:"BOOLEAN",34:"ID",35:"EQUALS",37:"SEP"}, -productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[17,1],[25,2],[25,1],[28,1],[28,1],[28,1],[28,1],[28,1],[26,1],[32,2],[32,1],[33,3],[33,3],[33,3],[33,3],[33,3],[21,1],[36,3],[36,1]], -performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { - -var $0 = $$.length - 1; -switch (yystate) { -case 1: return $$[$0-1]; -break; -case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]); -break; -case 3: this.$ = new yy.ProgramNode($$[$0]); -break; -case 4: this.$ = new yy.ProgramNode([]); -break; -case 5: this.$ = [$$[$0]]; -break; -case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; -break; -case 7: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]); -break; -case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]); -break; -case 9: this.$ = $$[$0]; -break; -case 10: this.$ = $$[$0]; -break; -case 11: this.$ = new yy.ContentNode($$[$0]); -break; -case 12: this.$ = new yy.CommentNode($$[$0]); -break; -case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); -break; -case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); -break; -case 15: this.$ = $$[$0-1]; -break; -case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); -break; -case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true); -break; -case 18: this.$ = new yy.PartialNode($$[$0-1]); -break; -case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]); -break; -case 20: -break; -case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]; -break; -case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null]; -break; -case 23: this.$ = [[$$[$0-1]], $$[$0]]; -break; -case 24: this.$ = [[$$[$0]], null]; -break; -case 25: this.$ = [[new yy.DataNode($$[$0])], null]; -break; -case 26: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; -break; -case 27: this.$ = [$$[$0]]; -break; -case 28: this.$ = $$[$0]; -break; -case 29: this.$ = new yy.StringNode($$[$0]); -break; -case 30: this.$ = new yy.IntegerNode($$[$0]); -break; -case 31: this.$ = new yy.BooleanNode($$[$0]); -break; -case 32: this.$ = new yy.DataNode($$[$0]); -break; -case 33: this.$ = new yy.HashNode($$[$0]); -break; -case 34: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; -break; -case 35: this.$ = [$$[$0]]; -break; -case 36: this.$ = [$$[$0-2], $$[$0]]; -break; -case 37: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]; -break; -case 38: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]; -break; -case 39: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]; -break; -case 40: this.$ = [$$[$0-2], new yy.DataNode($$[$0])]; -break; -case 41: this.$ = new yy.IdNode($$[$0]); -break; -case 42: $$[$0-2].push($$[$0]); this.$ = $$[$0-2]; -break; -case 43: this.$ = [$$[$0]]; -break; -} -}, -table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,27:[1,24],34:[1,26],36:25},{17:27,21:23,27:[1,24],34:[1,26],36:25},{17:28,21:23,27:[1,24],34:[1,26],36:25},{17:29,21:23,27:[1,24],34:[1,26],36:25},{21:30,34:[1,26],36:25},{1:[2,1]},{6:31,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,32],21:23,27:[1,24],34:[1,26],36:25},{10:33,20:[1,34]},{10:35,20:[1,34]},{18:[1,36]},{18:[2,24],21:41,25:37,26:38,27:[1,45],28:39,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,25]},{18:[2,41],27:[2,41],29:[2,41],30:[2,41],31:[2,41],34:[2,41],37:[1,48]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],37:[2,43]},{18:[1,49]},{18:[1,50]},{18:[1,51]},{18:[1,52],21:53,34:[1,26],36:25},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:54,34:[1,26],36:25},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:41,26:55,27:[1,45],28:56,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,23]},{18:[2,27],27:[2,27],29:[2,27],30:[2,27],31:[2,27],34:[2,27]},{18:[2,33],33:57,34:[1,58]},{18:[2,28],27:[2,28],29:[2,28],30:[2,28],31:[2,28],34:[2,28]},{18:[2,29],27:[2,29],29:[2,29],30:[2,29],31:[2,29],34:[2,29]},{18:[2,30],27:[2,30],29:[2,30],30:[2,30],31:[2,30],34:[2,30]},{18:[2,31],27:[2,31],29:[2,31],30:[2,31],31:[2,31],34:[2,31]},{18:[2,32],27:[2,32],29:[2,32],30:[2,32],31:[2,32],34:[2,32]},{18:[2,35],34:[2,35]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],35:[1,59],37:[2,43]},{34:[1,60]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,61]},{18:[1,62]},{18:[2,21]},{18:[2,26],27:[2,26],29:[2,26],30:[2,26],31:[2,26],34:[2,26]},{18:[2,34],34:[2,34]},{35:[1,59]},{21:63,27:[1,67],29:[1,64],30:[1,65],31:[1,66],34:[1,26],36:25},{18:[2,42],27:[2,42],29:[2,42],30:[2,42],31:[2,42],34:[2,42],37:[2,42]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,36],34:[2,36]},{18:[2,37],34:[2,37]},{18:[2,38],34:[2,38]},{18:[2,39],34:[2,39]},{18:[2,40],34:[2,40]}], -defaultActions: {16:[2,1],24:[2,25],38:[2,23],55:[2,21]}, -parseError: function parseError(str, hash) { - throw new Error(str); -}, -parse: function parse(input) { - var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; - this.lexer.setInput(input); - this.lexer.yy = this.yy; - this.yy.lexer = this.lexer; - this.yy.parser = this; - if (typeof this.lexer.yylloc == "undefined") - this.lexer.yylloc = {}; - var yyloc = this.lexer.yylloc; - lstack.push(yyloc); - var ranges = this.lexer.options && this.lexer.options.ranges; - if (typeof this.yy.parseError === "function") - this.parseError = this.yy.parseError; - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - function lex() { - var token; - token = self.lexer.lex() || 1; - if (typeof token !== "number") { - token = self.symbols_[token] || token; - } - return token; - } - var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == "undefined") { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === "undefined" || !action.length || !action[0]) { - var errStr = ""; - if (!recovering) { - expected = []; - for (p in table[state]) - if (this.terminals_[p] && p > 2) { - expected.push("'" + this.terminals_[p] + "'"); - } - if (this.lexer.showPosition) { - errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; - } else { - errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); - } - this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); - } - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(this.lexer.yytext); - lstack.push(this.lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = this.lexer.yyleng; - yytext = this.lexer.yytext; - yylineno = this.lexer.yylineno; - yyloc = this.lexer.yylloc; - if (recovering > 0) - recovering--; - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; - if (ranges) { - yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; - } - r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); - if (typeof r !== "undefined") { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; -} -}; -/* Jison generated lexer */ -var lexer = (function(){ -var lexer = ({EOF:1, -parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, -setInput:function (input) { - this._input = input; - this._more = this._less = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; - if (this.options.ranges) this.yylloc.range = [0,0]; - this.offset = 0; - return this; - }, -input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) this.yylloc.range[1]++; - - this._input = this._input.slice(1); - return ch; - }, -unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length-len-1); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length-1); - this.matched = this.matched.substr(0, this.matched.length-1); - - if (lines.length-1) this.yylineno -= lines.length-1; - var r = this.yylloc.range; - - this.yylloc = {first_line: this.yylloc.first_line, - last_line: this.yylineno+1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: - this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - return this; - }, -more:function () { - this._more = true; - return this; - }, -less:function (n) { - this.unput(this.match.slice(n)); - }, -pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, -upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); - }, -showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c+"^"; - }, -next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) this.done = true; - - var token, - match, - tempMatch, - index, - col, - lines; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i=0;i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (!this.options.flex) break; - } - } - if (match) { - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) this.yylineno += lines.length; - this.yylloc = {first_line: this.yylloc.last_line, - last_line: this.yylineno+1, - first_column: this.yylloc.last_column, - last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); - if (this.done && this._input) this.done = false; - if (token) return token; - else return; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), - {text: "", token: null, line: this.yylineno}); - } - }, -lex:function lex() { - var r = this.next(); - if (typeof r !== 'undefined') { - return r; - } else { - return this.lex(); - } - }, -begin:function begin(condition) { - this.conditionStack.push(condition); - }, -popState:function popState() { - return this.conditionStack.pop(); - }, -_currentRules:function _currentRules() { - return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; - }, -topState:function () { - return this.conditionStack[this.conditionStack.length-2]; - }, -pushState:function begin(condition) { - this.begin(condition); - }}); -lexer.options = {}; -lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { - -var YYSTATE=YY_START -switch($avoiding_name_collisions) { -case 0: - if(yy_.yytext.slice(-1) !== "\\") this.begin("mu"); - if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu"); - if(yy_.yytext) return 14; - -break; -case 1: return 14; -break; -case 2: - if(yy_.yytext.slice(-1) !== "\\") this.popState(); - if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1); - return 14; - -break; -case 3: return 24; -break; -case 4: return 16; -break; -case 5: return 20; -break; -case 6: return 19; -break; -case 7: return 19; -break; -case 8: return 23; -break; -case 9: return 23; -break; -case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; -break; -case 11: return 22; -break; -case 12: return 35; -break; -case 13: return 34; -break; -case 14: return 34; -break; -case 15: return 37; -break; -case 16: /*ignore whitespace*/ -break; -case 17: this.popState(); return 18; -break; -case 18: this.popState(); return 18; -break; -case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29; -break; -case 20: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29; -break; -case 21: yy_.yytext = yy_.yytext.substr(1); return 27; -break; -case 22: return 31; -break; -case 23: return 31; -break; -case 24: return 30; -break; -case 25: return 34; -break; -case 26: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 34; -break; -case 27: return 'INVALID'; -break; -case 28: return 5; -break; -} -}; -lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; -lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,28],"inclusive":true}}; -return lexer;})() -parser.lexer = lexer; -function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; -return new Parser; -})(); -if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = handlebars; -exports.Parser = handlebars.Parser; -exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); } -exports.main = function commonjsMain(args) { - if (!args[1]) - throw new Error('Usage: '+args[0]+' FILE'); - var source, cwd; - if (typeof process !== 'undefined') { - source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8"); - } else { - source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"}); - } - return exports.parser.parse(source); -} -if (typeof module !== 'undefined' && require.main === module) { - exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); -} -}; -; -// lib/handlebars/compiler/base.js -Handlebars.Parser = handlebars; - -Handlebars.parse = function(string) { - Handlebars.Parser.yy = Handlebars.AST; - return Handlebars.Parser.parse(string); -}; - -Handlebars.print = function(ast) { - return new Handlebars.PrintVisitor().accept(ast); -}; - -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, - - // override in the host environment - log: function(level, str) {} -}; - -Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; -; -// lib/handlebars/compiler/ast.js -(function() { - - Handlebars.AST = {}; - - Handlebars.AST.ProgramNode = function(statements, inverse) { - this.type = "program"; - this.statements = statements; - if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); } - }; - - Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) { - this.type = "mustache"; - this.escaped = !unescaped; - this.hash = hash; - - var id = this.id = rawParams[0]; - var params = this.params = rawParams.slice(1); - - // a mustache is an eligible helper if: - // * its id is simple (a single part, not `this` or `..`) - var eligibleHelper = this.eligibleHelper = id.isSimple; - - // a mustache is definitely a helper if: - // * it is an eligible helper, and - // * it has at least one parameter or hash segment - this.isHelper = eligibleHelper && (params.length || hash); - - // if a mustache is an eligible helper but not a definite - // helper, it is ambiguous, and will be resolved in a later - // pass or at runtime. - }; - - Handlebars.AST.PartialNode = function(id, context) { - this.type = "partial"; - - // TODO: disallow complex IDs - - this.id = id; - this.context = context; - }; - - var verifyMatch = function(open, close) { - if(open.original !== close.original) { - throw new Handlebars.Exception(open.original + " doesn't match " + close.original); - } - }; - - Handlebars.AST.BlockNode = function(mustache, program, inverse, close) { - verifyMatch(mustache.id, close); - this.type = "block"; - this.mustache = mustache; - this.program = program; - this.inverse = inverse; - - if (this.inverse && !this.program) { - this.isInverse = true; - } - }; - - Handlebars.AST.ContentNode = function(string) { - this.type = "content"; - this.string = string; - }; - - Handlebars.AST.HashNode = function(pairs) { - this.type = "hash"; - this.pairs = pairs; - }; - - Handlebars.AST.IdNode = function(parts) { - this.type = "ID"; - this.original = parts.join("."); - - var dig = [], depth = 0; - - for(var i=0,l=parts.length; i<l; i++) { - var part = parts[i]; - - if(part === "..") { depth++; } - else if(part === "." || part === "this") { this.isScoped = true; } - else { dig.push(part); } - } - - this.parts = dig; - this.string = dig.join('.'); - this.depth = depth; - - // an ID is simple if it only has one part, and that part is not - // `..` or `this`. - this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; - }; - - Handlebars.AST.DataNode = function(id) { - this.type = "DATA"; - this.id = id; - }; - - Handlebars.AST.StringNode = function(string) { - this.type = "STRING"; - this.string = string; - }; - - Handlebars.AST.IntegerNode = function(integer) { - this.type = "INTEGER"; - this.integer = integer; - }; - - Handlebars.AST.BooleanNode = function(bool) { - this.type = "BOOLEAN"; - this.bool = bool; - }; - - Handlebars.AST.CommentNode = function(comment) { - this.type = "comment"; - this.comment = comment; - }; - -})();; -// lib/handlebars/utils.js -Handlebars.Exception = function(message) { - var tmp = Error.prototype.constructor.apply(this, arguments); - - for (var p in tmp) { - if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; } - } - - this.message = tmp.message; -}; -Handlebars.Exception.prototype = new Error(); - -// Build out our basic SafeString type -Handlebars.SafeString = function(string) { - this.string = string; -}; -Handlebars.SafeString.prototype.toString = function() { - return this.string.toString(); -}; - -(function() { - var escape = { - "&": "&amp;", - "<": "&lt;", - ">": "&gt;", - '"': "&quot;", - "'": "&#x27;", - "`": "&#x60;" - }; - - var badChars = /[&<>"'`]/g; - var possible = /[&<>"'`]/; - - var escapeChar = function(chr) { - return escape[chr] || "&amp;"; - }; - - Handlebars.Utils = { - escapeExpression: function(string) { - // don't escape SafeStrings, since they're already safe - if (string instanceof Handlebars.SafeString) { - return string.toString(); - } else if (string == null || string === false) { - return ""; - } - - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - }, - - isEmpty: function(value) { - if (typeof value === "undefined") { - return true; - } else if (value === null) { - return true; - } else if (value === false) { - return true; - } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { - return true; - } else { - return false; - } - } - }; -})();; -// lib/handlebars/compiler/compiler.js - -/*jshint eqnull:true*/ -Handlebars.Compiler = function() {}; -Handlebars.JavaScriptCompiler = function() {}; - -(function(Compiler, JavaScriptCompiler) { - // the foundHelper register will disambiguate helper lookup from finding a - // function in a context. This is necessary for mustache compatibility, which - // requires that context functions in blocks are evaluated by blockHelperMissing, - // and then proceed as if the resulting value was provided to blockHelperMissing. - - Compiler.prototype = { - compiler: Compiler, - - disassemble: function() { - var opcodes = this.opcodes, opcode, out = [], params, param; - - for (var i=0, l=opcodes.length; i<l; i++) { - opcode = opcodes[i]; - - if (opcode.opcode === 'DECLARE') { - out.push("DECLARE " + opcode.name + "=" + opcode.value); - } else { - params = []; - for (var j=0; j<opcode.args.length; j++) { - param = opcode.args[j]; - if (typeof param === "string") { - param = "\"" + param.replace("\n", "\\n") + "\""; - } - params.push(param); - } - out.push(opcode.opcode + " " + params.join(" ")); - } - } - - return out.join("\n"); - }, - - guid: 0, - - compile: function(program, options) { - this.children = []; - this.depths = {list: []}; - this.options = options; - - // These changes will propagate to the other compiler components - var knownHelpers = this.options.knownHelpers; - this.options.knownHelpers = { - 'helperMissing': true, - 'blockHelperMissing': true, - 'each': true, - 'if': true, - 'unless': true, - 'with': true, - 'log': true - }; - if (knownHelpers) { - for (var name in knownHelpers) { - this.options.knownHelpers[name] = knownHelpers[name]; - } - } - - return this.program(program); - }, - - accept: function(node) { - return this[node.type](node); - }, - - program: function(program) { - var statements = program.statements, statement; - this.opcodes = []; - - for(var i=0, l=statements.length; i<l; i++) { - statement = statements[i]; - this[statement.type](statement); - } - this.isSimple = l === 1; - - this.depths.list = this.depths.list.sort(function(a, b) { - return a - b; - }); - - return this; - }, - - compileProgram: function(program) { - var result = new this.compiler().compile(program, this.options); - var guid = this.guid++, depth; - - this.usePartial = this.usePartial || result.usePartial; - - this.children[guid] = result; - - for(var i=0, l=result.depths.list.length; i<l; i++) { - depth = result.depths.list[i]; - - if(depth < 2) { continue; } - else { this.addDepth(depth - 1); } - } - - return guid; - }, - - block: function(block) { - var mustache = block.mustache, - program = block.program, - inverse = block.inverse; - - if (program) { - program = this.compileProgram(program); - } - - if (inverse) { - inverse = this.compileProgram(inverse); - } - - var type = this.classifyMustache(mustache); - - if (type === "helper") { - this.helperMustache(mustache, program, inverse); - } else if (type === "simple") { - this.simpleMustache(mustache); - - // now that the simple mustache is resolved, we need to - // evaluate it by executing `blockHelperMissing` - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - this.opcode('pushLiteral', '{}'); - this.opcode('blockValue'); - } else { - this.ambiguousMustache(mustache, program, inverse); - - // now that the simple mustache is resolved, we need to - // evaluate it by executing `blockHelperMissing` - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - this.opcode('pushLiteral', '{}'); - this.opcode('ambiguousBlockValue'); - } - - this.opcode('append'); - }, - - hash: function(hash) { - var pairs = hash.pairs, pair, val; - - this.opcode('push', '{}'); - - for(var i=0, l=pairs.length; i<l; i++) { - pair = pairs[i]; - val = pair[1]; - - this.accept(val); - this.opcode('assignToHash', pair[0]); - } - }, - - partial: function(partial) { - var id = partial.id; - this.usePartial = true; - - if(partial.context) { - this.ID(partial.context); - } else { - this.opcode('push', 'depth0'); - } - - this.opcode('invokePartial', id.original); - this.opcode('append'); - }, - - content: function(content) { - this.opcode('appendContent', content.string); - }, - - mustache: function(mustache) { - var options = this.options; - var type = this.classifyMustache(mustache); - - if (type === "simple") { - this.simpleMustache(mustache); - } else if (type === "helper") { - this.helperMustache(mustache); - } else { - this.ambiguousMustache(mustache); - } - - if(mustache.escaped && !options.noEscape) { - this.opcode('appendEscaped'); - } else { - this.opcode('append'); - } - }, - - ambiguousMustache: function(mustache, program, inverse) { - var id = mustache.id, name = id.parts[0]; - - this.opcode('getContext', id.depth); - - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - - this.opcode('invokeAmbiguous', name); - }, - - simpleMustache: function(mustache, program, inverse) { - var id = mustache.id; - - if (id.type === 'DATA') { - this.DATA(id); - } else if (id.parts.length) { - this.ID(id); - } else { - // Simplified ID for `this` - this.addDepth(id.depth); - this.opcode('getContext', id.depth); - this.opcode('pushContext'); - } - - this.opcode('resolvePossibleLambda'); - }, - - helperMustache: function(mustache, program, inverse) { - var params = this.setupFullMustacheParams(mustache, program, inverse), - name = mustache.id.parts[0]; - - if (this.options.knownHelpers[name]) { - this.opcode('invokeKnownHelper', params.length, name); - } else if (this.knownHelpersOnly) { - throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name); - } else { - this.opcode('invokeHelper', params.length, name); - } - }, - - ID: function(id) { - this.addDepth(id.depth); - this.opcode('getContext', id.depth); - - var name = id.parts[0]; - if (!name) { - this.opcode('pushContext'); - } else { - this.opcode('lookupOnContext', id.parts[0]); - } - - for(var i=1, l=id.parts.length; i<l; i++) { - this.opcode('lookup', id.parts[i]); - } - }, - - DATA: function(data) { - this.options.data = true; - this.opcode('lookupData', data.id); - }, - - STRING: function(string) { - this.opcode('pushString', string.string); - }, - - INTEGER: function(integer) { - this.opcode('pushLiteral', integer.integer); - }, - - BOOLEAN: function(bool) { - this.opcode('pushLiteral', bool.bool); - }, - - comment: function() {}, - - // HELPERS - opcode: function(name) { - this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) }); - }, - - declare: function(name, value) { - this.opcodes.push({ opcode: 'DECLARE', name: name, value: value }); - }, - - addDepth: function(depth) { - if(isNaN(depth)) { throw new Error("EWOT"); } - if(depth === 0) { return; } - - if(!this.depths[depth]) { - this.depths[depth] = true; - this.depths.list.push(depth); - } - }, - - classifyMustache: function(mustache) { - var isHelper = mustache.isHelper; - var isEligible = mustache.eligibleHelper; - var options = this.options; - - // if ambiguous, we can possibly resolve the ambiguity now - if (isEligible && !isHelper) { - var name = mustache.id.parts[0]; - - if (options.knownHelpers[name]) { - isHelper = true; - } else if (options.knownHelpersOnly) { - isEligible = false; - } - } - - if (isHelper) { return "helper"; } - else if (isEligible) { return "ambiguous"; } - else { return "simple"; } - }, - - pushParams: function(params) { - var i = params.length, param; - - while(i--) { - param = params[i]; - - if(this.options.stringParams) { - if(param.depth) { - this.addDepth(param.depth); - } - - this.opcode('getContext', param.depth || 0); - this.opcode('pushStringParam', param.string); - } else { - this[param.type](param); - } - } - }, - - setupMustacheParams: function(mustache) { - var params = mustache.params; - this.pushParams(params); - - if(mustache.hash) { - this.hash(mustache.hash); - } else { - this.opcode('pushLiteral', '{}'); - } - - return params; - }, - - // this will replace setupMustacheParams when we're done - setupFullMustacheParams: function(mustache, program, inverse) { - var params = mustache.params; - this.pushParams(params); - - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - - if(mustache.hash) { - this.hash(mustache.hash); - } else { - this.opcode('pushLiteral', '{}'); - } - - return params; - } - }; - - var Literal = function(value) { - this.value = value; - }; - - JavaScriptCompiler.prototype = { - // PUBLIC API: You can override these methods in a subclass to provide - // alternative compiled forms for name lookup and buffering semantics - nameLookup: function(parent, name, type) { - if (/^[0-9]+$/.test(name)) { - return parent + "[" + name + "]"; - } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { - return parent + "." + name; - } - else { - return parent + "['" + name + "']"; - } - }, - - appendToBuffer: function(string) { - if (this.environment.isSimple) { - return "return " + string + ";"; - } else { - return "buffer += " + string + ";"; - } - }, - - initializeBuffer: function() { - return this.quotedString(""); - }, - - namespace: "Handlebars", - // END PUBLIC API - - compile: function(environment, options, context, asObject) { - this.environment = environment; - this.options = options || {}; - - Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n"); - - this.name = this.environment.name; - this.isChild = !!context; - this.context = context || { - programs: [], - aliases: { } - }; - - this.preamble(); - - this.stackSlot = 0; - this.stackVars = []; - this.registers = { list: [] }; - this.compileStack = []; - - this.compileChildren(environment, options); - - var opcodes = environment.opcodes, opcode; - - this.i = 0; - - for(l=opcodes.length; this.i<l; this.i++) { - opcode = opcodes[this.i]; - - if(opcode.opcode === 'DECLARE') { - this[opcode.name] = opcode.value; - } else { - this[opcode.opcode].apply(this, opcode.args); - } - } - - return this.createFunctionContext(asObject); - }, - - nextOpcode: function() { - var opcodes = this.environment.opcodes, opcode = opcodes[this.i + 1]; - return opcodes[this.i + 1]; - }, - - eat: function(opcode) { - this.i = this.i + 1; - }, - - preamble: function() { - var out = []; - - if (!this.isChild) { - var namespace = this.namespace; - var copies = "helpers = helpers || " + namespace + ".helpers;"; - if (this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; } - if (this.options.data) { copies = copies + " data = data || {};"; } - out.push(copies); - } else { - out.push(''); - } - - if (!this.environment.isSimple) { - out.push(", buffer = " + this.initializeBuffer()); - } else { - out.push(""); - } - - // track the last context pushed into place to allow skipping the - // getContext opcode when it would be a noop - this.lastContext = 0; - this.source = out; - }, - - createFunctionContext: function(asObject) { - var locals = this.stackVars.concat(this.registers.list); - - if(locals.length > 0) { - this.source[1] = this.source[1] + ", " + locals.join(", "); - } - - // Generate minimizer alias mappings - if (!this.isChild) { - var aliases = []; - for (var alias in this.context.aliases) { - this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; - } - } - - if (this.source[1]) { - this.source[1] = "var " + this.source[1].substring(2) + ";"; - } - - // Merge children - if (!this.isChild) { - this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; - } - - if (!this.environment.isSimple) { - this.source.push("return buffer;"); - } - - var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; - - for(var i=0, l=this.environment.depths.list.length; i<l; i++) { - params.push("depth" + this.environment.depths.list[i]); - } - - if (asObject) { - params.push(this.source.join("\n ")); - - return Function.apply(this, params); - } else { - var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}'; - Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n"); - return functionSource; - } - }, - - // [blockValue] - // - // On stack, before: hash, inverse, program, value - // On stack, after: return value of blockHelperMissing - // - // The purpose of this opcode is to take a block of the form - // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and - // replace it on the stack with the result of properly - // invoking blockHelperMissing. - blockValue: function() { - this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; - - var params = ["depth0"]; - this.setupParams(0, params); - - this.replaceStack(function(current) { - params.splice(1, 0, current); - return current + " = blockHelperMissing.call(" + params.join(", ") + ")"; - }); - }, - - // [ambiguousBlockValue] - // - // On stack, before: hash, inverse, program, value - // Compiler value, before: lastHelper=value of last found helper, if any - // On stack, after, if no lastHelper: same as [blockValue] - // On stack, after, if lastHelper: value - ambiguousBlockValue: function() { - this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; - - var params = ["depth0"]; - this.setupParams(0, params); - - var current = this.topStack(); - params.splice(1, 0, current); - - this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); - }, - - // [appendContent] - // - // On stack, before: ... - // On stack, after: ... - // - // Appends the string value of `content` to the current buffer - appendContent: function(content) { - this.source.push(this.appendToBuffer(this.quotedString(content))); - }, - - // [append] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Coerces `value` to a String and appends it to the current buffer. - // - // If `value` is truthy, or 0, it is coerced into a string and appended - // Otherwise, the empty string is appended - append: function() { - var local = this.popStack(); - this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }"); - if (this.environment.isSimple) { - this.source.push("else { " + this.appendToBuffer("''") + " }"); - } - }, - - // [appendEscaped] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Escape `value` and append it to the buffer - appendEscaped: function() { - var opcode = this.nextOpcode(), extra = ""; - this.context.aliases.escapeExpression = 'this.escapeExpression'; - - if(opcode && opcode.opcode === 'appendContent') { - extra = " + " + this.quotedString(opcode.args[0]); - this.eat(opcode); - } - - this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra)); - }, - - // [getContext] - // - // On stack, before: ... - // On stack, after: ... - // Compiler value, after: lastContext=depth - // - // Set the value of the `lastContext` compiler value to the depth - getContext: function(depth) { - if(this.lastContext !== depth) { - this.lastContext = depth; - } - }, - - // [lookupOnContext] - // - // On stack, before: ... - // On stack, after: currentContext[name], ... - // - // Looks up the value of `name` on the current context and pushes - // it onto the stack. - lookupOnContext: function(name) { - this.pushStack(this.nameLookup('depth' + this.lastContext, name, 'context')); - }, - - // [pushContext] - // - // On stack, before: ... - // On stack, after: currentContext, ... - // - // Pushes the value of the current context onto the stack. - pushContext: function() { - this.pushStackLiteral('depth' + this.lastContext); - }, - - // [resolvePossibleLambda] - // - // On stack, before: value, ... - // On stack, after: resolved value, ... - // - // If the `value` is a lambda, replace it on the stack by - // the return value of the lambda - resolvePossibleLambda: function() { - this.context.aliases.functionType = '"function"'; - - this.replaceStack(function(current) { - return "typeof " + current + " === functionType ? " + current + "() : " + current; - }); - }, - - // [lookup] - // - // On stack, before: value, ... - // On stack, after: value[name], ... - // - // Replace the value on the stack with the result of looking - // up `name` on `value` - lookup: function(name) { - this.replaceStack(function(current) { - return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context'); - }); - }, - - // [lookupData] - // - // On stack, before: ... - // On stack, after: data[id], ... - // - // Push the result of looking up `id` on the current data - lookupData: function(id) { - this.pushStack(this.nameLookup('data', id, 'data')); - }, - - // [pushStringParam] - // - // On stack, before: ... - // On stack, after: string, currentContext, ... - // - // This opcode is designed for use in string mode, which - // provides the string value of a parameter along with its - // depth rather than resolving it immediately. - pushStringParam: function(string) { - this.pushStackLiteral('depth' + this.lastContext); - this.pushString(string); - }, - - // [pushString] - // - // On stack, before: ... - // On stack, after: quotedString(string), ... - // - // Push a quoted version of `string` onto the stack - pushString: function(string) { - this.pushStackLiteral(this.quotedString(string)); - }, - - // [push] - // - // On stack, before: ... - // On stack, after: expr, ... - // - // Push an expression onto the stack - push: function(expr) { - this.pushStack(expr); - }, - - // [pushLiteral] - // - // On stack, before: ... - // On stack, after: value, ... - // - // Pushes a value onto the stack. This operation prevents - // the compiler from creating a temporary variable to hold - // it. - pushLiteral: function(value) { - this.pushStackLiteral(value); - }, - - // [pushProgram] - // - // On stack, before: ... - // On stack, after: program(guid), ... - // - // Push a program expression onto the stack. This takes - // a compile-time guid and converts it into a runtime-accessible - // expression. - pushProgram: function(guid) { - if (guid != null) { - this.pushStackLiteral(this.programExpression(guid)); - } else { - this.pushStackLiteral(null); - } - }, - - // [invokeHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // Pops off the helper's parameters, invokes the helper, - // and pushes the helper's return value onto the stack. - // - // If the helper is not found, `helperMissing` is called. - invokeHelper: function(paramSize, name) { - this.context.aliases.helperMissing = 'helpers.helperMissing'; - - var helper = this.lastHelper = this.setupHelper(paramSize, name); - this.register('foundHelper', helper.name); - - this.pushStack("foundHelper ? foundHelper.call(" + - helper.callParams + ") " + ": helperMissing.call(" + - helper.helperMissingParams + ")"); - }, - - // [invokeKnownHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // This operation is used when the helper is known to exist, - // so a `helperMissing` fallback is not required. - invokeKnownHelper: function(paramSize, name) { - var helper = this.setupHelper(paramSize, name); - this.pushStack(helper.name + ".call(" + helper.callParams + ")"); - }, - - // [invokeAmbiguous] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of disambiguation - // - // This operation is used when an expression like `{{foo}}` - // is provided, but we don't know at compile-time whether it - // is a helper or a path. - // - // This operation emits more code than the other options, - // and can be avoided by passing the `knownHelpers` and - // `knownHelpersOnly` flags at compile-time. - invokeAmbiguous: function(name) { - this.context.aliases.functionType = '"function"'; - - this.pushStackLiteral('{}'); - var helper = this.setupHelper(0, name); - - var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - this.register('foundHelper', helperName); - - var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context'); - var nextStack = this.nextStack(); - - this.source.push('if (foundHelper) { ' + nextStack + ' = foundHelper.call(' + helper.callParams + '); }'); - this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '() : ' + nextStack + '; }'); - }, - - // [invokePartial] - // - // On stack, before: context, ... - // On stack after: result of partial invocation - // - // This operation pops off a context, invokes a partial with that context, - // and pushes the result of the invocation back. - invokePartial: function(name) { - var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"]; - - if (this.options.data) { - params.push("data"); - } - - this.context.aliases.self = "this"; - this.pushStack("self.invokePartial(" + params.join(", ") + ");"); - }, - - // [assignToHash] - // - // On stack, before: value, hash, ... - // On stack, after: hash, ... - // - // Pops a value and hash off the stack, assigns `hash[key] = value` - // and pushes the hash back onto the stack. - assignToHash: function(key) { - var value = this.popStack(); - var hash = this.topStack(); - - this.source.push(hash + "['" + key + "'] = " + value + ";"); - }, - - // HELPERS - - compiler: JavaScriptCompiler, - - compileChildren: function(environment, options) { - var children = environment.children, child, compiler; - - for(var i=0, l=children.length; i<l; i++) { - child = children[i]; - compiler = new this.compiler(); - - this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children - var index = this.context.programs.length; - child.index = index; - child.name = 'program' + index; - this.context.programs[index] = compiler.compile(child, options, this.context); - } - }, - - programExpression: function(guid) { - this.context.aliases.self = "this"; - - if(guid == null) { - return "self.noop"; - } - - var child = this.environment.children[guid], - depths = child.depths.list, depth; - - var programParams = [child.index, child.name, "data"]; - - for(var i=0, l = depths.length; i<l; i++) { - depth = depths[i]; - - if(depth === 1) { programParams.push("depth0"); } - else { programParams.push("depth" + (depth - 1)); } - } - - if(depths.length === 0) { - return "self.program(" + programParams.join(", ") + ")"; - } else { - programParams.shift(); - return "self.programWithDepth(" + programParams.join(", ") + ")"; - } - }, - - register: function(name, val) { - this.useRegister(name); - this.source.push(name + " = " + val + ";"); - }, - - useRegister: function(name) { - if(!this.registers[name]) { - this.registers[name] = true; - this.registers.list.push(name); - } - }, - - pushStackLiteral: function(item) { - this.compileStack.push(new Literal(item)); - return item; - }, - - pushStack: function(item) { - this.source.push(this.incrStack() + " = " + item + ";"); - this.compileStack.push("stack" + this.stackSlot); - return "stack" + this.stackSlot; - }, - - replaceStack: function(callback) { - var item = callback.call(this, this.topStack()); - - this.source.push(this.topStack() + " = " + item + ";"); - return "stack" + this.stackSlot; - }, - - nextStack: function(skipCompileStack) { - var name = this.incrStack(); - this.compileStack.push("stack" + this.stackSlot); - return name; - }, - - incrStack: function() { - this.stackSlot++; - if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } - return "stack" + this.stackSlot; - }, - - popStack: function() { - var item = this.compileStack.pop(); - - if (item instanceof Literal) { - return item.value; - } else { - this.stackSlot--; - return item; - } - }, - - topStack: function() { - var item = this.compileStack[this.compileStack.length - 1]; - - if (item instanceof Literal) { - return item.value; - } else { - return item; - } - }, - - quotedString: function(str) { - return '"' + str - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') + '"'; - }, - - setupHelper: function(paramSize, name) { - var params = []; - this.setupParams(paramSize, params); - var foundHelper = this.nameLookup('helpers', name, 'helper'); - - return { - params: params, - name: foundHelper, - callParams: ["depth0"].concat(params).join(", "), - helperMissingParams: ["depth0", this.quotedString(name)].concat(params).join(", ") - }; - }, - - // the params and contexts arguments are passed in arrays - // to fill in - setupParams: function(paramSize, params) { - var options = [], contexts = [], param, inverse, program; - - options.push("hash:" + this.popStack()); - - inverse = this.popStack(); - program = this.popStack(); - - // Avoid setting fn and inverse if neither are set. This allows - // helpers to do a check for `if (options.fn)` - if (program || inverse) { - if (!program) { - this.context.aliases.self = "this"; - program = "self.noop"; - } - - if (!inverse) { - this.context.aliases.self = "this"; - inverse = "self.noop"; - } - - options.push("inverse:" + inverse); - options.push("fn:" + program); - } - - for(var i=0; i<paramSize; i++) { - param = this.popStack(); - params.push(param); - - if(this.options.stringParams) { - contexts.push(this.popStack()); - } - } - - if (this.options.stringParams) { - options.push("contexts:[" + contexts.join(",") + "]"); - } - - if(this.options.data) { - options.push("data:data"); - } - - params.push("{" + options.join(",") + "}"); - return params.join(", "); - } - }; - - var reservedWords = ( - "break else new var" + - " case finally return void" + - " catch for switch while" + - " continue function this with" + - " default if throw" + - " delete in try" + - " do instanceof typeof" + - " abstract enum int short" + - " boolean export interface static" + - " byte extends long super" + - " char final native synchronized" + - " class float package throws" + - " const goto private transient" + - " debugger implements protected volatile" + - " double import public let yield" - ).split(" "); - - var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; - - for(var i=0, l=reservedWords.length; i<l; i++) { - compilerWords[reservedWords[i]] = true; - } - - JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { - if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) { - return true; - } - return false; - }; - -})(Handlebars.Compiler, Handlebars.JavaScriptCompiler); - -Handlebars.precompile = function(string, options) { - options = options || {}; - - var ast = Handlebars.parse(string); - var environment = new Handlebars.Compiler().compile(ast, options); - return new Handlebars.JavaScriptCompiler().compile(environment, options); -}; - -Handlebars.compile = function(string, options) { - options = options || {}; - - var compiled; - function compile() { - var ast = Handlebars.parse(string); - var environment = new Handlebars.Compiler().compile(ast, options); - var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true); - return Handlebars.template(templateSpec); - } - - // Template is only compiled on first use and cached after that point. - return function(context, options) { - if (!compiled) { - compiled = compile(); - } - return compiled.call(this, context, options); - }; -}; -; -// lib/handlebars/runtime.js -Handlebars.VM = { - template: function(templateSpec) { - // Just add water - var container = { - escapeExpression: Handlebars.Utils.escapeExpression, - invokePartial: Handlebars.VM.invokePartial, - programs: [], - program: function(i, fn, data) { - var programWrapper = this.programs[i]; - if(data) { - return Handlebars.VM.program(fn, data); - } else if(programWrapper) { - return programWrapper; - } else { - programWrapper = this.programs[i] = Handlebars.VM.program(fn); - return programWrapper; - } - }, - programWithDepth: Handlebars.VM.programWithDepth, - noop: Handlebars.VM.noop - }; - - return function(context, options) { - options = options || {}; - return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); - }; - }, - - programWithDepth: function(fn, data, $depth) { - var args = Array.prototype.slice.call(arguments, 2); - - return function(context, options) { - options = options || {}; - - return fn.apply(this, [context, options.data || data].concat(args)); - }; - }, - program: function(fn, data) { - return function(context, options) { - options = options || {}; - - return fn(context, options.data || data); - }; - }, - noop: function() { return ""; }, - invokePartial: function(partial, name, context, helpers, partials, data) { - var options = { helpers: helpers, partials: partials, data: data }; - - if(partial === undefined) { - throw new Handlebars.Exception("The partial " + name + " could not be found"); - } else if(partial instanceof Function) { - return partial(context, options); - } else if (!Handlebars.compile) { - throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); - } else { - partials[name] = Handlebars.compile(partial, {data: data !== undefined}); - return partials[name](context, options); - } - } -}; - -Handlebars.template = Handlebars.VM.template; -; diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/highlight.7.3.pack.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/highlight.7.3.pack.js deleted file mode 100644 index 9a95a75ea16..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/highlight.7.3.pack.js +++ /dev/null @@ -1 +0,0 @@ -var hljs=new function(){function l(o){return o.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o<p.length;o++){if(e[p[o]]||p[o]=="no-highlight"){return p[o]}}}function c(q){var o=[];(function p(r,s){for(var t=r.firstChild;t;t=t.nextSibling){if(t.nodeType==3){s+=t.nodeValue.length}else{if(t.nodeName=="BR"){s+=1}else{if(t.nodeType==1){o.push({event:"start",offset:s,node:t});s=p(t,s);o.push({event:"stop",offset:s,node:t})}}}}return s})(q,0);return o}function j(x,v,w){var p=0;var y="";var r=[];function t(){if(x.length&&v.length){if(x[0].offset!=v[0].offset){return(x[0].offset<v[0].offset)?x:v}else{return v[0].event=="start"?x:v}}else{return x.length?x:v}}function s(A){function z(B){return" "+B.nodeName+'="'+l(B.value)+'"'}return"<"+A.nodeName+Array.prototype.map.call(A.attributes,z).join("")+">"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("</"+o.nodeName.toLowerCase()+">")}while(o!=u.node);r.splice(q,1);while(q<r.length){y+=s(r[q]);q++}}}}return y+l(w.substr(p))}function f(q){function o(s,r){return RegExp(s,"m"+(q.cI?"i":"")+(r?"g":""))}function p(y,w){if(y.compiled){return}y.compiled=true;var s=[];if(y.k){var r={};function z(A,t){t.split(" ").forEach(function(B){var C=B.split("|");r[C[0]]=[A,C[1]?Number(C[1]):1];s.push(C[0])})}y.lR=o(y.l||hljs.IR,true);if(typeof y.k=="string"){z("keyword",y.k)}else{for(var x in y.k){if(!y.k.hasOwnProperty(x)){continue}z(x,y.k[x])}}y.k=r}if(w){if(y.bWK){y.b="\\b("+s.join("|")+")\\s"}y.bR=o(y.b?y.b:"\\B|\\b");if(!y.e&&!y.eW){y.e="\\B|\\b"}if(y.e){y.eR=o(y.e)}y.tE=y.e||"";if(y.eW&&w.tE){y.tE+=(y.e?"|":"")+w.tE}}if(y.i){y.iR=o(y.i)}if(y.r===undefined){y.r=1}if(!y.c){y.c=[]}for(var v=0;v<y.c.length;v++){if(y.c[v]=="self"){y.c[v]=y}p(y.c[v],y)}if(y.starts){p(y.starts,w)}var u=[];for(var v=0;v<y.c.length;v++){u.push(y.c[v].b)}if(y.tE){u.push(y.tE)}if(y.i){u.push(y.i)}y.t=u.length?o(u.join("|"),true):{exec:function(t){return null}}}p(q)}function d(D,E){function o(r,M){for(var L=0;L<M.c.length;L++){var K=M.c[L].bR.exec(r);if(K&&K.index==0){return M.c[L]}}}function s(K,r){if(K.e&&K.eR.test(r)){return K}if(K.eW){return s(K.parent,r)}}function t(r,K){return K.i&&K.iR.test(r)}function y(L,r){var K=F.cI?r[0].toLowerCase():r[0];return L.k.hasOwnProperty(K)&&L.k[K]}function G(){var K=l(w);if(!A.k){return K}var r="";var N=0;A.lR.lastIndex=0;var L=A.lR.exec(K);while(L){r+=K.substr(N,L.index-N);var M=y(A,L);if(M){v+=M[1];r+='<span class="'+M[0]+'">'+L[0]+"</span>"}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return'<span class="'+r.language+'">'+r.value+"</span>"}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'<span class="'+L.cN+'">':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+="</span>"}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"<br>")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.xml=function(a){var c="[A-Za-z0-9\\._:-]+";var b={eW:true,c:[{cN:"attribute",b:c,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"<!--",e:"-->",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{title:"style"},c:[b],starts:{e:"</style>",rE:true,sL:"css"}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"title",b:"[^ />]+"},b]}]}}(hljs);hljs.LANGUAGES.json=function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}(hljs); \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery-1.8.0.min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery-1.8.0.min.js deleted file mode 100644 index 066d72c7e3a..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery-1.8.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v@1.8.0 jquery.com | jquery.org/license */ -(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bX(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bV.length;while(e--){b=bV[e]+c;if(b in a)return b}return d}function bY(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function bZ(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bY(c)&&(e[f]=p._data(c,"olddisplay",cb(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b$(a,b,c){var d=bO.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function b_(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bU[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bU[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bU[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bU[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bU[e]+"Width"))||0));return f}function ca(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bP.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+b_(a,b,c||(f?"border":"content"),e)+"px"}function cb(a){if(bR[a])return bR[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bR[a]=c,c}function ch(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||cd.test(a)?d(a,e):ch(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ch(a+"["+e+"]",b[e],c,d);else d(a,b)}function cy(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cz(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cu;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cz(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cz(a,c,d,e,"*",g)),h}function cA(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cB(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cC(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cK(){try{return new a.XMLHttpRequest}catch(b){}}function cL(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cT(){return setTimeout(function(){cM=b},0),cM=p.now()}function cU(a,b){p.each(b,function(b,c){var d=(cS[b]||[]).concat(cS["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cV(a,b,c){var d,e=0,f=0,g=cR.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cM||cT(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cM||cT(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cW(k,j.opts.specialEasing);for(;e<g;e++){d=cR[e].call(j,a,k,j.opts);if(d)return d}return cU(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cW(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cX(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bY(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cb(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cO.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cY(a,b,c,d,e){return new cY.prototype.init(a,b,c,d,e)}function cZ(a,b){var c,d={height:a},e=0;for(;e<4;e+=2-b)c=bU[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function c_(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=r.test(" ")?/^[\s\xA0]+|[\s\xA0]+$/g:/^\s+|\s+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.0",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":a.toString().replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||f.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete"||e.readyState!=="loading"&&e.addEventListener)setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){p.isFunction(c)&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return typeof a=="object"?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length||!d)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/^(?:\{.*\}|\[.*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||++p.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")===0&&(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.shift(),e=p._queueHooks(a,b),f=function(){p.dequeue(a,b)};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),delete e.stop,d.call(a,f,e)),!c.length&&e&&e.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)(d=p._data(g[h],a+"queueHooks"))&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>-1)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,k,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=[].slice.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click")){g=p(this),g.context=this;for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){i={},k=[],g[0]=f;for(d=0;d<q;d++)l=o[d],m=l.selector,i[m]===b&&(i[m]=g.is(m)),i[m]&&k.push(l);k.length&&u.push({elem:f,matches:k})}}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){j=u[d],c.currentTarget=j.elem;for(e=0;e<j.matches.length&&!c.isImmediatePropagationStopped();e++){l=j.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,h=((p.event.special[l.origType]||{}).handle||l.handler).apply(j.elem,r),h!==b&&(c.result=h,h===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{ready:{setup:p.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bd(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)Z(a,b[e],c,d)}function be(a,b,c,d,e,f){var g,h=$.setFilters[b.toLowerCase()];return h||Z.error(b),(a||!(g=e))&&bd(a||"*",d,g=[],e),g.length>0?h(g,c,f):[]}function bf(a,c,d,e,f){var g,h,i,j,k,l,m,n,p=0,q=f.length,s=L.POS,t=new RegExp("^"+s.source+"(?!"+r+")","i"),u=function(){var a=1,c=arguments.length-2;for(;a<c;a++)arguments[a]===b&&(g[a]=b)};for(;p<q;p++){s.exec(""),a=f[p],j=[],i=0,k=e;while(g=s.exec(a)){n=s.lastIndex=g.index+g[0].length;if(n>i){m=a.slice(i,g.index),i=n,l=[c],B.test(m)&&(k&&(l=k),k=e);if(h=H.test(m))m=m.slice(0,-5).replace(B,"$&*");g.length>1&&g[0].replace(t,u),k=be(m,g[1],g[2],l,k,h)}}k?(j=j.concat(k),(m=a.slice(i))&&m!==")"?B.test(m)?bd(m,j,d,e):Z(m,c,d,e?e.concat(k):k):o.apply(d,j)):Z(a,c,d,e)}return q===1?d:Z.uniqueSort(d)}function bg(a,b,c){var d,e,f,g=[],i=0,j=D.exec(a),k=!j.pop()&&!j.pop(),l=k&&a.match(C)||[""],m=$.preFilter,n=$.filter,o=!c&&b!==h;for(;(e=l[i])!=null&&k;i++){g.push(d=[]),o&&(e=" "+e);while(e){k=!1;if(j=B.exec(e))e=e.slice(j[0].length),k=d.push({part:j.pop().replace(A," "),captures:j});for(f in n)(j=L[f].exec(e))&&(!m[f]||(j=m[f](j,b,c)))&&(e=e.slice(j.shift().length),k=d.push({part:f,captures:j}));if(!k)break}}return k||Z.error(a),g}function bh(a,b,e){var f=b.dir,g=m++;return a||(a=function(a){return a===e}),b.first?function(b,c){while(b=b[f])if(b.nodeType===1)return a(b,c)&&b}:function(b,e){var h,i=g+"."+d,j=i+"."+c;while(b=b[f])if(b.nodeType===1){if((h=b[q])===j)return b.sizset;if(typeof h=="string"&&h.indexOf(i)===0){if(b.sizset)return b}else{b[q]=j;if(a(b,e))return b.sizset=!0,b;b.sizset=!1}}}}function bi(a,b){return a?function(c,d){var e=b(c,d);return e&&a(e===!0?c:e,d)}:b}function bj(a,b,c){var d,e,f=0;for(;d=a[f];f++)$.relative[d.part]?e=bh(e,$.relative[d.part],b):(d.captures.push(b,c),e=bi(e,$.filter[d.part].apply(null,d.captures)));return e}function bk(a){return function(b,c){var d,e=0;for(;d=a[e];e++)if(d(b,c))return!0;return!1}}var c,d,e,f,g,h=a.document,i=h.documentElement,j="undefined",k=!1,l=!0,m=0,n=[].slice,o=[].push,q=("sizcache"+Math.random()).replace(".",""),r="[\\x20\\t\\r\\n\\f]",s="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",t=s.replace("w","w#"),u="([*^$|!~]?=)",v="\\["+r+"*("+s+")"+r+"*(?:"+u+r+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+t+")|)|)"+r+"*\\]",w=":("+s+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",x=":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",y=r+"*([\\x20\\t\\r\\n\\f>+~])"+r+"*",z="(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|"+v+"|"+w.replace(2,7)+"|[^\\\\(),])+",A=new RegExp("^"+r+"+|((?:^|[^\\\\])(?:\\\\.)*)"+r+"+$","g"),B=new RegExp("^"+y),C=new RegExp(z+"?(?="+r+"*,|$)","g"),D=new RegExp("^(?:(?!,)(?:(?:^|,)"+r+"*"+z+")*?|"+r+"*(.*?))(\\)|$)"),E=new RegExp(z.slice(19,-6)+"\\x20\\t\\r\\n\\f>+~])+|"+y,"g"),F=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,G=/[\x20\t\r\n\f]*[+~]/,H=/:not\($/,I=/h\d/i,J=/input|select|textarea|button/i,K=/\\(?!\\)/g,L={ID:new RegExp("^#("+s+")"),CLASS:new RegExp("^\\.("+s+")"),NAME:new RegExp("^\\[name=['\"]?("+s+")['\"]?\\]"),TAG:new RegExp("^("+s.replace("[-","[-\\*")+")"),ATTR:new RegExp("^"+v),PSEUDO:new RegExp("^"+w),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+r+"*(even|odd|(([+-]|)(\\d*)n|)"+r+"*(?:([+-]|)"+r+"*(\\d+)|))"+r+"*\\)|)","i"),POS:new RegExp(x,"ig"),needsContext:new RegExp("^"+r+"*[>+~]|"+x,"i")},M={},N=[],O={},P=[],Q=function(a){return a.sizzleFilter=!0,a},R=function(a){return function(b){return b.nodeName.toLowerCase()==="input"&&b.type===a}},S=function(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}},T=function(a){var b=!1,c=h.createElement("div");try{b=a(c)}catch(d){}return c=null,b},U=T(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),V=T(function(a){a.id=q+0,a.innerHTML="<a name='"+q+"'></a><div name='"+q+"'></div>",i.insertBefore(a,i.firstChild);var b=h.getElementsByName&&h.getElementsByName(q).length===2+h.getElementsByName(q+0).length;return g=!h.getElementById(q),i.removeChild(a),b}),W=T(function(a){return a.appendChild(h.createComment("")),a.getElementsByTagName("*").length===0}),X=T(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==j&&a.firstChild.getAttribute("href")==="#"}),Y=T(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||a.getElementsByClassName("e").length===0?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length!==1)}),Z=function(a,b,c,d){c=c||[],b=b||h;var e,f,g,i,j=b.nodeType;if(j!==1&&j!==9)return[];if(!a||typeof a!="string")return c;g=ba(b);if(!g&&!d)if(e=F.exec(a))if(i=e[1]){if(j===9){f=b.getElementById(i);if(!f||!f.parentNode)return c;if(f.id===i)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(i))&&bb(b,f)&&f.id===i)return c.push(f),c}else{if(e[2])return o.apply(c,n.call(b.getElementsByTagName(a),0)),c;if((i=e[3])&&Y&&b.getElementsByClassName)return o.apply(c,n.call(b.getElementsByClassName(i),0)),c}return bm(a,b,c,d,g)},$=Z.selectors={cacheLength:50,match:L,order:["ID","TAG"],attrHandle:{},createPseudo:Q,find:{ID:g?function(a,b,c){if(typeof b.getElementById!==j&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==j&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==j&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:W?function(a,b){if(typeof b.getElementsByTagName!==j)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(K,""),a[3]=(a[4]||a[5]||"").replace(K,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||Z.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&Z.error(a[0]),a},PSEUDO:function(a){var b,c=a[4];return L.CHILD.test(a[0])?null:(c&&(b=D.exec(c))&&b.pop()&&(a[0]=a[0].slice(0,b[0].length-c.length-1),c=b[0].slice(0,-1)),a.splice(2,3,c||a[3]),a)}},filter:{ID:g?function(a){return a=a.replace(K,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(K,""),function(b){var c=typeof b.getAttributeNode!==j&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(K,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=M[a];return b||(b=M[a]=new RegExp("(^|"+r+")"+a+"("+r+"|$)"),N.push(a),N.length>$.cacheLength&&delete M[N.shift()]),function(a){return b.test(a.className||typeof a.getAttribute!==j&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=Z.attr(d,a),f=e+"";if(e==null)return b==="!=";switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&f.indexOf(c)===0;case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return Z.attr(b,a)!=null}},CHILD:function(a,b,c,d){if(a==="nth"){var e=m++;return function(a){var b,f,g=0,h=a;if(c===1&&d===0)return!0;b=a.parentNode;if(b&&(b[q]!==e||!a.sizset)){for(h=b.firstChild;h;h=h.nextSibling)if(h.nodeType===1){h.sizset=++g;if(h===a)break}b[q]=e}return f=a.sizset-d,c===0?f===0:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e=$.pseudos[a]||$.pseudos[a.toLowerCase()];return e||Z.error("unsupported pseudo: "+a),e.sizzleFilter?e(b,c,d):e}},pseudos:{not:Q(function(a,b,c){var d=bl(a.replace(A,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!$.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},contains:Q(function(a){return function(b){return(b.textContent||b.innerText||bc(b)).indexOf(a)>-1}}),has:Q(function(a){return function(b){return Z(a,b).length>0}}),header:function(a){return I.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:R("radio"),checkbox:R("checkbox"),file:R("file"),password:R("password"),image:R("image"),submit:S("submit"),reset:S("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return J.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(a,b,c){var d=[],e=c?1:0,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},odd:function(a,b,c){var d=[],e=c?0:1,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}};$.setFilters.nth=$.setFilters.eq,$.filters=$.pseudos,X||($.attrHandle={href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}}),V&&($.order.push("NAME"),$.find.NAME=function(a,b){if(typeof b.getElementsByName!==j)return b.getElementsByName(a)}),Y&&($.order.splice(1,0,"CLASS"),$.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!==j&&!c)return b.getElementsByClassName(a)});try{n.call(i.childNodes,0)[0].nodeType}catch(_){n=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}var ba=Z.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},bb=Z.contains=i.compareDocumentPosition?function(a,b){return!!(a.compareDocumentPosition(b)&16)}:i.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc=Z.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=bc(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=bc(b);return c};Z.attr=function(a,b){var c,d=ba(a);return d||(b=b.toLowerCase()),$.attrHandle[b]?$.attrHandle[b](a):U||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},Z.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},[0,0].sort(function(){return l=0}),i.compareDocumentPosition?e=function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:(e=function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],g=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return f(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)g.unshift(j),j=j.parentNode;c=e.length,d=g.length;for(var l=0;l<c&&l<d;l++)if(e[l]!==g[l])return f(e[l],g[l]);return l===c?f(a,g[l],-1):f(e[l],b,1)},f=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),Z.uniqueSort=function(a){var b,c=1;if(e){k=l,a.sort(e);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1)}return a};var bl=Z.compile=function(a,b,c){var d,e,f,g=O[a];if(g&&g.context===b)return g;e=bg(a,b,c);for(f=0;d=e[f];f++)e[f]=bj(d,b,c);return g=O[a]=bk(e),g.context=b,g.runs=g.dirruns=0,P.push(a),P.length>$.cacheLength&&delete O[P.shift()],g};Z.matches=function(a,b){return Z(a,null,null,b)},Z.matchesSelector=function(a,b){return Z(b,null,null,[a]).length>0};var bm=function(a,b,e,f,g){a=a.replace(A,"$1");var h,i,j,k,l,m,p,q,r,s=a.match(C),t=a.match(E),u=b.nodeType;if(L.POS.test(a))return bf(a,b,e,f,s);if(f)h=n.call(f,0);else if(s&&s.length===1){if(t.length>1&&u===9&&!g&&(s=L.ID.exec(t[0]))){b=$.find.ID(s[1],b,g)[0];if(!b)return e;a=a.slice(t.shift().length)}q=(s=G.exec(t[0]))&&!s.index&&b.parentNode||b,r=t.pop(),m=r.split(":not")[0];for(j=0,k=$.order.length;j<k;j++){p=$.order[j];if(s=L[p].exec(m)){h=$.find[p]((s[1]||"").replace(K,""),q,g);if(h==null)continue;m===r&&(a=a.slice(0,a.length-r.length)+m.replace(L[p],""),a||o.apply(e,n.call(h,0)));break}}}if(a){i=bl(a,b,g),d=i.dirruns++,h==null&&(h=$.find.TAG("*",G.test(a)&&b.parentNode||b));for(j=0;l=h[j];j++)c=i.runs++,i(l,b)&&e.push(l)}return e};h.querySelectorAll&&function(){var a,b=bm,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=i.matchesSelector||i.mozMatchesSelector||i.webkitMatchesSelector||i.oMatchesSelector||i.msMatchesSelector;T(function(a){a.innerHTML="<select><option selected></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+r+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),T(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+r+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),bm=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a)))if(d.nodeType===9)try{return o.apply(f,n.call(d.querySelectorAll(a),0)),f}catch(i){}else if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){var j=d.getAttribute("id"),k=j||q,l=G.test(a)&&d.parentNode||d;j?k=k.replace(c,"\\$&"):d.setAttribute("id",k);try{return o.apply(f,n.call(l.querySelectorAll(a.replace(C,"[id='"+k+"'] $&")),0)),f}catch(i){}finally{j||d.removeAttribute("id")}}return b(a,d,f,g,h)},g&&(T(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push($.match.PSEUDO)}catch(c){}}),f=new RegExp(f.join("|")),Z.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!ba(b)&&!f.test(c)&&(!e||!e.test(c)))try{var h=g.call(b,c);if(h||a||b.document&&b.document.nodeType!==11)return h}catch(i){}return Z(c,null,null,[b]).length>0})}(),Z.attr=p.attr,p.find=Z,p.expr=Z.selectors,p.expr[":"]=p.expr.pseudos,p.unique=Z.uniqueSort,p.text=Z.getText,p.isXMLDoc=Z.isXML,p.contains=Z.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=(c[0]||c).ownerDocument||c[0]||c,typeof c.createDocumentFragment=="undefined"&&(c=e),a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=0,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(g=b===e&&bA;(h=a[s])!=null;s++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{g=g||bk(b),l=l||g.appendChild(b.createElement("div")),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(f=n.length-1;f>=0;--f)p.nodeName(n[f],"tbody")&&!n[f].childNodes.length&&n[f].parentNode.removeChild(n[f])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l=g.lastChild}h.nodeType?t.push(h):t=p.merge(t,h)}l&&(g.removeChild(l),h=l=g=null);if(!p.support.appendChecked)for(s=0;(h=t[s])!=null;s++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(s=0;(h=t[s])!=null;s++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[s+1,0].concat(r)),s+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^margin/,bO=new RegExp("^("+q+")(.*)$","i"),bP=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bQ=new RegExp("^([-+])=("+q+")","i"),bR={},bS={position:"absolute",visibility:"hidden",display:"block"},bT={letterSpacing:0,fontWeight:400,lineHeight:1},bU=["Top","Right","Bottom","Left"],bV=["Webkit","O","Moz","ms"],bW=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return bZ(this,!0)},hide:function(){return bZ(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bW.apply(this,arguments):this.each(function(){(c?a:bY(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bX(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bQ.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bX(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bT&&(f=bT[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(a,b){var c,d,e,f,g=getComputedStyle(a,null),h=a.style;return g&&(c=g[b],c===""&&!p.contains(a.ownerDocument.documentElement,a)&&(c=p.style(a,b)),bP.test(c)&&bN.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=c,c=g.width,h.width=d,h.minWidth=e,h.maxWidth=f)),c}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bP.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0||bH(a,"display")!=="none"?ca(a,b,d):p.swap(a,bS,function(){return ca(a,b,d)})},set:function(a,c,d){return b$(a,c,d?b_(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bP.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bU[d]+b]=e[d]||e[d-2]||e[0];return f}},bN.test(a)||(p.cssHooks[a+b].set=b$)});var cc=/%20/g,cd=/\[\]$/,ce=/\r?\n/g,cf=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,cg=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||cg.test(this.nodeName)||cf.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(ce,"\r\n")}}):{name:b.name,value:c.replace(ce,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ch(d,a[d],c,f);return e.join("&").replace(cc,"+")};var ci,cj,ck=/#.*$/,cl=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cm=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,cn=/^(?:GET|HEAD)$/,co=/^\/\//,cp=/\?/,cq=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cr=/([?&])_=[^&]*/,cs=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,ct=p.fn.load,cu={},cv={},cw=["*/"]+["*"];try{ci=f.href}catch(cx){ci=e.createElement("a"),ci.href="",ci=ci.href}cj=cs.exec(ci.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&ct)return ct.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cq,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cA(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cA(a,b),a},ajaxSettings:{url:ci,isLocal:cm.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cw},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cy(cu),ajaxTransport:cy(cv),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cB(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cC(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=""+(c||y),k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cl.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(ck,"").replace(co,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=cs.exec(l.url.toLowerCase()),l.crossDomain=!(!i||i[1]==cj[1]&&i[2]==cj[2]&&(i[3]||(i[1]==="http:"?80:443))==(cj[3]||(cj[1]==="http:"?80:443)))),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cz(cu,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!cn.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cp.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cr,"$1_="+z);l.url=A+(A===l.url?(cp.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cw+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cz(cv,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cD=[],cE=/\?/,cF=/(=)\?(?=&|$)|\?\?/,cG=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cD.pop()||p.expando+"_"+cG++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cF.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cF.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cF,"$1"+f):m?c.data=i.replace(cF,"$1"+f):k&&(c.url+=(cE.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cD.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cH,cI=a.ActiveXObject?function(){for(var a in cH)cH[a](0,1)}:!1,cJ=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cK()||cL()}:cK,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cI&&delete cH[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cJ,cI&&(cH||(cH={},p(a).unload(cI)),cH[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cM,cN,cO=/^(?:toggle|show|hide)$/,cP=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cQ=/queueHooks$/,cR=[cX],cS={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=cP.exec(b),h=f.cur(),i=+h||0,j=1;if(g){c=+g[2],d=g[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&i){i=p.css(f.elem,a,!0)||c||1;do e=j=j||".5",i=i/j,p.style(f.elem,a,i+d),j=f.cur()/h;while(j!==1&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};p.Animation=p.extend(cV,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cS[c]=cS[c]||[],cS[c].unshift(b)},prefilter:function(a,b){b?cR.unshift(a):cR.push(a)}}),p.Tween=cY,cY.prototype={constructor:cY,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cY.propHooks[this.prop];return a&&a.get?a.get(this):cY.propHooks._default.get(this)},run:function(a){var b,c=cY.propHooks[this.prop];return this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration),this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cY.propHooks._default.set(this),this}},cY.prototype.init.prototype=cY.prototype,cY.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cY.propHooks.scrollTop=cY.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(cZ(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bY).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cV(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cQ.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:cZ("show"),slideUp:cZ("hide"),slideToggle:cZ("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cY.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cN&&(cN=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cN),cN=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c$=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j,k,l,m=this[0],n=m&&m.ownerDocument;if(!n)return;return(e=n.body)===m?p.offset.bodyOffset(m):(d=n.documentElement,p.contains(d,m)?(c=m.getBoundingClientRect(),f=c_(n),g=d.clientTop||e.clientTop||0,h=d.clientLeft||e.clientLeft||0,i=f.pageYOffset||d.scrollTop,j=f.pageXOffset||d.scrollLeft,k=c.top+i-g,l=c.left+j-h,{top:k,left:l}):{top:0,left:0})},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c$.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c$.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=c_(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window); \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.ba-bbq.min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.ba-bbq.min.js deleted file mode 100644 index bcbf24834ac..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.ba-bbq.min.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 - * http://benalman.com/projects/jquery-bbq-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ -(function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M<N?O[P]||(R[M+1]&&isNaN(R[M+1])?{}:[]):J}}else{if($.isArray(H[P])){H[P].push(J)}else{if(H[P]!==i){H[P]=[H[P],J]}else{H[P]=J}}}}else{if(P){H[P]=F?i:""}}});return H};function z(H,F,G){if(F===i||typeof F==="boolean"){G=F;F=a[H?D:A]()}else{F=E(F)?F.replace(H?w:x,""):F}return l(F,G)}l[A]=B(z,0);l[D]=v=B(z,1);$[y]||($[y]=function(F){return $.extend(C,F)})({a:k,base:k,iframe:t,img:t,input:t,form:"action",link:k,script:t});j=$[y];function s(I,G,H,F){if(!E(H)&&typeof H!=="object"){F=H;H=G;G=i}return this.each(function(){var L=$(this),J=G||j()[(this.nodeName||"").toLowerCase()]||"",K=J&&L.attr(J)||"";L.attr(J,a[I](K,H,F))})}$.fn[A]=B(s,A);$.fn[D]=B(s,D);b.pushState=q=function(I,F){if(E(I)&&/^#/.test(I)&&F===i){F=2}var H=I!==i,G=c(p[g][k],H?I:{},H?F:2);p[g][k]=G+(/#/.test(G)?"":"#")};b.getState=u=function(F,G){return F===i||typeof F==="boolean"?v(F):v(G)[F]};b.removeState=function(F){var G={};if(F!==i){G=u();$.each($.isArray(F)?F:arguments,function(I,H){delete G[H]})}q(G,2)};e[d]=$.extend(e[d],{add:function(F){var H;function G(J){var I=J[D]=c();J.getState=function(K,L){return K===i||typeof K==="boolean"?l(I,K):l(I,L)[K]};H.apply(this,arguments)}if($.isFunction(F)){H=F;return G}else{H=F.handler;F.handler=G}}})})(jQuery,this); -/* - * jQuery hashchange event - v1.2 - 2/11/2010 - * http://benalman.com/projects/jquery-hashchange-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ -(function($,i,b){var j,k=$.event.special,c="location",d="hashchange",l="href",f=$.browser,g=document.documentMode,h=f.msie&&(g===b||g<8),e="on"+d in i&&!h;function a(m){m=m||i[c][l];return m.replace(/^[^#]*#?(.*)$/,"$1")}$[d+"Delay"]=100;k[d]=$.extend(k[d],{setup:function(){if(e){return false}$(j.start)},teardown:function(){if(e){return false}$(j.stop)}});j=(function(){var m={},r,n,o,q;function p(){o=q=function(s){return s};if(h){n=$('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.slideto.min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.slideto.min.js deleted file mode 100644 index ba32cff3651..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.slideto.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.wiggle.min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.wiggle.min.js deleted file mode 100644 index 2adb0d6d54a..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/jquery.wiggle.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/* -jQuery Wiggle -Author: WonderGroup, Jordan Thomas -URL: http://labs.wondergroup.com/demos/mini-ui/index.html -License: MIT (http://en.wikipedia.org/wiki/MIT_License) -*/ -jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('<div class="wiggle-wrap"></div>').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);} -if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});}; \ No newline at end of file diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/swagger.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/swagger.js deleted file mode 100644 index c6f0cd3790b..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/swagger.js +++ /dev/null @@ -1,772 +0,0 @@ -// Generated by CoffeeScript 1.4.0 -(function() { - var SwaggerApi, SwaggerModel, SwaggerModelProperty, SwaggerOperation, SwaggerRequest, SwaggerResource, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - SwaggerApi = (function() { - - SwaggerApi.prototype.discoveryUrl = "http://api.wordnik.com/v4/resources.json"; - - SwaggerApi.prototype.debug = false; - - SwaggerApi.prototype.api_key = null; - - SwaggerApi.prototype.basePath = null; - - function SwaggerApi(options) { - if (options == null) { - options = {}; - } - if (options.discoveryUrl != null) { - this.discoveryUrl = options.discoveryUrl; - } - if (options.debug != null) { - this.debug = options.debug; - } - this.apiKeyName = options.apiKeyName != null ? options.apiKeyName : 'api_key'; - if (options.apiKey != null) { - this.api_key = options.apiKey; - } - if (options.api_key != null) { - this.api_key = options.api_key; - } - if (options.verbose != null) { - this.verbose = options.verbose; - } - this.supportHeaderParams = options.supportHeaderParams != null ? options.supportHeaderParams : false; - this.supportedSubmitMethods = options.supportedSubmitMethods != null ? options.supportedSubmitMethods : ['get']; - if (options.success != null) { - this.success = options.success; - } - this.failure = options.failure != null ? options.failure : function() {}; - this.progress = options.progress != null ? options.progress : function() {}; - this.headers = options.headers != null ? options.headers : {}; - this.booleanValues = options.booleanValues != null ? options.booleanValues : new Array('true', 'false'); - this.discoveryUrl = this.suffixApiKey(this.discoveryUrl); - if (options.success != null) { - this.build(); - } - } - - SwaggerApi.prototype.build = function() { - var _this = this; - this.progress('fetching resource list: ' + this.discoveryUrl); - return jQuery.getJSON(this.discoveryUrl, function(response) { - var res, resource, _i, _j, _len, _len1, _ref, _ref1; - if (response.apiVersion != null) { - _this.apiVersion = response.apiVersion; - } - if ((response.basePath != null) && jQuery.trim(response.basePath).length > 0) { - _this.basePath = response.basePath; - if (_this.basePath.match(/^HTTP/i) == null) { - _this.fail("discoveryUrl basePath must be a URL."); - } - _this.basePath = _this.basePath.replace(/\/$/, ''); - } else { - _this.basePath = _this.discoveryUrl.substring(0, _this.discoveryUrl.lastIndexOf('/')); - log('derived basepath from discoveryUrl as ' + _this.basePath); - } - _this.apis = {}; - _this.apisArray = []; - if (response.resourcePath != null) { - _this.resourcePath = response.resourcePath; - res = null; - _ref = response.apis; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - resource = _ref[_i]; - if (res === null) { - res = new SwaggerResource(resource, _this); - } else { - res.addOperations(resource.path, resource.operations); - } - } - if (res != null) { - _this.apis[res.name] = res; - _this.apisArray.push(res); - res.ready = true; - _this.selfReflect(); - } - } else { - _ref1 = response.apis; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - resource = _ref1[_j]; - res = new SwaggerResource(resource, _this); - _this.apis[res.name] = res; - _this.apisArray.push(res); - } - } - return _this; - }).error(function(error) { - if (_this.discoveryUrl.substring(0, 4) !== 'http') { - return _this.fail('Please specify the protocol for ' + _this.discoveryUrl); - } else if (error.status === 0) { - return _this.fail('Can\'t read from server. It may not have the appropriate access-control-origin settings.'); - } else if (error.status === 404) { - return _this.fail('Can\'t read swagger JSON from ' + _this.discoveryUrl); - } else { - return _this.fail(error.status + ' : ' + error.statusText + ' ' + _this.discoveryUrl); - } - }); - }; - - SwaggerApi.prototype.selfReflect = function() { - var resource, resource_name, _ref; - if (this.apis == null) { - return false; - } - _ref = this.apis; - for (resource_name in _ref) { - resource = _ref[resource_name]; - if (resource.ready == null) { - return false; - } - } - this.setConsolidatedModels(); - this.ready = true; - if (this.success != null) { - return this.success(); - } - }; - - SwaggerApi.prototype.fail = function(message) { - this.failure(message); - throw message; - }; - - SwaggerApi.prototype.setConsolidatedModels = function() { - var model, modelName, resource, resource_name, _i, _len, _ref, _ref1, _results; - this.modelsArray = []; - this.models = {}; - _ref = this.apis; - for (resource_name in _ref) { - resource = _ref[resource_name]; - for (modelName in resource.models) { - if (!(this.models[modelName] != null)) { - this.models[modelName] = resource.models[modelName]; - this.modelsArray.push(resource.models[modelName]); - } - } - } - _ref1 = this.modelsArray; - _results = []; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - model = _ref1[_i]; - _results.push(model.setReferencedModels(this.models)); - } - return _results; - }; - - SwaggerApi.prototype.suffixApiKey = function(url) { - var sep; - if ((this.api_key != null) && jQuery.trim(this.api_key).length > 0 && (url != null)) { - sep = url.indexOf('?') > 0 ? '&' : '?'; - return url + sep + this.apiKeyName + '=' + this.api_key; - } else { - return url; - } - }; - - SwaggerApi.prototype.help = function() { - var operation, operation_name, parameter, resource, resource_name, _i, _len, _ref, _ref1, _ref2; - _ref = this.apis; - for (resource_name in _ref) { - resource = _ref[resource_name]; - console.log(resource_name); - _ref1 = resource.operations; - for (operation_name in _ref1) { - operation = _ref1[operation_name]; - console.log(" " + operation.nickname); - _ref2 = operation.parameters; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - parameter = _ref2[_i]; - console.log(" " + parameter.name + (parameter.required ? ' (required)' : '') + " - " + parameter.description); - } - } - } - return this; - }; - - return SwaggerApi; - - })(); - - SwaggerResource = (function() { - - function SwaggerResource(resourceObj, api) { - var parts, - _this = this; - this.api = api; - this.path = this.api.resourcePath != null ? this.api.resourcePath : resourceObj.path; - this.description = resourceObj.description; - parts = this.path.split("/"); - this.name = parts[parts.length - 1].replace('.{format}', ''); - this.basePath = this.api.basePath; - this.operations = {}; - this.operationsArray = []; - this.modelsArray = []; - this.models = {}; - if ((resourceObj.operations != null) && (this.api.resourcePath != null)) { - this.api.progress('reading resource ' + this.name + ' models and operations'); - this.addModels(resourceObj.models); - this.addOperations(resourceObj.path, resourceObj.operations); - this.api[this.name] = this; - } else { - if (this.path == null) { - this.api.fail("SwaggerResources must have a path."); - } - this.url = this.api.suffixApiKey(this.api.basePath + this.path.replace('{format}', 'json')); - this.api.progress('fetching resource ' + this.name + ': ' + this.url); - jQuery.getJSON(this.url, function(response) { - var endpoint, _i, _len, _ref; - if ((response.basePath != null) && jQuery.trim(response.basePath).length > 0) { - _this.basePath = response.basePath; - _this.basePath = _this.basePath.replace(/\/$/, ''); - } - _this.addModels(response.models); - if (response.apis) { - _ref = response.apis; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - endpoint = _ref[_i]; - _this.addOperations(endpoint.path, endpoint.operations); - } - } - _this.api[_this.name] = _this; - _this.ready = true; - return _this.api.selfReflect(); - }).error(function(error) { - return _this.api.fail("Unable to read api '" + _this.name + "' from path " + _this.url + " (server returned " + error.statusText + ")"); - }); - } - } - - SwaggerResource.prototype.addModels = function(models) { - var model, modelName, swaggerModel, _i, _len, _ref, _results; - if (models != null) { - for (modelName in models) { - if (!(this.models[modelName] != null)) { - swaggerModel = new SwaggerModel(modelName, models[modelName]); - this.modelsArray.push(swaggerModel); - this.models[modelName] = swaggerModel; - } - } - _ref = this.modelsArray; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - model = _ref[_i]; - _results.push(model.setReferencedModels(this.models)); - } - return _results; - } - }; - - SwaggerResource.prototype.addOperations = function(resource_path, ops) { - var consumes, o, op, _i, _len, _results; - if (ops) { - _results = []; - for (_i = 0, _len = ops.length; _i < _len; _i++) { - o = ops[_i]; - consumes = o.consumes; - if (o.supportedContentTypes) { - consumes = o.supportedContentTypes; - } - op = new SwaggerOperation(o.nickname, resource_path, o.httpMethod, o.parameters, o.summary, o.notes, o.responseClass, o.errorResponses, this, o.consumes, o.produces); - this.operations[op.nickname] = op; - _results.push(this.operationsArray.push(op)); - } - return _results; - } - }; - - SwaggerResource.prototype.help = function() { - var operation, operation_name, parameter, _i, _len, _ref, _ref1; - _ref = this.operations; - for (operation_name in _ref) { - operation = _ref[operation_name]; - console.log(" " + operation.nickname); - _ref1 = operation.parameters; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - parameter = _ref1[_i]; - console.log(" " + parameter.name + (parameter.required ? ' (required)' : '') + " - " + parameter.description); - } - } - return this; - }; - - return SwaggerResource; - - })(); - - SwaggerModel = (function() { - - function SwaggerModel(modelName, obj) { - var propertyName; - this.name = obj.id != null ? obj.id : modelName; - this.properties = []; - for (propertyName in obj.properties) { - this.properties.push(new SwaggerModelProperty(propertyName, obj.properties[propertyName])); - } - } - - SwaggerModel.prototype.setReferencedModels = function(allModels) { - var prop, _i, _len, _ref, _results; - _ref = this.properties; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - prop = _ref[_i]; - if (allModels[prop.dataType] != null) { - _results.push(prop.refModel = allModels[prop.dataType]); - } else if ((prop.refDataType != null) && (allModels[prop.refDataType] != null)) { - _results.push(prop.refModel = allModels[prop.refDataType]); - } else { - _results.push(void 0); - } - } - return _results; - }; - - SwaggerModel.prototype.getMockSignature = function(modelsToIgnore) { - var classClose, classOpen, prop, propertiesStr, returnVal, strong, strongClose, stronger, _i, _j, _len, _len1, _ref, _ref1; - propertiesStr = []; - _ref = this.properties; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - prop = _ref[_i]; - propertiesStr.push(prop.toString()); - } - strong = '<span class="strong">'; - stronger = '<span class="stronger">'; - strongClose = '</span>'; - classOpen = strong + this.name + ' {' + strongClose; - classClose = strong + '}' + strongClose; - returnVal = classOpen + '<div>' + propertiesStr.join(',</div><div>') + '</div>' + classClose; - if (!modelsToIgnore) { - modelsToIgnore = []; - } - modelsToIgnore.push(this); - _ref1 = this.properties; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - prop = _ref1[_j]; - if ((prop.refModel != null) && (modelsToIgnore.indexOf(prop.refModel)) === -1) { - returnVal = returnVal + ('<br>' + prop.refModel.getMockSignature(modelsToIgnore)); - } - } - return returnVal; - }; - - SwaggerModel.prototype.createJSONSample = function(modelsToIgnore) { - var prop, result, _i, _len, _ref; - result = {}; - modelsToIgnore = modelsToIgnore || []; - modelsToIgnore.push(this.name); - _ref = this.properties; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - prop = _ref[_i]; - result[prop.name] = prop.getSampleValue(modelsToIgnore); - } - return result; - }; - - return SwaggerModel; - - })(); - - SwaggerModelProperty = (function() { - - function SwaggerModelProperty(name, obj) { - this.name = name; - this.dataType = obj.type; - this.isCollection = this.dataType && (this.dataType.toLowerCase() === 'array' || this.dataType.toLowerCase() === 'list' || this.dataType.toLowerCase() === 'set'); - this.descr = obj.description; - this.required = obj.required; - if (obj.items != null) { - if (obj.items.type != null) { - this.refDataType = obj.items.type; - } - if (obj.items.$ref != null) { - this.refDataType = obj.items.$ref; - } - } - this.dataTypeWithRef = this.refDataType != null ? this.dataType + '[' + this.refDataType + ']' : this.dataType; - if (obj.allowableValues != null) { - this.valueType = obj.allowableValues.valueType; - this.values = obj.allowableValues.values; - if (this.values != null) { - this.valuesString = "'" + this.values.join("' or '") + "'"; - } - } - } - - SwaggerModelProperty.prototype.getSampleValue = function(modelsToIgnore) { - var result; - if ((this.refModel != null) && (modelsToIgnore.indexOf(this.refModel.name) === -1)) { - result = this.refModel.createJSONSample(modelsToIgnore); - } else { - if (this.isCollection) { - result = this.refDataType; - } else { - result = this.dataType; - } - } - if (this.isCollection) { - return [result]; - } else { - return result; - } - }; - - SwaggerModelProperty.prototype.toString = function() { - var req, str; - req = this.required ? 'propReq' : 'propOpt'; - str = '<span class="propName ' + req + '">' + this.name + '</span> (<span class="propType">' + this.dataTypeWithRef + '</span>'; - if (!this.required) { - str += ', <span class="propOptKey">optional</span>'; - } - str += ')'; - if (this.values != null) { - str += " = <span class='propVals'>['" + this.values.join("' or '") + "']</span>"; - } - if (this.descr != null) { - str += ': <span class="propDesc">' + this.descr + '</span>'; - } - return str; - }; - - return SwaggerModelProperty; - - })(); - - SwaggerOperation = (function() { - - function SwaggerOperation(nickname, path, httpMethod, parameters, summary, notes, responseClass, errorResponses, resource, consumes, produces) { - var parameter, v, _i, _j, _len, _len1, _ref, _ref1, _ref2, - _this = this; - this.nickname = nickname; - this.path = path; - this.httpMethod = httpMethod; - this.parameters = parameters != null ? parameters : []; - this.summary = summary; - this.notes = notes; - this.responseClass = responseClass; - this.errorResponses = errorResponses; - this.resource = resource; - this.consumes = consumes; - this.produces = produces; - this["do"] = __bind(this["do"], this); - - if (this.nickname == null) { - this.resource.api.fail("SwaggerOperations must have a nickname."); - } - if (this.path == null) { - this.resource.api.fail("SwaggerOperation " + nickname + " is missing path."); - } - if (this.httpMethod == null) { - this.resource.api.fail("SwaggerOperation " + nickname + " is missing httpMethod."); - } - this.path = this.path.replace('{format}', 'json'); - this.httpMethod = this.httpMethod.toLowerCase(); - this.isGetMethod = this.httpMethod === "get"; - this.resourceName = this.resource.name; - if (((_ref = this.responseClass) != null ? _ref.toLowerCase() : void 0) === 'void') { - this.responseClass = void 0; - } - if (this.responseClass != null) { - this.responseClassSignature = this.getSignature(this.responseClass, this.resource.models); - this.responseSampleJSON = this.getSampleJSON(this.responseClass, this.resource.models); - } - this.errorResponses = this.errorResponses || []; - _ref1 = this.parameters; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - parameter = _ref1[_i]; - parameter.name = parameter.name || parameter.dataType; - if (parameter.dataType.toLowerCase() === 'boolean') { - parameter.allowableValues = {}; - parameter.allowableValues.values = this.resource.api.booleanValues; - } - parameter.signature = this.getSignature(parameter.dataType, this.resource.models); - parameter.sampleJSON = this.getSampleJSON(parameter.dataType, this.resource.models); - if (parameter.allowableValues != null) { - if (parameter.allowableValues.valueType === "RANGE") { - parameter.isRange = true; - } else { - parameter.isList = true; - } - if (parameter.allowableValues.values != null) { - parameter.allowableValues.descriptiveValues = []; - _ref2 = parameter.allowableValues.values; - for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { - v = _ref2[_j]; - if ((parameter.defaultValue != null) && parameter.defaultValue === v) { - parameter.allowableValues.descriptiveValues.push({ - value: v, - isDefault: true - }); - } else { - parameter.allowableValues.descriptiveValues.push({ - value: v, - isDefault: false - }); - } - } - } - } - } - this.resource[this.nickname] = function(args, callback, error) { - return _this["do"](args, callback, error); - }; - } - - SwaggerOperation.prototype.isListType = function(dataType) { - if (dataType.indexOf('[') >= 0) { - return dataType.substring(dataType.indexOf('[') + 1, dataType.indexOf(']')); - } else { - return void 0; - } - }; - - SwaggerOperation.prototype.getSignature = function(dataType, models) { - var isPrimitive, listType; - listType = this.isListType(dataType); - isPrimitive = ((listType != null) && models[listType]) || (models[dataType] != null) ? false : true; - if (isPrimitive) { - return dataType; - } else { - if (listType != null) { - return models[listType].getMockSignature(); - } else { - return models[dataType].getMockSignature(); - } - } - }; - - SwaggerOperation.prototype.getSampleJSON = function(dataType, models) { - var isPrimitive, listType, val; - listType = this.isListType(dataType); - isPrimitive = ((listType != null) && models[listType]) || (models[dataType] != null) ? false : true; - val = isPrimitive ? void 0 : (listType != null ? models[listType].createJSONSample() : models[dataType].createJSONSample()); - if (val) { - val = listType ? [val] : val; - return JSON.stringify(val, null, 2); - } - }; - - SwaggerOperation.prototype["do"] = function(args, callback, error) { - var body, headers; - if (args == null) { - args = {}; - } - if ((typeof args) === "function") { - error = callback; - callback = args; - args = {}; - } - if (error == null) { - error = function(xhr, textStatus, error) { - return console.log(xhr, textStatus, error); - }; - } - if (callback == null) { - callback = function(data) { - return console.log(data); - }; - } - if (args.headers != null) { - headers = args.headers; - delete args.headers; - } - if (args.body != null) { - body = args.body; - delete args.body; - } - return new SwaggerRequest(this.httpMethod, this.urlify(args), headers, body, callback, error, this); - }; - - SwaggerOperation.prototype.pathJson = function() { - return this.path.replace("{format}", "json"); - }; - - SwaggerOperation.prototype.pathXml = function() { - return this.path.replace("{format}", "xml"); - }; - - SwaggerOperation.prototype.urlify = function(args, includeApiKey) { - var param, queryParams, reg, url, _i, _len, _ref; - if (includeApiKey == null) { - includeApiKey = true; - } - url = this.resource.basePath + this.pathJson(); - _ref = this.parameters; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - param = _ref[_i]; - if (param.paramType === 'path') { - if (args[param.name]) { - reg = new RegExp('\{' + param.name + '[^\}]*\}', 'gi'); - url = url.replace(reg, encodeURIComponent(args[param.name])); - delete args[param.name]; - } else { - throw "" + param.name + " is a required path param."; - } - } - } - if (includeApiKey && (this.resource.api.api_key != null) && this.resource.api.api_key.length > 0) { - args[this.apiKeyName] = this.resource.api.api_key; - } - if (this.supportHeaderParams()) { - queryParams = jQuery.param(this.getQueryParams(args, includeApiKey)); - } else { - queryParams = jQuery.param(this.getQueryAndHeaderParams(args, includeApiKey)); - } - if ((queryParams != null) && queryParams.length > 0) { - url += "?" + queryParams; - } - return url; - }; - - SwaggerOperation.prototype.supportHeaderParams = function() { - return this.resource.api.supportHeaderParams; - }; - - SwaggerOperation.prototype.supportedSubmitMethods = function() { - return this.resource.api.supportedSubmitMethods; - }; - - SwaggerOperation.prototype.getQueryAndHeaderParams = function(args, includeApiKey) { - if (includeApiKey == null) { - includeApiKey = true; - } - return this.getMatchingParams(['query', 'header'], args, includeApiKey); - }; - - SwaggerOperation.prototype.getQueryParams = function(args, includeApiKey) { - if (includeApiKey == null) { - includeApiKey = true; - } - return this.getMatchingParams(['query'], args, includeApiKey); - }; - - SwaggerOperation.prototype.getHeaderParams = function(args, includeApiKey) { - if (includeApiKey == null) { - includeApiKey = true; - } - return this.getMatchingParams(['header'], args, includeApiKey); - }; - - SwaggerOperation.prototype.getMatchingParams = function(paramTypes, args, includeApiKey) { - var matchingParams, name, param, value, _i, _len, _ref, _ref1; - matchingParams = {}; - _ref = this.parameters; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - param = _ref[_i]; - if ((jQuery.inArray(param.paramType, paramTypes) >= 0) && args[param.name]) { - matchingParams[param.name] = args[param.name]; - } - } - if (includeApiKey && (this.resource.api.api_key != null) && this.resource.api.api_key.length > 0) { - matchingParams[this.resource.api.apiKeyName] = this.resource.api.api_key; - } - if (jQuery.inArray('header', paramTypes) >= 0) { - _ref1 = this.resource.api.headers; - for (name in _ref1) { - value = _ref1[name]; - matchingParams[name] = value; - } - } - return matchingParams; - }; - - SwaggerOperation.prototype.help = function() { - var parameter, _i, _len, _ref; - _ref = this.parameters; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - parameter = _ref[_i]; - console.log(" " + parameter.name + (parameter.required ? ' (required)' : '') + " - " + parameter.description); - } - return this; - }; - - return SwaggerOperation; - - })(); - - SwaggerRequest = (function() { - - function SwaggerRequest(type, url, headers, body, successCallback, errorCallback, operation) { - var obj, - _this = this; - this.type = type; - this.url = url; - this.headers = headers; - this.body = body; - this.successCallback = successCallback; - this.errorCallback = errorCallback; - this.operation = operation; - if (this.type == null) { - throw "SwaggerRequest type is required (get/post/put/delete)."; - } - if (this.url == null) { - throw "SwaggerRequest url is required."; - } - if (this.successCallback == null) { - throw "SwaggerRequest successCallback is required."; - } - if (this.errorCallback == null) { - throw "SwaggerRequest error callback is required."; - } - if (this.operation == null) { - throw "SwaggerRequest operation is required."; - } - if (this.operation.resource.api.verbose) { - console.log(this.asCurl()); - } - this.headers || (this.headers = {}); - if (this.operation.resource.api.api_key != null) { - this.headers[this.apiKeyName] = this.operation.resource.api.api_key; - } - if (this.headers.mock == null) { - obj = { - type: this.type, - url: this.url, - data: JSON.stringify(this.body), - dataType: 'json', - error: function(xhr, textStatus, error) { - return _this.errorCallback(xhr, textStatus, error); - }, - success: function(data) { - return _this.successCallback(data); - } - }; - if (obj.type.toLowerCase() === "post" || obj.type.toLowerCase() === "put") { - obj.contentType = "application/json"; - } - jQuery.ajax(obj); - } - } - - SwaggerRequest.prototype.asCurl = function() { - var header_args, k, v; - header_args = (function() { - var _ref, _results; - _ref = this.headers; - _results = []; - for (k in _ref) { - v = _ref[k]; - _results.push("--header \"" + k + ": " + v + "\""); - } - return _results; - }).call(this); - return "curl " + (header_args.join(" ")) + " " + this.url; - }; - - return SwaggerRequest; - - })(); - - window.SwaggerApi = SwaggerApi; - - window.SwaggerResource = SwaggerResource; - - window.SwaggerOperation = SwaggerOperation; - - window.SwaggerRequest = SwaggerRequest; - - window.SwaggerModelProperty = SwaggerModelProperty; - -}).call(this); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/underscore-min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/underscore-min.js deleted file mode 100644 index 5a0cb3b008d..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/lib/underscore-min.js +++ /dev/null @@ -1,32 +0,0 @@ -// Underscore.js 1.3.3 -// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore is freely distributable under the MIT license. -// Portions of Underscore are inspired or borrowed from Prototype, -// Oliver Steele's Functional, and John Resig's Micro-Templating. -// For all details and documentation: -// http://documentcloud.github.com/underscore -(function(){function r(a,c,d){if(a===c)return 0!==a||1/a==1/c;if(null==a||null==c)return a===c;a._chain&&(a=a._wrapped);c._chain&&(c=c._wrapped);if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return!1;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:0==a?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== -c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if("object"!=typeof a||"object"!=typeof c)return!1;for(var f=d.length;f--;)if(d[f]==a)return!0;d.push(a);var f=0,g=!0;if("[object Array]"==e){if(f=a.length,g=f==c.length)for(;f--&&(g=f in a==f in c&&r(a[f],c[f],d)););}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return!1;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,h)&&!f--)break; -g=!f}}d.pop();return g}var s=this,I=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,J=k.unshift,l=p.toString,K=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,L=Object.keys,t=Function.prototype.bind,b=function(a){return new m(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a, -c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(A&& -a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a, -c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b, -a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= -function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&& -(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){d=Math.floor(Math.random()*(f+1));b[f]=b[d];b[d]=a});return b};b.sortBy=function(a,c,d){var e=b.isFunction(c)?c:function(a){return a[c]};return b.pluck(b.map(a,function(a,b,c){return{value:a,criteria:e.call(d,a,b,c)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c===void 0?1:d===void 0?-1:c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]}; -j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a, -0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a, -e=[];a.length<3&&(c=true);b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a= -i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<= -1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+d}return g};var H=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));H.prototype=a.prototype;var b=new H,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c= -i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h= -g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));g?h=true:i=a.apply(d,e);j();g=true;return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments;d&&!e&&a.apply(f,g);clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0)); -return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&& -c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty= -function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"}; -b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a, -b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId= -function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape|| -u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c}; -b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d, -this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/swagger-ui.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/swagger-ui.js deleted file mode 100644 index 7ac8ed7b523..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/swagger-ui.js +++ /dev/null @@ -1,2020 +0,0 @@ -$(function() { - - // Helper function for vertically aligning DOM elements - // http://www.seodenver.com/simple-vertical-align-plugin-for-jquery/ - $.fn.vAlign = function() { - return this.each(function(i){ - var ah = $(this).height(); - var ph = $(this).parent().height(); - var mh = (ph - ah) / 2; - $(this).css('margin-top', mh); - }); - }; - - $.fn.stretchFormtasticInputWidthToParent = function() { - return this.each(function(i){ - var p_width = $(this).closest("form").innerWidth(); - var p_padding = parseInt($(this).closest("form").css('padding-left') ,10) + parseInt($(this).closest("form").css('padding-right'), 10); - var this_padding = parseInt($(this).css('padding-left'), 10) + parseInt($(this).css('padding-right'), 10); - $(this).css('width', p_width - p_padding - this_padding); - }); - }; - - $('form.formtastic li.string input, form.formtastic textarea').stretchFormtasticInputWidthToParent(); - - // Vertically center these paragraphs - // Parent may need a min-height for this to work.. - $('ul.downplayed li div.content p').vAlign(); - - // When a sandbox form is submitted.. - $("form.sandbox").submit(function(){ - - var error_free = true; - - // Cycle through the forms required inputs - $(this).find("input.required").each(function() { - - // Remove any existing error styles from the input - $(this).removeClass('error'); - - // Tack the error style on if the input is empty.. - if ($(this).val() == '') { - $(this).addClass('error'); - $(this).wiggle(); - error_free = false; - } - - }); - - return error_free; - }); - -}); - -function clippyCopiedCallback(a) { - $('#api_key_copied').fadeIn().delay(1000).fadeOut(); - - // var b = $("#clippy_tooltip_" + a); - // b.length != 0 && (b.attr("title", "copied!").trigger("tipsy.reload"), setTimeout(function() { - // b.attr("title", "copy to clipboard") - // }, - // 500)) -} - -// Logging function that accounts for browsers that don't have window.console -function log() { - if (window.console) console.log.apply(console,arguments); -} -// Handle browsers that do console incorrectly (IE9 and below, see http://stackoverflow.com/a/5539378/7913) -if (Function.prototype.bind && console && typeof console.log == "object") { - [ - "log","info","warn","error","assert","dir","clear","profile","profileEnd" - ].forEach(function (method) { - console[method] = this.bind(console[method], console); - }, Function.prototype.call); -} - -var Docs = { - - shebang: function() { - - // If shebang has an operation nickname in it.. - // e.g. /docs/#!/words/get_search - var fragments = $.param.fragment().split('/'); - fragments.shift(); // get rid of the bang - - switch (fragments.length) { - case 1: - // Expand all operations for the resource and scroll to it -// log('shebang resource:' + fragments[0]); - var dom_id = 'resource_' + fragments[0]; - - Docs.expandEndpointListForResource(fragments[0]); - $("#"+dom_id).slideto({highlight: false}); - break; - case 2: - // Refer to the endpoint DOM element, e.g. #words_get_search -// log('shebang endpoint: ' + fragments.join('_')); - - // Expand Resource - Docs.expandEndpointListForResource(fragments[0]); - $("#"+dom_id).slideto({highlight: false}); - - // Expand operation - var li_dom_id = fragments.join('_'); - var li_content_dom_id = li_dom_id + "_content"; - -// log("li_dom_id " + li_dom_id); -// log("li_content_dom_id " + li_content_dom_id); - - Docs.expandOperation($('#'+li_content_dom_id)); - $('#'+li_dom_id).slideto({highlight: false}); - break; - } - - }, - - toggleEndpointListForResource: function(resource) { - var elem = $('li#resource_' + Docs.escapeResourceName(resource) + ' ul.endpoints'); - if (elem.is(':visible')) { - Docs.collapseEndpointListForResource(resource); - } else { - Docs.expandEndpointListForResource(resource); - } - }, - - // Expand resource - expandEndpointListForResource: function(resource) { - var resource = Docs.escapeResourceName(resource); - if (resource == '') { - $('.resource ul.endpoints').slideDown(); - return; - } - - $('li#resource_' + resource).addClass('active'); - - var elem = $('li#resource_' + resource + ' ul.endpoints'); - elem.slideDown(); - }, - - // Collapse resource and mark as explicitly closed - collapseEndpointListForResource: function(resource) { - var resource = Docs.escapeResourceName(resource); - $('li#resource_' + resource).removeClass('active'); - - var elem = $('li#resource_' + resource + ' ul.endpoints'); - elem.slideUp(); - }, - - expandOperationsForResource: function(resource) { - // Make sure the resource container is open.. - Docs.expandEndpointListForResource(resource); - - if (resource == '') { - $('.resource ul.endpoints li.operation div.content').slideDown(); - return; - } - - $('li#resource_' + Docs.escapeResourceName(resource) + ' li.operation div.content').each(function() { - Docs.expandOperation($(this)); - }); - }, - - collapseOperationsForResource: function(resource) { - // Make sure the resource container is open.. - Docs.expandEndpointListForResource(resource); - - $('li#resource_' + Docs.escapeResourceName(resource) + ' li.operation div.content').each(function() { - Docs.collapseOperation($(this)); - }); - }, - - escapeResourceName: function(resource) { - return resource.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g, "\\$&"); - }, - - expandOperation: function(elem) { - elem.slideDown(); - }, - - collapseOperation: function(elem) { - elem.slideUp(); - } - -}; -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['content_type'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0; - -function program1(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.produces; - stack1 = foundHelper || depth0.produces; - stack2 = helpers.each; - tmp1 = self.program(2, program2, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n"; - return buffer;} -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <option value=\""; - stack1 = depth0; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "this", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\">"; - stack1 = depth0; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "this", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</option>\n "; - return buffer;} - -function program4(depth0,data) { - - - return "\n <option value=\"application/json\">application/json</option>\n";} - - buffer += "<label for=\"contentType\"></label>\n<select name=\"contentType\">\n"; - foundHelper = helpers.produces; - stack1 = foundHelper || depth0.produces; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(4, program4, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n</select>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['main'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n , <span style=\"font-variant: small-caps\">api version</span>: "; - foundHelper = helpers.apiVersion; - stack1 = foundHelper || depth0.apiVersion; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "apiVersion", { hash: {} }); } - buffer += escapeExpression(stack1) + "\n "; - return buffer;} - - buffer += "\n<div class='container' id='resources_container'>\n <ul id='resources'>\n </ul>\n\n <div class=\"footer\">\n <br>\n <br>\n <h4 style=\"color: #999\">[ <span style=\"font-variant: small-caps\">base url</span>: "; - foundHelper = helpers.basePath; - stack1 = foundHelper || depth0.basePath; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "basePath", { hash: {} }); } - buffer += escapeExpression(stack1) + "\n "; - foundHelper = helpers.apiVersion; - stack1 = foundHelper || depth0.apiVersion; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "]</h4>\n </div>\n</div>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['operation'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <h4>Implementation Notes</h4>\n <p>"; - foundHelper = helpers.notes; - stack1 = foundHelper || depth0.notes; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "notes", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</p>\n "; - return buffer;} - -function program3(depth0,data) { - - - return "\n <h4>Response Class</h4>\n <p><span class=\"model-signature\" /></p>\n <br/>\n <div class=\"content-type\" />\n ";} - -function program5(depth0,data) { - - - return "\n <h4>Parameters</h4>\n <table class='fullwidth'>\n <thead>\n <tr>\n <th style=\"width: 100px; max-width: 100px\">Parameter</th>\n <th style=\"width: 310px; max-width: 310px\">Value</th>\n <th style=\"width: 200px; max-width: 200px\">Description</th>\n <th style=\"width: 100px; max-width: 100px\">Parameter Type</th>\n <th style=\"width: 220px; max-width: 230px\">Data Type</th>\n </tr>\n </thead>\n <tbody class=\"operation-params\">\n\n </tbody>\n </table>\n ";} - -function program7(depth0,data) { - - - return "\n <div style='margin:0;padding:0;display:inline'></div>\n <h4>Error Status Codes</h4>\n <table class='fullwidth'>\n <thead>\n <tr>\n <th>HTTP Status Code</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody class=\"operation-status\">\n \n </tbody>\n </table>\n ";} - -function program9(depth0,data) { - - - return "\n ";} - -function program11(depth0,data) { - - - return "\n <div class='sandbox_header'>\n <input class='submit' name='commit' type='button' value='Try it out!' />\n <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n <img alt='Throbber' class='response_throbber' src='images/throbber.gif' style='display:none' />\n </div>\n ";} - - buffer += "\n <ul class='operations' >\n <li class='"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + " operation' id='"; - foundHelper = helpers.resourceName; - stack1 = foundHelper || depth0.resourceName; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "resourceName", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.nickname; - stack1 = foundHelper || depth0.nickname; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "nickname", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.number; - stack1 = foundHelper || depth0.number; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "number", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>\n <div class='heading'>\n <h3>\n <span class='http_method'>\n <a href='#!/"; - foundHelper = helpers.resourceName; - stack1 = foundHelper || depth0.resourceName; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "resourceName", { hash: {} }); } - buffer += escapeExpression(stack1) + "/"; - foundHelper = helpers.nickname; - stack1 = foundHelper || depth0.nickname; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "nickname", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.number; - stack1 = foundHelper || depth0.number; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "number", { hash: {} }); } - buffer += escapeExpression(stack1) + "' class=\"toggleOperation\">"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + "</a>\n </span>\n <span class='path'>\n <a href='#!/"; - foundHelper = helpers.resourceName; - stack1 = foundHelper || depth0.resourceName; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "resourceName", { hash: {} }); } - buffer += escapeExpression(stack1) + "/"; - foundHelper = helpers.nickname; - stack1 = foundHelper || depth0.nickname; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "nickname", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.number; - stack1 = foundHelper || depth0.number; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "number", { hash: {} }); } - buffer += escapeExpression(stack1) + "' class=\"toggleOperation\">"; - foundHelper = helpers.path; - stack1 = foundHelper || depth0.path; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "path", { hash: {} }); } - buffer += escapeExpression(stack1) + "</a>\n </span>\n </h3>\n <ul class='options'>\n <li>\n <a href='#!/"; - foundHelper = helpers.resourceName; - stack1 = foundHelper || depth0.resourceName; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "resourceName", { hash: {} }); } - buffer += escapeExpression(stack1) + "/"; - foundHelper = helpers.nickname; - stack1 = foundHelper || depth0.nickname; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "nickname", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.number; - stack1 = foundHelper || depth0.number; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "number", { hash: {} }); } - buffer += escapeExpression(stack1) + "' class=\"toggleOperation\">"; - foundHelper = helpers.summary; - stack1 = foundHelper || depth0.summary; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "summary", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</a>\n </li>\n </ul>\n </div>\n <div class='content' id='"; - foundHelper = helpers.resourceName; - stack1 = foundHelper || depth0.resourceName; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "resourceName", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.nickname; - stack1 = foundHelper || depth0.nickname; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "nickname", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.httpMethod; - stack1 = foundHelper || depth0.httpMethod; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "httpMethod", { hash: {} }); } - buffer += escapeExpression(stack1) + "_"; - foundHelper = helpers.number; - stack1 = foundHelper || depth0.number; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "number", { hash: {} }); } - buffer += escapeExpression(stack1) + "_content' style='display:none'>\n "; - foundHelper = helpers.notes; - stack1 = foundHelper || depth0.notes; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - foundHelper = helpers.responseClass; - stack1 = foundHelper || depth0.responseClass; - stack2 = helpers['if']; - tmp1 = self.program(3, program3, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n <form accept-charset='UTF-8' class='sandbox'>\n <div style='margin:0;padding:0;display:inline'></div>\n "; - foundHelper = helpers.parameters; - stack1 = foundHelper || depth0.parameters; - stack2 = helpers['if']; - tmp1 = self.program(5, program5, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - foundHelper = helpers.errorResponses; - stack1 = foundHelper || depth0.errorResponses; - stack2 = helpers['if']; - tmp1 = self.program(7, program7, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - foundHelper = helpers.isReadOnly; - stack1 = foundHelper || depth0.isReadOnly; - stack2 = helpers['if']; - tmp1 = self.program(9, program9, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(11, program11, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n </form>\n <div class='response' style='display:none'>\n <h4>Request URL</h4>\n <div class='block request_url'></div>\n <h4>Response Body</h4>\n <div class='block response_body'></div>\n <h4>Response Code</h4>\n <div class='block response_code'></div>\n <h4>Response Headers</h4>\n <div class='block response_headers'></div>\n </div>\n </div>\n </li>\n </ul>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['param'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.isFile; - stack1 = foundHelper || depth0.isFile; - stack2 = helpers['if']; - tmp1 = self.program(2, program2, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(4, program4, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input type=\"file\" name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'/>\n "; - return buffer;} - -function program4(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(5, program5, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(7, program7, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program5(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <textarea class='body-textarea' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>"; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "</textarea>\n "; - return buffer;} - -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <textarea class='body-textarea' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'></textarea>\n <br />\n <div class=\"content-type\" />\n "; - return buffer;} - -function program9(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(10, program10, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(12, program12, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program10(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input class='parameter' minlength='0' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "' placeholder='' type='text' value='"; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "'/>\n "; - return buffer;} - -function program12(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input class='parameter' minlength='0' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "' placeholder='' type='text' value=''/>\n "; - return buffer;} - - buffer += "<td class='code'>"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "</td>\n<td>\n\n "; - foundHelper = helpers.isBody; - stack1 = foundHelper || depth0.isBody; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(9, program9, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n\n</td>\n<td>"; - foundHelper = helpers.description; - stack1 = foundHelper || depth0.description; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td>"; - foundHelper = helpers.paramType; - stack1 = foundHelper || depth0.paramType; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "paramType", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td>\n <span class=\"model-signature\"></span>\n</td>\n\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['param_list'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - - return "\n ";} - -function program3(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(4, program4, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(6, program6, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program4(depth0,data) { - - - return "\n ";} - -function program6(depth0,data) { - - - return "\n <option selected=\"\" value=''></option>\n ";} - -function program8(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.isDefault; - stack1 = foundHelper || depth0.isDefault; - stack2 = helpers['if']; - tmp1 = self.program(9, program9, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(11, program11, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program9(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <option value='"; - foundHelper = helpers.value; - stack1 = foundHelper || depth0.value; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "value", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>"; - foundHelper = helpers.value; - stack1 = foundHelper || depth0.value; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "value", { hash: {} }); } - buffer += escapeExpression(stack1) + " (default)</option>\n "; - return buffer;} - -function program11(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <option value='"; - foundHelper = helpers.value; - stack1 = foundHelper || depth0.value; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "value", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>"; - foundHelper = helpers.value; - stack1 = foundHelper || depth0.value; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "value", { hash: {} }); } - buffer += escapeExpression(stack1) + "</option>\n "; - return buffer;} - - buffer += "<td class='code'>"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "</td>\n<td>\n <select class='parameter' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>\n "; - foundHelper = helpers.required; - stack1 = foundHelper || depth0.required; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(3, program3, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - foundHelper = helpers.allowableValues; - stack1 = foundHelper || depth0.allowableValues; - stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.descriptiveValues); - stack2 = helpers.each; - tmp1 = self.program(8, program8, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.noop; - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n </select>\n</td>\n<td>"; - foundHelper = helpers.description; - stack1 = foundHelper || depth0.description; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td>"; - foundHelper = helpers.paramType; - stack1 = foundHelper || depth0.paramType; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "paramType", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td><span class=\"model-signature\"></span></td>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['param_readonly'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <textarea class='body-textarea' readonly='readonly' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>"; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "</textarea>\n "; - return buffer;} - -function program3(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(4, program4, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(6, program6, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program4(depth0,data) { - - var buffer = "", stack1; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "\n "; - return buffer;} - -function program6(depth0,data) { - - - return "\n (empty)\n ";} - - buffer += "<td class='code'>"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "</td>\n<td>\n "; - foundHelper = helpers.isBody; - stack1 = foundHelper || depth0.isBody; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(3, program3, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n</td>\n<td>"; - foundHelper = helpers.description; - stack1 = foundHelper || depth0.description; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td>"; - foundHelper = helpers.paramType; - stack1 = foundHelper || depth0.paramType; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "paramType", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td><span class=\"model-signature\"></span></td>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['param_readonly_required'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <textarea class='body-textarea' readonly='readonly' placeholder='(required)' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>"; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "</textarea>\n "; - return buffer;} - -function program3(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(4, program4, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(6, program6, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program4(depth0,data) { - - var buffer = "", stack1; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "\n "; - return buffer;} - -function program6(depth0,data) { - - - return "\n (empty)\n ";} - - buffer += "<td class='code required'>"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "</td>\n<td>\n "; - foundHelper = helpers.isBody; - stack1 = foundHelper || depth0.isBody; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(3, program3, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n</td>\n<td>"; - foundHelper = helpers.description; - stack1 = foundHelper || depth0.description; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td>"; - foundHelper = helpers.paramType; - stack1 = foundHelper || depth0.paramType; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "paramType", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td><span class=\"model-signature\"></span></td>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['param_required'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - -function program1(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.isFile; - stack1 = foundHelper || depth0.isFile; - stack2 = helpers['if']; - tmp1 = self.program(2, program2, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(4, program4, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program2(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input type=\"file\" name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'/>\n "; - return buffer;} - -function program4(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(5, program5, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(7, program7, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program5(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <textarea class='body-textarea' placeholder='(required)' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>"; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "</textarea>\n "; - return buffer;} - -function program7(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <textarea class='body-textarea' placeholder='(required)' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'></textarea>\n <br />\n <div class=\"content-type\" />\n "; - return buffer;} - -function program9(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.isFile; - stack1 = foundHelper || depth0.isFile; - stack2 = helpers['if']; - tmp1 = self.program(10, program10, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(12, program12, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program10(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input class='parameter' class='required' type='file' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'/>\n "; - return buffer;} - -function program12(depth0,data) { - - var buffer = "", stack1, stack2; - buffer += "\n "; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - stack2 = helpers['if']; - tmp1 = self.program(13, program13, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(15, program15, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n "; - return buffer;} -function program13(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input class='parameter required' minlength='1' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "' placeholder='(required)' type='text' value='"; - foundHelper = helpers.defaultValue; - stack1 = foundHelper || depth0.defaultValue; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "defaultValue", { hash: {} }); } - buffer += escapeExpression(stack1) + "'/>\n "; - return buffer;} - -function program15(depth0,data) { - - var buffer = "", stack1; - buffer += "\n <input class='parameter required' minlength='1' name='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "' placeholder='(required)' type='text' value=''/>\n "; - return buffer;} - - buffer += "<td class='code required'>"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "</td>\n<td>\n "; - foundHelper = helpers.isBody; - stack1 = foundHelper || depth0.isBody; - stack2 = helpers['if']; - tmp1 = self.program(1, program1, data); - tmp1.hash = {}; - tmp1.fn = tmp1; - tmp1.inverse = self.program(9, program9, data); - stack1 = stack2.call(depth0, stack1, tmp1); - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n</td>\n<td>\n <strong>"; - foundHelper = helpers.description; - stack1 = foundHelper || depth0.description; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</strong>\n</td>\n<td>"; - foundHelper = helpers.paramType; - stack1 = foundHelper || depth0.paramType; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "paramType", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n<td><span class=\"model-signature\"></span></td>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['resource'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - - - buffer += "<div class='heading'>\n <h2>\n <a href='#!/"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "' onclick=\"Docs.toggleEndpointListForResource('"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "');\">/"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "</a>\n </h2>\n <ul class='options'>\n <li>\n <a href='#!/"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "' id='endpointListTogger_"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'\n onclick=\"Docs.toggleEndpointListForResource('"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "');\">Show/Hide</a>\n </li>\n <li>\n <a href='#' onclick=\"Docs.collapseOperationsForResource('"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'); return false;\">\n List Operations\n </a>\n </li>\n <li>\n <a href='#' onclick=\"Docs.expandOperationsForResource('"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "'); return false;\">\n Expand Operations\n </a>\n </li>\n <li>\n <a href='"; - foundHelper = helpers.url; - stack1 = foundHelper || depth0.url; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "url", { hash: {} }); } - buffer += escapeExpression(stack1) + "'>Raw</a>\n </li>\n </ul>\n</div>\n<ul class='endpoints' id='"; - foundHelper = helpers.name; - stack1 = foundHelper || depth0.name; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); } - buffer += escapeExpression(stack1) + "_endpoint_list' style='display:none'>\n\n</ul>\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['signature'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - - - buffer += "<div>\n<ul class=\"signature-nav\">\n <li><a class=\"description-link\" href=\"#\">Model</a></li>\n <li><a class=\"snippet-link\" href=\"#\">Model Schema</a></li>\n</ul>\n<div>\n\n<div class=\"signature-container\">\n <div class=\"description\">\n "; - foundHelper = helpers.signature; - stack1 = foundHelper || depth0.signature; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "signature", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\n </div>\n\n <div class=\"snippet\">\n <pre><code>"; - foundHelper = helpers.sampleJSON; - stack1 = foundHelper || depth0.sampleJSON; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "sampleJSON", { hash: {} }); } - buffer += escapeExpression(stack1) + "</code></pre>\n <small class=\"notice\"></small>\n </div>\n</div>\n\n"; - return buffer;}); -})(); - -(function() { - var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; -templates['status_code'] = template(function (Handlebars,depth0,helpers,partials,data) { - helpers = helpers || Handlebars.helpers; - var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression; - - - buffer += "<td width='15%' class='code'>"; - foundHelper = helpers.code; - stack1 = foundHelper || depth0.code; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "code", { hash: {} }); } - buffer += escapeExpression(stack1) + "</td>\n<td>"; - foundHelper = helpers.reason; - stack1 = foundHelper || depth0.reason; - if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); } - else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "reason", { hash: {} }); } - if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "</td>\n\n"; - return buffer;}); -})(); - - - -// Generated by CoffeeScript 1.4.0 -(function() { - var ContentTypeView, HeaderView, MainView, OperationView, ParameterView, ResourceView, SignatureView, StatusCodeView, SwaggerUi, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - SwaggerUi = (function(_super) { - - __extends(SwaggerUi, _super); - - function SwaggerUi() { - return SwaggerUi.__super__.constructor.apply(this, arguments); - } - - SwaggerUi.prototype.dom_id = "swagger_ui"; - - SwaggerUi.prototype.options = null; - - SwaggerUi.prototype.api = null; - - SwaggerUi.prototype.headerView = null; - - SwaggerUi.prototype.mainView = null; - - SwaggerUi.prototype.initialize = function(options) { - var _this = this; - if (options == null) { - options = {}; - } - if (options.dom_id != null) { - this.dom_id = options.dom_id; - delete options.dom_id; - } - if (!($('#' + this.dom_id) != null)) { - $('body').append('<div id="' + this.dom_id + '"></div>'); - } - this.options = options; - this.options.success = function() { - return _this.render(); - }; - this.options.progress = function(d) { - return _this.showMessage(d); - }; - this.options.failure = function(d) { - return _this.onLoadFailure(d); - }; - this.headerView = new HeaderView({ - el: $('#header') - }); - return this.headerView.on('update-swagger-ui', function(data) { - return _this.updateSwaggerUi(data); - }); - }; - - SwaggerUi.prototype.updateSwaggerUi = function(data) { - this.options.discoveryUrl = data.discoveryUrl; - this.options.apiKey = data.apiKey; - return this.load(); - }; - - SwaggerUi.prototype.load = function() { - var _ref; - if ((_ref = this.mainView) != null) { - _ref.clear(); - } - this.headerView.update(this.options.discoveryUrl, this.options.apiKey); - return this.api = new SwaggerApi(this.options); - }; - - SwaggerUi.prototype.render = function() { - var _this = this; - this.showMessage('Finished Loading Resource Information. Rendering Swagger UI...'); - this.mainView = new MainView({ - model: this.api, - el: $('#' + this.dom_id) - }).render(); - this.showMessage(); - switch (this.options.docExpansion) { - case "full": - Docs.expandOperationsForResource(''); - break; - case "list": - Docs.collapseOperationsForResource(''); - } - if (this.options.onComplete) { - this.options.onComplete(this.api, this); - } - return setTimeout(function() { - return Docs.shebang(); - }, 400); - }; - - SwaggerUi.prototype.showMessage = function(data) { - if (data == null) { - data = ''; - } - $('#message-bar').removeClass('message-fail'); - $('#message-bar').addClass('message-success'); - return $('#message-bar').html(data); - }; - - SwaggerUi.prototype.onLoadFailure = function(data) { - var val; - if (data == null) { - data = ''; - } - $('#message-bar').removeClass('message-success'); - $('#message-bar').addClass('message-fail'); - val = $('#message-bar').html(data); - if (this.options.onFailure != null) { - this.options.onFailure(data); - } - return val; - }; - - return SwaggerUi; - - })(Backbone.Router); - - window.SwaggerUi = SwaggerUi; - - HeaderView = (function(_super) { - - __extends(HeaderView, _super); - - function HeaderView() { - return HeaderView.__super__.constructor.apply(this, arguments); - } - - HeaderView.prototype.events = { - 'click #show-pet-store-icon': 'showPetStore', - 'click #show-wordnik-dev-icon': 'showWordnikDev', - 'click #explore': 'showCustom', - 'keyup #input_baseUrl': 'showCustomOnKeyup', - 'keyup #input_apiKey': 'showCustomOnKeyup' - }; - - HeaderView.prototype.initialize = function() {}; - - HeaderView.prototype.showPetStore = function(e) { - return this.trigger('update-swagger-ui', { - discoveryUrl: "http://petstore.swagger.wordnik.com/api/api-docs.json", - apiKey: "special-key" - }); - }; - - HeaderView.prototype.showWordnikDev = function(e) { - return this.trigger('update-swagger-ui', { - discoveryUrl: "http://api.wordnik.com/v4/resources.json", - apiKey: "" - }); - }; - - HeaderView.prototype.showCustomOnKeyup = function(e) { - if (e.keyCode === 13) { - return this.showCustom(); - } - }; - - HeaderView.prototype.showCustom = function(e) { - if (e != null) { - e.preventDefault(); - } - return this.trigger('update-swagger-ui', { - discoveryUrl: $('#input_baseUrl').val(), - apiKey: $('#input_apiKey').val() - }); - }; - - HeaderView.prototype.update = function(url, apiKey, trigger) { - if (trigger == null) { - trigger = false; - } - $('#input_baseUrl').val(url); - $('#input_apiKey').val(apiKey); - if (trigger) { - return this.trigger('update-swagger-ui', { - discoveryUrl: url, - apiKey: apiKey - }); - } - }; - - return HeaderView; - - })(Backbone.View); - - MainView = (function(_super) { - - __extends(MainView, _super); - - function MainView() { - return MainView.__super__.constructor.apply(this, arguments); - } - - MainView.prototype.initialize = function() {}; - - MainView.prototype.render = function() { - var resource, _i, _len, _ref; - $(this.el).html(Handlebars.templates.main(this.model)); - _ref = this.model.apisArray; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - resource = _ref[_i]; - this.addResource(resource); - } - return this; - }; - - MainView.prototype.addResource = function(resource) { - var resourceView; - resourceView = new ResourceView({ - model: resource, - tagName: 'li', - id: 'resource_' + resource.name, - className: 'resource' - }); - return $('#resources').append(resourceView.render().el); - }; - - MainView.prototype.clear = function() { - return $(this.el).html(''); - }; - - return MainView; - - })(Backbone.View); - - ResourceView = (function(_super) { - - __extends(ResourceView, _super); - - function ResourceView() { - return ResourceView.__super__.constructor.apply(this, arguments); - } - - ResourceView.prototype.initialize = function() {}; - - ResourceView.prototype.render = function() { - var operation, _i, _len, _ref; - $(this.el).html(Handlebars.templates.resource(this.model)); - this.number = 0; - _ref = this.model.operationsArray; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - operation = _ref[_i]; - this.addOperation(operation); - } - return this; - }; - - ResourceView.prototype.addOperation = function(operation) { - var operationView; - operation.number = this.number; - operationView = new OperationView({ - model: operation, - tagName: 'li', - className: 'endpoint' - }); - $('.endpoints', $(this.el)).append(operationView.render().el); - return this.number++; - }; - - return ResourceView; - - })(Backbone.View); - - OperationView = (function(_super) { - - __extends(OperationView, _super); - - function OperationView() { - return OperationView.__super__.constructor.apply(this, arguments); - } - - OperationView.prototype.events = { - 'submit .sandbox': 'submitOperation', - 'click .submit': 'submitOperation', - 'click .response_hider': 'hideResponse', - 'click .toggleOperation': 'toggleOperationContent' - }; - - OperationView.prototype.initialize = function() {}; - - OperationView.prototype.render = function() { - var contentTypeModel, contentTypeView, isMethodSubmissionSupported, param, responseSignatureView, signatureModel, statusCode, _i, _j, _len, _len1, _ref, _ref1; - isMethodSubmissionSupported = jQuery.inArray(this.model.httpMethod, this.model.supportedSubmitMethods()) >= 0; - if (!isMethodSubmissionSupported) { - this.model.isReadOnly = true; - } - $(this.el).html(Handlebars.templates.operation(this.model)); - if (this.model.responseClassSignature && this.model.responseClassSignature !== 'string') { - signatureModel = { - sampleJSON: this.model.responseSampleJSON, - isParam: false, - signature: this.model.responseClassSignature - }; - responseSignatureView = new SignatureView({ - model: signatureModel, - tagName: 'div' - }); - $('.model-signature', $(this.el)).append(responseSignatureView.render().el); - } else { - $('.model-signature', $(this.el)).html(this.model.responseClass); - } - contentTypeModel = { - isParam: false - }; - if (this.model.supportedContentTypes) { - contentTypeModel.produces = this.model.supportedContentTypes; - } - if (this.model.produces) { - contentTypeModel.produces = this.model.produces; - } - contentTypeView = new ContentTypeView({ - model: contentTypeModel - }); - $('.content-type', $(this.el)).append(contentTypeView.render().el); - _ref = this.model.parameters; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - param = _ref[_i]; - this.addParameter(param); - } - _ref1 = this.model.errorResponses; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - statusCode = _ref1[_j]; - this.addStatusCode(statusCode); - } - return this; - }; - - OperationView.prototype.addParameter = function(param) { - var paramView; - paramView = new ParameterView({ - model: param, - tagName: 'tr', - readOnly: this.model.isReadOnly - }); - return $('.operation-params', $(this.el)).append(paramView.render().el); - }; - - OperationView.prototype.addStatusCode = function(statusCode) { - var statusCodeView; - statusCodeView = new StatusCodeView({ - model: statusCode, - tagName: 'tr' - }); - return $('.operation-status', $(this.el)).append(statusCodeView.render().el); - }; - - OperationView.prototype.submitOperation = function(e) { - var bodyParam, consumes, error_free, form, headerParams, invocationUrl, isFileUpload, isFormPost, map, o, obj, param, paramContentTypeField, responseContentTypeField, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4, - _this = this; - if (e != null) { - e.preventDefault(); - } - form = $('.sandbox', $(this.el)); - error_free = true; - form.find("input.required").each(function() { - var _this = this; - $(this).removeClass("error"); - if (jQuery.trim($(this).val()) === "") { - $(this).addClass("error"); - $(this).wiggle({ - callback: function() { - return $(_this).focus(); - } - }); - return error_free = false; - } - }); - if (error_free) { - map = {}; - _ref = form.serializeArray(); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - o = _ref[_i]; - if ((o.value != null) && jQuery.trim(o.value).length > 0) { - map[o.name] = o.value; - } - } - isFileUpload = form.children().find('input[type~="file"]').size() !== 0; - isFormPost = false; - consumes = "application/json"; - if (this.model.consumes && this.model.consumes.length > 0) { - consumes = this.model.consumes[0]; - } else { - _ref1 = this.model.parameters; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - o = _ref1[_j]; - if (o.paramType === 'form') { - isFormPost = true; - consumes = false; - } - } - if (isFileUpload) { - consumes = false; - } else if (this.model.httpMethod.toLowerCase() === "post" && isFormPost === false) { - consumes = "application/json"; - } - } - if (isFileUpload) { - bodyParam = new FormData(); - _ref2 = this.model.parameters; - for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { - param = _ref2[_k]; - if ((param.paramType === 'body' || 'form') && param.name !== 'file' && param.name !== 'File' && (map[param.name] != null)) { - bodyParam.append(param.name, map[param.name]); - } - } - $.each(form.children().find('input[type~="file"]'), function(i, el) { - return bodyParam.append($(el).attr('name'), el.files[0]); - }); - console.log(bodyParam); - } else if (isFormPost) { - bodyParam = new FormData(); - _ref3 = this.model.parameters; - for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { - param = _ref3[_l]; - if (map[param.name] != null) { - bodyParam.append(param.name, map[param.name]); - } - } - } else { - bodyParam = null; - _ref4 = this.model.parameters; - for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) { - param = _ref4[_m]; - if (param.paramType === 'body') { - bodyParam = map[param.name]; - } - } - } - log("bodyParam = " + bodyParam); - headerParams = null; - invocationUrl = this.model.supportHeaderParams() ? (headerParams = this.model.getHeaderParams(map), this.model.urlify(map, false)) : this.model.urlify(map, true); - log('submitting ' + invocationUrl); - $(".request_url", $(this.el)).html("<pre>" + invocationUrl + "</pre>"); - $(".response_throbber", $(this.el)).show(); - obj = { - type: this.model.httpMethod, - url: invocationUrl, - headers: headerParams, - data: bodyParam, - contentType: consumes, - dataType: 'json', - processData: false, - error: function(xhr, textStatus, error) { - return _this.showErrorStatus(xhr, textStatus, error); - }, - success: function(data) { - return _this.showResponse(data); - }, - complete: function(data) { - return _this.showCompleteStatus(data); - } - }; - paramContentTypeField = $("td select[name=contentType]", $(this.el)).val(); - if (paramContentTypeField) { - obj.contentType = paramContentTypeField; - } - log('content type = ' + obj.contentType); - if (!(obj.data || (obj.type === 'GET' || obj.type === 'DELETE')) && obj.contentType === !"application/x-www-form-urlencoded") { - obj.contentType = false; - } - log('content type is now = ' + obj.contentType); - responseContentTypeField = $('.content > .content-type > div > select[name=contentType]', $(this.el)).val(); - if (responseContentTypeField) { - obj.headers = obj.headers != null ? obj.headers : {}; - obj.headers.accept = responseContentTypeField; - } - jQuery.ajax(obj); - return false; - } - }; - - OperationView.prototype.hideResponse = function(e) { - if (e != null) { - e.preventDefault(); - } - $(".response", $(this.el)).slideUp(); - return $(".response_hider", $(this.el)).fadeOut(); - }; - - OperationView.prototype.showResponse = function(response) { - var prettyJson; - prettyJson = JSON.stringify(response, null, "\t").replace(/\n/g, "<br>"); - return $(".response_body", $(this.el)).html(escape(prettyJson)); - }; - - OperationView.prototype.showErrorStatus = function(data) { - return this.showStatus(data); - }; - - OperationView.prototype.showCompleteStatus = function(data) { - return this.showStatus(data); - }; - - OperationView.prototype.formatXml = function(xml) { - var contexp, formatted, indent, lastType, lines, ln, pad, reg, transitions, wsexp, _fn, _i, _len; - reg = /(>)(<)(\/*)/g; - wsexp = /[ ]*(.*)[ ]+\n/g; - contexp = /(<.+>)(.+\n)/g; - xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); - pad = 0; - formatted = ''; - lines = xml.split('\n'); - indent = 0; - lastType = 'other'; - transitions = { - 'single->single': 0, - 'single->closing': -1, - 'single->opening': 0, - 'single->other': 0, - 'closing->single': 0, - 'closing->closing': -1, - 'closing->opening': 0, - 'closing->other': 0, - 'opening->single': 1, - 'opening->closing': 0, - 'opening->opening': 1, - 'opening->other': 1, - 'other->single': 0, - 'other->closing': -1, - 'other->opening': 0, - 'other->other': 0 - }; - _fn = function(ln) { - var fromTo, j, key, padding, type, types, value; - types = { - single: Boolean(ln.match(/<.+\/>/)), - closing: Boolean(ln.match(/<\/.+>/)), - opening: Boolean(ln.match(/<[^!?].*>/)) - }; - type = ((function() { - var _results; - _results = []; - for (key in types) { - value = types[key]; - if (value) { - _results.push(key); - } - } - return _results; - })())[0]; - type = type === void 0 ? 'other' : type; - fromTo = lastType + '->' + type; - lastType = type; - padding = ''; - indent += transitions[fromTo]; - padding = ((function() { - var _j, _ref, _results; - _results = []; - for (j = _j = 0, _ref = indent; 0 <= _ref ? _j < _ref : _j > _ref; j = 0 <= _ref ? ++_j : --_j) { - _results.push(' '); - } - return _results; - })()).join(''); - if (fromTo === 'opening->closing') { - return formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; - } else { - return formatted += padding + ln + '\n'; - } - }; - for (_i = 0, _len = lines.length; _i < _len; _i++) { - ln = lines[_i]; - _fn(ln); - } - return formatted; - }; - - OperationView.prototype.showStatus = function(data) { - var code, pre, response_body; - try { - code = $('<code />').text(JSON.stringify(JSON.parse(data.responseText), null, 2)); - pre = $('<pre class="json" />').append(code); - } catch (error) { - code = $('<code />').text(this.formatXml(data.responseText)); - pre = $('<pre class="xml" />').append(code); - } - response_body = pre; - $(".response_code", $(this.el)).html("<pre>" + data.status + "</pre>"); - $(".response_body", $(this.el)).html(response_body); - $(".response_headers", $(this.el)).html("<pre>" + data.getAllResponseHeaders() + "</pre>"); - $(".response", $(this.el)).slideDown(); - $(".response_hider", $(this.el)).show(); - $(".response_throbber", $(this.el)).hide(); - return hljs.highlightBlock($('.response_body', $(this.el))[0]); - }; - - OperationView.prototype.toggleOperationContent = function() { - var elem; - elem = $('#' + Docs.escapeResourceName(this.model.resourceName) + "_" + this.model.nickname + "_" + this.model.httpMethod + "_" + this.model.number + "_content"); - if (elem.is(':visible')) { - return Docs.collapseOperation(elem); - } else { - return Docs.expandOperation(elem); - } - }; - - return OperationView; - - })(Backbone.View); - - StatusCodeView = (function(_super) { - - __extends(StatusCodeView, _super); - - function StatusCodeView() { - return StatusCodeView.__super__.constructor.apply(this, arguments); - } - - StatusCodeView.prototype.initialize = function() {}; - - StatusCodeView.prototype.render = function() { - var template; - template = this.template(); - $(this.el).html(template(this.model)); - return this; - }; - - StatusCodeView.prototype.template = function() { - return Handlebars.templates.status_code; - }; - - return StatusCodeView; - - })(Backbone.View); - - ParameterView = (function(_super) { - - __extends(ParameterView, _super); - - function ParameterView() { - return ParameterView.__super__.constructor.apply(this, arguments); - } - - ParameterView.prototype.initialize = function() {}; - - ParameterView.prototype.render = function() { - var contentTypeModel, contentTypeView, signatureModel, signatureView, template; - if (this.model.paramType === 'body') { - this.model.isBody = true; - } - if (this.model.dataType === 'file') { - this.model.isFile = true; - } - template = this.template(); - $(this.el).html(template(this.model)); - signatureModel = { - sampleJSON: this.model.sampleJSON, - isParam: true, - signature: this.model.signature - }; - if (this.model.sampleJSON) { - signatureView = new SignatureView({ - model: signatureModel, - tagName: 'div' - }); - $('.model-signature', $(this.el)).append(signatureView.render().el); - } else { - $('.model-signature', $(this.el)).html(this.model.signature); - } - contentTypeModel = { - isParam: false - }; - if (this.model.supportedContentTypes) { - contentTypeModel.produces = this.model.supportedContentTypes; - } - if (this.model.produces) { - contentTypeModel.produces = this.model.produces; - } - contentTypeView = new ContentTypeView({ - model: contentTypeModel - }); - $('.content-type', $(this.el)).append(contentTypeView.render().el); - return this; - }; - - ParameterView.prototype.template = function() { - if (this.model.isList) { - return Handlebars.templates.param_list; - } else { - if (this.options.readOnly) { - if (this.model.required) { - return Handlebars.templates.param_readonly_required; - } else { - return Handlebars.templates.param_readonly; - } - } else { - if (this.model.required) { - return Handlebars.templates.param_required; - } else { - return Handlebars.templates.param; - } - } - } - }; - - return ParameterView; - - })(Backbone.View); - - SignatureView = (function(_super) { - - __extends(SignatureView, _super); - - function SignatureView() { - return SignatureView.__super__.constructor.apply(this, arguments); - } - - SignatureView.prototype.events = { - 'click a.description-link': 'switchToDescription', - 'click a.snippet-link': 'switchToSnippet', - 'mousedown .snippet': 'snippetToTextArea' - }; - - SignatureView.prototype.initialize = function() {}; - - SignatureView.prototype.render = function() { - var template; - template = this.template(); - $(this.el).html(template(this.model)); - this.switchToDescription(); - this.isParam = this.model.isParam; - if (this.isParam) { - $('.notice', $(this.el)).text('Click to set as parameter value'); - } - return this; - }; - - SignatureView.prototype.template = function() { - return Handlebars.templates.signature; - }; - - SignatureView.prototype.switchToDescription = function(e) { - if (e != null) { - e.preventDefault(); - } - $(".snippet", $(this.el)).hide(); - $(".description", $(this.el)).show(); - $('.description-link', $(this.el)).addClass('selected'); - return $('.snippet-link', $(this.el)).removeClass('selected'); - }; - - SignatureView.prototype.switchToSnippet = function(e) { - if (e != null) { - e.preventDefault(); - } - $(".description", $(this.el)).hide(); - $(".snippet", $(this.el)).show(); - $('.snippet-link', $(this.el)).addClass('selected'); - return $('.description-link', $(this.el)).removeClass('selected'); - }; - - SignatureView.prototype.snippetToTextArea = function(e) { - var textArea; - if (this.isParam) { - if (e != null) { - e.preventDefault(); - } - textArea = $('textarea', $(this.el.parentNode.parentNode.parentNode)); - if ($.trim(textArea.val()) === '') { - return textArea.val(this.model.sampleJSON); - } - } - }; - - return SignatureView; - - })(Backbone.View); - - ContentTypeView = (function(_super) { - - __extends(ContentTypeView, _super); - - function ContentTypeView() { - return ContentTypeView.__super__.constructor.apply(this, arguments); - } - - ContentTypeView.prototype.initialize = function() {}; - - ContentTypeView.prototype.render = function() { - var template; - template = this.template(); - $(this.el).html(template(this.model)); - this.isParam = this.model.isParam; - if (this.isParam) { - $('label[for=contentType]', $(this.el)).text('Parameter content type:'); - } else { - $('label[for=contentType]', $(this.el)).text('Response Content Type'); - } - return this; - }; - - ContentTypeView.prototype.template = function() { - return Handlebars.templates.content_type; - }; - - return ContentTypeView; - - })(Backbone.View); - -}).call(this); diff --git a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/swagger-ui.min.js b/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/swagger-ui.min.js deleted file mode 100644 index 4947965ee13..00000000000 --- a/tests/ServiceStack.WebHost.IntegrationTests/swagger-ui/swagger-ui.min.js +++ /dev/null @@ -1 +0,0 @@ -$(function(){$.fn.vAlign=function(){return this.each(function(c){var a=$(this).height();var d=$(this).parent().height();var b=(d-a)/2;$(this).css("margin-top",b)})};$.fn.stretchFormtasticInputWidthToParent=function(){return this.each(function(b){var d=$(this).closest("form").innerWidth();var c=parseInt($(this).closest("form").css("padding-left"),10)+parseInt($(this).closest("form").css("padding-right"),10);var a=parseInt($(this).css("padding-left"),10)+parseInt($(this).css("padding-right"),10);$(this).css("width",d-c-a)})};$("form.formtastic li.string input, form.formtastic textarea").stretchFormtasticInputWidthToParent();$("ul.downplayed li div.content p").vAlign();$("form.sandbox").submit(function(){var a=true;$(this).find("input.required").each(function(){$(this).removeClass("error");if($(this).val()==""){$(this).addClass("error");$(this).wiggle();a=false}});return a})});function clippyCopiedCallback(b){$("#api_key_copied").fadeIn().delay(1000).fadeOut()}function log(){if(window.console){console.log.apply(console,arguments)}}if(Function.prototype.bind&&console&&typeof console.log=="object"){["log","info","warn","error","assert","dir","clear","profile","profileEnd"].forEach(function(a){console[a]=this.bind(console[a],console)},Function.prototype.call)}var Docs={shebang:function(){var b=$.param.fragment().split("/");b.shift();switch(b.length){case 1:var d="resource_"+b[0];Docs.expandEndpointListForResource(b[0]);$("#"+d).slideto({highlight:false});break;case 2:Docs.expandEndpointListForResource(b[0]);$("#"+d).slideto({highlight:false});var c=b.join("_");var a=c+"_content";Docs.expandOperation($("#"+a));$("#"+c).slideto({highlight:false});break}},toggleEndpointListForResource:function(b){var a=$("li#resource_"+Docs.escapeResourceName(b)+" ul.endpoints");if(a.is(":visible")){Docs.collapseEndpointListForResource(b)}else{Docs.expandEndpointListForResource(b)}},expandEndpointListForResource:function(b){var b=Docs.escapeResourceName(b);if(b==""){$(".resource ul.endpoints").slideDown();return}$("li#resource_"+b).addClass("active");var a=$("li#resource_"+b+" ul.endpoints");a.slideDown()},collapseEndpointListForResource:function(b){var b=Docs.escapeResourceName(b);$("li#resource_"+b).removeClass("active");var a=$("li#resource_"+b+" ul.endpoints");a.slideUp()},expandOperationsForResource:function(a){Docs.expandEndpointListForResource(a);if(a==""){$(".resource ul.endpoints li.operation div.content").slideDown();return}$("li#resource_"+Docs.escapeResourceName(a)+" li.operation div.content").each(function(){Docs.expandOperation($(this))})},collapseOperationsForResource:function(a){Docs.expandEndpointListForResource(a);$("li#resource_"+Docs.escapeResourceName(a)+" li.operation div.content").each(function(){Docs.collapseOperation($(this))})},escapeResourceName:function(a){return a.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g,"\\$&")},expandOperation:function(a){a.slideDown()},collapseOperation:function(a){a.slideUp()}};(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.content_type=b(function(g,p,f,n,m){f=f||g.helpers;var l="",c,s,k,j,q=this,h="function",o=f.helperMissing,i=void 0;function e(x,w){var t="",v,u;t+="\n ";k=f.produces;v=k||x.produces;u=f.each;j=q.program(2,d,w);j.hash={};j.fn=j;j.inverse=q.noop;v=u.call(x,v,j);if(v||v===0){t+=v}t+="\n";return t}function d(w,v){var t="",u;t+='\n <option value="';u=w;if(typeof u===h){u=u.call(w,{hash:{}})}else{if(u===i){u=o.call(w,"this",{hash:{}})}}if(u||u===0){t+=u}t+='">';u=w;if(typeof u===h){u=u.call(w,{hash:{}})}else{if(u===i){u=o.call(w,"this",{hash:{}})}}if(u||u===0){t+=u}t+="</option>\n ";return t}function r(u,t){return'\n <option value="application/json">application/json</option>\n'}l+='<label for="contentType"></label>\n<select name="contentType">\n';k=f.produces;c=k||p.produces;s=f["if"];j=q.program(1,e,m);j.hash={};j.fn=j;j.inverse=q.program(4,r,m);c=s.call(p,c,j);if(c||c===0){l+=c}l+="\n</select>\n";return l})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.main=b(function(f,p,e,n,m){e=e||f.helpers;var k="",c,r,j,i,q=this,g="function",o=e.helperMissing,h=void 0,l=this.escapeExpression;function d(v,u){var s="",t;s+='\n , <span style="font-variant: small-caps">api version</span>: ';j=e.apiVersion;t=j||v.apiVersion;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"apiVersion",{hash:{}})}}s+=l(t)+"\n ";return s}k+="\n<div class='container' id='resources_container'>\n <ul id='resources'>\n </ul>\n\n <div class=\"footer\">\n <br>\n <br>\n <h4 style=\"color: #999\">[ <span style=\"font-variant: small-caps\">base url</span>: ";j=e.basePath;c=j||p.basePath;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"basePath",{hash:{}})}}k+=l(c)+"\n ";j=e.apiVersion;c=j||p.apiVersion;r=e["if"];i=q.program(1,d,m);i.hash={};i.fn=i;i.inverse=q.noop;c=r.call(p,c,i);if(c||c===0){k+=c}k+="]</h4>\n </div>\n</div>\n";return k})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.operation=b(function(h,u,s,m,w){s=s||h.helpers;var t="",j,g,i,q,p=this,e="function",r=s.helperMissing,c=void 0,d=this.escapeExpression;function o(A,z){var x="",y;x+="\n <h4>Implementation Notes</h4>\n <p>";i=s.notes;y=i||A.notes;if(typeof y===e){y=y.call(A,{hash:{}})}else{if(y===c){y=r.call(A,"notes",{hash:{}})}}if(y||y===0){x+=y}x+="</p>\n ";return x}function n(y,x){return'\n <h4>Response Class</h4>\n <p><span class="model-signature" /></p>\n <br/>\n <div class="content-type" />\n '}function l(y,x){return'\n <h4>Parameters</h4>\n <table class=\'fullwidth\'>\n <thead>\n <tr>\n <th style="width: 100px; max-width: 100px">Parameter</th>\n <th style="width: 310px; max-width: 310px">Value</th>\n <th style="width: 200px; max-width: 200px">Description</th>\n <th style="width: 100px; max-width: 100px">Parameter Type</th>\n <th style="width: 220px; max-width: 230px">Data Type</th>\n </tr>\n </thead>\n <tbody class="operation-params">\n\n </tbody>\n </table>\n '}function k(y,x){return"\n <div style='margin:0;padding:0;display:inline'></div>\n <h4>Error Status Codes</h4>\n <table class='fullwidth'>\n <thead>\n <tr>\n <th>HTTP Status Code</th>\n <th>Reason</th>\n </tr>\n </thead>\n <tbody class=\"operation-status\">\n \n </tbody>\n </table>\n "}function f(y,x){return"\n "}function v(y,x){return"\n <div class='sandbox_header'>\n <input class='submit' name='commit' type='button' value='Try it out!' />\n <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n <img alt='Throbber' class='response_throbber' src='images/throbber.gif' style='display:none' />\n </div>\n "}t+="\n <ul class='operations' >\n <li class='";i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+" operation' id='";i=s.resourceName;j=i||u.resourceName;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"resourceName",{hash:{}})}}t+=d(j)+"_";i=s.nickname;j=i||u.nickname;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"nickname",{hash:{}})}}t+=d(j)+"_";i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+"_";i=s.number;j=i||u.number;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"number",{hash:{}})}}t+=d(j)+"'>\n <div class='heading'>\n <h3>\n <span class='http_method'>\n <a href='#!/";i=s.resourceName;j=i||u.resourceName;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"resourceName",{hash:{}})}}t+=d(j)+"/";i=s.nickname;j=i||u.nickname;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"nickname",{hash:{}})}}t+=d(j)+"_";i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+"_";i=s.number;j=i||u.number;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"number",{hash:{}})}}t+=d(j)+'\' class="toggleOperation">';i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+"</a>\n </span>\n <span class='path'>\n <a href='#!/";i=s.resourceName;j=i||u.resourceName;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"resourceName",{hash:{}})}}t+=d(j)+"/";i=s.nickname;j=i||u.nickname;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"nickname",{hash:{}})}}t+=d(j)+"_";i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+"_";i=s.number;j=i||u.number;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"number",{hash:{}})}}t+=d(j)+'\' class="toggleOperation">';i=s.path;j=i||u.path;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"path",{hash:{}})}}t+=d(j)+"</a>\n </span>\n </h3>\n <ul class='options'>\n <li>\n <a href='#!/";i=s.resourceName;j=i||u.resourceName;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"resourceName",{hash:{}})}}t+=d(j)+"/";i=s.nickname;j=i||u.nickname;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"nickname",{hash:{}})}}t+=d(j)+"_";i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+"_";i=s.number;j=i||u.number;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"number",{hash:{}})}}t+=d(j)+'\' class="toggleOperation">';i=s.summary;j=i||u.summary;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"summary",{hash:{}})}}if(j||j===0){t+=j}t+="</a>\n </li>\n </ul>\n </div>\n <div class='content' id='";i=s.resourceName;j=i||u.resourceName;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"resourceName",{hash:{}})}}t+=d(j)+"_";i=s.nickname;j=i||u.nickname;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"nickname",{hash:{}})}}t+=d(j)+"_";i=s.httpMethod;j=i||u.httpMethod;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"httpMethod",{hash:{}})}}t+=d(j)+"_";i=s.number;j=i||u.number;if(typeof j===e){j=j.call(u,{hash:{}})}else{if(j===c){j=r.call(u,"number",{hash:{}})}}t+=d(j)+"_content' style='display:none'>\n ";i=s.notes;j=i||u.notes;g=s["if"];q=p.program(1,o,w);q.hash={};q.fn=q;q.inverse=p.noop;j=g.call(u,j,q);if(j||j===0){t+=j}t+="\n ";i=s.responseClass;j=i||u.responseClass;g=s["if"];q=p.program(3,n,w);q.hash={};q.fn=q;q.inverse=p.noop;j=g.call(u,j,q);if(j||j===0){t+=j}t+="\n <form accept-charset='UTF-8' class='sandbox'>\n <div style='margin:0;padding:0;display:inline'></div>\n ";i=s.parameters;j=i||u.parameters;g=s["if"];q=p.program(5,l,w);q.hash={};q.fn=q;q.inverse=p.noop;j=g.call(u,j,q);if(j||j===0){t+=j}t+="\n ";i=s.errorResponses;j=i||u.errorResponses;g=s["if"];q=p.program(7,k,w);q.hash={};q.fn=q;q.inverse=p.noop;j=g.call(u,j,q);if(j||j===0){t+=j}t+="\n ";i=s.isReadOnly;j=i||u.isReadOnly;g=s["if"];q=p.program(9,f,w);q.hash={};q.fn=q;q.inverse=p.program(11,v,w);j=g.call(u,j,q);if(j||j===0){t+=j}t+="\n </form>\n <div class='response' style='display:none'>\n <h4>Request URL</h4>\n <div class='block request_url'></div>\n <h4>Response Body</h4>\n <div class='block response_body'></div>\n <h4>Response Code</h4>\n <div class='block response_code'></div>\n <h4>Response Headers</h4>\n <div class='block response_headers'></div>\n </div>\n </div>\n </li>\n </ul>\n";return t})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param=b(function(h,v,t,m,y){t=t||h.helpers;var u="",j,g,i,r,q=this,e="function",s=t.helperMissing,c=void 0,d=this.escapeExpression;function p(D,C){var z="",B,A;z+="\n ";i=t.isFile;B=i||D.isFile;A=t["if"];r=q.program(2,o,C);r.hash={};r.fn=r;r.inverse=q.program(4,n,C);B=A.call(D,B,r);if(B||B===0){z+=B}z+="\n ";return z}function o(C,B){var z="",A;z+='\n <input type="file" name=\'';i=t.name;A=i||C.name;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"name",{hash:{}})}}z+=d(A)+"'/>\n ";return z}function n(D,C){var z="",B,A;z+="\n ";i=t.defaultValue;B=i||D.defaultValue;A=t["if"];r=q.program(5,l,C);r.hash={};r.fn=r;r.inverse=q.program(7,k,C);B=A.call(D,B,r);if(B||B===0){z+=B}z+="\n ";return z}function l(C,B){var z="",A;z+="\n <textarea class='body-textarea' name='";i=t.name;A=i||C.name;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"name",{hash:{}})}}z+=d(A)+"'>";i=t.defaultValue;A=i||C.defaultValue;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"defaultValue",{hash:{}})}}z+=d(A)+"</textarea>\n ";return z}function k(C,B){var z="",A;z+="\n <textarea class='body-textarea' name='";i=t.name;A=i||C.name;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"name",{hash:{}})}}z+=d(A)+'\'></textarea>\n <br />\n <div class="content-type" />\n ';return z}function f(D,C){var z="",B,A;z+="\n ";i=t.defaultValue;B=i||D.defaultValue;A=t["if"];r=q.program(10,x,C);r.hash={};r.fn=r;r.inverse=q.program(12,w,C);B=A.call(D,B,r);if(B||B===0){z+=B}z+="\n ";return z}function x(C,B){var z="",A;z+="\n <input class='parameter' minlength='0' name='";i=t.name;A=i||C.name;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"name",{hash:{}})}}z+=d(A)+"' placeholder='' type='text' value='";i=t.defaultValue;A=i||C.defaultValue;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"defaultValue",{hash:{}})}}z+=d(A)+"'/>\n ";return z}function w(C,B){var z="",A;z+="\n <input class='parameter' minlength='0' name='";i=t.name;A=i||C.name;if(typeof A===e){A=A.call(C,{hash:{}})}else{if(A===c){A=s.call(C,"name",{hash:{}})}}z+=d(A)+"' placeholder='' type='text' value=''/>\n ";return z}u+="<td class='code'>";i=t.name;j=i||v.name;if(typeof j===e){j=j.call(v,{hash:{}})}else{if(j===c){j=s.call(v,"name",{hash:{}})}}u+=d(j)+"</td>\n<td>\n\n ";i=t.isBody;j=i||v.isBody;g=t["if"];r=q.program(1,p,y);r.hash={};r.fn=r;r.inverse=q.program(9,f,y);j=g.call(v,j,r);if(j||j===0){u+=j}u+="\n\n</td>\n<td>";i=t.description;j=i||v.description;if(typeof j===e){j=j.call(v,{hash:{}})}else{if(j===c){j=s.call(v,"description",{hash:{}})}}if(j||j===0){u+=j}u+="</td>\n<td>";i=t.paramType;j=i||v.paramType;if(typeof j===e){j=j.call(v,{hash:{}})}else{if(j===c){j=s.call(v,"paramType",{hash:{}})}}if(j||j===0){u+=j}u+='</td>\n<td>\n <span class="model-signature"></span>\n</td>\n\n';return u})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_list=b(function(h,v,t,m,x){t=t||h.helpers;var u="",k,g,j,r,q=this,e="function",s=t.helperMissing,c=void 0,d=this.escapeExpression;function p(z,y){return"\n "}function o(C,B){var y="",A,z;y+="\n ";j=t.defaultValue;A=j||C.defaultValue;z=t["if"];r=q.program(4,n,B);r.hash={};r.fn=r;r.inverse=q.program(6,l,B);A=z.call(C,A,r);if(A||A===0){y+=A}y+="\n ";return y}function n(z,y){return"\n "}function l(z,y){return"\n <option selected=\"\" value=''></option>\n "}function i(C,B){var y="",A,z;y+="\n ";j=t.isDefault;A=j||C.isDefault;z=t["if"];r=q.program(9,f,B);r.hash={};r.fn=r;r.inverse=q.program(11,w,B);A=z.call(C,A,r);if(A||A===0){y+=A}y+="\n ";return y}function f(B,A){var y="",z;y+="\n <option value='";j=t.value;z=j||B.value;if(typeof z===e){z=z.call(B,{hash:{}})}else{if(z===c){z=s.call(B,"value",{hash:{}})}}y+=d(z)+"'>";j=t.value;z=j||B.value;if(typeof z===e){z=z.call(B,{hash:{}})}else{if(z===c){z=s.call(B,"value",{hash:{}})}}y+=d(z)+" (default)</option>\n ";return y}function w(B,A){var y="",z;y+="\n <option value='";j=t.value;z=j||B.value;if(typeof z===e){z=z.call(B,{hash:{}})}else{if(z===c){z=s.call(B,"value",{hash:{}})}}y+=d(z)+"'>";j=t.value;z=j||B.value;if(typeof z===e){z=z.call(B,{hash:{}})}else{if(z===c){z=s.call(B,"value",{hash:{}})}}y+=d(z)+"</option>\n ";return y}u+="<td class='code'>";j=t.name;k=j||v.name;if(typeof k===e){k=k.call(v,{hash:{}})}else{if(k===c){k=s.call(v,"name",{hash:{}})}}u+=d(k)+"</td>\n<td>\n <select class='parameter' name='";j=t.name;k=j||v.name;if(typeof k===e){k=k.call(v,{hash:{}})}else{if(k===c){k=s.call(v,"name",{hash:{}})}}u+=d(k)+"'>\n ";j=t.required;k=j||v.required;g=t["if"];r=q.program(1,p,x);r.hash={};r.fn=r;r.inverse=q.program(3,o,x);k=g.call(v,k,r);if(k||k===0){u+=k}u+="\n ";j=t.allowableValues;k=j||v.allowableValues;k=(k===null||k===undefined||k===false?k:k.descriptiveValues);g=t.each;r=q.program(8,i,x);r.hash={};r.fn=r;r.inverse=q.noop;k=g.call(v,k,r);if(k||k===0){u+=k}u+="\n </select>\n</td>\n<td>";j=t.description;k=j||v.description;if(typeof k===e){k=k.call(v,{hash:{}})}else{if(k===c){k=s.call(v,"description",{hash:{}})}}if(k||k===0){u+=k}u+="</td>\n<td>";j=t.paramType;k=j||v.paramType;if(typeof k===e){k=k.call(v,{hash:{}})}else{if(k===c){k=s.call(v,"paramType",{hash:{}})}}if(k||k===0){u+=k}u+='</td>\n<td><span class="model-signature"></span></td>\n';return u})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_readonly=b(function(g,t,r,k,u){r=r||g.helpers;var s="",i,f,h,p,o=this,e="function",q=r.helperMissing,c=void 0,d=this.escapeExpression;function n(y,x){var v="",w;v+="\n <textarea class='body-textarea' readonly='readonly' name='";h=r.name;w=h||y.name;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"name",{hash:{}})}}v+=d(w)+"'>";h=r.defaultValue;w=h||y.defaultValue;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"defaultValue",{hash:{}})}}v+=d(w)+"</textarea>\n ";return v}function m(z,y){var v="",x,w;v+="\n ";h=r.defaultValue;x=h||z.defaultValue;w=r["if"];p=o.program(4,l,y);p.hash={};p.fn=p;p.inverse=o.program(6,j,y);x=w.call(z,x,p);if(x||x===0){v+=x}v+="\n ";return v}function l(y,x){var v="",w;v+="\n ";h=r.defaultValue;w=h||y.defaultValue;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"defaultValue",{hash:{}})}}v+=d(w)+"\n ";return v}function j(w,v){return"\n (empty)\n "}s+="<td class='code'>";h=r.name;i=h||t.name;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"name",{hash:{}})}}s+=d(i)+"</td>\n<td>\n ";h=r.isBody;i=h||t.isBody;f=r["if"];p=o.program(1,n,u);p.hash={};p.fn=p;p.inverse=o.program(3,m,u);i=f.call(t,i,p);if(i||i===0){s+=i}s+="\n</td>\n<td>";h=r.description;i=h||t.description;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"description",{hash:{}})}}if(i||i===0){s+=i}s+="</td>\n<td>";h=r.paramType;i=h||t.paramType;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"paramType",{hash:{}})}}if(i||i===0){s+=i}s+='</td>\n<td><span class="model-signature"></span></td>\n';return s})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_readonly_required=b(function(g,t,r,k,u){r=r||g.helpers;var s="",i,f,h,p,o=this,e="function",q=r.helperMissing,c=void 0,d=this.escapeExpression;function n(y,x){var v="",w;v+="\n <textarea class='body-textarea' readonly='readonly' placeholder='(required)' name='";h=r.name;w=h||y.name;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"name",{hash:{}})}}v+=d(w)+"'>";h=r.defaultValue;w=h||y.defaultValue;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"defaultValue",{hash:{}})}}v+=d(w)+"</textarea>\n ";return v}function m(z,y){var v="",x,w;v+="\n ";h=r.defaultValue;x=h||z.defaultValue;w=r["if"];p=o.program(4,l,y);p.hash={};p.fn=p;p.inverse=o.program(6,j,y);x=w.call(z,x,p);if(x||x===0){v+=x}v+="\n ";return v}function l(y,x){var v="",w;v+="\n ";h=r.defaultValue;w=h||y.defaultValue;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"defaultValue",{hash:{}})}}v+=d(w)+"\n ";return v}function j(w,v){return"\n (empty)\n "}s+="<td class='code required'>";h=r.name;i=h||t.name;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"name",{hash:{}})}}s+=d(i)+"</td>\n<td>\n ";h=r.isBody;i=h||t.isBody;f=r["if"];p=o.program(1,n,u);p.hash={};p.fn=p;p.inverse=o.program(3,m,u);i=f.call(t,i,p);if(i||i===0){s+=i}s+="\n</td>\n<td>";h=r.description;i=h||t.description;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"description",{hash:{}})}}if(i||i===0){s+=i}s+="</td>\n<td>";h=r.paramType;i=h||t.paramType;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"paramType",{hash:{}})}}if(i||i===0){s+=i}s+='</td>\n<td><span class="model-signature"></span></td>\n';return s})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.param_required=b(function(h,v,t,m,A){t=t||h.helpers;var u="",j,g,i,r,q=this,e="function",s=t.helperMissing,c=void 0,d=this.escapeExpression;function p(F,E){var B="",D,C;B+="\n ";i=t.isFile;D=i||F.isFile;C=t["if"];r=q.program(2,o,E);r.hash={};r.fn=r;r.inverse=q.program(4,n,E);D=C.call(F,D,r);if(D||D===0){B+=D}B+="\n ";return B}function o(E,D){var B="",C;B+='\n <input type="file" name=\'';i=t.name;C=i||E.name;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"name",{hash:{}})}}B+=d(C)+"'/>\n ";return B}function n(F,E){var B="",D,C;B+="\n ";i=t.defaultValue;D=i||F.defaultValue;C=t["if"];r=q.program(5,l,E);r.hash={};r.fn=r;r.inverse=q.program(7,k,E);D=C.call(F,D,r);if(D||D===0){B+=D}B+="\n ";return B}function l(E,D){var B="",C;B+="\n <textarea class='body-textarea' placeholder='(required)' name='";i=t.name;C=i||E.name;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"name",{hash:{}})}}B+=d(C)+"'>";i=t.defaultValue;C=i||E.defaultValue;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"defaultValue",{hash:{}})}}B+=d(C)+"</textarea>\n ";return B}function k(E,D){var B="",C;B+="\n <textarea class='body-textarea' placeholder='(required)' name='";i=t.name;C=i||E.name;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"name",{hash:{}})}}B+=d(C)+'\'></textarea>\n <br />\n <div class="content-type" />\n ';return B}function f(F,E){var B="",D,C;B+="\n ";i=t.isFile;D=i||F.isFile;C=t["if"];r=q.program(10,z,E);r.hash={};r.fn=r;r.inverse=q.program(12,y,E);D=C.call(F,D,r);if(D||D===0){B+=D}B+="\n ";return B}function z(E,D){var B="",C;B+="\n <input class='parameter' class='required' type='file' name='";i=t.name;C=i||E.name;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"name",{hash:{}})}}B+=d(C)+"'/>\n ";return B}function y(F,E){var B="",D,C;B+="\n ";i=t.defaultValue;D=i||F.defaultValue;C=t["if"];r=q.program(13,x,E);r.hash={};r.fn=r;r.inverse=q.program(15,w,E);D=C.call(F,D,r);if(D||D===0){B+=D}B+="\n ";return B}function x(E,D){var B="",C;B+="\n <input class='parameter required' minlength='1' name='";i=t.name;C=i||E.name;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"name",{hash:{}})}}B+=d(C)+"' placeholder='(required)' type='text' value='";i=t.defaultValue;C=i||E.defaultValue;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"defaultValue",{hash:{}})}}B+=d(C)+"'/>\n ";return B}function w(E,D){var B="",C;B+="\n <input class='parameter required' minlength='1' name='";i=t.name;C=i||E.name;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=s.call(E,"name",{hash:{}})}}B+=d(C)+"' placeholder='(required)' type='text' value=''/>\n ";return B}u+="<td class='code required'>";i=t.name;j=i||v.name;if(typeof j===e){j=j.call(v,{hash:{}})}else{if(j===c){j=s.call(v,"name",{hash:{}})}}u+=d(j)+"</td>\n<td>\n ";i=t.isBody;j=i||v.isBody;g=t["if"];r=q.program(1,p,A);r.hash={};r.fn=r;r.inverse=q.program(9,f,A);j=g.call(v,j,r);if(j||j===0){u+=j}u+="\n</td>\n<td>\n <strong>";i=t.description;j=i||v.description;if(typeof j===e){j=j.call(v,{hash:{}})}else{if(j===c){j=s.call(v,"description",{hash:{}})}}if(j||j===0){u+=j}u+="</strong>\n</td>\n<td>";i=t.paramType;j=i||v.paramType;if(typeof j===e){j=j.call(v,{hash:{}})}else{if(j===c){j=s.call(v,"paramType",{hash:{}})}}if(j||j===0){u+=j}u+='</td>\n<td><span class="model-signature"></span></td>\n';return u})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.resource=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+="<div class='heading'>\n <h2>\n <a href='#!/";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"' onclick=\"Docs.toggleEndpointListForResource('";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"');\">/";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"</a>\n </h2>\n <ul class='options'>\n <li>\n <a href='#!/";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"' id='endpointListTogger_";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"'\n onclick=\"Docs.toggleEndpointListForResource('";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"');\">Show/Hide</a>\n </li>\n <li>\n <a href='#' onclick=\"Docs.collapseOperationsForResource('";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"'); return false;\">\n List Operations\n </a>\n </li>\n <li>\n <a href='#' onclick=\"Docs.expandOperationsForResource('";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"'); return false;\">\n Expand Operations\n </a>\n </li>\n <li>\n <a href='";h=d.url;c=h||n.url;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"url",{hash:{}})}}i+=j(c)+"'>Raw</a>\n </li>\n </ul>\n</div>\n<ul class='endpoints' id='";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"_endpoint_list' style='display:none'>\n\n</ul>\n";return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.signature=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<div>\n<ul class="signature-nav">\n <li><a class="description-link" href="#">Model</a></li>\n <li><a class="snippet-link" href="#">Model Schema</a></li>\n</ul>\n<div>\n\n<div class="signature-container">\n <div class="description">\n ';h=d.signature;c=h||n.signature;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"signature",{hash:{}})}}if(c||c===0){i+=c}i+='\n </div>\n\n <div class="snippet">\n <pre><code>';h=d.sampleJSON;c=h||n.sampleJSON;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"sampleJSON",{hash:{}})}}i+=j(c)+'</code></pre>\n <small class="notice"></small>\n </div>\n</div>\n\n';return i})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.status_code=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+="<td width='15%' class='code'>";h=d.code;c=h||n.code;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"code",{hash:{}})}}i+=j(c)+"</td>\n<td>";h=d.reason;c=h||n.reason;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"reason",{hash:{}})}}if(c||c===0){i+=c}i+="</td>\n\n";return i})})();(function(){var f,b,h,c,e,j,k,i,a,g={}.hasOwnProperty,d=function(o,m){for(var l in m){if(g.call(m,l)){o[l]=m[l]}}function n(){this.constructor=o}n.prototype=m.prototype;o.prototype=new n();o.__super__=m.prototype;return o};a=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.dom_id="swagger_ui";l.prototype.options=null;l.prototype.api=null;l.prototype.headerView=null;l.prototype.mainView=null;l.prototype.initialize=function(n){var o=this;if(n==null){n={}}if(n.dom_id!=null){this.dom_id=n.dom_id;delete n.dom_id}if(!($("#"+this.dom_id)!=null)){$("body").append('<div id="'+this.dom_id+'"></div>')}this.options=n;this.options.success=function(){return o.render()};this.options.progress=function(p){return o.showMessage(p)};this.options.failure=function(p){return o.onLoadFailure(p)};this.headerView=new b({el:$("#header")});return this.headerView.on("update-swagger-ui",function(p){return o.updateSwaggerUi(p)})};l.prototype.updateSwaggerUi=function(n){this.options.discoveryUrl=n.discoveryUrl;this.options.apiKey=n.apiKey;return this.load()};l.prototype.load=function(){var n;if((n=this.mainView)!=null){n.clear()}this.headerView.update(this.options.discoveryUrl,this.options.apiKey);return this.api=new SwaggerApi(this.options)};l.prototype.render=function(){var n=this;this.showMessage("Finished Loading Resource Information. Rendering Swagger UI...");this.mainView=new h({model:this.api,el:$("#"+this.dom_id)}).render();this.showMessage();switch(this.options.docExpansion){case"full":Docs.expandOperationsForResource("");break;case"list":Docs.collapseOperationsForResource("")}if(this.options.onComplete){this.options.onComplete(this.api,this)}return setTimeout(function(){return Docs.shebang()},400)};l.prototype.showMessage=function(n){if(n==null){n=""}$("#message-bar").removeClass("message-fail");$("#message-bar").addClass("message-success");return $("#message-bar").html(n)};l.prototype.onLoadFailure=function(n){var o;if(n==null){n=""}$("#message-bar").removeClass("message-success");$("#message-bar").addClass("message-fail");o=$("#message-bar").html(n);if(this.options.onFailure!=null){this.options.onFailure(n)}return o};return l})(Backbone.Router);window.SwaggerUi=a;b=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.events={"click #show-pet-store-icon":"showPetStore","click #show-wordnik-dev-icon":"showWordnikDev","click #explore":"showCustom","keyup #input_baseUrl":"showCustomOnKeyup","keyup #input_apiKey":"showCustomOnKeyup"};l.prototype.initialize=function(){};l.prototype.showPetStore=function(n){return this.trigger("update-swagger-ui",{discoveryUrl:"http://petstore.swagger.wordnik.com/api/api-docs.json",apiKey:"special-key"})};l.prototype.showWordnikDev=function(n){return this.trigger("update-swagger-ui",{discoveryUrl:"http://api.wordnik.com/v4/resources.json",apiKey:""})};l.prototype.showCustomOnKeyup=function(n){if(n.keyCode===13){return this.showCustom()}};l.prototype.showCustom=function(n){if(n!=null){n.preventDefault()}return this.trigger("update-swagger-ui",{discoveryUrl:$("#input_baseUrl").val(),apiKey:$("#input_apiKey").val()})};l.prototype.update=function(o,p,n){if(n==null){n=false}$("#input_baseUrl").val(o);$("#input_apiKey").val(p);if(n){return this.trigger("update-swagger-ui",{discoveryUrl:o,apiKey:p})}};return l})(Backbone.View);h=(function(l){d(m,l);function m(){return m.__super__.constructor.apply(this,arguments)}m.prototype.initialize=function(){};m.prototype.render=function(){var q,p,n,o;$(this.el).html(Handlebars.templates.main(this.model));o=this.model.apisArray;for(p=0,n=o.length;p<n;p++){q=o[p];this.addResource(q)}return this};m.prototype.addResource=function(o){var n;n=new j({model:o,tagName:"li",id:"resource_"+o.name,className:"resource"});return $("#resources").append(n.render().el)};m.prototype.clear=function(){return $(this.el).html("")};return m})(Backbone.View);j=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.initialize=function(){};l.prototype.render=function(){var o,q,n,p;$(this.el).html(Handlebars.templates.resource(this.model));this.number=0;p=this.model.operationsArray;for(q=0,n=p.length;q<n;q++){o=p[q];this.addOperation(o)}return this};l.prototype.addOperation=function(n){var o;n.number=this.number;o=new c({model:n,tagName:"li",className:"endpoint"});$(".endpoints",$(this.el)).append(o.render().el);return this.number++};return l})(Backbone.View);c=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.events={"submit .sandbox":"submitOperation","click .submit":"submitOperation","click .response_hider":"hideResponse","click .toggleOperation":"toggleOperationContent"};l.prototype.initialize=function(){};l.prototype.render=function(){var n,x,y,p,u,z,v,s,r,w,o,t,q;y=jQuery.inArray(this.model.httpMethod,this.model.supportedSubmitMethods())>=0;if(!y){this.model.isReadOnly=true}$(this.el).html(Handlebars.templates.operation(this.model));if(this.model.responseClassSignature&&this.model.responseClassSignature!=="string"){z={sampleJSON:this.model.responseSampleJSON,isParam:false,signature:this.model.responseClassSignature};u=new k({model:z,tagName:"div"});$(".model-signature",$(this.el)).append(u.render().el)}else{$(".model-signature",$(this.el)).html(this.model.responseClass)}n={isParam:false};if(this.model.supportedContentTypes){n.produces=this.model.supportedContentTypes}if(this.model.produces){n.produces=this.model.produces}x=new f({model:n});$(".content-type",$(this.el)).append(x.render().el);t=this.model.parameters;for(s=0,w=t.length;s<w;s++){p=t[s];this.addParameter(p)}q=this.model.errorResponses;for(r=0,o=q.length;r<o;r++){v=q[r];this.addStatusCode(v)}return this};l.prototype.addParameter=function(o){var n;n=new e({model:o,tagName:"tr",readOnly:this.model.isReadOnly});return $(".operation-params",$(this.el)).append(n.render().el)};l.prototype.addStatusCode=function(o){var n;n=new i({model:o,tagName:"tr"});return $(".operation-status",$(this.el)).append(n.render().el)};l.prototype.submitOperation=function(K){var F,L,E,v,q,A,P,J,Q,H,D,B,G,s,x,u,r,p,O,S,R,N,M,n,C,z,y,w,t,I=this;if(K!=null){K.preventDefault()}v=$(".sandbox",$(this.el));E=true;v.find("input.required").each(function(){var o=this;$(this).removeClass("error");if(jQuery.trim($(this).val())===""){$(this).addClass("error");$(this).wiggle({callback:function(){return $(o).focus()}});return E=false}});if(E){Q={};C=v.serializeArray();for(x=0,O=C.length;x<O;x++){H=C[x];if((H.value!=null)&&jQuery.trim(H.value).length>0){Q[H.name]=H.value}}P=v.children().find('input[type~="file"]').size()!==0;J=false;L="application/json";if(this.model.consumes&&this.model.consumes.length>0){L=this.model.consumes[0]}else{z=this.model.parameters;for(u=0,S=z.length;u<S;u++){H=z[u];if(H.paramType==="form"){J=true;L=false}}if(P){L=false}else{if(this.model.httpMethod.toLowerCase()==="post"&&J===false){L="application/json"}}}if(P){F=new FormData();y=this.model.parameters;for(r=0,R=y.length;r<R;r++){B=y[r];if((B.paramType==="body"||"form")&&B.name!=="file"&&B.name!=="File"&&(Q[B.name]!=null)){F.append(B.name,Q[B.name])}}$.each(v.children().find('input[type~="file"]'),function(o,T){return F.append($(T).attr("name"),T.files[0])});console.log(F)}else{if(J){F=new FormData();w=this.model.parameters;for(p=0,N=w.length;p<N;p++){B=w[p];if(Q[B.name]!=null){F.append(B.name,Q[B.name])}}}else{F=null;t=this.model.parameters;for(n=0,M=t.length;n<M;n++){B=t[n];if(B.paramType==="body"){F=Q[B.name]}}}}log("bodyParam = "+F);q=null;A=this.model.supportHeaderParams()?(q=this.model.getHeaderParams(Q),this.model.urlify(Q,false)):this.model.urlify(Q,true);log("submitting "+A);$(".request_url",$(this.el)).html("<pre>"+A+"</pre>");$(".response_throbber",$(this.el)).show();D={type:this.model.httpMethod,url:A,headers:q,data:F,contentType:L,dataType:"json",processData:false,error:function(T,U,o){return I.showErrorStatus(T,U,o)},success:function(o){return I.showResponse(o)},complete:function(o){return I.showCompleteStatus(o)}};G=$("td select[name=contentType]",$(this.el)).val();if(G){D.contentType=G}log("content type = "+D.contentType);if(!(D.data||(D.type==="GET"||D.type==="DELETE"))&&D.contentType===!"application/x-www-form-urlencoded"){D.contentType=false}log("content type is now = "+D.contentType);s=$(".content > .content-type > div > select[name=contentType]",$(this.el)).val();if(s){D.headers=D.headers!=null?D.headers:{};D.headers.accept=s}jQuery.ajax(D);return false}};l.prototype.hideResponse=function(n){if(n!=null){n.preventDefault()}$(".response",$(this.el)).slideUp();return $(".response_hider",$(this.el)).fadeOut()};l.prototype.showResponse=function(n){var o;o=JSON.stringify(n,null,"\t").replace(/\n/g,"<br>");return $(".response_body",$(this.el)).html(escape(o))};l.prototype.showErrorStatus=function(n){return this.showStatus(n)};l.prototype.showCompleteStatus=function(n){return this.showStatus(n)};l.prototype.formatXml=function(u){var q,t,o,v,A,w,p,n,y,z,s,r,x;n=/(>)(<)(\/*)/g;z=/[ ]*(.*)[ ]+\n/g;q=/(<.+>)(.+\n)/g;u=u.replace(n,"$1\n$2$3").replace(z,"$1\n").replace(q,"$1\n$2");p=0;t="";A=u.split("\n");o=0;v="other";y={"single->single":0,"single->closing":-1,"single->opening":0,"single->other":0,"closing->single":0,"closing->closing":-1,"closing->opening":0,"closing->other":0,"opening->single":1,"opening->closing":0,"opening->opening":1,"opening->other":1,"other->single":0,"other->closing":-1,"other->opening":0,"other->other":0};s=function(G){var C,B,E,I,F,D,H;D={single:Boolean(G.match(/<.+\/>/)),closing:Boolean(G.match(/<\/.+>/)),opening:Boolean(G.match(/<[^!?].*>/))};F=((function(){var J;J=[];for(E in D){H=D[E];if(H){J.push(E)}}return J})())[0];F=F===void 0?"other":F;C=v+"->"+F;v=F;I="";o+=y[C];I=((function(){var K,L,J;J=[];for(B=K=0,L=o;0<=L?K<L:K>L;B=0<=L?++K:--K){J.push(" ")}return J})()).join("");if(C==="opening->closing"){return t=t.substr(0,t.length-1)+G+"\n"}else{return t+=I+G+"\n"}};for(r=0,x=A.length;r<x;r++){w=A[r];s(w)}return t};l.prototype.showStatus=function(q){var p,r,o;try{p=$("<code />").text(JSON.stringify(JSON.parse(q.responseText),null,2));r=$('<pre class="json" />').append(p)}catch(n){p=$("<code />").text(this.formatXml(q.responseText));r=$('<pre class="xml" />').append(p)}o=r;$(".response_code",$(this.el)).html("<pre>"+q.status+"</pre>");$(".response_body",$(this.el)).html(o);$(".response_headers",$(this.el)).html("<pre>"+q.getAllResponseHeaders()+"</pre>");$(".response",$(this.el)).slideDown();$(".response_hider",$(this.el)).show();$(".response_throbber",$(this.el)).hide();return hljs.highlightBlock($(".response_body",$(this.el))[0])};l.prototype.toggleOperationContent=function(){var n;n=$("#"+Docs.escapeResourceName(this.model.resourceName)+"_"+this.model.nickname+"_"+this.model.httpMethod+"_"+this.model.number+"_content");if(n.is(":visible")){return Docs.collapseOperation(n)}else{return Docs.expandOperation(n)}};return l})(Backbone.View);i=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.initialize=function(){};l.prototype.render=function(){var n;n=this.template();$(this.el).html(n(this.model));return this};l.prototype.template=function(){return Handlebars.templates.status_code};return l})(Backbone.View);e=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.initialize=function(){};l.prototype.render=function(){var q,o,n,r,p;if(this.model.paramType==="body"){this.model.isBody=true}if(this.model.dataType==="file"){this.model.isFile=true}p=this.template();$(this.el).html(p(this.model));n={sampleJSON:this.model.sampleJSON,isParam:true,signature:this.model.signature};if(this.model.sampleJSON){r=new k({model:n,tagName:"div"});$(".model-signature",$(this.el)).append(r.render().el)}else{$(".model-signature",$(this.el)).html(this.model.signature)}q={isParam:false};if(this.model.supportedContentTypes){q.produces=this.model.supportedContentTypes}if(this.model.produces){q.produces=this.model.produces}o=new f({model:q});$(".content-type",$(this.el)).append(o.render().el);return this};l.prototype.template=function(){if(this.model.isList){return Handlebars.templates.param_list}else{if(this.options.readOnly){if(this.model.required){return Handlebars.templates.param_readonly_required}else{return Handlebars.templates.param_readonly}}else{if(this.model.required){return Handlebars.templates.param_required}else{return Handlebars.templates.param}}}};return l})(Backbone.View);k=(function(m){d(l,m);function l(){return l.__super__.constructor.apply(this,arguments)}l.prototype.events={"click a.description-link":"switchToDescription","click a.snippet-link":"switchToSnippet","mousedown .snippet":"snippetToTextArea"};l.prototype.initialize=function(){};l.prototype.render=function(){var n;n=this.template();$(this.el).html(n(this.model));this.switchToDescription();this.isParam=this.model.isParam;if(this.isParam){$(".notice",$(this.el)).text("Click to set as parameter value")}return this};l.prototype.template=function(){return Handlebars.templates.signature};l.prototype.switchToDescription=function(n){if(n!=null){n.preventDefault()}$(".snippet",$(this.el)).hide();$(".description",$(this.el)).show();$(".description-link",$(this.el)).addClass("selected");return $(".snippet-link",$(this.el)).removeClass("selected")};l.prototype.switchToSnippet=function(n){if(n!=null){n.preventDefault()}$(".description",$(this.el)).hide();$(".snippet",$(this.el)).show();$(".snippet-link",$(this.el)).addClass("selected");return $(".description-link",$(this.el)).removeClass("selected")};l.prototype.snippetToTextArea=function(n){var o;if(this.isParam){if(n!=null){n.preventDefault()}o=$("textarea",$(this.el.parentNode.parentNode.parentNode));if($.trim(o.val())===""){return o.val(this.model.sampleJSON)}}};return l})(Backbone.View);f=(function(l){d(m,l);function m(){return m.__super__.constructor.apply(this,arguments)}m.prototype.initialize=function(){};m.prototype.render=function(){var n;n=this.template();$(this.el).html(n(this.model));this.isParam=this.model.isParam;if(this.isParam){$("label[for=contentType]",$(this.el)).text("Parameter content type:")}else{$("label[for=contentType]",$(this.el)).text("Response Content Type")}return this};m.prototype.template=function(){return Handlebars.templates.content_type};return m})(Backbone.View)}).call(this); \ No newline at end of file diff --git a/tests/ServiceStack.WebHostApp/AppHost.cs b/tests/ServiceStack.WebHostApp/AppHost.cs deleted file mode 100644 index e8732355665..00000000000 --- a/tests/ServiceStack.WebHostApp/AppHost.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Funq; -using ServiceStack.CacheAccess; -using ServiceStack.CacheAccess.Providers; -using ServiceStack.ServiceInterface; -using ServiceStack.ServiceInterface.Auth; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Tests; - -namespace ServiceStack.WebHostApp -{ - public class AppHost - : AppHostBase - { - public AppHost() - : base("Validation Tests", typeof(SecuredService).Assembly) { } - - public override void Configure(Container container) - { - Plugins.Add(new AuthFeature(() => new CustomUserSession(), - new AuthProvider[] { - new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials - new BasicAuthProvider(), //Sign-in with Basic Auth - })); - - container.Register<ICacheClient>(new MemoryCacheClient()); - var userRep = new InMemoryAuthRepository(); - container.Register<IUserAuthRepository>(userRep); - - string hash; - string salt; - new SaltedHash().GetHashAndSaltString("test1", out hash, out salt); - - userRep.CreateUserAuth(new UserAuth { - Id = 1, - DisplayName = "DisplayName", - Email = "as@if.com", - UserName = "test1", - FirstName = "FirstName", - LastName = "LastName", - PasswordHash = hash, - Salt = salt, - }, "test1"); - } - } -} - diff --git a/tests/ServiceStack.WebHostApp/Default.aspx b/tests/ServiceStack.WebHostApp/Default.aspx deleted file mode 100644 index 4c6d57174c2..00000000000 --- a/tests/ServiceStack.WebHostApp/Default.aspx +++ /dev/null @@ -1,11 +0,0 @@ -<%@ Page Language="C#" Inherits="ServiceStack.WebHostApp.Default" %> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html> -<head runat="server"> - <title>Default</title> -</head> -<body> - <form id="form1" runat="server"> - </form> -</body> -</html> diff --git a/tests/ServiceStack.WebHostApp/Default.aspx.cs b/tests/ServiceStack.WebHostApp/Default.aspx.cs deleted file mode 100644 index c5d653f93c3..00000000000 --- a/tests/ServiceStack.WebHostApp/Default.aspx.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Web; -using System.Web.UI; - -namespace ServiceStack.WebHostApp -{ - public partial class Default : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - Response.Redirect("api/metadata"); - } - - } -} - diff --git a/tests/ServiceStack.WebHostApp/Default.aspx.designer.cs b/tests/ServiceStack.WebHostApp/Default.aspx.designer.cs deleted file mode 100644 index 009d3d75b5e..00000000000 --- a/tests/ServiceStack.WebHostApp/Default.aspx.designer.cs +++ /dev/null @@ -1,16 +0,0 @@ -// ------------------------------------------------------------------------------ -// <autogenerated> -// This code was generated by a tool. -// Mono Runtime Version: 4.0.30319.1 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// </autogenerated> -// ------------------------------------------------------------------------------ - -namespace ServiceStack.WebHostApp { - - - public partial class Default { - } -} diff --git a/tests/ServiceStack.WebHostApp/Global.asax b/tests/ServiceStack.WebHostApp/Global.asax deleted file mode 100644 index 984a0c62916..00000000000 --- a/tests/ServiceStack.WebHostApp/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Inherits="ServiceStack.WebHostApp.Global" %> diff --git a/tests/ServiceStack.WebHostApp/Global.asax.cs b/tests/ServiceStack.WebHostApp/Global.asax.cs deleted file mode 100644 index 1c009da5bca..00000000000 --- a/tests/ServiceStack.WebHostApp/Global.asax.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections; -using System.ComponentModel; -using System.Web; -using System.Web.SessionState; - -namespace ServiceStack.WebHostApp -{ - public class Global : System.Web.HttpApplication - { - - protected virtual void Application_Start (Object sender, EventArgs e) - { - var appHost= new AppHost(); - appHost.Init(); - } - - protected virtual void Session_Start (Object sender, EventArgs e) - { - } - - protected virtual void Application_BeginRequest (Object sender, EventArgs e) - { - } - - protected virtual void Application_EndRequest (Object sender, EventArgs e) - { - } - - protected virtual void Application_AuthenticateRequest (Object sender, EventArgs e) - { - } - - protected virtual void Application_Error (Object sender, EventArgs e) - { - } - - protected virtual void Session_End (Object sender, EventArgs e) - { - } - - protected virtual void Application_End (Object sender, EventArgs e) - { - } - } -} - diff --git a/tests/ServiceStack.WebHostApp/ServiceStack.WebHostApp.csproj b/tests/ServiceStack.WebHostApp/ServiceStack.WebHostApp.csproj deleted file mode 100644 index 8eef60a51a0..00000000000 --- a/tests/ServiceStack.WebHostApp/ServiceStack.WebHostApp.csproj +++ /dev/null @@ -1,136 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>10.0.0</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{BEF0AA4B-54FE-4EFC-988F-F96BD0779A33}</ProjectGuid> - <ProjectTypeGuids>{349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - <OutputType>Library</OutputType> - <RootNamespace>ServiceStack.WebHostApp</RootNamespace> - <AssemblyName>ServiceStack.WebHostApp</AssemblyName> - <UseIISExpress>false</UseIISExpress> - <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> - <FileUpgradeFlags> - </FileUpgradeFlags> - <OldToolsVersion>4.0</OldToolsVersion> - <UpgradeBackupLocation /> - <TargetFrameworkProfile /> - <IISExpressSSLPort /> - <IISExpressAnonymousAuthentication /> - <IISExpressWindowsAuthentication /> - <IISExpressUseClassicPipelineMode /> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>True</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>False</Optimize> - <OutputPath>bin</OutputPath> - <DefineConstants>DEBUG;</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>False</ConsolePause> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>none</DebugType> - <Optimize>True</Optimize> - <OutputPath>bin</OutputPath> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>False</ConsolePause> - </PropertyGroup> - <ItemGroup> - <Reference Include="System" /> - <Reference Include="System.Data.DataSetExtensions" /> - <Reference Include="System.Web" /> - <Reference Include="System.Web.ApplicationServices" /> - <Reference Include="System.Web.DynamicData" /> - <Reference Include="System.Web.Entity" /> - <Reference Include="System.Web.Extensions" /> - <Reference Include="System.Xml" /> - <Reference Include="System.Web.Services" /> - <Reference Include="ServiceStack.Redis"> - <HintPath>..\..\lib\ServiceStack.Redis.dll</HintPath> - </Reference> - <Reference Include="ServiceStack.Text"> - <HintPath>..\..\lib\ServiceStack.Text.dll</HintPath> - </Reference> - <Reference Include="System.Xml.Linq" /> - </ItemGroup> - <ItemGroup> - <Content Include="Global.asax" /> - <Content Include="web.config" /> - <Content Include="Default.aspx" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Global.asax.cs"> - <DependentUpon>Global.asax</DependentUpon> - </Compile> - <Compile Include="Default.aspx.cs"> - <DependentUpon>Default.aspx</DependentUpon> - <SubType>ASPXCodeBehind</SubType> - </Compile> - <Compile Include="Default.aspx.designer.cs"> - <DependentUpon>Default.aspx</DependentUpon> - </Compile> - <Compile Include="AppHost.cs" /> - </ItemGroup> - <PropertyGroup> - <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> - <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> - </PropertyGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" /> - <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" /> - <ProjectExtensions> - <MonoDevelop> - <Properties VerifyCodeBehindFields="True" VerifyCodeBehindEvents="True"> - <XspParameters Port="8080" Address="127.0.0.1" SslMode="None" SslProtocol="Default" KeyType="None" CertFile="" KeyFile="" PasswordOptions="None" Password="" Verbose="True" /> - </Properties> - </MonoDevelop> - <VisualStudio> - <FlavorProperties GUID="{349C5851-65DF-11DA-9384-00065B846F21}"> - <WebProjectProperties> - <UseIIS>False</UseIIS> - <AutoAssignPort>True</AutoAssignPort> - <DevelopmentServerPort>65323</DevelopmentServerPort> - <DevelopmentServerVPath>/</DevelopmentServerVPath> - <IISUrl> - </IISUrl> - <NTLMAuthentication>False</NTLMAuthentication> - <UseCustomServer>False</UseCustomServer> - <CustomServerUrl> - </CustomServerUrl> - <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> - </WebProjectProperties> - </FlavorProperties> - </VisualStudio> - </ProjectExtensions> - <ItemGroup> - <ProjectReference Include="..\ServiceStack.WebHost.Endpoints.Tests\ServiceStack.WebHost.Endpoints.Tests.csproj"> - <Project>{55C5C6DA-1834-4BA8-8D2F-19C091B6FC81}</Project> - <Name>ServiceStack.WebHost.Endpoints.Tests</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack\ServiceStack.csproj"> - <Project>{680A1709-25EB-4D52-A87F-EE03FFD94BAA}</Project> - <Name>ServiceStack</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.ServiceInterface\ServiceStack.ServiceInterface.csproj"> - <Project>{5A315F92-80D2-4C60-A5A4-22E027AC7E7E}</Project> - <Name>ServiceStack.ServiceInterface</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Interfaces\ServiceStack.Interfaces.csproj"> - <Project>{42E1C8C0-A163-44CC-92B1-8F416F2C0B01}</Project> - <Name>ServiceStack.Interfaces</Name> - </ProjectReference> - <ProjectReference Include="..\..\src\ServiceStack.Common\ServiceStack.Common.csproj"> - <Project>{982416DB-C143-4028-A0C3-CF41892D18D3}</Project> - <Name>ServiceStack.Common</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <Folder Include="Views\" /> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/tests/ServiceStack.WebHostApp/web.config b/tests/ServiceStack.WebHostApp/web.config deleted file mode 100644 index 51c72d9e65b..00000000000 --- a/tests/ServiceStack.WebHostApp/web.config +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Standard IIS 7.0 Web.config as created by Visual Studio.NET --> -<!-- All changes from the default configuaration is prefixed by '[ServiceStack Specific]:' --> -<configuration> - <location path="api"> - <system.web> - <httpHandlers> - <add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" /> - </httpHandlers> - </system.web> - <system.webServer> - <handlers> - <add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" /> - </handlers> - </system.webServer> - </location> - <httpRuntime executionTimeout="900" maxRequestLength="4096" useFullyQualifiedRedirectUrl="false" minFreeThreads="8" minLocalRequestFreeThreads="4" appRequestQueueLimit="100" /> - <system.web> - <!-- - Set compilation debug="true" to insert debugging - symbols into the compiled page. Because this - affects performance, set this value to true only - during development. - --> - <compilation debug="true" targetFramework="4.0" /> - <!-- - The <authentication> section enables configuration - of the security authentication mode used by - ASP.NET to identify an incoming user. - --> - <authentication mode="Windows" /> - <!-- - The <customErrors> section enables configuration - of what to do if/when an unhandled error occurs - during the execution of a request. Specifically, - it enables developers to configure html error pages - to be displayed in place of a error stack trace. - - <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm"> - <error statusCode="403" redirect="NoAccess.htm" /> - <error statusCode="404" redirect="FileNotFound.htm" /> - </customErrors> - --> - <httpHandlers> - <!-- ServiceStack: Required for MONO --> - <add path="api*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" /> - </httpHandlers> - <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" /> - </system.web> - <!-- - The system.webServer section is required for running ASP.NET AJAX under Internet - Information Services 7.0. It is not necessary for previous version of IIS. - --> - <system.webServer> - <validation validateIntegratedModeConfiguration="false" /> - <handlers> - <!-- ServiceStack: Only required for IIS 7.0 --> - <!--<add name="ServiceStack.Factory" path="servicestack" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true"/>--> - </handlers> - </system.webServer> - <runtime> - <assemblyBinding appliesTo="v2.0.50727" xmlns="urn:schemas-microsoft-com:asm.v1"> - <dependentAssembly> - <assemblyIdentity name="protobuf-net" publicKeyToken="257b51d87d2e4d67" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-2.0.0.640" newVersion="2.0.0.640" /> - </dependentAssembly> - </assemblyBinding> - </runtime> - <appSettings /> - <connectionStrings /> -</configuration> \ No newline at end of file